Commit f19a5cb30d61296fd8756d6fcd31ab39e755d5d7

Authored by 史婷婷
1 parent 1cfc0eb0

feat: 基础配置-班组管理-暂存(列表中中英文配置、查询&列表column&操作按钮显示、批量操作按钮显示、班组人员插槽写点击事件、新增-字段配置,还缺少其他的)

  1 +import {DeviceModel, DeviceQueryParam} from "/@/api/device/model/deviceModel";
  2 +import {omit} from "lodash-es";
  3 +import {defHttp} from "/@/utils/http/axios";
  4 +import {PaginationResult} from "/#/axios";
  5 +
  6 +enum DeviceManagerApi {
  7 + /**
  8 + * 设备URL
  9 + */
  10 + DEVICE_URL = '/device',
  11 +}
  12 +
  13 +
  14 +export const unitPage = (params: DeviceQueryParam) => {
  15 + const { page, pageSize } = params;
  16 + const otherParams = omit(params, ['page', 'pageSize']);
  17 + return defHttp.post<PaginationResult<DeviceModel>>({
  18 + url: `${DeviceManagerApi.DEVICE_URL}?page=${page}&pageSize=${pageSize}`,
  19 + params: otherParams,
  20 + });
  21 +};
\ No newline at end of file
... ...
  1 +export default {
  2 + unitCode: 'Team code',
  3 + unitName: 'Team name',
  4 + unitType: 'Team type',
  5 + unitMembers: 'Team members',
  6 + creator: 'Create members',
  7 + unitListText: 'Team management',
  8 + typeMaintenance: 'maintenance',
  9 + typeInspection: 'On-Site Inspection',
  10 + typeCheck: 'Spot check',
  11 + stop: 'stop using',
  12 + enable: 'go live',
  13 +};
... ...
... ... @@ -29,4 +29,5 @@ export default {
29 29 commandDeliveryText: 'Command delivery',
30 30 serviceText: 'Service',
31 31 dateRangeText: 'Date range',
  32 + directorName: 'person in charge',
32 33 };
... ...
  1 +export default {
  2 + unitCode: '班组编码',
  3 + unitName: '班组名称',
  4 + unitType: '班组类型',
  5 + unitMembers: '班组人员',
  6 + creator: '创建人',
  7 + unitListText: '班组管理',
  8 + typeMaintenance: '保养',
  9 + typeInspection: '巡检',
  10 + typeCheck: '点检',
  11 + stop: '停用',
  12 + enable: '启用',
  13 +};
... ...
  1 +<template>
  2 + <div class="stt">
  3 + <div>222</div>
  4 + <div>{{dialogMembersVisible}}</div>
  5 + </div>
  6 +</template>
  7 +
  8 +<script setup>
  9 +import { computed } from 'vue';
  10 +// 接收父组件传递的 props
  11 +const props = defineProps({
  12 + detailId: {
  13 + type: Object,
  14 + default: () => ({})
  15 + },
  16 + modelValue: { // v-model 控制显示
  17 + type: Boolean,
  18 + default: false
  19 + }
  20 +});
  21 +
  22 +// 更新 v-model 状态
  23 +const emit = defineEmits(['update:modelValue']);
  24 +const dialogMembersVisible = computed({
  25 + get: () => props.modelValue,
  26 + set: (value) => emit('update:modelValue', value)
  27 +});
  28 +</script>
