Commit 1b8b9c9a41f5ad46e2ba3b903c17a0e43685118c

Authored by dev001
1 parent 065df9b7

pref: 修改组态模板和组态 表单数据变更

... ... @@ -14,6 +14,7 @@ export interface ConfigurationCenterItemsModal {
14 14 export type queryPageParams = BasicPageParams & {
15 15 name?: Nullable<string>;
16 16 organizationId?: Nullable<number>;
  17 + isTemplate?: number;
17 18 };
18 19
19 20 export interface ConfigurationModal {
... ...
... ... @@ -41,6 +41,7 @@ import ApiSelectScrollLoad from './components/ApiSelectScrollLoad.vue';
41 41 import InputGroup from './components/InputGroup.vue';
42 42 import RegisterAddressInput from '/@/views/task/center/components/PollCommandInput/RegisterAddressInput.vue';
43 43 import ExtendDesc from '/@/components/Form/src/externalCompns/components/ExtendDesc/index.vue';
  44 +import DeviceProfileForm from '/@/components/Form/src/externalCompns/components/DeviceProfileForm/index.vue';
44 45
45 46 const componentMap = new Map<ComponentType, Component>();
46 47
... ... @@ -89,6 +90,7 @@ componentMap.set('ApiSelectScrollLoad', ApiSelectScrollLoad);
89 90 componentMap.set('InputGroup', InputGroup);
90 91 componentMap.set('RegisterAddressInput', RegisterAddressInput);
91 92 componentMap.set('ExtendDesc', ExtendDesc);
  93 +componentMap.set('DeviceProfileForm', DeviceProfileForm);
92 94
93 95 export function add(compName: ComponentType, component: Component) {
94 96 componentMap.set(compName, component);
... ...
  1 +<template>
  2 + <div v-for="(param, index) in dynamicInput.params" :key="index" style="display: flex">
  3 + <a-input placeholder="产品" v-model:value="param.label" :disabled="true" />
  4 + <Select
  5 + placeholder="请选择设备"
  6 + v-model:value="param.value"
  7 + style="width: 100%"
  8 + v-bind="createPickerSearch()"
  9 + mode="multiple"
  10 + labelInValue
  11 + />
  12 + <MinusCircleOutlined
  13 + v-if="dynamicInput.params.length > min && !disabled"
  14 + class="dynamic-delete-button"
  15 + @click="remove(param)"
  16 + style="width: 50px"
  17 + />
  18 + </div>
  19 +</template>
  20 +<script lang="ts" name="DeviceProfileForm">
  21 + import { MinusCircleOutlined } from '@ant-design/icons-vue';
  22 + import { defineComponent, reactive, UnwrapRef, watchEffect } from 'vue';
  23 + import { propTypes } from '/@/utils/propTypes';
  24 + import { isEmpty } from '/@/utils/is';
  25 + import { Select } from 'ant-design-vue';
  26 + import { createPickerSearch } from '/@/utils/pickerSearch';
  27 +
  28 + interface Params {
  29 + label: string;
  30 + value: string;
  31 + }
  32 +
  33 + export default defineComponent({
  34 + name: 'DeviceProfileForm',
  35 + components: {
  36 + MinusCircleOutlined,
  37 + Select,
  38 + },
  39 + //--------------不继承Antd Design Vue Input的所有属性 否则控制台报大片警告--------------
  40 + inheritAttrs: false,
  41 + props: {
  42 + value: propTypes.object.def({}),
  43 + //自定义删除按钮多少才会显示
  44 + min: propTypes.integer.def(0),
  45 + disabled: {
  46 + type: Boolean,
  47 + default: false,
  48 + },
  49 + },
  50 + emits: ['change', 'update:value'],
  51 + setup(props, { emit }) {
  52 + //input动态数据
  53 + const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({ params: [] });
  54 +
  55 + //删除Input
  56 + const remove = (item: Params) => {
  57 + let index = dynamicInput.params.indexOf(item);
  58 + if (index !== -1) {
  59 + dynamicInput.params.splice(index, 1);
  60 + }
  61 + emitChange();
  62 + };
  63 +
  64 + //监听传入数据value
  65 + watchEffect(() => {
  66 + initVal();
  67 + });
  68 +
  69 + /**
  70 + * 初始化数值
  71 + */
  72 + function initVal() {
  73 + dynamicInput.params = [];
  74 + if (props.value) {
  75 + let jsonObj = props.value;
  76 + Object.keys(jsonObj).forEach((key) => {
  77 + dynamicInput.params.push({ label: key, value: jsonObj[key] });
  78 + });
  79 + }
  80 + }
  81 +
  82 + /**
  83 + * 数值改变
  84 + */
  85 + function emitChange() {
  86 + let obj = {};
  87 + if (dynamicInput.params.length > 0) {
  88 + dynamicInput.params.forEach((item) => {
  89 + obj[item.label] = item.value;
  90 + });
  91 + }
  92 + emit('change', isEmpty(obj) ? '' : obj);
  93 + emit('update:value', isEmpty(obj) ? '' : obj);
  94 + }
  95 +
  96 + return {
  97 + dynamicInput,
  98 + emitChange,
  99 + remove,
  100 + createPickerSearch,
  101 + };
  102 + },
  103 + });
  104 +</script>
  105 +<style scoped>
  106 + .dynamic-delete-button {
  107 + cursor: pointer;
  108 + position: relative;
  109 + top: 4px;
  110 + font-size: 24px;
  111 + color: #999;
  112 + transition: all 0.3s;
  113 + }
  114 +
  115 + .dynamic-delete-button:hover {
  116 + color: #777;
  117 + }
  118 +
  119 + .dynamic-delete-button[disabled] {
  120 + cursor: not-allowed;
  121 + opacity: 0.5;
  122 + }
  123 +</style>
... ...
... ... @@ -137,4 +137,5 @@ export type ComponentType =
137 137 | 'CorrelationFilters'
138 138 | 'RelationsQuery'
139 139 | 'CredentialsCard'
140   - | 'ApiComplete';
  140 + | 'ApiComplete'
  141 + | 'DeviceProfileForm';
... ...
... ... @@ -7,36 +7,88 @@
7 7 width="30%"
8 8 @ok="handleSubmit"
9 9 >
10   - <BasicForm @register="registerForm" />
  10 + <BasicForm @register="registerForm">
  11 + <!-- 模板选择 -->
  12 + <template #templateId="{ model }">
  13 + <Select
  14 + v-model:value="model['templateId']"
  15 + placeholder="请选择模板"
  16 + style="width: 100%"
  17 + :options="selectTemplateOptions"
  18 + @change="handleTemplateChange"
  19 + v-bind="createPickerSearch()"
  20 + :disabled="templateDisabled"
  21 + />
  22 + </template>
  23 + <!-- 产品选择 -->
  24 + <template #productIds="{ model }">
  25 + <SelectDeviceProfile
  26 + v-if="model['templateId']"
  27 + ref="selectDeviceProfileRef"
  28 + :selectOptions="selectOptions"
  29 + :organizationId="model['organizationId']"
  30 + />
  31 + </template>
  32 + </BasicForm>
11 33 </BasicDrawer>
12 34 </template>
13 35 <script lang="ts">
14   - import { defineComponent, ref, computed, unref } from 'vue';
  36 + import { defineComponent, ref, computed, unref, Ref, onMounted, nextTick } from 'vue';
15 37 import { BasicForm, useForm } from '/@/components/Form';
  38 + import { Select } from 'ant-design-vue';
16 39 import { formSchema, PC_DEFAULT_CONTENT, PHONE_DEFAULT_CONTENT, Platform } from './center.data';
17 40 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
18 41 import { useMessage } from '/@/hooks/web/useMessage';
19   - import { saveOrUpdateConfigurationCenter } from '/@/api/configuration/center/configurationCenter';
  42 + import {
  43 + saveOrUpdateConfigurationCenter,
  44 + getPage,
  45 + } from '/@/api/configuration/center/configurationCenter';
20 46 import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
21 47 import { buildUUID } from '/@/utils/uuid';
  48 + import SelectDeviceProfile from './components/SelectDeviceProfile.vue';
  49 + import { createPickerSearch } from '/@/utils/pickerSearch';
  50 + import type { queryPageParams } from '/@/api/configuration/center/model/configurationCenterModal';
  51 + import { getDeviceProfile } from '/@/api/alarm/position';
22 52
23 53 export default defineComponent({
24 54 name: 'ConfigurationDrawer',
25   - components: { BasicDrawer, BasicForm },
  55 + components: { BasicDrawer, BasicForm, SelectDeviceProfile, Select },
26 56 emits: ['success', 'register'],
27 57 setup(_, { emit }) {
28 58 const isUpdate = ref(true);
29 59
30   - const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({
  60 + const selectDeviceProfileRef = ref<InstanceType<typeof SelectDeviceProfile>>();
  61 +
  62 + const [registerForm, { validate, setFieldsValue, resetFields, updateSchema }] = useForm({
31 63 labelWidth: 120,
32 64 schemas: formSchema,
33 65 showActionButtonGroup: false,
34 66 });
35 67
  68 + const updateEnableTemplate = async (enable: number, disabled: boolean) => {
  69 + await setFieldsValue({
  70 + enableTemplate: enable,
  71 + });
  72 + await updateSchema({
  73 + field: 'enableTemplate',
  74 + componentProps: {
  75 + disabled,
  76 + checkedValue: 1,
  77 + unCheckedValue: 0,
  78 + checkedChildren: '开',
  79 + unCheckedChildren: '关',
  80 + },
  81 + });
  82 + };
  83 +
36 84 const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  85 + await nextTick();
37 86 await resetFields();
38 87 setDrawerProps({ confirmLoading: false });
39 88 isUpdate.value = !!data?.isUpdate;
  89 + selectDeviceProfileRef.value?.retValue();
  90 + await updateEnableTemplate(0, false);
  91 + templateDisabled.value = false;
40 92 if (unref(isUpdate)) {
41 93 if (data.record.thumbnail) {
42 94 data.record.thumbnail = [
... ... @@ -49,9 +101,57 @@
49 101 Reflect.deleteProperty(data.record, 'organizationId');
50 102 await setFieldsValue(data.record);
51 103 }
  104 + // 业务 编辑如果有templateId 则启用模板开关禁用,模板不能选择,产品和设备可以选择
  105 + if (Reflect.get(data.record, 'templateId')) {
  106 + await updateEnableTemplate(1, true);
  107 + templateDisabled.value = true;
  108 + //回显产品和设备
  109 + const { productAndDevice } = data.record;
  110 + selectOptions.value = productAndDevice?.map((item) => ({
  111 + label: item.name,
  112 + value: item.profileId,
  113 + }));
  114 + selectDeviceProfileRef.value?.setValue(productAndDevice);
  115 + } else {
  116 + const productAndDevice = data.record['productAndDevice'];
  117 + setFieldsValue({
  118 + productId: productAndDevice?.map((item) => item.profileId),
  119 + });
  120 + }
52 121 }
53 122 });
54 123
  124 + //新增修改
  125 + const templateDisabled = ref(false);
  126 + onMounted(() => {
  127 + getTemplate({
  128 + page: 1,
  129 + pageSize: 30,
  130 + });
  131 + });
  132 +
  133 + const selectTemplateOptions: Ref<any[]> = ref([]);
  134 + const getTemplate = async (params: queryPageParams) => {
  135 + const { items } = await getPage({ ...params, isTemplate: 1 });
  136 + selectTemplateOptions.value = items.map((item) => ({
  137 + ...item,
  138 + label: item.name,
  139 + value: item.id,
  140 + }));
  141 + };
  142 +
  143 + const selectOptions: Ref<any[]> = ref([]);
  144 +
  145 + const handleTemplateChange = (_, option) => {
  146 + const { productAndDevice } = option;
  147 + if (!productAndDevice) return;
  148 + selectOptions.value = productAndDevice.map((item) => ({
  149 + label: item.name,
  150 + value: item.profileId,
  151 + }));
  152 + };
  153 + //
  154 +
55 155 const getTitle = computed(() => (!unref(isUpdate) ? '新增组态中心' : '编辑组态中心'));
56 156
57 157 const getDefaultContent = (platform: Platform) => {
... ... @@ -61,10 +161,44 @@
61 161 return PHONE_DEFAULT_CONTENT;
62 162 };
63 163
  164 + // 获取产品
  165 + const getCurrentAllProduct = async (products: string[]) => {
  166 + const resp = (await getDeviceProfile()) as any;
  167 + if (!resp) return;
  168 + const values = resp?.map((item) => ({ name: item.name, profileId: item.id }));
  169 + return values.filter((item) => products?.includes(item.profileId));
  170 + };
  171 +
64 172 async function handleSubmit() {
65 173 try {
66 174 const { createMessage } = useMessage();
67 175 const values = await validate();
  176 + if (!values) return;
  177 + const selectDevice = selectDeviceProfileRef.value?.getSelectDevice();
  178 + if (values['enableTemplate'] === 1) {
  179 + if (!values['templateId']) return createMessage.error('未选择模板');
  180 + // 业务 启用模板,产品和设备必填
  181 + if (values['templateId']) {
  182 + values.templateId = values['templateId'];
  183 + if (Array.isArray(selectDevice) && selectDevice.length == 0)
  184 + return createMessage.error('您已经选择了模板,但产品或者设备未选择');
  185 + if (
  186 + selectDevice?.some(
  187 + (item) =>
  188 + !item.name ||
  189 + item.deviceList.includes('' || undefined) ||
  190 + item.deviceList.length == 0
  191 + )
  192 + ) {
  193 + return createMessage.error('您已经选择了模板,但产品或者设备未选择');
  194 + }
  195 + values.productAndDevice = selectDevice;
  196 + }
  197 + } else {
  198 + const { productId } = values;
  199 + values.productAndDevice = await getCurrentAllProduct(productId);
  200 + Reflect.deleteProperty(values, 'productId');
  201 + }
68 202 if (Reflect.has(values, 'thumbnail')) {
69 203 const file = (values.thumbnail || []).at(0) || {};
70 204 values.thumbnail = file.url || null;
... ... @@ -87,6 +221,12 @@
87 221 registerDrawer,
88 222 registerForm,
89 223 handleSubmit,
  224 + selectOptions,
  225 + selectTemplateOptions,
  226 + handleTemplateChange,
  227 + createPickerSearch,
  228 + selectDeviceProfileRef,
  229 + templateDisabled,
90 230 };
91 231 },
92 232 });
... ...
... ... @@ -83,6 +83,7 @@ export const searchFormSchema: FormSchema[] = [
83 83 },
84 84 ];
85 85
  86 +// 表单
86 87 export const formSchema: FormSchema[] = [
87 88 {
88 89 field: 'thumbnail',
... ... @@ -112,14 +113,9 @@ export const formSchema: FormSchema[] = [
112 113 onPreview: (fileList: FileItem) => {
113 114 createImgPreview({ imageList: [fileList.url!] });
114 115 },
115   - // showUploadList: {
116   - // showDownloadIcon: true,
117   - // showRemoveIcon: true,
118   - // },
119 116 };
120 117 },
121 118 },
122   -
123 119 {
124 120 field: 'name',
125 121 label: '组态名称',
... ... @@ -137,17 +133,76 @@ export const formSchema: FormSchema[] = [
137 133 component: 'OrgTreeSelect',
138 134 },
139 135 {
  136 + field: 'platform',
  137 + label: '平台',
  138 + required: true,
  139 + component: 'RadioGroup',
  140 + defaultValue: Platform.PC,
  141 + componentProps: {
  142 + defaultValue: Platform.PC,
  143 + options: [
  144 + { label: 'PC端', value: Platform.PC },
  145 + { label: '移动端', value: Platform.PHONE },
  146 + ],
  147 + },
  148 + },
  149 + {
  150 + field: 'enableTemplate', //前端控制
  151 + label: '启用模版',
  152 + component: 'Switch',
  153 + defaultValue: 0,
  154 + componentProps: ({ formActionType }) => {
  155 + const { setFieldsValue } = formActionType;
  156 + return {
  157 + checkedValue: 1,
  158 + unCheckedValue: 0,
  159 + checkedChildren: '开',
  160 + unCheckedChildren: '关',
  161 + onChange() {
  162 + setFieldsValue({
  163 + productIds: [],
  164 + });
  165 + },
  166 + };
  167 + },
  168 + },
  169 + {
140 170 field: 'isTemplate',
141   - label: '模版',
  171 + label: '默认启用模版',
142 172 component: 'Switch',
143 173 defaultValue: 0,
144 174 componentProps: {
145 175 checkedValue: 1,
146 176 unCheckedValue: 0,
147 177 },
  178 + show: false,
148 179 },
149 180 {
150   - field: 'productIds',
  181 + field: 'templateId', //暂且使用插槽形式
  182 + label: '模板',
  183 + component: 'Input',
  184 + slot: 'templateId',
  185 + colProps: { span: 24 },
  186 + ifShow: ({ values }) => values['enableTemplate'] === 1,
  187 + },
  188 + {
  189 + field: 'productIds', //暂且使用插槽形式
  190 + label: '产品',
  191 + component: 'Input',
  192 + slot: 'productIds',
  193 + colProps: { span: 24 },
  194 + ifShow: ({ values }) => values['enableTemplate'] === 1 && values['templateId'],
  195 + },
  196 + {
  197 + field: 'deviceIds', //暂且使用插槽形式
  198 + label: '设备',
  199 + component: 'Input',
  200 + slot: 'deviceIds',
  201 + colProps: { span: 24 },
  202 + ifShow: ({ values }) => values['enableTemplate'] === 1 && values['templateId'],
  203 + },
  204 + {
  205 + field: 'productId',
151 206 label: '产品',
152 207 component: 'ApiSelect',
153 208 required: true,
... ... @@ -155,22 +210,18 @@ export const formSchema: FormSchema[] = [
155 210 api: getDeviceProfile,
156 211 mode: 'multiple',
157 212 labelField: 'name',
158   - valueField: 'tbProfileId',
159   - },
160   - },
161   - {
162   - field: 'platform',
163   - label: '平台',
164   - required: true,
165   - component: 'RadioGroup',
166   - defaultValue: Platform.PC,
167   - componentProps: {
168   - defaultValue: Platform.PC,
169   - options: [
170   - { label: 'PC端', value: Platform.PC },
171   - { label: '移动端', value: Platform.PHONE },
172   - ],
  213 + valueField: 'id',
  214 + placeholder: '请选择产品',
  215 + getPopupContainer: (triggerNode) => triggerNode.parentNode,
  216 + filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => {
  217 + let { label, value } = option;
  218 + label = label.toLowerCase();
  219 + value = value.toLowerCase();
  220 + inputValue = inputValue.toLowerCase();
  221 + return label.includes(inputValue) || value.includes(inputValue);
  222 + },
173 223 },
  224 + ifShow: ({ values }) => values['enableTemplate'] === 0,
174 225 },
175 226 {
176 227 field: 'remark',
... ...
  1 +<template>
  2 + <div v-for="param in dynamicInput.params" :key="param.name" class="mt-4 flex gap-2">
  3 + <a-input :disabled="true" v-model:value="param.name" class="w-1/2 flex-1" />
  4 + <Select
  5 + placeholder="请选择设备"
  6 + v-model:value="param.deviceList"
  7 + class="!w-1/2"
  8 + :options="selectOptions"
  9 + v-bind="createPickerSearch()"
  10 + @change="emitChange"
  11 + mode="multiple"
  12 + allowClear
  13 + />
  14 + </div>
  15 +</template>
  16 +<script lang="ts">
  17 + export default {
  18 + inheritAttrs: false,
  19 + };
  20 +</script>
  21 +<script lang="ts" setup name="SelectAttributes">
  22 + import { reactive, UnwrapRef, watchEffect, ref } from 'vue';
  23 + import { propTypes } from '/@/utils/propTypes';
  24 + import { Select } from 'ant-design-vue';
  25 + import { createPickerSearch } from '/@/utils/pickerSearch';
  26 + import { byOrganizationIdGetMasterDevice } from '/@/api/ruleengine/ruleengineApi';
  27 +
  28 + const props = defineProps({
  29 + value: propTypes.object.def({}),
  30 + organizationId: {
  31 + type: String,
  32 + required: true,
  33 + },
  34 + });
  35 +
  36 + const selectOptions: any = ref([]);
  37 +
  38 + //动态数据
  39 + const dynamicInput: UnwrapRef<{ params: any[] }> = reactive({ params: [] });
  40 +
  41 + const initVal = async () => {
  42 + if (props.value) {
  43 + if (props.organizationId) {
  44 + const resp = await byOrganizationIdGetMasterDevice({
  45 + organizationId: props.organizationId,
  46 + deviceProfileId: props.value.value,
  47 + });
  48 + selectOptions.value = resp.map((item) => ({ label: item.name, value: item.tbDeviceId }));
  49 + }
  50 + dynamicInput.params.push({
  51 + name: props.value.label,
  52 + profileId: props.value.value,
  53 + deviceList: props.value.deviceList?.filter(Boolean)?.map((item) => item.deviceId),
  54 + });
  55 + }
  56 + };
  57 +
  58 + //数值改变
  59 + const valEffect = watchEffect(() => {
  60 + initVal();
  61 + });
  62 +
  63 + valEffect();
  64 +
  65 + //chang改变
  66 + const emitChange = () => {
  67 + const findDeviceDict = selectOptions.value.map((item) => {
  68 + if (dynamicInput.params[0].deviceList?.includes(item.value)) {
  69 + return {
  70 + name: item.label,
  71 + deviceId: item.value,
  72 + };
  73 + }
  74 + });
  75 + return {
  76 + ...dynamicInput.params[0],
  77 + deviceList: findDeviceDict.filter(Boolean),
  78 + };
  79 + };
  80 + defineExpose({
  81 + emitChange,
  82 + });
  83 +</script>
  84 +<style scoped lang="css">
  85 + .dynamic-delete-button {
  86 + cursor: pointer;
  87 + position: relative;
  88 + top: 4px;
  89 + font-size: 24px;
  90 + color: #999;
  91 + transition: all 0.3s;
  92 + }
  93 +
  94 + .dynamic-delete-button:hover {
  95 + color: #777;
  96 + }
  97 +
  98 + .dynamic-delete-button[disabled] {
  99 + cursor: not-allowed;
  100 + opacity: 0.5;
  101 + }
  102 +</style>
... ...
  1 +<template>
  2 + <Select
  3 + placeholder="请选择产品"
  4 + v-model:value="selectValue"
  5 + style="width: 100%"
  6 + :options="selectOptions"
  7 + v-bind="createPickerSearch()"
  8 + @change="handleDeviceProfileChange"
  9 + mode="multiple"
  10 + labelInValue
  11 + />
  12 + <template v-for="(item, index) in profileList" :key="item.value">
  13 + <SelectDevice
  14 + :ref="bindDeviceRef.deviceAttrRef"
  15 + :value="item"
  16 + :index="index"
  17 + :organizationId="organizationId"
  18 + />
  19 + </template>
  20 +</template>
  21 +<script lang="ts" setup name="SelectDevice">
  22 + import { ref, Ref, PropType, unref } from 'vue';
  23 + import { Select } from 'ant-design-vue';
  24 + import SelectDevice from './SelectDevice.vue';
  25 + import { createPickerSearch } from '/@/utils/pickerSearch';
  26 +
  27 + defineProps({
  28 + selectOptions: {
  29 + type: Array as PropType<any[]>,
  30 + required: true,
  31 + },
  32 + organizationId: {
  33 + type: String,
  34 + required: true,
  35 + },
  36 + });
  37 +
  38 + const selectValue = ref([]);
  39 +
  40 + const bindDeviceRef = {
  41 + deviceAttrRef: ref([]),
  42 + };
  43 +
  44 + const profileList: Ref<any[]> = ref([]);
  45 +
  46 + const handleDeviceProfileChange = (_, options) => {
  47 + profileList.value = options;
  48 + };
  49 +
  50 + const getSelectDevice = () => {
  51 + return unref(bindDeviceRef.deviceAttrRef)?.map((item: any) => item.emitChange());
  52 + };
  53 +
  54 + const setValue = (value: any) => {
  55 + console.log(value);
  56 + selectValue.value = value.map((item) => ({
  57 + label: item.name,
  58 + key: item.profileId,
  59 + }));
  60 +
  61 + profileList.value = value.map((item) => {
  62 + return {
  63 + label: item.name,
  64 + value: item.profileId,
  65 + deviceList: item.deviceList,
  66 + };
  67 + });
  68 + };
  69 + const retValue = () => {
  70 + selectValue.value = [];
  71 + profileList.value = [];
  72 + };
  73 +
  74 + defineExpose({
  75 + getSelectDevice,
  76 + setValue,
  77 + retValue,
  78 + });
  79 +</script>
  80 +<style scoped lang="css"></style>
... ...
... ... @@ -77,6 +77,7 @@
77 77 const { items, total } = await getPage({
78 78 organizationId: unref(organizationId),
79 79 ...value,
  80 + isTemplate: 0,
80 81 page: pagination.current!,
81 82 pageSize,
82 83 });
... ...
... ... @@ -19,6 +19,7 @@
19 19 import { saveOrUpdateConfigurationCenter } from '/@/api/configuration/center/configurationCenter';
20 20 import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
21 21 import { buildUUID } from '/@/utils/uuid';
  22 + import { getDeviceProfile } from '/@/api/alarm/position';
22 23
23 24 export default defineComponent({
24 25 name: 'ConfigurationDrawer',
... ... @@ -49,10 +50,15 @@
49 50 Reflect.deleteProperty(data.record, 'organizationId');
50 51 await setFieldsValue(data.record);
51 52 }
  53 + if (!data.record?.productAndDevice) return;
  54 + const productAndDevice = data.record['productAndDevice'];
  55 + setFieldsValue({
  56 + productIds: productAndDevice.map((item) => item.profileId),
  57 + });
52 58 }
53 59 });
54 60
55   - const getTitle = computed(() => (!unref(isUpdate) ? '新增组态中心' : '编辑组态中心'));
  61 + const getTitle = computed(() => (!unref(isUpdate) ? '新增模板' : '编辑模板'));
56 62
57 63 const getDefaultContent = (platform: Platform) => {
58 64 if (platform === Platform.PC) {
... ... @@ -61,10 +67,20 @@
61 67 return PHONE_DEFAULT_CONTENT;
62 68 };
63 69
  70 + // 获取产品
  71 + const getCurrentAllProduct = async (products: string[]) => {
  72 + const resp = (await getDeviceProfile()) as any;
  73 + if (!resp) return;
  74 + const values = resp.map((item) => ({ name: item.name, profileId: item.id }));
  75 + return values.filter((item) => products.includes(item.profileId));
  76 + };
  77 +
64 78 async function handleSubmit() {
65 79 try {
66 80 const { createMessage } = useMessage();
67 81 const values = await validate();
  82 + if (!values) return;
  83 + const reflectProduct = await getCurrentAllProduct(values['productIds']);
68 84 if (Reflect.has(values, 'thumbnail')) {
69 85 const file = (values.thumbnail || []).at(0) || {};
70 86 values.thumbnail = file.url || null;
... ... @@ -73,6 +89,8 @@
73 89 let saveMessage = '添加成功';
74 90 let updateMessage = '修改成功';
75 91 values.defaultContent = getDefaultContent(values.platform);
  92 + values.productAndDevice = reflectProduct;
  93 + Reflect.deleteProperty(values, 'productIds');
76 94 await saveOrUpdateConfigurationCenter(values, unref(isUpdate));
77 95 closeDrawer();
78 96 emit('success');
... ...
... ... @@ -122,11 +122,11 @@ export const formSchema: FormSchema[] = [
122 122
123 123 {
124 124 field: 'name',
125   - label: '组态名称',
  125 + label: '模板名称',
126 126 required: true,
127 127 component: 'Input',
128 128 componentProps: {
129   - placeholder: '请输入组态名称',
  129 + placeholder: '请输入模板名称',
130 130 maxLength: 36,
131 131 },
132 132 },
... ... @@ -137,16 +137,6 @@ export const formSchema: FormSchema[] = [
137 137 component: 'OrgTreeSelect',
138 138 },
139 139 {
140   - field: 'isTemplate',
141   - label: '模版',
142   - component: 'Switch',
143   - defaultValue: 0,
144   - componentProps: {
145   - checkedValue: 1,
146   - unCheckedValue: 0,
147   - },
148   - },
149   - {
150 140 field: 'productIds',
151 141 label: '产品',
152 142 component: 'ApiSelect',
... ... @@ -155,10 +145,23 @@ export const formSchema: FormSchema[] = [
155 145 api: getDeviceProfile,
156 146 mode: 'multiple',
157 147 labelField: 'name',
158   - valueField: 'tbProfileId',
  148 + valueField: 'id',
159 149 },
160 150 },
161 151 {
  152 + field: 'isTemplate',
  153 + label: '',
  154 + component: 'Switch',
  155 + required: true,
  156 + defaultValue: 1,
  157 + componentProps: {
  158 + disabled: true,
  159 + checkedValue: 1,
  160 + unCheckedValue: 0,
  161 + },
  162 + show: false,
  163 + },
  164 + {
162 165 field: 'platform',
163 166 label: '平台',
164 167 required: true,
... ...
... ... @@ -79,6 +79,7 @@
79 79 ...value,
80 80 page: pagination.current!,
81 81 pageSize,
  82 + isTemplate: 1,
82 83 });
83 84
84 85 dataSource.value = items;
... ... @@ -213,7 +214,7 @@
213 214 <template #header>
214 215 <div class="flex gap-3 justify-end">
215 216 <Authority v-if="!isCustomerUser" :value="ConfigurationPermission.CREATE">
216   - <Button type="primary" @click="handleCreateOrUpdate()">新增组态</Button>
  217 + <Button type="primary" @click="handleCreateOrUpdate()">新增模板</Button>
217 218 </Authority>
218 219 <CardLayoutButton v-model:value="listColumn" @change="handleCardLayoutChange" />
219 220 <Tooltip title="刷新">
... ... @@ -250,14 +251,6 @@
250 251 </div>
251 252 </template>
252 253 <template class="ant-card-actions" #actions>
253   - <Tooltip title="预览">
254   - <AuthIcon
255   - :auth="ConfigurationPermission.PREVIEW"
256   - class="!text-lg"
257   - icon="ant-design:eye-outlined"
258   - @click="handlePreview(item)"
259   - />
260   - </Tooltip>
261 254 <Tooltip v-if="!isCustomerUser" title="设计">
262 255 <AuthIcon
263 256 :auth="ConfigurationPermission.DESIGN"
... ... @@ -313,7 +306,7 @@
313 306 <template #description>
314 307 <div class="truncate h-11">
315 308 <div class="truncate flex justify-between items-center">
316   - <div>{{ item.organizationDTO.name }}</div>
  309 + <div>{{ item.organizationDTO?.name }}</div>
317 310 <Icon
318 311 :icon="
319 312 item.platform === Platform.PC
... ...