Commit 813fd08b authored by baiyinhao's avatar baiyinhao

新增shell开发页面

parent 150a4442
......@@ -692,6 +692,30 @@ export const sqlExecuteRoute: AppRouteRecordRaw = {
},
],
};
/**shell开发*/
export const shellExecuteRoute: AppRouteRecordRaw = {
path: '/scriptDevelopment/shellDevelopment/shellExecute',
name: 'shellExecute',
component: LAYOUT,
meta: {
title: 'Shell开发',
icon: '',
hidden: true,
currentActiveMenu: '/scriptDevelopment/shellDevelopment/shellExecute',
},
children: [
{
path: 'shellExecute',
name: 'ShellExecute',
component: () =>
import('@/views/scriptDevelopment/shellDevelopment/shellExecute/shellExecute.vue'),
meta: {
title: 'Shell执行',
icon: '',
},
},
],
};
/**数据服务*/
export const serviceDevelopmentRoute: AppRouteRecordRaw = {
......@@ -846,6 +870,7 @@ export const basicRoutes = [
serviceDevelopmentRoute,
RootRoute,
sqlExecuteRoute,
shellExecuteRoute,
SyncMaintenanceRoute,
...mainOutRoutes,
REDIRECT_ROUTE,
......
<template>
<div class="m-5 mr-0 overflow-hidden bg-white">
<BasicTree
title=""
ref="treeRef"
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto"
:defaultExpandAll="true"
:treeData="treeData"
:fieldNames="{ key: 'businessId', title: 'workSpaceName' }"
@select="handleSelect"
:actionList="actionList"
/>
</div>
</template>
<script lang="ts" setup>
import { h, nextTick, onMounted, ref, unref } from 'vue';
import { BasicTree, TreeActionType, TreeItem } from '@/components/Tree';
import { Nullable } from '@vben/types';
import { DataTreeData } from './sqlDevelopmentData';
import { ReloadOutlined } from '@ant-design/icons-vue';
import { useMessage } from '@/hooks/web/useMessage';
defineOptions({ name: 'DataSourceTree' });
const emit = defineEmits(['select']);
const { createMessage } = useMessage();
const treeData = ref<TreeItem[]>([]);
const treeRef = ref<Nullable<TreeActionType>>(null);
function getTree() {
const tree = unref(treeRef);
if (!tree) {
throw new Error('tree is null!');
}
return tree;
}
async function fetch() {
const data = DataTreeData;
treeData.value = handleTree(data, 'businessId', undefined, undefined, undefined);
await nextTick(() => {
getTree().expandAll(true);
});
}
function handleTree(data, id, parentId, children, rootId) {
id = id || 'id';
parentId = parentId || 'parentId';
children = children || 'children';
rootId =
rootId ||
Math.min.apply(
Math,
data.map((item) => {
return item[parentId];
}),
) ||
0;
// 对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data));
// 循环所有项
const treeData = cloneData.filter((father) => {
const branchArr = cloneData.filter((child) => {
// 返回每一项的子级数组
return father[id] === child[parentId];
});
branchArr.length > 0 ? (father.children = branchArr) : '';
// 返回第一层
return father[parentId] === rootId;
});
return treeData !== '' ? treeData : data;
}
function handleSelect() {
const keys = getTree().getSelectedKeys();
const node = getTree().getSelectedNode(keys[0]);
// console.log('node', node);
emit('select', node);
}
// 树的操作列表
const actionList = [
{
render: () => {
return h(ReloadOutlined, {
class: 'ml-2',
onClick: () => {
refresh();
},
});
},
},
];
const refresh = () => {
createMessage.success('刷新成功');
};
onMounted(() => {
fetch();
});
</script>
<template>
<div class="m-5 mr-0 overflow-hidden bg-white">
<BasicTree
title=""
ref="treeRef"
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto"
:defaultExpandAll="true"
:treeData="treeData"
:fieldNames="{ key: 'businessId', title: 'workSpaceName' }"
@select="handleSelect"
:actionList="actionList"
/>
</div>
</template>
<script lang="ts" setup>
import { h, nextTick, onMounted, ref, unref } from 'vue';
import { BasicTree, TreeActionType, TreeItem } from '@/components/Tree';
import { Nullable } from '@vben/types';
import { GroupTreeData } from './sqlDevelopmentData';
import { ReloadOutlined } from '@ant-design/icons-vue';
import { useMessage } from '@/hooks/web/useMessage';
defineOptions({ name: 'DataSourceTree' });
const emit = defineEmits(['select']);
const { createMessage } = useMessage();
const treeData = ref<TreeItem[]>([]);
const treeRef = ref<Nullable<TreeActionType>>(null);
function getTree() {
const tree = unref(treeRef);
if (!tree) {
throw new Error('tree is null!');
}
return tree;
}
async function fetch() {
const data = GroupTreeData;
treeData.value = handleTree(data, 'businessId', undefined, undefined, undefined);
await nextTick(() => {
getTree().expandAll(true);
});
}
function handleTree(data, id, parentId, children, rootId) {
id = id || 'id';
parentId = parentId || 'parentId';
children = children || 'children';
rootId =
rootId ||
Math.min.apply(
Math,
data.map((item) => {
return item[parentId];
}),
) ||
0;
// 对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data));
// 循环所有项
const treeData = cloneData.filter((father) => {
const branchArr = cloneData.filter((child) => {
// 返回每一项的子级数组
return father[id] === child[parentId];
});
branchArr.length > 0 ? (father.children = branchArr) : '';
// 返回第一层
return father[parentId] === rootId;
});
return treeData !== '' ? treeData : data;
}
function handleSelect() {
const keys = getTree().getSelectedKeys();
const node = getTree().getSelectedNode(keys[0]);
// console.log('node', node);
emit('select', node);
}
// 树的操作列表
const actionList = [
{
render: () => {
return h(ReloadOutlined, {
class: 'ml-2',
onClick: () => {
refresh();
},
});
},
},
];
const refresh = () => {
createMessage.success('刷新成功');
};
onMounted(() => {
fetch();
});
</script>
import { BasicColumn, FormSchema } from '@/components/Table';
import { DescItem } from '@/components/Description';
export const columns: BasicColumn[] = [
{
title: '名称',
dataIndex: 'workSpaceName',
width: 150,
},
{
title: '拥有者',
dataIndex: 'createBy',
width: 120,
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 120,
sorter: true,
},
{
title: '更新时间',
dataIndex: 'updateTime',
width: 120,
sorter: true,
},
];
export const previewColumns: BasicColumn[] = [
{
title: 'id',
dataIndex: 'id',
width: 150,
},
{
title: 'em_name',
dataIndex: 'emName',
width: 120,
},
{
title: 'em_age',
dataIndex: 'emAge',
width: 120,
},
{
title: 'em_idcard',
dataIndex: 'emIdcard',
width: 120,
},
{
title: 'em_tel',
dataIndex: 'emTel',
width: 120,
},
{
title: 'em_typework',
dataIndex: 'emTypework',
width: 120,
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'name',
label: ' ',
component: 'Input',
colProps: { span: 8 },
componentProps: {
placeholder: '输入关键字搜索',
},
},
];
export const formSchema: FormSchema[] = [
{
field: 'name',
label: '数据连接',
component: 'Select',
colProps: { span: 8 },
componentProps: {
options: [
{
label: 'mysql',
value: 'mysql',
},
{
label: 'oracle',
value: 'oracle',
},
{
label: 'sqlserver',
value: 'sqlserver',
},
],
},
defaultValue: 'mysql',
},
];
export const recommendColumns: BasicColumn[] = [
{
title: '参数名',
dataIndex: 'name',
editable: true,
edit: true,
width: 120,
},
{
title: '默认值',
dataIndex: 'defaultValue',
editable: true,
edit: true,
width: 120,
},
];
export const recordColumns: BasicColumn[] = [
{
title: '执行人',
dataIndex: 'user',
width: 120,
},
{
title: '执行时间',
dataIndex: 'date',
width: 120,
},
{
title: '执行结果',
dataIndex: 'result',
width: 120,
},
{
title: '执行耗时',
dataIndex: 'cost',
width: 120,
},
{
title: '影响行数',
dataIndex: 'log',
width: 120,
},
];
export const refundSchema: DescItem[] = [
{
field: 'result',
label: '执行结果',
},
{
field: 'cost',
label: '执行耗时',
},
{
field: 'user',
label: '执行人',
},
{
field: 'date',
label: '执行时间',
},
{
field: 'log',
label: '影响行数',
},
];
export const partitionColumns: BasicColumn[] = [
{
title: 'name',
dataIndex: 'name',
width: 120,
},
{
title: 'partitionKey',
dataIndex: 'partitionKey',
width: 120,
},
{
title: 'partitionKeyType',
dataIndex: 'partitionKeyType',
width: 120,
},
{
title: 'partitionSize',
dataIndex: 'partitionSize',
width: 120,
},
];
export const resultViewSchema: FormSchema[] = [
{
field: 'name',
label: '图表名称',
component: 'Input',
colProps: { lg: 24, md: 24 },
},
{
field: 'type',
label: '图表类型',
component: 'Select',
componentProps: {
options: [{ label: '柱状图', value: '1' }],
},
colProps: { lg: 24, md: 24 },
required: true,
},
{
field: 'XData',
label: 'x轴',
component: 'Select',
componentProps: {
options: [
{ label: 'name', value: '1' },
{ label: 'partitionKey', value: '2' },
{ label: 'partitionKeyType', value: '3' },
{ label: 'partitionSize', value: '4' },
],
},
colProps: { lg: 24, md: 24 },
required: true,
},
{
field: 'YData',
label: 'y轴',
component: 'Select',
componentProps: {
mode: 'multiple',
options: [
{ label: 'name', value: '1' },
{ label: 'partitionKey', value: '2' },
{ label: 'partitionKeyType', value: '3' },
{ label: 'partitionSize', value: '4' },
],
},
colProps: { lg: 24, md: 24 },
required: true,
},
{
field: 'Sum',
label: '聚合方式',
component: 'Select',
componentProps: {
options: [{ label: 'SUM', value: '1' }],
},
colProps: { lg: 24, md: 24 },
required: true,
},
{
field: 'limit',
label: 'limit',
component: 'Input',
colProps: { lg: 24, md: 24 },
},
];
<template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
<div class="w-1/4 xl:w-1/5">
<DataTree @select="handleSelect" style="height: 50%" />
<GroupTree @select="handleGroupSelect" style="height: 50%" />
</div>
<BasicTable @register="registerTable" class="w-3/4 xl:w-4/5" :searchInfo="searchInfo" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, onMounted } from 'vue';
import { BasicTable, useTable } from '@/components/Table';
import { PageWrapper } from '@/components/Page';
import DataTree from './DataTree.vue';
import GroupTree from './GroupTree.vue';
import { DataTreeData } from './sqlDevelopmentData';
import { columns, searchFormSchema } from './data';
import { router } from '@/router';
defineOptions({ name: 'AccountManagement' });
const searchInfo = reactive<Recordable>({});
const [registerTable, { reload, getSearchInfo, getForm }] = useTable({
title: 'SQL文件',
api: async (params) => {
const response = {
pageNu: '1',
pageSize: '10',
pages: '1',
total: DataTreeData.length,
code: '',
message: '',
data: [],
};
let data = DataTreeData.filter((item) => item.parentId !== 0);
if (params.res !== undefined) {
if (params.res.parentId !== undefined) {
data = DataTreeData.filter((item) => item.parentId === params.res.businessId);
} else {
data = DataTreeData.filter((item) => item.parentId === 100);
}
} else {
data = DataTreeData.filter((item) => item.parentId === 100);
}
return { ...response, data: data };
},
columns,
showIndexColumn: false,
formConfig: {
labelWidth: 10,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
resetFunc: () => {
searchInfo.res = '';
},
},
useSearchForm: true,
showTableSetting: false,
bordered: true,
handleSearchInfoFn(info) {
return info;
},
});
/** 部门树的select*/
function handleSelect(workSpaceName = '') {
searchInfo.res = workSpaceName;
reload();
}
function handleGroupSelect() {
router.push({
path: '/scriptDevelopment/shellDevelopment/shellExecute/shellExecute',
});
}
onMounted(() => {});
</script>
<template>
<BasicModal
width="40%"
v-bind="$attrs"
@register="registerModal"
:title="getTitle"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
<div class="modalRow">
<div>可见范围</div>
<div class="right">
<div class="clearAll"> 清空 </div>
<div>
<a-button type="primary">添加工作组</a-button>
</div>
</div>
</div>
<div class="addDialogBG">
<div style="float: right">
<Icon icon="ant-design:delete-outlined" :size="25" :color="'#ED6F6F'" />
</div>
<TreeTwo class="w-1/4 xl:w-1/5" @select="handleSelect" />
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { BasicForm, useForm } from '@/components/Form';
import { formSchemaNewFolder } from './template.data';
import TreeTwo from './treeTwo.vue';
import { useMessage } from '@/hooks/web/useMessage';
import { treeDataList } from './mock';
defineOptions({ name: 'AccountModal' });
const emit = defineEmits(['success', 'register']);
const { createMessage } = useMessage();
const isUpdate = ref(true);
const rowId = ref('');
//获取接口数据并放在下拉框里(这里是打开了一个弹框)
//初始化表单
const [registerForm, { setFieldsValue, updateSchema, resetFields, validate }] = useForm({
labelWidth: 100,
baseColProps: { lg: 24, md: 24 },
schemas: formSchemaNewFolder,
showActionButtonGroup: false,
actionColOptions: {
span: 23,
},
});
//初始化弹框
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
// 通过id获取行详情信息
// 塞值
setFieldsValue({
...data.record,
});
}
updateSchema({
field: 'path',
componentProps: { treeData: treeDataList },
});
});
const getTitle = computed(() => (!unref(isUpdate) ? '新建文件夹' : '编辑文件夹'));
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
// TODO custom api
closeModal();
emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } });
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="scss" scoped>
.modalRow {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
.clearAll {
padding-right: 10px;
font-size: 16px;
}
.right {
display: flex;
align-items: center;
justify-content: space-between;
}
}
.addDialogBG {
width: 98%;
height: 400px;
margin: 10px;
padding: 20px;
border-radius: 10px;
background-color: #e8ecf7;
}
</style>
<template>
<BasicModal
width="55%"
v-bind="$attrs"
@register="registerModal"
:title="title"
@ok="handleSubmit"
>
<template #footer>
<a-button type="primary" @click="handleSubmit">关闭</a-button>
</template>
<BasicTable @register="registerTable" :searchInfo="searchInfo">
<template #toolbar>
<!-- 下载-->
<a-button type="primary" @click="handleDownload"
><Icon icon="bxs:download" :size="20"
/></a-button>
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { useMessage } from '@/hooks/web/useMessage';
import { BasicTable, useTable } from '@/components/Table';
import Icon from '@/components/Icon/Icon.vue';
import { previewData } from '../sqlDevelopmentData';
import { previewColumns } from '../data';
defineOptions({ name: 'KnowledgeModal' });
const emit = defineEmits(['success', 'register']);
const { createMessage } = useMessage();
const title = ref();
const searchInfo = reactive<Recordable>({});
const tableData = ref([]);
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
tableData.value = [];
await reload();
setModalProps({ confirmLoading: false });
title.value = data.title;
});
const [registerTable, { reload }] = useTable({
api: async () => {
const response = {
pageNu: '1',
pageSize: '10',
total: previewData.length,
data: previewData,
};
return { ...response };
},
rowKey: 'id',
rowSelection: true,
columns: previewColumns,
showIndexColumn: false,
pagination: false,
formConfig: {
labelWidth: 10,
autoSubmitOnEnter: true,
resetFunc: () => {
searchInfo.res = '';
},
},
useSearchForm: false,
showTableSetting: false,
bordered: true,
handleSearchInfoFn(info) {
return info;
},
});
function handleDownload() {
createMessage.success('下载成功');
}
async function handleSubmit() {
closeModal();
}
onMounted(() => {});
</script>
<template>
<BasicModal
width="50%"
v-bind="$attrs"
@register="registerModal"
:title="title"
@ok="handleSubmit"
>
<template #footer>
<a-button type="primary" @click="handleSubmit">关闭</a-button>
</template>
<BasicTable @register="registerTable">
<template #bodyCell="{ column }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
icon: 'uil:file-search-alt',
onClick: handleDetail.bind(null),
},
]"
/>
</template>
</template>
</BasicTable>
<recordDetailModal @register="registerDetailModal" />
</BasicModal>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { BasicModal, useModal, useModalInner } from '@/components/Modal';
import { BasicTable, TableAction, useTable } from '@/components/Table';
import { recordColumns } from '../data';
import { recordData } from '../sqlDevelopmentData';
import recordDetailModal from './recordDetailModal.vue';
defineOptions({ name: 'KnowledgeModal' });
const emit = defineEmits(['success', 'register']);
const title = ref();
const tableData = ref([]);
const [registerDetailModal, { openModal }] = useModal();
//初始化表单
const [registerTable, { reload }] = useTable({
api: async () => {
const response = {
pageNum: '1',
pageSize: '10',
pages: '1',
total: tableData.value.length,
code: '',
message: '',
data: [],
};
//过滤data中的数据,取出等于params.deptId的数据
var data = [];
data = tableData.value;
return { ...response, data: data };
},
pagination: false,
columns: recordColumns,
useSearchForm: false,
showTableSetting: false,
actionColumn: {
width: 100,
title: '操作',
dataIndex: 'action',
},
showIndexColumn: false,
});
//初始化弹框
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
await reload();
setModalProps({ confirmLoading: false });
title.value = data.title;
});
async function handleSubmit() {
closeModal();
}
function handleDetail() {
openModal(true, {
title: '执行记录详情',
});
}
onMounted(() => {
tableData.value = recordData;
});
</script>
import { data } from '@/views/demo/excel/data';
export const tableList: any[] = [
{
businessId: 1,
name: '指标导入',
des: '--------',
from: '指标汇总表',
creator: 'admin',
createDate: '2024-10-25 10:04:05',
updateDate: '2024-10-25 10:04:05',
qualityRule: 'grantee_type_1',
dataSource: 'mysql_1',
catalog: '-',
database: 'employees',
dataTable: 'departments',
fields: 'department_name',
qualityTemplate: '非空检查',
ruleGroup: 'bingtest',
qualityPassRate: '100',
},
{
businessId: 2,
name: '指标导入',
des: '--------',
from: '指标汇总表',
creator: 'admin',
createDate: '2024-10-25 10:04:05',
updateDate: '2024-10-25 10:04:05',
qualityRule: 'grantee_type_2',
dataSource: 'Trino-test',
catalog: 'jmx',
database: 'information_data',
dataTable: 'applicable_roles_table',
fields: 'grantee_type',
qualityTemplate: '主键唯一',
ruleGroup: 'bingtest',
qualityPassRate: '100',
},
{
businessId: 3,
name: '指标导入',
des: '--------',
from: '指标汇总表',
creator: 'admin',
createDate: '2024-10-25 10:04:05',
updateDate: '2024-10-25 10:04:05',
qualityRule: 'grantee_type_2',
dataSource: 'Trino-test',
catalog: 'jmx',
database: 'information_data',
dataTable: 'applicable_roles_table',
fields: 'grantee_type',
qualityTemplate: '主键唯一',
ruleGroup: 'Trinotest',
qualityPassRate: '100',
},
{
businessId: 4,
name: '指标导入',
des: '--------',
from: '指标汇总表',
creator: 'admin',
createDate: '2024-10-25 10:04:05',
updateDate: '2024-10-25 10:04:05',
qualityRule: 'grantee_type_2',
dataSource: 'Trino-test',
catalog: 'jmx',
database: 'information_data',
dataTable: 'applicable_roles_table',
fields: 'grantee_type',
qualityTemplate: '主键唯一',
ruleGroup: 'Trinotest',
qualityPassRate: '100',
},
];
export const treeDataList = [
{
label: '主体管理',
businessId: 1,
children: [
{
label: 'admin_个人工作区',
businessId: 2,
children: [
{ label: '个人工作区1', businessId: 6 },
{ label: '个人工作区2', businessId: 7 },
],
},
{ label: '共享工作区', businessId: 3 },
{ label: '商城工作区', businessId: 4 },
{ label: '指标工作区', businessId: 5 },
],
},
];
export const treeDataListTwo = [
{
label: '主体管理',
businessId: 1,
children: [
{
label: 'admin_个人工作区',
businessId: 2,
children: [
{ label: '个人工作区1', businessId: 6 },
{ label: '个人工作区2', businessId: 7 },
],
},
{ label: '共享工作区', businessId: 3 },
{ label: '商城工作区', businessId: 4 },
{ label: '指标工作区', businessId: 5 },
],
},
];
<template>
<BasicModal
width="30%"
v-bind="$attrs"
@register="registerModal"
:title="title"
@ok="handleSubmit"
>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="addProperty()">添加参数</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
color: 'error',
label: '删除',
popConfirm: {
title: '是否确认删除',
placement: 'left',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { useMessage } from '@/hooks/web/useMessage';
import { BasicTable, TableAction, useTable } from '@/components/Table';
import { recommendColumns } from '../data';
defineOptions({ name: 'KnowledgeModal' });
const emit = defineEmits(['success', 'register']);
const { createMessage } = useMessage();
const title = ref();
const n = ref(1000);
const tableData = ref([]);
//获取接口数据并放在下拉框里(这里是打开了一个弹框)
//初始化表单
const [registerTable, { reload }] = useTable({
api: async () => {
const response = {
pageNum: '1',
pageSize: '10',
pages: '1',
total: tableData.value.length,
code: '',
message: '',
data: [],
};
let data = [];
data = tableData.value;
return { ...response, data: data };
},
pagination: false,
columns: recommendColumns,
useSearchForm: false,
actionColumn: {
width: 150,
title: '操作',
dataIndex: 'action',
},
scroll: {
y: 300,
},
showTableSetting: false,
bordered: true,
showIndexColumn: false,
});
//初始化弹框
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
tableData.value = [];
await reload();
setModalProps({ confirmLoading: false });
title.value = data.title;
});
async function handleSubmit() {
closeModal();
createMessage.success('提交成功');
}
/**新增属性*/
function addProperty() {
const data = {
businessId: n.value + 1,
name: '',
defaultValue: '',
};
tableData.value.push(data);
n.value++;
reload();
}
/** 删除按钮*/
function handleDelete(record: Recordable) {
tableData.value.splice(
tableData.value.findIndex((item) => item.businessId === record.businessId),
1,
);
createMessage.success('删除成功!');
reload();
}
onMounted(() => {});
</script>
<template>
<BasicModal
width="50%"
v-bind="$attrs"
@register="registerModal"
:title="title"
@ok="handleSubmit"
>
<template #footer>
<a-button type="primary" @click="handleSubmit">关闭</a-button>
</template>
<Description
size="middle"
:bordered="false"
:column="3"
:data="refundData"
:schema="refundSchema"
/>
<CodeEditor v-model:value="jsonData" :mode="MODE.JSON" />
</BasicModal>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { jsonData, refundData } from '../sqlDevelopmentData';
import { CodeEditor, MODE } from '@/components/CodeEditor';
import { refundSchema } from '../data';
import Description from '@/components/Description/src/Description.vue';
defineOptions({ name: 'KnowledgeModal' });
const emit = defineEmits(['success', 'register']);
const title = ref();
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
title.value = data.title;
});
async function handleSubmit() {
closeModal();
}
onMounted(() => {});
</script>
<template>
<BasicModal
width="90%"
v-bind="$attrs"
@register="registerModal"
:title="title"
@ok="handleSubmit"
>
<template #footer>
<a-button type="primary" @click="handleSubmit">关闭</a-button>
</template>
<div style="display: flex">
<div class="w-2/5 xl:w-2/5">
<Description size="middle" title="运行语句" :bordered="false" />
<div :class="`${prefixCls}__content`">
<List>
<template v-for="item in cardList" :key="item.id">
<List.Item class="list" @click="handleData(item)">
<List.Item.Meta>
<template #title>
<Icon class="icon" v-if="item.icon" :icon="item.icon" :color="item.color" />
<span class="title">{{ item.title }}</span>
</template>
<template #description>
<div class="description">
{{ item.description }}
</div>
<div class="info">
<div><span>运行时间</span>{{ item.datetime }}</div>
</div>
<div class="progress">
<Progress :percent="item.percent" :color="item.color" status="active" />
</div>
</template>
</List.Item.Meta>
</List.Item>
</template>
</List>
</div>
</div>
<div class="w-3/5 xl:w-3/5">
<Description size="middle" title="执行结果" :bordered="false" />
<BasicTable @register="registerTable" v-if="tableShow">
<template #footer>
<a-button type="primary" style="margin-right: 5px" @click="handleDownload"
>保存结果</a-button
>
<a-button type="primary" style="margin-right: 5px" @click="handleView"
>可视化分析</a-button
>
</template>
</BasicTable>
</div>
</div>
<viewModal @register="registerViewModal" />
</BasicModal>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { BasicModal, useModal, useModalInner } from '@/components/Modal';
import { Progress, List } from 'ant-design-vue';
import { cardList, partitionData } from '../sqlDevelopmentData';
import Icon from '@/components/Icon/Icon.vue';
import { BasicTable, useTable } from '@/components/Table';
import { partitionColumns } from '../data';
import { Description } from '@/components/Description';
import { useMessage } from '@/hooks/web/useMessage';
import viewModal from './resultViewModal.vue';
const prefixCls = 'list-basic';
defineOptions({ name: 'KnowledgeModal' });
const emit = defineEmits(['success', 'register']);
const title = ref();
const tableShow = ref(true);
const { createMessage } = useMessage();
const [registerViewModal, { openModal: openViewModal }] = useModal();
//初始化弹框
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
title.value = data.title;
});
const [registerTable] = useTable({
dataSource: partitionData,
columns: partitionColumns,
pagination: false,
showIndexColumn: false,
scroll: { y: 300 },
});
function handleData(item) {
if (item.color === 'green') {
tableShow.value = true;
} else {
tableShow.value = false;
}
}
function handleDownload() {
createMessage.success('下载成功');
}
function handleView() {
openViewModal(true, {
title: '可视化分析',
});
}
async function handleSubmit() {
closeModal();
}
onMounted(() => {});
</script>
<style lang="less" scoped>
.list-basic {
&__top {
padding: 24px;
background-color: @component-background;
text-align: center;
&-col {
&:not(:last-child) {
border-right: 1px dashed @border-color-base;
}
div {
margin-bottom: 12px;
color: @text-color-base;
font-size: 14px;
line-height: 22px;
}
p {
margin: 0;
color: @text-color-base;
font-size: 24px;
line-height: 32px;
}
}
}
&__content {
margin-top: 12px;
padding: 24px;
background-color: @component-background;
.list {
position: relative;
}
.icon {
font-size: 20px !important;
margin-right: 10px;
margin-top: 10px;
}
.extra {
position: absolute;
top: 20px;
right: 15px;
color: @primary-color;
font-weight: normal;
cursor: pointer;
}
.description {
display: inline-block;
width: 40%;
}
.info {
display: inline-block;
width: 30%;
text-align: center;
div {
display: inline-block;
padding: 0 20px;
span {
display: block;
}
}
}
.progress {
display: inline-block;
width: 15%;
vertical-align: top;
}
}
}
</style>
<template>
<BasicModal
width="80%"
v-bind="$attrs"
@register="registerModal"
:title="title"
@ok="handleSubmit"
>
<template #footer>
<a-button type="primary" @click="handleSubmit">关闭</a-button>
</template>
<div class="flex">
<BasicForm @register="registerForm" class="w-1/5 xl:w-1/5">
<template #formFooter>
<a-button type="primary" @click="handleFormSubmit" style="margin-left: 100px"
>提交</a-button
>
</template>
</BasicForm>
<div class="w-4/5 xl:w-4/5">
<div class="charts-container1">
<div class="chart" id="chart"></div>
</div>
<a-button type="primary" @click="handleDownload" style="margin-left: 100px"
>下载图表</a-button
>
</div>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { useMessage } from '@/hooks/web/useMessage';
import { BasicForm, useForm } from '@/components/Form';
import { resultViewSchema } from '@/views/scriptDevelopment/sqlDevelopment/data';
import * as echarts from 'echarts';
import { chartData } from '@/views/scriptDevelopment/sqlDevelopment/sqlDevelopmentData';
defineOptions({ name: 'KnowledgeModal' });
const emit = defineEmits(['success', 'register']);
const { createMessage } = useMessage();
const title = ref();
//获取接口数据并放在下拉框里(这里是打开了一个弹框)
//初始化表单
const [registerForm, { resetFields }] = useForm({
labelWidth: 100,
baseColProps: { lg: 12, md: 24 },
schemas: resultViewSchema,
showActionButtonGroup: false,
actionColOptions: {
span: 23,
},
});
//初始化弹框
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
initCharts();
await resetFields();
setModalProps({ confirmLoading: false });
title.value = data.title;
});
function initCharts() {
// 获取图表容器
const chartContainer = document.getElementById('chart');
console.log('1111111', chartContainer);
// 初始化图表实例
const chartInstance = echarts.init(chartContainer);
chartInstance.setOption({
title: {
text: '柱状图',
},
tooltip: {},
xAxis: {
type: 'category',
data: chartData.map((item) => item.name),
axisLabel: {
interval: 0, // 强制显示所有标签
rotate: 30, // 旋转标签防止重叠
},
},
legend: {
orient: 'horizontal', // 图例项水平排列
left: 'left', // 图例放置于底部中心位置
top: 'center', // 图例放置于图表的底部
},
yAxis: {
type: 'value',
min: 0, // 设置 Y 轴的最小值
max: 8,
splitNumber: 0.5,
},
series: [
{
color: '#87b078',
name: 'id',
type: 'bar',
data: chartData.map((item) => item.id),
},
],
});
}
async function handleSubmit() {
closeModal();
}
async function handleFormSubmit() {
createMessage.success('提交成功');
}
async function handleDownload() {
createMessage.success('下载成功');
}
</script>
<style lang="scss" scoped>
.charts-container1 {
display: flex;
justify-content: space-between;
gap: 20px;
}
.chart {
width: 100%;
height: 350px;
background-color: white;
}
</style>
<template>
<PageWrapper
title="shell执行"
dense
contentFullHeight
fixedHeight
contentClass="flex"
@back="goBack"
>
<GroupTree @select="handleSelect" class="w-1/4 xl:w-1/5" />
<div class="w-3/4 xl:w-4/5" style="padding-top: 20px">
<BasicForm @register="registerForm">
<template #formFooter>
<!-- 新窗口运行-->
<a-button
type="primary"
style="margin-right: 10px; margin-left: 500px"
@click="handleExecute"
>
<Icon icon="si:play-forward-duotone" :size="20"
/></a-button>
<!-- 运行-->
<a-button type="primary" style="margin-right: 10px" @click="handleExecute"
><Icon icon="si:play-line" :size="20"
/></a-button>
<!-- 执行记录-->
<a-button type="primary" style="margin-right: 10px" @click="handleRecord"
><Icon icon="si:clock-alt-line" :size="20"
/></a-button>
<!-- 提交版本-->
<a-button type="primary" style="margin-right: 10px" @click="handleSubmit"
><Icon icon="majesticons:file-plus-line" :size="20"
/></a-button>
<!-- 版本管理-->
<a-button type="primary" style="margin-right: 10px" @click="handleSubmit"
><Icon icon="majesticons:file-line" :size="20"
/></a-button>
<!-- 参数配置-->
<a-button type="primary" style="margin-right: 10px" @click="handleOptions"
><Icon icon="majesticons:link-circle-line" :size="20"
/></a-button>
<!-- 格式化-->
<a-button type="primary" style="margin-right: 10px" @click="handleChange"
><Icon icon="gg:align-left" :size="20"
/></a-button>
<!-- 保存-->
<a-button type="primary" style="margin-right: 10px" @click="handleSubmit"
><Icon icon="majesticons:save-line" :size="20"
/></a-button>
<!-- 新建文件夹-->
<a-button type="primary" style="margin-right: 10px" @click="handleAddFolder"
><Icon icon="majesticons:save-line" :size="20"
/></a-button>
</template>
</BasicForm>
<CodeEditor v-model:value="jsonData" :mode="MODE.JSON" />
</div>
<optionsModal @register="registerModal" />
<resultModal @register="registerResultModal" />
<PreviewModal @register="registerPreviewModal" />
<RecordModal @register="registerRecordModal" />
<AddFolder @register="register" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue';
import { PageWrapper } from '@/components/Page';
import GroupTree from '../GroupTree.vue';
import { jsonData } from '../sqlDevelopmentData';
import { formSchema } from '../data';
import { useGo } from '@/hooks/web/usePage';
import { CodeEditor, MODE } from '@/components/CodeEditor';
import { BasicForm, useForm } from '@/components/Form';
import optionsModal from './optionsModal.vue';
import { useModal } from '@/components/Modal';
import resultModal from './resultModal.vue';
import PreviewModal from './dataPreviewModal.vue';
import { useMessage } from '@/hooks/web/useMessage';
import Icon from '@/components/Icon/Icon.vue';
import RecordModal from './executeRecordModal.vue';
import AddFolder from './addFolder.vue';
defineOptions({ name: 'AccountManagement' });
const { createMessage } = useMessage();
const go = useGo();
const [register, { openModal: openAddFolder }] = useModal();
const [registerModal, { openModal }] = useModal();
const [registerResultModal, { openModal: openResultModal }] = useModal();
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();
const [registerRecordModal, { openModal: openRecordModal }] = useModal();
const [registerForm] = useForm({
labelWidth: 100,
baseColProps: { lg: 6, md: 4 },
schemas: formSchema,
showActionButtonGroup: false,
});
/** 部门树的select*/
function handleSelect() {
openPreviewModal(true, {
title: '数据预览',
});
}
function handleOptions() {
openModal(true, {
title: '参数配置',
});
}
function handleExecute() {
openResultModal(true, {
title: '执行结果',
});
}
function handleRecord() {
openRecordModal(true, {
title: '执行记录',
});
}
function handleAddFolder() {
openAddFolder(true, {
title: '添加文件夹',
});
}
function handleSubmit() {
createMessage.success('保存成功');
}
function handleChange() {
createMessage.success('格式化成功');
}
// 页面左侧点击返回链接时的操作
function goBack() {
// 本例的效果时点击返回始终跳转到账号列表页,实际应用时可返回上一页
go('/scriptDevelopment/sqlDevelopment/index');
}
onMounted(() => {});
</script>
import { getAllRoleList } from '@/api/system/role/role';
import { BasicColumn, FormSchema } from '@/components/Table';
export const columns: BasicColumn[] = [
{
title: '名称',
dataIndex: 'name',
width: 120,
slots: { customRender: 'name' },
},
{
title: '数据源',
dataIndex: 'dataSource',
slots: { customRender: 'dataSource' },
width: 150,
},
{
title: '模板编号',
dataIndex: 'templateNumber',
width: 120,
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 150,
},
{
title: '更新时间',
dataIndex: 'updateTime',
width: 150,
},
{
title: '拥有者',
dataIndex: 'owner',
width: 100,
},
{
title: '权属工作组',
dataIndex: 'workgroup',
width: 120,
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'name',
label: ' ',
component: 'Input',
colProps: { span: 8 },
componentProps: {
placeholder: '输入关键字搜索',
},
},
];
/**移动*/
export const MoveFormSchema: any[] = [
{
field: 'taskId',
label: '路径',
component: 'TreeSelect',
colProps: { lg: 24, md: 24 },
componentProps: {
// border: 'none',
fieldNames: {
label: 'fileName',
value: 'businessId',
},
getPopupContainer: () => document.body,
},
required: true,
},
];
export const formSchemaNewFolder: any = [
{
field: 'path',
label: '路径',
component: 'TreeSelect',
rules: [
{
required: true,
message: '请选择上级菜单',
},
],
componentProps: {
fieldNames: {
label: 'label',
value: 'businessId',
},
getPopupContainer: () => document.body,
},
},
{
field: 'name',
label: '文件夹名称',
component: 'Input',
colProps: { span: 8 },
componentProps: {
placeholder: '输入文件夹名称',
},
},
{
field: 'fileType',
label: '权限模式',
component: 'RadioGroup',
defaultValue: '本级定义',
colProps: { span: 8 },
componentProps: {
options: [
{ label: '本级定义', value: '本级定义' },
{ label: '资源自定义', value: '资源自定义' },
],
placeholder: '输入描述',
},
},
{
field: 'group',
label: '权属工作组',
component: 'Select',
defaultValue: '默认工作组',
colProps: { span: 8 },
componentProps: {
placeholder: '输入描述',
options: [{ label: '默认工作组', value: '默认工作组' }],
},
},
];
export const formSchemaTemplate: any = [
{
field: 'path',
label: '路径',
component: 'TreeSelect',
rules: [
{
required: true,
message: '请选择上级菜单',
},
],
componentProps: {
fieldNames: {
label: 'label',
value: 'businessId',
},
getPopupContainer: () => document.body,
},
},
{
field: 'name',
label: '文件名称',
component: 'Input',
colProps: { span: 8 },
componentProps: {
placeholder: '输入文件夹名称',
},
required: true,
},
{
field: 'fileType',
label: '文件类型',
component: 'Input',
defaultValue: '质量模板',
colProps: { span: 8 },
componentProps: {
readonly: true,
style: {
border: 'none',
backgroundColor: 'transparent',
},
},
},
{
field: 'dataSource',
label: '支持数据源',
component: 'Select',
colProps: { span: 8 },
componentProps: {
options: [
{ label: 'INCEPTOR', value: 'INCEPTOR' },
{ label: 'IMPALA', value: 'IMPALA' },
{ label: 'MYSQL', value: 'MYSQL' },
],
},
required: true,
},
{
field: 'model',
label: '目录权属模式',
component: 'RadioGroup',
defaultValue: '本级定义',
colProps: { span: 8 },
componentProps: {
options: [
{ label: '本级定义', value: '本级定义' },
{ label: '资源自定义', value: '资源自定义' },
],
},
},
{
field: 'group',
label: '权属工作组',
component: 'Select',
defaultValue: '默认工作组',
colProps: { span: 8 },
componentProps: {
placeholder: '输入描述',
options: [{ label: '默认工作组', value: '默认工作组' }],
},
},
];
export const importFormSchema: any[] = [
{
field: 'fileMethods',
label: '导入文件选择',
slot: 'fileMethods',
colProps: { lg: 24, md: 24, offset: 3 },
},
{
field: 'fileRename',
label: '文件重名',
component: 'RadioGroup',
required: true,
colProps: { lg: 24, md: 24, offset: 3 },
componentProps: {
options: [
{ label: '全部放弃', value: '1' },
{ label: '全部替换', value: '2' },
{ label: '自动重命名', value: '3' },
],
},
},
];
<template>
<div class="m-4 mr-0 overflow-hidden bg-white">
<BasicTree
title="工作组"
ref="treeRef"
toolbar
search
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto"
:clickRowToExpand="true"
:checkable="true"
:defaultExpandAll="true"
:treeData="treeData"
:fieldNames="{ key: 'businessId', title: 'label' }"
@select="handleSelect"
/>
</div>
</template>
<script lang="ts" setup>
import { nextTick, onMounted, ref, unref } from 'vue';
import { BasicTree, TreeActionType, TreeItem } from '@/components/Tree';
import { getDeptList } from '@/api/system/dept/dept';
import { Nullable } from '@vben/types';
import { treeDataListTwo } from './mock';
defineOptions({ name: 'DeptTree' });
const emit = defineEmits(['select']);
const treeData = ref<TreeItem[]>([]);
const treeRef = ref<Nullable<TreeActionType>>(null);
async function fetch() {
treeData.value = treeDataListTwo;
await nextTick(() => {
getTree().expandAll(true);
});
}
function getTree() {
const tree = unref(treeRef);
if (!tree) {
throw new Error('tree is null!');
}
return tree;
}
function handleSelect(keys) {
emit('select', keys[0]);
}
onMounted(() => {
fetch();
});
</script>
<style lang="scss" scoped>
.bg-white {
width: 97%;
}
::v-deep(.vben-tree) {
background-color: #e8ecf7 !important;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment