Commit 2ef6cb196f588d42ca07805468582ac9d63630a8

Authored by xp.Huang
2 parents cb97b1cf 09ba7a46

Merge branch 'dev-fix-ww' into 'main_dev'

fix: 修复teambation BUG

See merge request yunteng/thingskit-front!554
... ... @@ -3,24 +3,32 @@ import { Rule } from '/@/components/Form';
3 3 export { default as JSONEditor } from './index.vue';
4 4
5 5 export const parseStringToJSON = <T = Recordable>(value: string) => {
  6 + let valid = false;
6 7 try {
7 8 const json = JSON.parse(value) as T;
8   - return { json, valid: true };
  9 + typeof json === 'object' ? (valid = true) : (valid = false);
  10 + return { json, valid };
9 11 } catch (error) {
10   - return { json: null, valid: false };
  12 + return { json: null, valid };
11 13 }
12 14 };
13 15
14   -export const JSONEditorValidator = (message = 'json格式校验失败'): Rule[] => {
  16 +export const JSONEditorValidator = (
  17 + message = 'JSON格式校验失败',
  18 + noEmpty = false,
  19 + emptyMessage = 'JSON不能为空对象'
  20 +): Rule[] => {
15 21 return [
16 22 {
17 23 validateTrigger: 'blur',
18 24 validator(_rule: Rule, value: any, _callback: Fn) {
19   - const { valid } = parseStringToJSON(value);
  25 + const { valid, json } = parseStringToJSON(value);
20 26 if (valid) {
  27 + if (noEmpty && json && !Object.keys(json).length) return Promise.reject(emptyMessage);
21 28 return Promise.resolve();
  29 + } else {
  30 + return Promise.reject(message);
22 31 }
23   - return Promise.reject(message);
24 32 },
25 33 },
26 34 ];
... ...
... ... @@ -18,6 +18,7 @@
18 18 defineProps<{
19 19 value?: string;
20 20 options?: JSONEditorOptions;
  21 + height?: number;
21 22 }>(),
22 23 {
23 24 options: () =>
... ... @@ -26,6 +27,7 @@
26 27 mainMenuBar: false,
27 28 statusBar: false,
28 29 } as JSONEditorOptions),
  30 + height: 150,
29 31 }
30 32 );
31 33
... ... @@ -106,7 +108,7 @@
106 108 </script>
107 109
108 110 <template>
109   - <div class="p-2 bg-gray-200">
  111 + <div class="p-2 bg-gray-200" :style="{ height: `${height - 16}px` }">
110 112 <div ref="jsonEditorElRef" class="jsoneditor"></div>
111 113 </div>
112 114 </template>
... ...
1 1 <script setup lang="ts">
2 2 import { List, Card, Button, PaginationProps, Tooltip } from 'ant-design-vue';
3 3 import { ReloadOutlined } from '@ant-design/icons-vue';
4   - import { onMounted, reactive, ref, unref } from 'vue';
  4 + import { computed, onMounted, reactive, ref, unref } from 'vue';
5 5 import { OrganizationIdTree, useResetOrganizationTree } from '../common/organizationIdTree';
6 6 import {
7 7 bigScreenCancelPublish,
... ... @@ -30,6 +30,8 @@
30 30 import { ViewTypeNameEnum } from '../common/ShareModal/config';
31 31 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
32 32 import { ViewType } from '../visual/board/config/panelDetail';
  33 + import { useUserStore } from '/@/store/modules/user';
  34 + import { RoleEnum } from '/@/enums/roleEnum';
33 35
34 36 const listColumn = ref(5);
35 37
... ... @@ -173,6 +175,11 @@
173 175 return `${origin}${largeDesignerPrefix}/#/share/preview/${record.id}/${record.publicId}`;
174 176 };
175 177
  178 + const userStore = useUserStore();
  179 + const hasPublicInterfacePermission = computed(() => {
  180 + return userStore.getUserInfo.roles![0] !== RoleEnum.CUSTOMER_USER;
  181 + });
  182 +
