Browse Source

feat: 分组管理

main
xuziqiang 6 months ago
parent
commit
4614c8699f
  1. 289
      hx-ai-intelligent/src/view/equipmentManage/group/config.ts
  2. 96
      hx-ai-intelligent/src/view/equipmentManage/group/edit.vue
  3. 116
      hx-ai-intelligent/src/view/equipmentManage/group/editFormula.vue
  4. 145
      hx-ai-intelligent/src/view/equipmentManage/group/editGroup.vue
  5. 0
      hx-ai-intelligent/src/view/equipmentManage/group/groupEdit.vue
  6. 18
      hx-ai-intelligent/src/view/equipmentManage/group/index.vue
  7. 33
      hx-ai-intelligent/src/view/equipmentManage/group/mock.json
  8. 11
      lib/component/drawer/drawer.vue
  9. 2
      lib/component/form/form/child-form.vue
  10. 3
      lib/component/form/form/form-item.vue
  11. 4
      lib/component/form/form/form.d.ts
  12. 4
      lib/component/table/table.vue
  13. 6
      lib/component/tree/tree-api.vue
  14. 2
      lib/saas/config/table.config.ts

289
hx-ai-intelligent/src/view/equipmentManage/group/config.ts

@ -41,169 +41,182 @@ const doWnload = (url) => {
}; };
const mockData = ref(data.listData); const mockData = ref(data.listData);
export const tableConfig = { export const tableConfig = (el, elGroup, elFormula) => {
title: '设备台账', return {
// api: '/carbon_emission/device/getDeviceList', title: '设备台账',
value: mockData.value, // api: '/carbon_emission/device/getDeviceList',
treeConfig: { value: mockData.value,
defaultExpandAll: true, treeConfig: {
api: () => { defaultExpandAll: true,
return Promise.resolve(data); api: () => {
}, return Promise.resolve(data);
},
rowSelection: () => {
return {
columnWidth: 30,
};
},
headerActions: [
{
label: '编辑',
name: 'groupEdit',
type: 'primary',
handle: (a, b) => {
console.log(a, b);
},
},
{
label: '批量删除',
name: 'groupTemDownload',
type: 'primary',
dynamicDisabled: (data: any) => {
return data.list.length === 0;
},
handle: () => {
mockData.value.splice(0, 2);
},
},
{
label: '批量导出',
name: 'groupExports',
type: 'primary',
dynamicDisabled: (data: any) => {
return data.list.length === 0;
},
extra: {
xlsxMap: tableKeyMap,
xlsxName: '分组信息YYYY-MM-DD',
},
},
{
label: '批量导入',
name: 'groupImport',
type: 'primary',
extra: {
// api: props.postImportApi, // 导入接口名
title: '设备信息', // 弹窗title
templateName: 'whiteListUser', // 所使用的文件名称
indexName: '设备id', // 匹配类型字段
message: [
{ label: '1、若必填项未填写,则不能进行导入操作' },
{ label: `2、当重复时,则更新数据。` },
{ label: '3、数据将从模版的第五行进行导入。' },
{ label: '4、文件导入勿超过5MB。' },
],
}, },
}, },
{ headerActions: [
label: '模板下载',
name: 'groupTemDownload',
type: 'primary',
handle: () => {
// http.get('/asset/file/whiteListUser.xlsx');
doWnload('/hx-ai-intelligent/asset/file/whiteListUser.xlsx');
},
},
{
label: '批量分组',
name: 'groupTemDownload',
type: 'primary',
},
{
label: '公式编辑',
name: 'groupTemDownload',
type: 'primary',
},
],
columns: tableKeyMap,
columnActions: {
title: '操作',
actions: [
{ {
label: '删除', label: '编辑',
name: 'FeedBackDetail', name: 'groupEdit',
dynamicParams: ['uuid', 'appealType'], type: 'primary',
confirm: true, handle: (a, b) => {
handle: () => { el.value.toggle();
mockData.value.splice(0, 1);
}, },
}, },
],
},
formConfig: {
schemas: [
{ {
field: 'name', label: '批量删除',
label: '设备名称', name: 'groupTemDownload',
component: 'NsInput', type: 'primary',
componentProps: { dynamicDisabled: (data: any) => {
placeholder: '请输入', return data.list.length === 0;
},
handle: () => {
mockData.value.splice(0, 2);
}, },
}, },
{ {
field: 'provider', label: '批量导出',
label: '设备厂商', name: 'groupExports',
component: 'NsInput', type: 'primary',
componentProps: { dynamicDisabled: (data: any) => {
placeholder: '请输入', return data.list.length === 0;
},
extra: {
xlsxMap: tableKeyMap,
xlsxName: '分组信息YYYY-MM-DD',
}, },
}, },
{ {
field: 'payWay', label: '批量导入',
label: '设备区域', name: 'groupImport',
component: 'NsSelect', type: 'primary',
componentProps: { extra: {
placeholder: '请选择', // api: props.postImportApi, // 导入接口名
options: [ title: '设备信息', // 弹窗title
{ templateName: 'whiteListUser', // 所使用的文件名称
label: '全部', indexName: '设备id', // 匹配类型字段
value: '', message: [
}, { label: '1、若必填项未填写,则不能进行导入操作' },
{ label: `2、当重复时,则更新数据。` },
{ label: '3、数据将从模版的第五行进行导入。' },
{ label: '4、文件导入勿超过5MB。' },
], ],
}, },
}, },
{ {
field: 'createTime', label: '模板下载',
label: '生产日期', name: 'groupTemDownload',
component: 'NsRangePicker', type: 'primary',
fieldMap: ['queryStartDate', 'queryEndDate'], handle: () => {
componentProps: { // http.get('/asset/file/whiteListUser.xlsx');
valueFormat: 'YYYY-MM-DD', doWnload('/hx-ai-intelligent/asset/file/whiteListUser.xlsx');
}, },
}, },
{ {
field: 'createTime1', label: '批量分组',
label: '采购日期', name: 'groupTemDownload',
component: 'NsRangePicker', type: 'primary',
fieldMap: ['queryStartDate', 'queryEndDate'], handle: () => {
componentProps: { elGroup.value.toggle();
valueFormat: 'YYYY-MM-DD',
}, },
}, },
{ {
field: 'createTime2', label: '公式编辑',
label: '启用日期', name: 'groupTemDownload',
component: 'NsRangePicker', type: 'primary',
fieldMap: ['queryStartDate', 'queryEndDate'], handle: () => {
componentProps: { elFormula.value.toggle();
valueFormat: 'YYYY-MM-DD',
}, },
}, },
], ],
columns: tableKeyMap,
columnActions: {
title: '操作',
actions: [
{
label: '删除',
name: 'FeedBackDetail',
dynamicParams: ['uuid', 'appealType'],
confirm: true,
handle: () => {
mockData.value.splice(0, 1);
},
},
],
},
formConfig: {
schemas: [
{
field: 'name',
label: '设备名称',
component: 'NsInput',
componentProps: {
placeholder: '请输入',
},
},
{
field: 'provider',
label: '设备厂商',
component: 'NsInput',
componentProps: {
placeholder: '请输入',
},
},
{
field: 'payWay',
label: '设备区域',
component: 'NsSelect',
componentProps: {
placeholder: '请选择',
options: [
{
label: '全部',
value: '',
},
],
},
},
{
field: 'createTime',
label: '生产日期',
component: 'NsRangePicker',
fieldMap: ['queryStartDate', 'queryEndDate'],
componentProps: {
valueFormat: 'YYYY-MM-DD',
},
},
{
field: 'createTime1',
label: '采购日期',
component: 'NsRangePicker',
fieldMap: ['queryStartDate', 'queryEndDate'],
componentProps: {
valueFormat: 'YYYY-MM-DD',
},
},
{
field: 'createTime2',
label: '启用日期',
component: 'NsRangePicker',
fieldMap: ['queryStartDate', 'queryEndDate'],
componentProps: {
valueFormat: 'YYYY-MM-DD',
},
},
],
},
// pagination: { pageSizeOptions: false },
rowKey: 'id',
};
};
export const treeConfig = {
defaultExpandAll: true,
defaultSelectedKeys: ['A008'],
resultField: 'insertData',
api: () => {
return Promise.resolve(data);
}, },
// pagination: { pageSizeOptions: false },
rowKey: 'id',
}; };