\ No newline at end of file
... ...
  1 +<template>
  2 + 2
  3 + <BasicDrawer
  4 + destroyOnClose
  5 + v-bind="$attrs"
  6 + showFooter
  7 + width="35%"
  8 + :maskClosable="true"
  9 + :title="titleText"
  10 + @register="registerDrawer"
  11 + wrapClassName="report-drawer"
  12 + @ok="handleSubmit"
  13 + @close="handleClose"
  14 + >
  15 + <BasicForm @register="registerForm" />
  16 + </BasicDrawer>
  17 +</template>
  18 +<script setup lang="ts">
  19 + import { nextTick, reactive, ref } from 'vue';
  20 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  21 + import { SchemaFiled } from '../../config/enum';
  22 + import { BasicForm, useForm } from '/@/components/Form';
  23 + import { formSchema } from '../../config/data';
  24 + import { useHooks } from '/@/views/report/config/hooks/index.hooks';
  25 + // import { getEquipmentTypeDetail, saveEquipmentType } from '/@/api/archive/type';
  26 + import { useThrottleFn } from '@vueuse/shared/index';
  27 + import { useMessage } from '/@/hooks/web/useMessage';
  28 + import { useI18n } from '/@/hooks/web/useI18n';
  29 + const { setDefaultTime, disableCustomWeekly, removeFields } = useHooks();
  30 + const restData = reactive({
  31 + data: {},
  32 + });
  33 + const { createMessage } = useMessage();
  34 + const { t } = useI18n();
  35 +
  36 + const emits = defineEmits(['success', 'register']);
  37 + const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({
  38 + labelWidth: 140,
  39 + schemas: formSchema,
  40 + showActionButtonGroup: false,
  41 + fieldMapToTime: [[SchemaFiled.DATE_RANGE, [SchemaFiled.START_TS, SchemaFiled.END_TS]]],
  42 + });
  43 +
  44 + const titleText = ref('');
  45 + const businessText = ref('');
  46 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  47 + try {
  48 + await nextTick();
  49 + handleClose();
  50 + businessText.value = data.text;
  51 + titleText.value =
  52 + data.text === 'add'
  53 + ? '创建设备类型'
  54 + : data.text === 'edit'
  55 + ? '编辑设备类型'
  56 + : '查看设备类型';
  57 + setFieldsValue(setDefaultTime());
  58 + updateSchema(disableCustomWeekly(0));
  59 + if (businessText.value === 'add') return;
  60 + // const rest = await getEquipmentTypeDetail({ id: data.record?.id });
  61 + // restData.data = rest ?? {};
  62 + // await setFieldsValue({
  63 + // ...restData.data,
  64 + // });
  65 + } finally {
  66 + setDrawerProps({ loading: false });
  67 + }
  68 + });
  69 + const handleClose = () => {
  70 + resetValue();
  71 + };
  72 + //重置表单
  73 + const resetValue = () => {
  74 + resetFields();
  75 + };
  76 +
  77 + const handleSubmit = () => {
  78 + if (businessText.value === 'view') {
  79 + closeDrawer();
  80 + handleClose();
  81 + return;
  82 + }
  83 + useThrottle();
  84 + };
  85 +
  86 + const useThrottle = useThrottleFn(() => {
  87 + getValue();
  88 + }, 2000);
  89 +
  90 + const getValue = async () => {
  91 + try {
  92 + setDrawerProps({ confirmLoading: true });
  93 + const values = await validate();
  94 + if (!values) return;
  95 + const data = {
  96 + ...values,
  97 + };
  98 + removeFields.forEach((item) => {
  99 + Reflect.deleteProperty(data, item);
  100 + });
  101 + // businessText.value === 'add'
  102 + // ? await saveEquipmentType(data)
  103 + // : saveEquipmentType({ ...restData.data, ...data });
  104 + // createMessage.success(
  105 + // t(businessText.value !== 'add' ? 'common.editSuccessText' : 'common.createSuccessText')
  106 + // );
  107 + closeDrawer();
  108 + handleClose();
  109 + setTimeout(() => {
  110 + emits('success');
  111 + }, 500);
  112 + } finally {
  113 + setDrawerProps({ confirmLoading: false });
  114 + }
  115 + };
  116 +</script>
  117 +<style scoped>
  118 + .inputTitle::before {
  119 + display: inline-block;
  120 + margin-right: 4px;
  121 + color: #ff4d4f;
  122 + font-size: 14px;
  123 + font-family: SimSun, sans-serif;
  124 + line-height: 1;
  125 + content: '*';
  126 + }
  127 +</style>
... ...
  1 +import TypeDrawer from './TypeDrawer.vue';
  2 +import MembersDialog from './MembersDialog.vue';
  3 +
  4 +export { TypeDrawer, MembersDialog };