176 183 const { clipboardRef, isSuccessRef } = useCopyToClipboard();
177 184 const handleCreateShareUrl = (record: BigScreenCenterItemsModel) => {
178 185 clipboardRef.value = createShareUrl(record);
... ... @@ -214,7 +221,7 @@
214 221 <Authority :value="ConfigurationPermission.CREATE">
215 222 <Button type="primary" @click="handleCreateOrUpdate()">新增大屏</Button>
216 223 </Authority>
217   - <Authority :value="ConfigurationPermission.CREATE">
  224 + <Authority v-if="hasPublicInterfacePermission" :value="ConfigurationPermission.CREATE">
218 225 <Button type="primary" @click="handleCreateOrUpdatePublicApi()">公共接口管理</Button>
219 226 </Authority>
220 227 <CardLayoutButton v-model:value="listColumn" @change="handleCardLayoutChange" />
... ...
1   -import { FormSchema } from '/@/components/Form';
  1 +import { FormSchema, useComponentRegister } from '/@/components/Form';
2 2 import { findDictItemByCode } from '/@/api/system/dict';
3 3 import { deviceProfile, getGatewayDevice } from '/@/api/device/deviceManager';
4 4 import { TransportTypeEnum } from '../../profiles/components/TransportDescript/const';
  5 +import { JSONEditorValidator } from '/@/components/CodeEditor/src/JSONEditor';
  6 +import { JSONEditor } from '/@/components/CodeEditor';
  7 +useComponentRegister('JSONEditor', JSONEditor);
5 8
6 9 export enum TypeEnum {
7 10 IS_GATEWAY = 'GATEWAY',
... ... @@ -751,6 +754,7 @@ export const CommandSchemas = (transportType: TransportTypeEnum): FormSchema[] =
751 754 minRows: 6,
752 755 },
753 756 },
  757 + colProps: { span: 20 },