96
hx-ai-intelligent/src/view/equipmentManage/group/edit.vue

@ -0,0 +1,96 @@
<template>
<ns-drawer
v-model:visible="visible"
size="large"
class="custom-class"
title="编辑"
:ok="btnClick"
:cancel="() => (visible = false)"
placement="right">
<div class="drawerContainer">
<ns-tree-api v-bind="treeConfig" @select="treeSelect" />
<a-transfer
v-model:target-keys="targetKeys"
:data-source="mockData"
style="height: 100%; width: 66%"
:listStyle="listStyle"
show-search
:filter-option="filterOption"
:render="(item) => item.title" />
</div>
</ns-drawer>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { NsMessage } from '/nerv-lib/component';
import { treeConfig } from './config';
const visible = ref(false);
const mockData = ref([]);
const listStyle = {
height: '100%',
width: '100%',
};
const targetKeys = ref<string[]>([]);
const toggle = () => {
visible.value = !visible.value;
};
onMounted(() => {
getMock('上海公司');
});
const filterOption = (inputValue: string, option: MockData) => {
return option.description.indexOf(inputValue) > -1;
};
const btnClick = () => {
visible.value = false;
NsMessage.success('编辑成功');
};
function treeSelect(
selectedKeys: never[],
e: {
selected: boolean;
selectedNodes: { props: { dataRef: any } }[];
node: any;
event: any;
},
) {
console.log(selectedKeys, e);
const {
dataRef: { title },
} = e.node;
getMock(title);
}
const getMock = (company) => {
const keys = [];
const mData = [];
for (let i = 0; i < 60; i++) {
const data = {
key: i.toString(),
title: `A00${i + 1}总用电量(${company})`,
description: `description of content${i + 1}`,
chosen: Math.random() * 2 > 1,
};
if (data.chosen) {
keys.push(data.key);
}
mData.push(data);
}
mockData.value = mData;
targetKeys.value = keys;
};
defineExpose({
toggle,
});
</script>
<style scoped lang="less">
.drawerContainer {
height: 100%;
display: flex;
justify-content: space-between;
}
</style>