... ...
  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 +const typeOptions = [
  9 + { label: t('common.maintenance'), value: '1' },
  10 + { label: t('basicConfiguration.unit.typeMaintenance'), value: '2' },
  11 + { label: t('basicConfiguration.unit.typeInspection'), value: '3' },
  12 + { label: t('basicConfiguration.unit.typeCheck'), value: '4' },
  13 +];
  14 +
  15 +export const formSchema: BFormSchema[] = [
  16 + {
  17 + field: 'code',
  18 + label: t('basicConfiguration.unit.unitCode'),
  19 + component: 'Input',
  20 + colProps: { span: 24 },
  21 + required: true,
  22 + componentProps: {
  23 + maxLength: 20,
  24 + },
  25 + },
  26 + {
  27 + field: 'name',
  28 + label: t('basicConfiguration.unit.unitName'),
  29 + component: 'Input',
  30 + colProps: { span: 24 },
  31 + required: true,
  32 + componentProps: {
  33 + maxLength: 20,
  34 + },
  35 + },
  36 + {
  37 + field: 'type',
  38 + component: 'Select',
  39 + label: t('basicConfiguration.unit.unitType'),
  40 + required: true,
  41 + colProps: { span: 24 },
  42 + componentProps: {
  43 + options: typeOptions,
  44 + },
  45 + },
  46 + {
  47 + field: 'status',
  48 + component: 'Select',
  49 + label: t('common.status'),
  50 + required: true,
  51 + colProps: { span: 24 },
  52 + componentProps: {
  53 + options: statusOptions,
  54 + },
  55 + },
  56 + {
  57 + field: 'notes',
  58 + label: t('common.remarkText'),
  59 + component: 'InputTextArea',
  60 + colProps: { span: 24 },
  61 + componentProps: {
  62 + maxLength: 200,
  63 + },
  64 + },
  65 +];
... ...
  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 { useI18n } from '/@/hooks/web/useI18n';
  5 +import { Tag } from 'ant-design-vue';
  6 +const { t } = useI18n();
  7 +
  8 +export enum UnitListAuthEnum {
  9 + /**
  10 + * @description 新增
  11 + */
  12 + CREATE = 'api:yt:basicConfiguration:unit:post',
  13 +
  14 + /**
  15 + * @description 删除
  16 + */
  17 + DELETE = 'api:yt:basicConfiguration:unit:delete',
  18 +
  19 + /**
  20 + * @description 编辑
  21 + */
  22 + UPDATE = 'api:yt:basicConfiguration:unit:update',
  23 +
  24 + /**
  25 + * @description 启用
  26 + */
  27 + ENABLE = 'api:yt:basicConfiguration:unit:enable',
  28 +
  29 + /**
  30 + * @description 停用
  31 + */
  32 + STOP = 'api:yt:basicConfiguration:unit:stop',
  33 +}
  34 +
  35 +// 表格列数据
  36 +export const columns: BasicColumn[] = [
  37 + {
  38 + dataIndex: 'code',
  39 + title: t('basicConfiguration.unit.unitCode'),
  40 + width: 120,
  41 + },
  42 + {
  43 + title: t('basicConfiguration.unit.unitName'),
  44 + dataIndex: 'name',
  45 + width: 100,
  46 + },
  47 + {
  48 + title: t('basicConfiguration.unit.unitType'),
  49 + dataIndex: 'type',
  50 + width: 100,
  51 + },
  52 + {
  53 + title: t('business.directorName'),
  54 + dataIndex: 'directorName',
  55 + width: 100,
  56 + },
  57 + {
  58 + title: t('basicConfiguration.unit.unitMembers'),
  59 + dataIndex: 'members',
  60 + slots: { customRender: 'members' },
  61 + width: 200
  62 + },
  63 + {
  64 + title: t('common.status'),
  65 + dataIndex: 'status',
  66 + width: 110,
  67 + customRender: ({ record }) => {
  68 + console.log('record', record)
  69 + const color = record?.status == 'ENABLE' ? 'blue' : 'red';
  70 + const text = record.status == 'ENABLE' ? t('basicConfiguration.unit.enable') : t('basicConfiguration.unit.stop');
  71 + return h(Tag, { color: color }, () => text);
  72 + },
  73 + },
  74 + {
  75 + title: t('common.remarkText'),
  76 + dataIndex: 'notes',
  77 + width: 120,
  78 + },
  79 + {
  80 + title: t('basicConfiguration.unit.creator'),
  81 + dataIndex: 'creatorName',
  82 + width: 120,
  83 + },
  84 + {
  85 + title: t('common.createTimeText'),
  86 + dataIndex: 'createTime',
  87 + width: 120,
  88 + },
  89 +];
  90 +
  91 +// 查询字段
  92 +export const searchFormSchema: FormSchema[] = [
  93 + {
  94 + field: 'name',
  95 + label: t('basicConfiguration.unit.unitName'),
  96 + component: 'Input',
  97 + colProps: { span: 6 },
  98 + componentProps: {
  99 + maxLength: 255,
  100 + },
  101 + },
  102 + {
  103 + field: 'creatorName',
  104 + label: t('basicConfiguration.unit.creator'),
  105 + component: 'Input',
  106 + colProps: { span: 6 },
  107 + componentProps: {
  108 + maxLength: 255,
  109 + },
  110 + },
  111 +];
