Showing
12 changed files
with
610 additions
and
1 deletions
src/api/archive/ledger.ts
0 → 100644
src/api/archive/position.ts
0 → 100644
1 | +import { defHttp } from '/@/utils/http/axios'; | |
2 | +import { omit } from 'lodash-es'; | |
3 | + | |
4 | +/** | |
5 | + * 获取列表 | |
6 | + */ | |
7 | +export const getEquipmentPositionList = (params) => { | |
8 | + const { page, pageSize } = params; | |
9 | + const otherParams = omit(params, ['page', 'pageSize']); | |
10 | + return defHttp.post<any>({ | |
11 | + url: `/brain/position/pageData?page=${page}&pageSize=${pageSize}`, | |
12 | + params: otherParams, | |
13 | + }); | |
14 | +}; | |
15 | + | |
16 | +/** | |
17 | + * 新增 | |
18 | + */ | |
19 | +export const saveEquipmentPosition = (params) => { | |
20 | + return defHttp.post<any>({ | |
21 | + url: `/brain/position/save`, | |
22 | + params, | |
23 | + }); | |
24 | +}; | |
25 | + | |
26 | +/** | |
27 | + *详情 | |
28 | + */ | |
29 | +export const getEquipmentPositionDetail = (params) => { | |
30 | + return defHttp.get<any>({ | |
31 | + url: `/brain/position/detail`, | |
32 | + params, | |
33 | + }); | |
34 | +}; | |
35 | + | |
36 | +/** | |
37 | + *删除 | |
38 | + */ | |
39 | +export const deleteEquipmentPosition = (params) => { | |
40 | + return defHttp.delete<any>({ | |
41 | + url: `/brain/position`, | |
42 | + params, | |
43 | + }); | |
44 | +}; | |
45 | + | |
46 | +/** | |
47 | + *停用 启用 | |
48 | + */ | |
49 | +export const updateEquipmentPositionStatus = (params) => { | |
50 | + return defHttp.post<any>({ | |
51 | + url: `/brain/position/updateStatus`, | |
52 | + params, | |
53 | + }); | |
54 | +}; | ... | ... |
src/locales/lang/zh-CN/archive/ledger.ts
0 → 100644
src/locales/lang/zh-CN/archive/position.ts
0 → 100644
1 | +<template> | |
2 | + <BasicDrawer | |
3 | + destroyOnClose | |
4 | + v-bind="$attrs" | |
5 | + showFooter | |
6 | + width="35%" | |
7 | + :maskClosable="true" | |
8 | + :title="titleText" | |
9 | + @register="registerDrawer" | |
10 | + wrapClassName="report-drawer" | |
11 | + @ok="handleSubmit" | |
12 | + @close="handleClose" | |
13 | + > | |
14 | + <BasicForm @register="registerForm" /> | |
15 | + </BasicDrawer> | |
16 | +</template> | |
17 | +<script setup lang="ts"> | |
18 | + import { nextTick, reactive, ref } from 'vue'; | |
19 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
20 | + import { SchemaFiled } from '../../config/enum'; | |
21 | + import { BasicForm, useForm } from '/@/components/Form'; | |
22 | + import { formSchema } from '../../config/data'; | |
23 | + import { useHooks } from '/@/views/report/config/hooks/index.hooks'; | |
24 | + import { getEquipmentPositionDetail, saveEquipmentPosition } from '/@/api/archive/position'; | |
25 | + import { useThrottleFn } from '@vueuse/shared/index'; | |
26 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
27 | + import { useI18n } from '/@/hooks/web/useI18n'; | |
28 | + const { setDefaultTime, disableCustomWeekly, removeFields } = useHooks(); | |
29 | + const restData = reactive({ | |
30 | + data: {}, | |
31 | + }); | |
32 | + const { createMessage } = useMessage(); | |
33 | + const { t } = useI18n(); | |
34 | + | |
35 | + const emits = defineEmits(['success', 'register']); | |
36 | + const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({ | |
37 | + labelWidth: 140, | |
38 | + schemas: formSchema, | |
39 | + showActionButtonGroup: false, | |
40 | + fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]], | |
41 | + }); | |
42 | + | |
43 | + const titleText = ref(''); | |
44 | + const businessText = ref(''); | |
45 | + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { | |
46 | + try { | |
47 | + await nextTick(); | |
48 | + handleClose(); | |
49 | + businessText.value = data.text; | |
50 | + titleText.value = | |
51 | + data.text === 'add' | |
52 | + ? '创建存放位置' | |
53 | + : data.text === 'edit' | |
54 | + ? '编辑存放位置' | |
55 | + : '查看存放位置'; | |
56 | + setFieldsValue(setDefaultTime()); | |
57 | + updateSchema(disableCustomWeekly(0)); | |
58 | + if (businessText.value === 'add') return; | |
59 | + const rest = await getEquipmentPositionDetail({ id: data.record?.id }); | |
60 | + restData.data = rest ?? {}; | |
61 | + await setFieldsValue({ | |
62 | + ...restData.data, | |
63 | + }); | |
64 | + } finally { | |
65 | + setDrawerProps({ loading: false }); | |
66 | + } | |
67 | + }); | |
68 | + const handleClose = () => { | |
69 | + resetValue(); | |
70 | + }; | |
71 | + //重置表单 | |
72 | + const resetValue = () => { | |
73 | + resetFields(); | |
74 | + }; | |
75 | + | |
76 | + const handleSubmit = () => { | |
77 | + if (businessText.value === 'view') { | |
78 | + closeDrawer(); | |
79 | + handleClose(); | |
80 | + return; | |
81 | + } | |
82 | + useThrottle(); | |
83 | + }; | |
84 | + | |
85 | + const useThrottle = useThrottleFn(() => { | |
86 | + getValue(); | |
87 | + }, 2000); | |
88 | + | |
89 | + const getValue = async () => { | |
90 | + try { | |
91 | + setDrawerProps({ confirmLoading: true }); | |
92 | + const values = await validate(); | |
93 | + if (!values) return; | |
94 | + const data = { | |
95 | + ...values, | |
96 | + }; | |
97 | + removeFields.forEach((item) => { | |
98 | + Reflect.deleteProperty(data, item); | |
99 | + }); | |
100 | + businessText.value === 'add' | |
101 | + ? await saveEquipmentPosition(data) | |
102 | + : saveEquipmentPosition({ ...restData.data, ...data }); | |
103 | + createMessage.success( | |
104 | + t(businessText.value !== 'add' ? 'common.editSuccessText' : 'common.createSuccessText') | |
105 | + ); | |
106 | + closeDrawer(); | |
107 | + handleClose(); | |
108 | + setTimeout(() => { | |
109 | + emits('success'); | |
110 | + }, 500); | |
111 | + } finally { | |
112 | + setDrawerProps({ confirmLoading: false }); | |
113 | + } | |
114 | + }; | |
115 | +</script> | |
116 | +<style scoped> | |
117 | + .inputTitle::before { | |
118 | + display: inline-block; | |
119 | + margin-right: 4px; | |
120 | + color: #ff4d4f; | |
121 | + font-size: 14px; | |
122 | + font-family: SimSun, sans-serif; | |
123 | + line-height: 1; | |
124 | + content: '*'; | |
125 | + } | |
126 | +</style> | ... | ... |
src/views/archive/position/config/data.ts
0 → 100644
1 | +import { FormSchema as BFormSchema } from '../../../../components/Form'; | |
2 | +import { useI18n } from '/@/hooks/web/useI18n'; | |
3 | +const { t } = useI18n(); | |
4 | +const statusOptions = [ | |
5 | + { label: t('common.enableText'), value: 'ENABLE' }, | |
6 | + { label: t('common.stop'), value: 'STOP' }, | |
7 | +]; | |
8 | + | |
9 | +export const formSchema: BFormSchema[] = [ | |
10 | + { | |
11 | + field: 'position', | |
12 | + label: t('archive.position.positionName'), | |
13 | + component: 'Input', | |
14 | + colProps: { span: 24 }, | |
15 | + required: true, | |
16 | + componentProps: { | |
17 | + maxLength: 20, | |
18 | + }, | |
19 | + }, | |
20 | + { | |
21 | + field: 'status', | |
22 | + component: 'Select', | |
23 | + label: t('archive.position.status'), | |
24 | + required: true, | |
25 | + colProps: { span: 24 }, | |
26 | + componentProps: { | |
27 | + options: statusOptions, | |
28 | + }, | |
29 | + }, | |
30 | + { | |
31 | + field: 'notes', | |
32 | + label: t('archive.position.remark'), | |
33 | + component: 'InputTextArea', | |
34 | + colProps: { span: 24 }, | |
35 | + componentProps: { | |
36 | + maxLength: 200, | |
37 | + }, | |
38 | + }, | |
39 | +]; | ... | ... |
src/views/archive/position/config/enum.ts
0 → 100644
1 | +export enum SchemaFiled { | |
2 | + WAY = 'queryMode', | |
3 | + TIME_PERIOD = 'timePeriod', | |
4 | + KEYS = 'keys', | |
5 | + DATE_RANGE = 'dataRange', | |
6 | + START_TS = 'startTs', | |
7 | + END_TS = 'endTs', | |
8 | + INTERVAL = 'interval', | |
9 | + LIMIT = 'limit', | |
10 | + AGG = 'agg', | |
11 | + ORDER_BY = 'orderBy', | |
12 | + DATA_TYPE = 'dataType', | |
13 | +} | ... | ... |
1 | +import { BasicColumn } from '/@/components/Table'; | |
2 | +import { FormSchema } from '/@/components/Table'; | |
3 | +import { h } from 'vue'; | |
4 | +import { Tooltip } from 'ant-design-vue'; | |
5 | +import { handeleCopy } from '../../../device/profiles/step/topic'; | |
6 | +import { useI18n } from '/@/hooks/web/useI18n'; | |
7 | +import { Tag } from 'ant-design-vue'; | |
8 | +const { t } = useI18n(); | |
9 | + | |
10 | +export enum PositionListAuthEnum { | |
11 | + /** | |
12 | + * @description 新增 | |
13 | + */ | |
14 | + CREATE = 'api:yt:archive:position:post', | |
15 | + | |
16 | + /** | |
17 | + * @description 删除 | |
18 | + */ | |
19 | + DELETE = 'api:yt:archive:position:delete', | |
20 | + | |
21 | + /** | |
22 | + * @description 编辑 | |
23 | + */ | |
24 | + UPDATE = 'api:yt:archive:position:update', | |
25 | + | |
26 | + /** | |
27 | + * @description 启用 | |
28 | + */ | |
29 | + ENABLE = 'api:yt:archive:position:enable', | |
30 | + | |
31 | + /** | |
32 | + * @description 停用 | |
33 | + */ | |
34 | + STOP = 'api:yt:archive:position:stop', | |
35 | +} | |
36 | + | |
37 | +// 表格列数据 | |
38 | +export const columns: BasicColumn[] = [ | |
39 | + { | |
40 | + dataIndex: 'position', | |
41 | + title: t('archive.position.positionName'), | |
42 | + width: 210, | |
43 | + slots: { customRender: 'position', title: 'deviceTitle' }, | |
44 | + className: 'position-name-edge', | |
45 | + customRender: ({ record }) => { | |
46 | + return h('div', { class: 'py-3 px-3.5' }, [ | |
47 | + h( | |
48 | + 'div', | |
49 | + { | |
50 | + class: 'cursor-pointer text-blue-500 truncate', | |
51 | + onClick: () => { | |
52 | + handeleCopy(`${record.position}`); | |
53 | + }, | |
54 | + }, | |
55 | + h( | |
56 | + Tooltip, | |
57 | + { | |
58 | + placement: 'topLeft', | |
59 | + title: `${record.position}`, | |
60 | + }, | |
61 | + () => `${record.position}` | |
62 | + ) | |
63 | + ), | |
64 | + ]); | |
65 | + }, | |
66 | + }, | |
67 | + { | |
68 | + title: t('archive.position.status'), | |
69 | + dataIndex: 'status', | |
70 | + width: 110, | |
71 | + customRender: ({ record }) => { | |
72 | + const color = record?.status == 'ENABLE' ? 'blue' : 'red'; | |
73 | + const text = record.status == 'ENABLE' ? t('common.enableText') : t('common.stop'); | |
74 | + return h(Tag, { color: color }, () => text); | |
75 | + }, | |
76 | + }, | |
77 | + { | |
78 | + title: t('archive.position.remark'), | |
79 | + dataIndex: 'notes', | |
80 | + width: 120, | |
81 | + }, | |
82 | + { | |
83 | + title: t('archive.position.creator'), | |
84 | + dataIndex: 'creatorName', | |
85 | + width: 120, | |
86 | + }, | |
87 | + { | |
88 | + title: t('archive.position.createTime'), | |
89 | + dataIndex: 'createTime', | |
90 | + width: 120, | |
91 | + }, | |
92 | +]; | |
93 | + | |
94 | +// 查询字段 | |
95 | +export const searchFormSchema: FormSchema[] = [ | |
96 | + { | |
97 | + field: 'position', | |
98 | + label: t('archive.position.positionName'), | |
99 | + component: 'Input', | |
100 | + colProps: { span: 6 }, | |
101 | + componentProps: { | |
102 | + maxLength: 255, | |
103 | + }, | |
104 | + }, | |
105 | +]; | ... | ... |
src/views/archive/position/index.ts
0 → 100644
src/views/archive/position/index.vue
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <PageWrapper dense contentFullHeight contentClass="flex"> | |
4 | + <BasicTable | |
5 | + style="flex: auto" | |
6 | + @register="registerTable" | |
7 | + class="w-5/6 xl:w-4/5 position-table" | |
8 | + > | |
9 | + <template #toolbar> | |
10 | + <Authority :value="PositionListAuthEnum.CREATE"> | |
11 | + <a-button | |
12 | + type="primary" | |
13 | + @click="handleBussinessDrawer('add', null)" | |
14 | + v-if="authBtn(role)" | |
15 | + > | |
16 | + {{ t('common.createText') }} | |
17 | + </a-button> | |
18 | + </Authority> | |
19 | + <Authority :value="PositionListAuthEnum.DELETE"> | |
20 | + <Popconfirm :title="t('common.deleteConfirmText')" @click="handleDelete()"> | |
21 | + <a-button color="error" :disabled="!isExistOption"> | |
22 | + {{ t('common.batchDeleteText') }} | |
23 | + </a-button> | |
24 | + </Popconfirm> | |
25 | + </Authority> | |
26 | + <Authority :value="PositionListAuthEnum.ENABLE"> | |
27 | + <a-button | |
28 | + @click="handleChangeStatus('enable')" | |
29 | + v-if="authBtn(role)" | |
30 | + :disabled="!isExistOption" | |
31 | + > | |
32 | + {{ t('common.enableText') }} | |
33 | + </a-button> | |
34 | + </Authority> | |
35 | + <Authority :value="PositionListAuthEnum.STOP"> | |
36 | + <a-button | |
37 | + @click="handleChangeStatus('stop')" | |
38 | + v-if="authBtn(role)" | |
39 | + :disabled="!isExistOption" | |
40 | + > | |
41 | + {{ t('common.stop') }} | |
42 | + </a-button> | |
43 | + </Authority> | |
44 | + </template> | |
45 | + <template #action="{ record }"> | |
46 | + <TableAction | |
47 | + :actions="[ | |
48 | + // { | |
49 | + // label: t('common.viewText'), | |
50 | + // auth: 'api:yt:ledger:get', | |
51 | + // icon: 'ant-design:eye-outlined', | |
52 | + // onClick: handleBussinessDrawer.bind(null, 'view', record), | |
53 | + // }, | |
54 | + { | |
55 | + label: t('common.editText'), | |
56 | + auth: PositionListAuthEnum.UPDATE, | |
57 | + icon: 'clarity:note-edit-line', | |
58 | + onClick: handleBussinessDrawer.bind(null, 'edit', record), | |
59 | + }, | |
60 | + { | |
61 | + label: t('common.delText'), | |
62 | + icon: 'ant-design:delete-outlined', | |
63 | + auth: PositionListAuthEnum.DELETE, | |
64 | + color: 'error', | |
65 | + popConfirm: { | |
66 | + title: t('common.isDelete'), | |
67 | + confirm: handleDelete.bind(null, record), | |
68 | + }, | |
69 | + }, | |
70 | + { | |
71 | + label: t('common.stop'), | |
72 | + auth: PositionListAuthEnum.STOP, | |
73 | + icon: 'ant-design:check-circle-outlined', | |
74 | + onClick: handleChangeStatus.bind(null, 'stop', record), | |
75 | + ifShow: record.status === 'ENABLE', | |
76 | + }, | |
77 | + { | |
78 | + label: t('common.enableText'), | |
79 | + auth: PositionListAuthEnum.ENABLE, | |
80 | + icon: 'ant-design:close-circle-outlined', | |
81 | + ifShow: record.status === 'STOP', | |
82 | + onClick: handleChangeStatus.bind(null, 'enable', record), | |
83 | + }, | |
84 | + ]" | |
85 | + /> | |
86 | + </template> | |
87 | + </BasicTable> | |
88 | + <TypeDrawer @register="registerDrawer" @success="handleSuccess" @reload="handleSuccess" /> | |
89 | + </PageWrapper> | |
90 | + </div> | |
91 | +</template> | |
92 | +<script setup lang="ts"> | |
93 | + import { reactive } from 'vue'; | |
94 | + import { PageWrapper } from '/@/components/Page'; | |
95 | + import { TypeDrawer } from './components/modal/index'; | |
96 | + const searchInfo = reactive<Recordable>({}); | |
97 | + import { BasicTable, TableAction, useTable } from '/@/components/Table'; | |
98 | + import { | |
99 | + getEquipmentPositionList, | |
100 | + deleteEquipmentPosition, | |
101 | + updateEquipmentPositionStatus, | |
102 | + } from '/@/api/archive/position'; | |
103 | + import { columns, searchFormSchema, PositionListAuthEnum } from './config/position.data'; | |
104 | + import { useBatchOperation } from '/@/utils/useBatchOperation'; | |
105 | + import { useI18n } from '/@/hooks/web/useI18n'; | |
106 | + import { authBtn } from '/@/enums/roleEnum'; | |
107 | + import { Authority } from '/@/components/Authority'; | |
108 | + import { getAuthCache } from '/@/utils/auth'; | |
109 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
110 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
111 | + | |
112 | + import { useDrawer } from '/@/components/Drawer'; | |
113 | + | |
114 | + // 业务弹窗 | |
115 | + const [registerDrawer, { openDrawer }] = useDrawer(); | |
116 | + const { t } = useI18n(); | |
117 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | |
118 | + const role: string = userInfo.roles[0]; | |
119 | + | |
120 | + const { createMessage } = useMessage(); | |
121 | + | |
122 | + const [ | |
123 | + registerTable, | |
124 | + { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection }, | |
125 | + ] = useTable({ | |
126 | + title: t('archive.position.positionListText'), | |
127 | + api: getEquipmentPositionList, | |
128 | + columns, | |
129 | + beforeFetch: (params) => { | |
130 | + const { deviceProfileId } = params; | |
131 | + if (!deviceProfileId) return; | |
132 | + const obj = { | |
133 | + ...params, | |
134 | + ...{ | |
135 | + deviceProfileIds: deviceProfileId ? [deviceProfileId] : null, | |
136 | + }, | |
137 | + }; | |
138 | + delete obj.deviceProfileId; | |
139 | + return obj; | |
140 | + }, | |
141 | + formConfig: { | |
142 | + labelWidth: 140, | |
143 | + schemas: searchFormSchema, | |
144 | + }, | |
145 | + useSearchForm: true, | |
146 | + showTableSetting: true, | |
147 | + bordered: true, | |
148 | + showIndexColumn: false, | |
149 | + rowKey: 'id', | |
150 | + searchInfo: searchInfo, | |
151 | + clickToRowSelect: false, | |
152 | + rowClassName: (record) => ((record as any).alarmStatus ? 'device-alarm-badge' : ''), | |
153 | + rowSelection: { type: 'checkbox' }, | |
154 | + actionColumn: { | |
155 | + width: 200, | |
156 | + title: t('common.actionText'), | |
157 | + slots: { customRender: 'action' }, | |
158 | + fixed: 'right', | |
159 | + }, | |
160 | + }); | |
161 | + | |
162 | + const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys); | |
163 | + | |
164 | + // 业务弹窗 | |
165 | + const handleBussinessDrawer = (text, record) => { | |
166 | + const modalParams = { | |
167 | + text, | |
168 | + record, | |
169 | + }; | |
170 | + openDrawer(true, modalParams); | |
171 | + }; | |
172 | + | |
173 | + // 删除 | |
174 | + const handleDelete = async (record?: any) => { | |
175 | + // eslint-disable-next-line no-console | |
176 | + console.log(record, '这是一条临时调试用的日志'); | |
177 | + let ids: string[] = []; | |
178 | + if (record) { | |
179 | + ids = [record.id]; | |
180 | + } else { | |
181 | + ids = getSelectRowKeys(); | |
182 | + } | |
183 | + try { | |
184 | + setLoading(true); | |
185 | + await deleteEquipmentPosition({ ids }); | |
186 | + createMessage.success(t('common.deleteSuccessText')); | |
187 | + handleReload(); | |
188 | + } catch (error) { | |
189 | + throw error; | |
190 | + } finally { | |
191 | + setLoading(false); | |
192 | + } | |
193 | + }; | |
194 | + | |
195 | + // 启用 停用 | |
196 | + const handleChangeStatus = async (type: 'enable' | 'stop', record?: any) => { | |
197 | + let ids: string[] = []; | |
198 | + if (record) { | |
199 | + ids = [record?.id]; | |
200 | + } else { | |
201 | + ids = getSelectRowKeys(); | |
202 | + } | |
203 | + if (ids?.length) | |
204 | + try { | |
205 | + setLoading(true); | |
206 | + if (type === 'enable') { | |
207 | + await updateEquipmentPositionStatus({ ids, status: 'ENABLE' }); | |
208 | + } else { | |
209 | + await updateEquipmentPositionStatus({ ids, status: 'STOP' }); | |
210 | + } | |
211 | + createMessage.success(t('common.editSuccessText')); | |
212 | + handleReload(); | |
213 | + } catch (error) { | |
214 | + throw error; | |
215 | + } finally { | |
216 | + setLoading(false); | |
217 | + } | |
218 | + }; | |
219 | + | |
220 | + // 重置 | |
221 | + function handleReload() { | |
222 | + setSelectedRowKeys([]); | |
223 | + handleSuccess(); | |
224 | + } | |
225 | + | |
226 | + function handleSuccess() { | |
227 | + reload(); | |
228 | + } | |
229 | +</script> | |
230 | + | |
231 | +<style scoped lang="less"> | |
232 | + .position-table { | |
233 | + :deep(.ant-form-item-control-input-content) { | |
234 | + & > div > div { | |
235 | + width: 100%; | |
236 | + } | |
237 | + } | |
238 | + } | |
239 | +</style> | |
240 | + | |
241 | +<style lang="less"> | |
242 | + .position-status { | |
243 | + position: relative; | |
244 | + | |
245 | + .position-collect { | |
246 | + width: 0; | |
247 | + height: 0; | |
248 | + border-top: 30px solid #377dff; | |
249 | + border-right: 30px solid transparent; | |
250 | + } | |
251 | + } | |
252 | + | |
253 | + .position-name-edge { | |
254 | + width: 100%; | |
255 | + height: 100%; | |
256 | + padding: 0 !important; | |
257 | + position: relative; | |
258 | + } | |
259 | +</style> | ... | ... |