116
hx-ai-intelligent/src/view/equipmentManage/group/editFormula.vue

@ -0,0 +1,116 @@
<template>
<ns-drawer
v-model:visible="visible"
width="520"
title="公式编辑"
:ok="btnClick"
:cancel="() => (visible = false)"
placement="right">
<ns-form :schemas="schemas" :model="model" formLayout="vertical" />
</ns-drawer>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { NsMessage } from '/nerv-lib/component';
const visible = ref(false);
const model = ref({});
const toggle = () => {
visible.value = !visible.value;
};
const mockDataSource = ref([
{
groupName: '1号厂区',
},
{
groupName: '2号厂区',
},
{
groupName: '3号厂区',
},
]);
const schemas = [
{
field: 'basicInfo',
label: '',
displayFormItem: false,
class: 'ns-form-item-full',
component: 'NsChildForm',
componentProps: {
title: '公式编辑',
schemas: [
{
label: '',
field: 'formula',
component: 'NsTextarea',
defaultValue: '(A+B)*2',
style: { width: '450px' },
componentProps: {
placeholder: '请输入',
autosize: {
minRows: 6,
maxRows: 6,
},
},
},
],
},
},
{
field: 'list',
label: '',
displayFormItem: false,
class: 'ns-form-item-full',
component: 'NsChildForm',
componentProps: {
title: '分组列表',
schemas: [
{
label: '',
field: 'NsBasicTable',
component: 'NsBasicTable',
componentProps: {
disabled: true,
placeholder: '请输入',
dataSource: mockDataSource.value,
style: { width: '450px' },
pagination: false,
rowKey: (record) => record.groupName,
columns: [
{
title: '序号',
dataIndex: 'name',
customRender: ({ index }) => index + 1,
width: 80,
align: 'center',
},
{
title: '分组名称',
dataIndex: 'groupName',
align: 'center',
},
],
},
},
],
},
},
];
const btnClick = () => {
visible.value = false;
NsMessage.success('操作成功');
};
defineExpose({
toggle,
});
</script>
<style scoped lang="less">
.drawerContainer {
height: 100%;
display: flex;
justify-content: space-between;
}
</style>