754 758 dynamicRules: () => {
755 759 return [
756 760 {
... ... @@ -770,11 +774,17 @@ export const CommandSchemas = (transportType: TransportTypeEnum): FormSchema[] =
770 774 {
771 775 field: 'commandValue',
772 776 label: '请输入命令内容',
773   - slot: 'commandSlot',
774   - component: 'InputTextArea',
775   - show: ({ model }) => {
  777 + component: 'JSONEditor',
  778 + colProps: { span: 20 },
  779 + changeEvent: 'update:value',
  780 + valueField: 'value',
  781 + rules: [...JSONEditorValidator()],
  782 + ifShow: ({ model }) => {
776 783 return model['valueType'] === 'json';
777 784 },
  785 + componentProps: {
  786 + height: 250,
  787 + },
778 788 },
779 789 ];
780 790 };
... ...
1 1 <template>
2   - <div style="background-color: #f0f2f5">
  2 + <div class="bg-neutral-100 dark:text-gray-300 dark:bg-dark-700">
3 3 <BasicTable @register="registerTable">
4 4 <template #action="{ record }">
5 5 <TableAction
... ...
1 1 <template>
2   - <div style="background-color: #f0f2f5">
  2 + <div class="bg-neutral-100 dark:text-gray-300 dark:bg-dark-700">
3 3 <BasicTable @register="registerTable">
4 4 <template #tbDeviceName="{ record }">
5 5 <div style="color: #619eff" class="cursor-pointer" @click="handleGetTbDeviceId(record)">
... ...
1 1 <template>
2 2 <div class="tabs-detail">
3   - <div class="mt-4">
4   - <BasicForm @register="registerForm">
5   - <template #commandSlot>
6   - <div class="flex">
7   - <div ref="jsoneditorRef" style="height: 100%; width: 100%"></div>
8   - <a-button style="margin: -5px 0" type="text" @click="handlePremitter">格式化</a-button>
9   - <Tooltip title='{"method":"methodThingskit","params":{"pin":7,"value":1}}' class="ml-2">
10   - <QuestionCircleOutlined style="font-size: 1rem" />
11   - </Tooltip>
12   - </div>
13   - </template>
14   - </BasicForm>
15   - <Space class="w-full justify-end" justify="end">
16   - <Button :disabled="disable" type="primary" @click="handleOk" class="mr-2">确定</Button>
  3 + <div>
  4 + <BasicForm @register="registerForm" />
  5 + <Space class="w-full justify-end py-2" justify="end">
  6 + <Button :loading="loading" type="primary" @click="handleOk" class="mr-2">确定</Button>
17 7 <Button type="default" @click="handleCancel" class="mr-2">重置</Button>
18 8 </Space>
19 9 </div>
20 10 </div>
21 11 </template>
22 12 <script lang="ts">
23   - import { defineComponent, ref, onMounted, unref, nextTick } from 'vue';
  13 + import { defineComponent, ref } from 'vue';
24 14 import { BasicForm, useForm } from '/@/components/Form';
25 15 import { CommandSchemas } from '../../config/data';
26 16 import { commandIssuanceApi } from '/@/api/device/deviceManager';
27 17 import { useMessage } from '/@/hooks/web/useMessage';
28 18 import { Button } from '/@/components/Button';
29   - import jsoneditor from 'jsoneditor';
30   - import 'jsoneditor/dist/jsoneditor.min.css';
31   - import { QuestionCircleOutlined } from '@ant-design/icons-vue';
32   - import { Space, Tooltip } from 'ant-design-vue';
  19 + import { Space } from 'ant-design-vue';
33 20 import { DeviceRecord } from '/@/api/device/model/deviceModel';
34 21 import { TransportTypeEnum } from '../../../profiles/components/TransportDescript/const';
35   -
36   - interface CommandParams {
37   - additionalInfo: Recordable;
38   - cmdType: string;
39   - method: string;
40   - params: string | Recordable;
41   - persistent: boolean;
42   - }
  22 + import { parseStringToJSON } from '/@/components/CodeEditor/src/JSONEditor';
43 23
44 24 export default defineComponent({
45   - components: { BasicForm, Button, QuestionCircleOutlined, Tooltip, Space },
  25 + components: { BasicForm, Button, Space },
46 26 props: {
47 27 deviceDetail: {
48 28 type: Object as PropType<DeviceRecord>,
... ... @@ -52,8 +32,7 @@
52 32 emits: ['register'],
53 33 setup(props) {
54 34 const { createMessage } = useMessage();
55   - const jsonData = ref<CommandParams>({} as unknown as CommandParams);
56   - const disable = ref(false);
  35 + const loading = ref(false);
57 36
58 37 const [registerForm, { getFieldsValue, validate, resetFields }] = useForm({
59 38 labelWidth: 120,
... ... @@ -63,78 +42,35 @@
63 42 labelAlign: 'right',
64 43 showSubmitButton: false,
65 44 showResetButton: false,
66   - wrapperCol: {
67   - span: 12,
68   - },
69 45 });
70   - // json 以及初始化JSON
71   - const jsoneditorRef = ref();
72   - const jsonValue = ref({});
73   - const jsonInstance = ref();
74   - onMounted(() => {
75   - nextTick(() => {
76   - let options = {
77   - mode: 'code',
78   - mainMenuBar: false,
79   - statusBar: false,
80   - };
81   - let editor = new jsoneditor(jsoneditorRef.value, options);
82   - editor.set(jsonValue.value);
83   - jsonInstance.value = editor;
84   - });
85   - });
86   - const handlePremitter = () => {
87   - const value = unref(jsonInstance).get();
88   - if (!value) return;
89   - return unref(jsonInstance).set(value);
90   - };
  46 +
91 47 const handleCancel = () => {
92 48 resetFields();
93   - unref(jsonInstance).set({});
94 49 };
  50 +
95 51 const handleOk = async () => {
96   - disable.value = true;
  52 + loading.value = true;
97 53 try {
98 54 // 验证
99 55 const valid = await validate();
100 56 if (!valid) return;
101 57 // 收集表单数据
102 58 const field = getFieldsValue();
103   - let passStatus = false;
  59 + let command = {
  60 + persistent: true,
  61 + method: 'methodThingskit',
  62 + params: field.commandText,
  63 + };
104 64 if (field.valueType === 'json') {
105   - const getJson = unref(jsonInstance).get();
106   - if (Object.prototype.isPrototypeOf(getJson) && Object.keys(getJson).length === 0) {
107   - createMessage.error('命令内容不能为空');
108   - passStatus = true;
109   - }
110   - if (getJson === '') {
111   - passStatus = true;
112   - createMessage.error('命令内容不能为空');
113   - }
114   - jsonData.value.params = getJson;
115   - } else {
116   - jsonData.value.params = field.commandText;
117   - if (!jsonData.value.params) {
118   - createMessage.error('命令内容不能为空');
119   - passStatus = true;
120   - }
121   - if (
122   - jsonData.value.params == '""' ||
123   - jsonData.value.params == "''" ||
124   - jsonData.value.params == '“”'
125   - ) {
126   - createMessage.error('命令内容不能为空');
127   - passStatus = true;
128   - }
  65 + const { json } = parseStringToJSON(field.commandValue);
  66 + command.params = json;
129 67 }
130   - jsonData.value.persistent = true;
131   - jsonData.value.method = 'methodThingskit';
132   - if (passStatus) return;
133   - commandIssuanceApi(field.commandType, props.deviceDetail.tbDeviceId, jsonData.value)
  68 +
  69 + commandIssuanceApi(field.commandType, props.deviceDetail.tbDeviceId, command)
134 70 .then((res) => {
135 71 if (!res) return;
136 72 createMessage.success('命令下发成功');
137   - disable.value = true;
  73 + loading.value = true;
138 74 // 请求
139 75 handleCancel();
140 76 })
... ... @@ -146,25 +82,20 @@
146 82 })
147 83 .finally(() => {
148 84 setTimeout(() => {
149   - disable.value = false;
  85 + loading.value = false;
150 86 }, 300);
151 87 });
152 88 } catch (e) {
  89 + throw e;
153 90 } finally {
154   - //这里捕获json插件的错误
155   - disable.value = false;
  91 + loading.value = false;
156 92 }
157 93 };
158 94 return {
159 95 registerForm,
160 96 handleCancel,
161 97 handleOk,
162   - disable,
163   - jsonData,
164   - jsoneditorRef,
165   - jsonValue,
166   - jsonInstance,
167   - handlePremitter,
  98 + loading,
168 99 };
169 100 },
170 101 });
... ...
... ... @@ -53,7 +53,7 @@
53 53 </script>
54 54
55 55 <template>
56   - <BasicTable class="event-manage-table" @register="register">
  56 + <BasicTable class="bg-neutral-100 dark:text-gray-300 dark:bg-dark-700" @register="register">
57 57 <template #outputParams="{ record }">
58 58 <span class="cursor-pointer text-blue-500" @click="handleViewDetail(record)">
59 59 <EyeOutlined class="svg:text-blue-500" />
... ... @@ -65,9 +65,3 @@
65 65 <Input.TextArea v-model:value="outputData" :autosize="true" />
66 66 </BasicModal>
67 67 </template>
68   -
69   -<style lang="less" scoped>
70   - .event-manage-table {
71   - background-color: #f0f2f5;
72   - }
73   -</style>
... ...
... ... @@ -230,15 +230,16 @@
230 230 <template>
231 231 <PageWrapper
232 232 dense
233   - content-class="flex flex-col bg-transparent p-4"
234   - :content-style="{ backgroundColor: '#F0F2F5' }"
  233 + content-class="flex flex-col bg-transparent p-4 bg-neutral-100 dark:text-gray-300 dark:bg-dark-700"
235 234 >
236   - <section class="flex flex-col justify-between w-full bg-light-50 pt-3 mb-4">
  235 + <section
  236 + class="flex flex-col justify-between w-full bg-light-50 pt-3 mb-4 dark:text-gray-300 dark:bg-dark-900"
  237 + >
237 238 <div class="flex-auto">
238 239 <BasicForm @register="registerForm" />
239 240 </div>
240 241 </section>
241   - <section class="bg-light-50">
  242 + <section class="bg-light-50 !dark:text-gray-300 !dark:bg-dark-900">
242 243 <div
243 244 v-show="mode === EnumTableCardMode.CARD"
244 245 class="flex h-70px items-center justify-end p-2"
... ...
... ... @@ -102,7 +102,9 @@
102 102 </script>
103 103
104 104 <template>
105   - <PageWrapper class="bg-gray-100 device-task-list-container">
  105 + <PageWrapper
  106 + class="bg-neutral-100 dark:text-gray-300 dark:bg-dark-700 device-task-list-container"
  107 + >
106 108 <section
107 109 class="form-container bg-light-50 px-4 pt-4 mt-4 x dark:text-gray-300 dark:bg-dark-900"
108 110 >
... ...
1 1 <template>
2   - <BasicTable class="command-record-table" @register="registerTable">
  2 + <BasicTable
  3 + class="bg-neutral-100 dark:text-gray-300 dark:bg-dark-700 p-4"
  4 + @register="registerTable"
  5 + >
3 6 <template #toolbar>
4 7 <Space>
5 8 <Button type="primary" @click="openModal(true)">命令下发</Button>
... ... @@ -21,11 +24,11 @@
21 24
22 25 <BasicModal
23 26 @register="registerCommandIssuanceModal"
24   - width="600px"
  27 + width="700px"
25 28 title="命令下发"
26 29 :showOkBtn="false"
27 30 cancelText="关闭"
28   - :footer="h('div')"
  31 + :footer="null"
29 32 >
30 33 <CommandIssuance :deviceDetail="deviceDetail" />
31 34 </BasicModal>
... ... @@ -91,10 +94,3 @@
91 94 commonModalInfo('响应内容', jsonParams);
92 95 };
93 96 </script>
94   -
95   -<style lang="less" scoped>
96   - .command-record-table {
97   - background-color: #f0f2f5;
98   - padding: 16px;
99   - }
100   -</style>
... ...
... ... @@ -151,7 +151,7 @@
151 151 </Tabs>
152 152 <template #footer>
153 153 <div
154   - class="absolute right-0 bottom-0 w-full border-t bg-light-50 border-t-gray-100 py-2 px-4 text-right"
  154 + class="absolute right-0 bottom-0 w-full border-t bg-light-50 dark:text-gray-300 dark:bg-dark-700 dark:border-t-gray-700 border-t-gray-100 py-2 px-4 text-right"
155 155 >
156 156 <Button class="mr-2" @click="closeDrawer">取消</Button>
157 157 <Authority :value="OtaPermissionKey.UPDATE">
... ...
... ... @@ -193,7 +193,11 @@
193 193 const userStore = useUserStore();
194 194
195 195 const permissionStore = usePermissionStore();
196   - async function handleLoginCustomAdmin(record: { tbUser: string; id: string }) {
  196 + async function handleLoginCustomAdmin(record: {
  197 + tbUser: string;
  198 + id: string;
  199 + hasPassword: boolean;
  200 + }) {
197 201 try {
198 202 const { token, refreshToken } = await getUserToken(record.id);
199 203 userStore.storeToken(token, refreshToken);
... ... @@ -208,7 +212,7 @@
208 212 });
209 213 router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
210 214 permissionStore.setDynamicAddedRoute(true);
211   - go(PageEnum.BASE_HOME);
  215 + record.hasPassword ? go(PageEnum.BASE_HOME) : go(PageEnum.SYSTEM_PASSWORD);
212 216 } catch (error) {
213 217 } finally {
214 218 }
... ...
... ... @@ -161,18 +161,21 @@
161 161 api: async () => {
162 162 try {
163 163 if (!organizationId) return [];
164   - return await getMeetTheConditionsDevice({
  164 + const result = await getMeetTheConditionsDevice({
165 165 deviceProfileId,
166 166 deviceType,
167 167 organizationId,
168 168 });
  169 + return result.map((item) => ({
  170 + ...item,
  171 + value: item.tbDeviceId,
  172 + label: item.alias || item.name,
  173 + }));
169 174 } catch (error) {
170 175 return [];
171 176 }
172 177 },
173 178 mode: props.multiple ? 'multiple' : 'combobox',
174   - labelField: 'name',
175   - valueField: 'tbDeviceId',
176 179 placeholder: '请选择设备',
177 180 maxTagCount: 3,
178 181 maxTagTextLength: 4,
... ...
... ... @@ -118,7 +118,7 @@
118 118 <template>
119 119 <PageWrapper class="task-center-container">
120 120 <section
121   - class="bg-light-50 flex p-4 justify-between items-center x dark:text-gray-300 dark:bg-dark-900"
  121 + class="bg-light-50 flex p-4 justify-between items-center dark:text-gray-300 dark:bg-dark-900"
122 122 >
123 123 <div class="text-2xl">任务中心</div>
124 124 <Authority :value="PermissionEnum.CREATE">
... ...
... ... @@ -333,7 +333,12 @@
333 333 <h3 class="w-24 flex-shrink-0 text-right pr-2 my-4">选择数据源</h3>
334 334
335 335 <section ref="formListEl">
336   - <div v-for="item in dataSource" :data-id="item.id" :key="item.id" class="flex bg-light-50">
  336 + <div
  337 + v-for="item in dataSource"
  338 + :data-id="item.id"
  339 + :key="item.id"
  340 + class="flex bg-neutral-100 dark:text-gray-300 dark:bg-dark-700"
  341 + >
337 342 <div class="w-24 text-right flex justify-end" style="flex: 0 0 96px"> 选择设备 </div>
338 343 <div class="pl-2 flex-auto">
339 344 <component
... ...