... ...
  1 +<template>
  2 + <div>
  3 + <PageWrapper dense contentFullHeight contentClass="flex">
  4 + <BasicTable style="flex: auto" @register="registerTable" class="w-5/6 xl:w-4/5 type-table">
  5 + <template #toolbar>
  6 + <Authority :value="UnitListAuthEnum.CREATE">
  7 + <a-button
  8 + type="primary"
  9 + @click="handleBussinessDrawer('add', null)"
  10 + v-if="authBtn(role)"
  11 + >
  12 + {{ t('common.createText') }}
  13 + </a-button>
  14 + </Authority>
  15 + <Authority
  16 + :value="[UnitListAuthEnum.DELETE, UnitListAuthEnum.ENABLE, UnitListAuthEnum.STOP]"
  17 + >
  18 + <AuthDropDown
  19 + v-if="authBtn(role)"
  20 + :disabled="!isExistOption"
  21 + :dropMenuList="[
  22 + {
  23 + text: t('common.delText'),
  24 + auth: UnitListAuthEnum.DELETE,
  25 + icon: 'ant-design:delete-outlined',
  26 + popconfirm: {
  27 + title: t('common.batchDeleteConfirmText'),
  28 + onConfirm: () => handleDelete(),
  29 + },
  30 + },
  31 + {
  32 + text: t('common.enableText'),
  33 + auth: UnitListAuthEnum.ENABLE,
  34 + icon: 'ant-design:check-circle-outlined',
  35 + onClick: handleChangeStatus.bind(null, 'enable'),
  36 + },
  37 +
  38 + {
  39 + text: t('common.stop'),
  40 + auth: UnitListAuthEnum.STOP,
  41 + icon: 'ant-design:close-circle-outlined',
  42 + onClick: handleChangeStatus.bind(null, 'stop'),
  43 + },
  44 + ]"
  45 + >
  46 + <a-button type="primary" :disabled="!isExistOption">
  47 + {{ t('deviceManagement.device.batchActionText') }}
  48 + </a-button>
  49 + </AuthDropDown>
  50 + </Authority>
  51 + </template>
  52 + <template #members="{ record }">
  53 + <span @click="lookMembers(record)">
  54 + {{ record.profileName }}
  55 + </span>
  56 + </template>
  57 + <template #action="{ record }">
  58 + <TableAction
  59 + :actions="[
  60 + {
  61 + label: t('common.editText'),
  62 + auth: UnitListAuthEnum.UPDATE,
  63 + icon: 'clarity:note-edit-line',
  64 + onClick: handleBussinessDrawer.bind(null, 'edit', record),
  65 + },
  66 + {
  67 + label: t('common.delText'),
  68 + icon: 'ant-design:delete-outlined',
  69 + auth: UnitListAuthEnum.DELETE,
  70 + color: 'error',
  71 + popConfirm: {
  72 + title: t('common.isDelete'),
  73 + confirm: handleDelete.bind(null, record),
  74 + },
  75 + },
  76 + {
  77 + label: t('common.stop'),
  78 + auth: UnitListAuthEnum.STOP,
  79 + icon: 'ant-design:check-circle-outlined',
  80 + onClick: handleChangeStatus.bind(null, 'stop', record),
  81 + ifShow: record.status === 'ENABLE',
  82 + },
  83 + {
  84 + label: t('common.enableText'),
  85 + auth: UnitListAuthEnum.ENABLE,
  86 + icon: 'ant-design:close-circle-outlined',
  87 + ifShow: record.status === 'STOP',
  88 + onClick: handleChangeStatus.bind(null, 'enable', record),
  89 + },
  90 + ]"
  91 + />
  92 + </template>
  93 + </BasicTable>
  94 + <TypeDrawer @register="registerDrawer" @success="handleSuccess" @reload="handleSuccess" />
  95 + <!-- 弹窗组件 -->
  96 + <MembersDialog
  97 + v-model="dialogMembersVisible"
  98 + :detail-id="selectedRowId"
  99 + />
  100 + </PageWrapper>
  101 + </div>
  102 +</template>
  103 +<script setup lang="ts">
  104 +import {reactive, ref} from 'vue';
  105 + import { PageWrapper } from '/@/components/Page';
  106 + import { TypeDrawer, MembersDialog } from './components/modal/index';
  107 + const searchInfo = reactive<Recordable>({});
  108 + import { BasicTable, TableAction, useTable } from '/@/components/Table';
  109 + // import {
  110 + // getEquipmentTypeList,
  111 + // deleteEquipmentType,
  112 + // updateEquipmentTypeStatus,
  113 + // } from '/@/api/archive/type';
  114 +import {
  115 + unitPage,
  116 +} from '/@/api/basicConfiguration/unit';
  117 + import { columns, searchFormSchema, UnitListAuthEnum } from './config/type.data';
  118 + import { useBatchOperation } from '/@/utils/useBatchOperation';
  119 + import { useI18n } from '/@/hooks/web/useI18n';
  120 +import { AuthDropDown } from '/@/components/Widget';
  121 + import { authBtn } from '/@/enums/roleEnum';
  122 + import { Authority } from '/@/components/Authority';
  123 + import { getAuthCache } from '/@/utils/auth';
  124 + import { USER_INFO_KEY } from '/@/enums/cacheEnum';
  125 + import { useMessage } from '/@/hooks/web/useMessage';
  126 +
  127 + import { useDrawer } from '/@/components/Drawer';
  128 +
  129 +
  130 + // 业务弹窗
  131 + const [registerDrawer, { openDrawer }] = useDrawer();
  132 + const { t } = useI18n();
  133 + const userInfo: any = getAuthCache(USER_INFO_KEY);
  134 + const role: string = userInfo.roles[0];
  135 +
  136 + console.log('role----', role)
  137 +
  138 + const { createMessage } = useMessage();
  139 +
  140 +
  141 + const [
  142 + registerTable,
  143 + { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection },
  144 + ] = useTable({
  145 + title: t('basicConfiguration.unit.unitListText'),
  146 + api: unitPage,
  147 + columns,
  148 + beforeFetch: (params) => {
  149 + const { deviceProfileId } = params;
  150 + if (!deviceProfileId) return;
  151 + const obj = {
  152 + ...params,
  153 + ...{
  154 + deviceProfileIds: deviceProfileId ? [deviceProfileId] : null,
  155 + },
  156 + };
  157 + delete obj.deviceProfileId;
  158 + return obj;
  159 + },
  160 + formConfig: {
  161 + labelWidth: 140,
  162 + schemas: searchFormSchema,
  163 + },
  164 + useSearchForm: true,
  165 + showTableSetting: true,
  166 + bordered: true,
  167 + showIndexColumn: false,
  168 + rowKey: 'id',
  169 + searchInfo: searchInfo,
  170 + clickToRowSelect: false,
  171 + rowClassName: (record) => ((record as any).alarmStatus ? 'device-alarm-badge' : ''),
  172 + rowSelection: { type: 'checkbox' },
  173 + actionColumn: {
  174 + width: 200,
  175 + title: t('common.actionText'),
  176 + slots: { customRender: 'action' },
  177 + fixed: 'right',
  178 + },
  179 + });
  180 +
  181 + const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys);
  182 +
  183 + // 业务弹窗
  184 + const handleBussinessDrawer = (text, record) => {
  185 + const modalParams = {
  186 + text,
  187 + record,
  188 + };
  189 + openDrawer(true, modalParams);
  190 + };
  191 +
  192 + // 删除
  193 + const handleDelete = async (record?: any) => {
  194 + // eslint-disable-next-line no-console
  195 + console.log(record, '这是一条临时调试用的日志');
  196 + let ids: string[] = [];
  197 + if (record) {
  198 + ids = [record.id];
  199 + } else {
  200 + ids = getSelectRowKeys();
  201 + }
  202 + try {
  203 + setLoading(true);
  204 + // await deleteEquipmentType({ ids });
  205 + createMessage.success(t('common.deleteSuccessText'));
  206 + handleReload();
  207 + } catch (error) {
  208 + throw error;
  209 + } finally {
  210 + setLoading(false);
  211 + }
  212 + };
  213 +
  214 + // 启用 停用
  215 + const handleChangeStatus = async (type: 'enable' | 'stop', record?: any) => {
  216 + let ids: string[] = [];
  217 + if (record?.id) {
  218 + ids = [record?.id];
  219 + } else {
  220 + ids = getSelectRowKeys();
  221 + }
  222 + if (ids?.length)
  223 + try {
  224 + setLoading(true);
  225 + if (type === 'enable') {
  226 + // await updateEquipmentTypeStatus({ ids, status: 'ENABLE' });
  227 + } else {
  228 + // await updateEquipmentTypeStatus({ ids, status: 'STOP' });
  229 + }
  230 + createMessage.success(t('common.editSuccessText'));
  231 + handleReload();
  232 + } catch (error) {
  233 + throw error;
  234 + } finally {
  235 + setLoading(false);
  236 + }
  237 + };
  238 +
  239 +
  240 + // 控制弹窗显示
  241 + const dialogMembersVisible = ref(false);
  242 + // 存储当前选中行数据
  243 + const selectedRowId = ref(null);
  244 +
  245 + const lookMembers = (item: any) => {
  246 + console.log('lookMembers--item', item)
  247 + console.log('lookMembers--item.organizationName', item.organizationName)
  248 + selectedRowId.value = item.id; // 存储行数据
  249 + dialogMembersVisible.value = true; // 显示弹窗
  250 + }
  251 +
  252 + // 重置
  253 + function handleReload() {
  254 + setSelectedRowKeys([]);
  255 + handleSuccess();
  256 + }
  257 +
  258 + function handleSuccess() {
  259 + reload();
  260 + }
  261 +
  262 +</script>
  263 +
  264 +<style scoped lang="less">
  265 + .type-table {
  266 + :deep(.ant-form-item-control-input-content) {
  267 + & > div > div {
  268 + width: 100%;
  269 + }
  270 + }
  271 + }
  272 +</style>
  273 +
  274 +<style lang="less">
  275 + .type-status {
  276 + position: relative;
  277 +
  278 + .type-collect {
  279 + width: 0;
  280 + height: 0;
  281 + border-top: 30px solid #377dff;
  282 + border-right: 30px solid transparent;
  283 + }
  284 + }
  285 +
  286 + .type-name-edge {
  287 + width: 100%;
  288 + height: 100%;
  289 + padding: 0 !important;
  290 + position: relative;
  291 + }
  292 +</style>
... ...