145
hx-ai-intelligent/src/view/equipmentManage/group/editGroup.vue

@ -0,0 +1,145 @@
<template>
<ns-drawer
v-model:visible="visible"
width="520"
title="分组编辑"
:ok="btnClick"
:cancel="() => (visible = false)"
placement="right">
<ns-form :schemas="schemas" :model="model" formLayout="vertical" />
</ns-drawer>
</template>
<script lang="ts" setup>
import { createVNode, onMounted, ref, unref } from 'vue';
import { NsMessage } from '/nerv-lib/component';
import { DeleteOutlined } from '@ant-design/icons-vue';
const visible = ref(false);
const model = ref({});
const toggle = () => {
visible.value = !visible.value;
};
const deleteRow = (index) => {
console.log(index);
mockDataSource.value.splice(index, 1);
};
const addRow = () => {
console.log(model);
if (model.value?.groupName) mockDataSource.value.push(unref(model) as any);
};
const mockDataSource = ref([
{
groupName: '1号厂区',
},
{
groupName: '2号厂区',
},
{
groupName: '3号厂区',
},
]);
const schemas = [
{
field: 'basicInfo',
label: '',
displayFormItem: false,
class: 'ns-form-item-full',
component: 'NsChildForm',
componentProps: {
title: '分组信息',
schemas: [
{
label: '分组编号',
field: 'groupCode',
component: 'NsInput',
defaultValue: 'WDIFHSUNGNDOR',
componentProps: {
disabled: true,
placeholder: '请输入',
},
},
{
label: '分组名称',
field: 'groupName',
component: 'NsInput',
componentProps: {
placeholder: '请输入',
addonAfter: createVNode(
'div',
{ style: { cursor: 'pointer' }, onclick: addRow },
'新增',
),
},
rules: [{ required: true }],
},
],
},
},
{
field: 'list',
label: '',
displayFormItem: false,
class: 'ns-form-item-full',
component: 'NsChildForm',
componentProps: {
title: '分组列表',
schemas: [
{
label: '',
field: 'NsBasicTable',
component: 'NsBasicTable',
componentProps: {
disabled: true,
placeholder: '请输入',
dataSource: mockDataSource.value,
style: { width: '450px' },
rowSelection: { type: 'radio' },
pagination: false,
rowKey: (record) => record.groupName,
columns: [
{
title: '序号',
dataIndex: 'name',
customRender: ({ index }) => index + 1,
width: 80,
align: 'center',
},
{
title: '分组名称',
dataIndex: 'groupName',
align: 'center',
},
{
title: '删除',
dataIndex: 'delete',
width: 80,
align: 'center',
customRender: ({ index }) =>
createVNode(DeleteOutlined, {
style: { color: 'red', cursor: 'pointer' },
onClick: () => deleteRow(index),
}),
},
],
},
},
],
},
},
];
const btnClick = () => {
visible.value = false;
NsMessage.success('操作成功');
};
defineExpose({
toggle,
});
</script>
<style scoped lang="less">
.drawerContainer {
height: 100%;
display: flex;
justify-content: space-between;
}
</style>

