Commit a40c40a2810c5907a90906cca1a2fdfda5cfd992

Authored by 严涛
1 parent ac57eaaa

设备类型

  1 +import { defHttp } from '/@/utils/http/axios';
  2 +import { omit } from 'lodash-es';
\ No newline at end of file
... ...
  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 +};
... ...
  1 +export default {
  2 + positionListText: '设备存放位置列表',
  3 + positionName: '存放位置',
  4 + status: '状态',
  5 + remark: '备注',
  6 + creator: '创建人',
  7 + createTime: '创建时间',
  8 +};
... ...
  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>
... ...
  1 +import TypeDrawer from './TypeDrawer.vue';
  2 +
  3 +export { TypeDrawer };
... ...
  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 +];
... ...
  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 +];
... ...
  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>
... ...
... ... @@ -39,7 +39,7 @@ export const formSchema: BFormSchema[] = [
39 39 },
40 40 {
41 41 field: 'notes',
42   - label: t('equipment.ledger.description'),
  42 + label: t('archive.type.remark'),
43 43 component: 'InputTextArea',
44 44 colProps: { span: 24 },
45 45 componentProps: {
... ...