0
hx-ai-intelligent/src/view/equipmentManage/group/groupEdit.vue

18
hx-ai-intelligent/src/view/equipmentManage/group/index.vue

@ -1,7 +1,21 @@
<template> <template>
<ns-view-list-table v-bind="tableConfig" /> <editDrawer ref="editDrawerRef" />
<editGroup ref="editGroupRef" />
<editFormula ref="editFormulaRef" />
<ns-view-list-table v-bind="config" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { tableConfig } from './config'; import { createVNode, onMounted, ref } from 'vue';
import { tableConfig, treeConfig } from './config';
import { useParams } from '/nerv-lib/use';
import editDrawer from './edit.vue';
import editGroup from './editGroup.vue';
import editFormula from './editFormula.vue';
const { getParams } = useParams();
const editDrawerRef = ref();
const editGroupRef = ref();
const editFormulaRef = ref();
const config = tableConfig(editDrawerRef, editGroupRef, editFormulaRef);
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>

33
hx-ai-intelligent/src/view/equipmentManage/group/mock.json

@ -39,6 +39,38 @@
] ]
} }
], ],
"insertData":[
{
"title": "北京公司",
"key": "A001"
},
{
"title": "广州公司",
"key": "A002"
},
{
"title": "南京公司",
"key": "A004"
},
{
"title": "上海公司",
"key": "A008",
"children": [
{
"title": "上海长宁",
"key": "A009"
},
{
"title": "上海徐汇",
"key": "A010"
},
{
"title": "上海浦东",
"key": "A011"
}
]
}
],
"listData":[ "listData":[
{ {
"id": "d4", "id": "d4",
@ -84,7 +116,6 @@
"devicePointList": null, "devicePointList": null,
"insertUser": null "insertUser": null
} }
] ]
} }

11
lib/component/drawer/drawer.vue

@ -6,22 +6,27 @@
<slot :name="item" v-bind="data || {}"></slot> <slot :name="item" v-bind="data || {}"></slot>
</template> </template>
<template #footer> <template #footer>
<a-button>取消</a-button> <a-space>
<a-button v-if="cancel" @click="cancel">取消</a-button>
<a-button type="primary" @click="ok">确定</a-button>
</a-space>
</template> </template>
</a-drawer> </a-drawer>
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, toRefs } from 'vue'; import { computed, defineComponent, getCurrentInstance, toRefs } from 'vue';
import { drawerProps } from 'ant-design-vue/es/drawer'; import { drawerProps } from 'ant-design-vue/es/drawer';
export default defineComponent({ export default defineComponent({
name: 'NsDrawer', name: 'NsDrawer',
props: { props: {
...drawerProps(), ...drawerProps(),
ok: Function,
cancel: Function,
}, },
setup(props, { attrs, emit, slots }) { setup(props, { attrs, emit, slots }) {
console.log(props, slots); console.log(props, getCurrentInstance());
const getBindValue = computed(() => ({ const getBindValue = computed(() => ({
...attrs, ...attrs,

2
lib/component/form/form/child-form.vue

@ -110,7 +110,7 @@
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
line-height: 24px; line-height: 24px;
padding: 32px 0 24px 0; padding: 16px 0;
} }
.ns-child-form-divider { .ns-child-form-divider {
margin: 8px 0 0 0; margin: 8px 0 0 0;

3
lib/component/form/form/form-item.vue

@ -99,7 +99,7 @@
const formItemProps = computed(() => { const formItemProps = computed(() => {
const { const {
schema: { field, rules, label, component, autoLink, formItemProps, extra }, schema: { field, rules, label, component, autoLink, formItemProps, extra, style },
} = props; } = props;
const tableComponent = ['nsTable']; const tableComponent = ['nsTable'];
let nsClass = ''; let nsClass = '';
@ -111,6 +111,7 @@
label: label, label: label,
autoLink: autoLink || true, autoLink: autoLink || true,
extra: extra, extra: extra,
style,
...formItemProps, ...formItemProps,
...validateRef.value, ...validateRef.value,
}; };

4
lib/component/form/form/form.d.ts

@ -1,5 +1,3 @@
import type { RuleObject } from 'ant-design-vue/es/form/interface'; import type { RuleObject } from 'ant-design-vue/es/form/interface';
declare global { declare global {
type Rule = RuleObject & { type Rule = RuleObject & {
@ -33,5 +31,7 @@ declare global {
class?: String; //添加额外样式 class?: String; //添加额外样式
autoSubmit: Boolean; //是否操作后提交表单 autoSubmit: Boolean; //是否操作后提交表单
format: Function; format: Function;
extra: string;
style: Object;
} }
} }

4
lib/component/table/table.vue

@ -332,7 +332,7 @@
tableState.selectedRows = selectedRows; tableState.selectedRows = selectedRows;
}, },
}, },
rowSelection, isFunction(rowSelection) ? rowSelection(tableState) : rowSelection,
); );
}); });
@ -392,6 +392,8 @@
} }
return total; return total;
} }
console.log('current', (current >= 0 ? current : 0) + props.pageFieldOffset);
return { return {
showQuickJumper: true, showQuickJumper: true,
showLessItems: true, showLessItems: true,

6
lib/component/tree/tree-api.vue

@ -1,5 +1,5 @@
<template> <template>
<ns-tree v-if="treeData.length" v-bind="getBindValue"> <ns-tree v-if="treeData?.length" v-bind="getBindValue" v-model:selectedKeys="selectedKeys">
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item"> <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
<slot :name="item" v-bind="data || {}"></slot> <slot :name="item" v-bind="data || {}"></slot>
</template> </template>
@ -20,6 +20,7 @@
resultField?: string; resultField?: string;
defaultExpandAll?: boolean; defaultExpandAll?: boolean;
blockNode?: boolean; blockNode?: boolean;
defaultSelectedKeys?: Array<string>;
} }
defineOptions({ defineOptions({
name: 'NsTreeApi', name: 'NsTreeApi',
@ -31,6 +32,7 @@
transform: (data) => data, transform: (data) => data,
}); });
const treeData = ref<TreeDataItem[]>([]); const treeData = ref<TreeDataItem[]>([]);
const selectedKeys = ref(props.defaultSelectedKeys || []);
const { httpRequest } = useApi(); const { httpRequest } = useApi();
const requestConfig: AxiosRequestConfig = { method: 'get' }; const requestConfig: AxiosRequestConfig = { method: 'get' };
const route = useRoute(); const route = useRoute();
@ -55,6 +57,8 @@
}).then((res) => { }).then((res) => {
let data = []; let data = [];
data = get(res, resultField); data = get(res, resultField);
console.log('sdfasfasf', res);
treeData.value = transform(data); treeData.value = transform(data);
}); });
}; };

2
lib/saas/config/table.config.ts

@ -5,7 +5,7 @@ export const tableConfig = {
listField: 'data.records', // 数据集合 listField: 'data.records', // 数据集合
totalField: 'data.total', // 数据总数 totalField: 'data.total', // 数据总数
pageFieldOffset: 0, //前端页码1开始,后端0 偏移量 1 pageFieldOffset: 1, //前端页码1开始,后端0 偏移量 1
pageSizeOptions: ['10', '20', '40'], // 分页设置种类 pageSizeOptions: ['10', '20', '40'], // 分页设置种类
defaultPageSize: 10, // 默认每页数量 defaultPageSize: 10, // 默认每页数量
paramsPageSizeField: 'pageSize', paramsPageSizeField: 'pageSize',

Loading…
Cancel
Save