Commit 738df9674546ae2d73721e615f16315998e9413b

Authored by xp.Huang
2 parents e26aac7e 021aa9bb

Merge branch 'local_dev_ft' into 'main'

feat:设备新增命令下发记录;styles:调整企业定制部分样式

See merge request yunteng/thingskit-front!481
1 -import { defHttp } from '/@/utils/http/axios';  
2 -import {  
3 - TDeviceConfigParams,  
4 - IDeviceConfigAddOrEditModel,  
5 - ProfileRecord,  
6 - RuleChainRecord,  
7 -} from '/@/api/device/model/deviceConfigModel';  
8 -import { PaginationResult } from '/#/axios';  
9 -  
10 -enum EDeviceConfigApi {  
11 - /**  
12 - * 设备配置URL  
13 - */  
14 - DEVICE_CONFIG_GET_PAGE = '/device_profile',  
15 - DEVICE_CONFIG_POST_ADD_OR_EDIT = '/device_profile',  
16 - DEVICE_CONFIG_GET_DETAIL = '/device_profile/',  
17 - DEVICE_CONFIG_DELETE = '/device_profile',  
18 - DEVICE_CONFIG_GET_RULECHAIN = '/rule_chain/me/list',  
19 - ALARM_CONTACT_GET_PAGE = '/alarm_contact',  
20 - DEVICE_CONFIG_EXPORT = '/device_profile/export',  
21 - DEVICE_CONFIG_IMPORT = '/device_profile/import',  
22 - SET_DEVICE_ISDEFAULT = '/deviceProfile',  
23 - FRP_API = '/frp/',  
24 - GET_TB_DEVICE_ID = '/device/get_subset',  
25 -}  
26 -  
27 -/**  
28 - * 设备配置详情  
29 - */  
30 -export const deviceConfigGetDetail = (id: string) => {  
31 - return defHttp.get({  
32 - url: `${EDeviceConfigApi.DEVICE_CONFIG_GET_DETAIL}${id}`,  
33 - });  
34 -};  
35 -  
36 -/**  
37 - * 获取规则链  
38 - */  
39 -export const deviceConfigGetRuleChain = () => {  
40 - return defHttp.get<RuleChainRecord[]>({  
41 - url: EDeviceConfigApi.DEVICE_CONFIG_GET_RULECHAIN,  
42 - });  
43 -};  
44 -  
45 -/**  
46 - * 获取告警联系人  
47 - */  
48 -export const alarmContactGetPage = () => {  
49 - return defHttp.get({  
50 - url: `${EDeviceConfigApi.ALARM_CONTACT_GET_PAGE}?page=1&pageSize=10`,  
51 - });  
52 -};  
53 -  
54 -/**  
55 - * 分页查询设备配置页面  
56 - */  
57 -export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => {  
58 - return defHttp.get<PaginationResult<ProfileRecord>>({  
59 - url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE,  
60 - params,  
61 - });  
62 -};  
63 -  
64 -/**  
65 - * 新增或者编辑设备配置  
66 -  
67 - */  
68 -export const deviceConfigAddOrEdit = (params: IDeviceConfigAddOrEditModel) => {  
69 - return defHttp.post<IDeviceConfigAddOrEditModel>({  
70 - url: EDeviceConfigApi.DEVICE_CONFIG_POST_ADD_OR_EDIT,  
71 - params,  
72 - });  
73 -};  
74 -  
75 -/**  
76 - * 删除设备配置  
77 - */  
78 -export const deviceConfigDelete = (ids: string[]) => {  
79 - return defHttp.delete({  
80 - url: EDeviceConfigApi.DEVICE_CONFIG_DELETE,  
81 - data: {  
82 - ids,  
83 - },  
84 - });  
85 -};  
86 -  
87 -/**  
88 - * 导出设备配置  
89 - */  
90 -export const deviceConfigExport = (params: IDeviceConfigAddOrEditModel) => {  
91 - return defHttp.post<IDeviceConfigAddOrEditModel>({  
92 - url: EDeviceConfigApi.DEVICE_CONFIG_EXPORT,  
93 - params,  
94 - });  
95 -};  
96 -  
97 -/**  
98 - * 导入设备配置  
99 - */  
100 -export const deviceConfigImport = (params: IDeviceConfigAddOrEditModel) => {  
101 - return defHttp.post<IDeviceConfigAddOrEditModel>({  
102 - url: EDeviceConfigApi.DEVICE_CONFIG_IMPORT,  
103 - params,  
104 - });  
105 -};  
106 -  
107 -/**  
108 - *  
109 - * 设置该设备配置为默认  
110 - */  
111 -export const setDeviceProfileIsDefaultApi = (id: string, v, params?: {}) => {  
112 - return defHttp.post(  
113 - {  
114 - url: EDeviceConfigApi.SET_DEVICE_ISDEFAULT + '/' + id + '/' + v,  
115 - params,  
116 - },  
117 - {  
118 - joinPrefix: false,  
119 - }  
120 - );  
121 -};  
122 -  
123 -/**  
124 - * Frp内网穿透信息API  
125 - */  
126 -export const frpGetInfoApi = (proxyName: string) => {  
127 - return defHttp.get({  
128 - url: `${EDeviceConfigApi.FRP_API}${proxyName}`,  
129 - });  
130 -};  
131 -  
132 -export const frpPutInfoApi = (proxyName: string, enableRemote: number) => {  
133 - return defHttp.put({  
134 - url: `${EDeviceConfigApi.FRP_API}${proxyName}/${enableRemote}`,  
135 - });  
136 -};  
137 -  
138 -export const getTbDeviceId = (params: string) => {  
139 - return defHttp.get({  
140 - url: `${EDeviceConfigApi.GET_TB_DEVICE_ID}/${params}`,  
141 - });  
142 -}; 1 +import { defHttp } from '/@/utils/http/axios';
  2 +import {
  3 + TDeviceConfigParams,
  4 + IDeviceConfigAddOrEditModel,
  5 + ProfileRecord,
  6 + RuleChainRecord,
  7 +} from '/@/api/device/model/deviceConfigModel';
  8 +import { PaginationResult } from '/#/axios';
  9 +
  10 +enum EDeviceConfigApi {
  11 + /**
  12 + * 设备配置URL
  13 + */
  14 + DEVICE_CONFIG_GET_PAGE = '/device_profile',
  15 + DEVICE_CONFIG_POST_ADD_OR_EDIT = '/device_profile',
  16 + DEVICE_CONFIG_GET_DETAIL = '/device_profile/',
  17 + DEVICE_CONFIG_DELETE = '/device_profile',
  18 + DEVICE_CONFIG_GET_RULECHAIN = '/rule_chain/me/list',
  19 + ALARM_CONTACT_GET_PAGE = '/alarm_contact',
  20 + DEVICE_CONFIG_EXPORT = '/device_profile/export',
  21 + DEVICE_CONFIG_IMPORT = '/device_profile/import',
  22 + SET_DEVICE_ISDEFAULT = '/deviceProfile',
  23 + FRP_API = '/frp/',
  24 + GET_TB_DEVICE_ID = '/device/get_subset',
  25 + COMMODRECORD = '/rpc',
  26 +}
  27 +
  28 +/**
  29 + * 设备配置详情
  30 + */
  31 +export const deviceConfigGetDetail = (id: string) => {
  32 + return defHttp.get({
  33 + url: `${EDeviceConfigApi.DEVICE_CONFIG_GET_DETAIL}${id}`,
  34 + });
  35 +};
  36 +
  37 +/**
  38 + * 获取规则链
  39 + */
  40 +export const deviceConfigGetRuleChain = () => {
  41 + return defHttp.get<RuleChainRecord[]>({
  42 + url: EDeviceConfigApi.DEVICE_CONFIG_GET_RULECHAIN,
  43 + });
  44 +};
  45 +
  46 +/**
  47 + * 获取告警联系人
  48 + */
  49 +export const alarmContactGetPage = () => {
  50 + return defHttp.get({
  51 + url: `${EDeviceConfigApi.ALARM_CONTACT_GET_PAGE}?page=1&pageSize=10`,
  52 + });
  53 +};
  54 +
  55 +/**
  56 + * 分页查询设备配置页面
  57 + */
  58 +export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => {
  59 + return defHttp.get<PaginationResult<ProfileRecord>>({
  60 + url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE,
  61 + params,
  62 + });
  63 +};
  64 +
  65 +/**
  66 + * 新增或者编辑设备配置
  67 +
  68 + */
  69 +export const deviceConfigAddOrEdit = (params: IDeviceConfigAddOrEditModel) => {
  70 + return defHttp.post<IDeviceConfigAddOrEditModel>({
  71 + url: EDeviceConfigApi.DEVICE_CONFIG_POST_ADD_OR_EDIT,
  72 + params,
  73 + });
  74 +};
  75 +
  76 +/**
  77 + * 删除设备配置
  78 + */
  79 +export const deviceConfigDelete = (ids: string[]) => {
  80 + return defHttp.delete({
  81 + url: EDeviceConfigApi.DEVICE_CONFIG_DELETE,
  82 + data: {
  83 + ids,
  84 + },
  85 + });
  86 +};
  87 +
  88 +/**
  89 + * 导出设备配置
  90 + */
  91 +export const deviceConfigExport = (params: IDeviceConfigAddOrEditModel) => {
  92 + return defHttp.post<IDeviceConfigAddOrEditModel>({
  93 + url: EDeviceConfigApi.DEVICE_CONFIG_EXPORT,
  94 + params,
  95 + });
  96 +};
  97 +
  98 +/**
  99 + * 导入设备配置
  100 + */
  101 +export const deviceConfigImport = (params: IDeviceConfigAddOrEditModel) => {
  102 + return defHttp.post<IDeviceConfigAddOrEditModel>({
  103 + url: EDeviceConfigApi.DEVICE_CONFIG_IMPORT,
  104 + params,
  105 + });
  106 +};
  107 +
  108 +/**
  109 + *
  110 + * 设置该设备配置为默认
  111 + */
  112 +export const setDeviceProfileIsDefaultApi = (id: string, v, params?: {}) => {
  113 + return defHttp.post(
  114 + {
  115 + url: EDeviceConfigApi.SET_DEVICE_ISDEFAULT + '/' + id + '/' + v,
  116 + params,
  117 + },
  118 + {
  119 + joinPrefix: false,
  120 + }
  121 + );
  122 +};
  123 +
  124 +/**
  125 + * Frp内网穿透信息API
  126 + */
  127 +export const frpGetInfoApi = (proxyName: string) => {
  128 + return defHttp.get({
  129 + url: `${EDeviceConfigApi.FRP_API}${proxyName}`,
  130 + });
  131 +};
  132 +
  133 +export const frpPutInfoApi = (proxyName: string, enableRemote: number) => {
  134 + return defHttp.put({
  135 + url: `${EDeviceConfigApi.FRP_API}${proxyName}/${enableRemote}`,
  136 + });
  137 +};
  138 +
  139 +export const getTbDeviceId = (params: string) => {
  140 + return defHttp.get({
  141 + url: `${EDeviceConfigApi.GET_TB_DEVICE_ID}/${params}`,
  142 + });
  143 +};
  144 +
  145 +/**
  146 + * 命令下发记录
  147 + */
  148 +export const deviceCommandRecordGetQuery = (params?: TDeviceConfigParams) => {
  149 + return defHttp.get({
  150 + url: EDeviceConfigApi.COMMODRECORD,
  151 + params,
  152 + });
  153 +};
1 -import { BasicPageParams } from '/@/api/model/baseModel';  
2 -  
3 -export type TDeviceConfigPageQueryParam = BasicPageParams & TDeviceConfigParams;  
4 -  
5 -export type TDeviceConfigParams = {  
6 - page?: any;  
7 - pageSize?: any;  
8 - name?: string;  
9 - transportType?: string;  
10 - orderFiled?: string;  
11 - orderType?: string;  
12 -};  
13 -  
14 -export interface IDeviceConfigAddOrEditModel {  
15 - defaultQueueName?: string; //处理队列  
16 - alarmProfile?: {  
17 - alarmContactId: string;  
18 - createTime: '2021-12-15T02:17:26.644Z';  
19 - creator: string;  
20 - defaultConfig: string;  
21 - description: string;  
22 - deviceProfileId: string;  
23 - enabled: true;  
24 - icon: string;  
25 - id: string;  
26 - messageMode: string;  
27 - name: string;  
28 - roleIds: [string];  
29 - tenantExpireTime: '2021-12-15T02:17:26.644Z';  
30 - tenantId: string;  
31 - tenantStatus: 'DISABLED';  
32 - updateTime: '2021-12-15T02:17:26.644Z';  
33 - updater: string;  
34 - };  
35 - convertJs?: string;  
36 - createTime?: '2021-12-15T02:17:26.644Z';  
37 - creator?: string;  
38 - defaultConfig?: string;  
39 - defaultRuleChainId?: string;  
40 - description?: string;  
41 - enabled?: true;  
42 - icon?: string;  
43 - id?: string;  
44 - name?: string;  
45 - profileData?: {  
46 - configuration: {};  
47 - transportConfiguration: {};  
48 - provisionConfiguration: {  
49 - provisionDeviceSecret: string;  
50 - };  
51 - //报警类型字段  
52 - alarms: [  
53 - {  
54 - id: 'highTemperatureAlarmID';  
55 - alarmType: 'High Temperature Alarm';  
56 - createRules: {  
57 - additionalProp1: {  
58 - condition: {  
59 - condition: [  
60 - {  
61 - key: {  
62 - type: 'TIME_SERIES';  
63 - key: 'temp';  
64 - };  
65 - valueType: 'NUMERIC';  
66 - value: {};  
67 - predicate: {};  
68 - }  
69 - ];  
70 - spec: {};  
71 - };  
72 - schedule: {  
73 - type: 'ANY_TIME';  
74 - };  
75 - alarmDetails: string;  
76 - dashboardId: {  
77 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
78 - entityType: 'DASHBOARD';  
79 - };  
80 - };  
81 - additionalProp2: {  
82 - condition: {  
83 - condition: [  
84 - {  
85 - key: {  
86 - type: 'TIME_SERIES';  
87 - key: 'temp';  
88 - };  
89 - valueType: 'NUMERIC';  
90 - value: {};  
91 - predicate: {};  
92 - }  
93 - ];  
94 - spec: {};  
95 - };  
96 - schedule: {  
97 - type: 'ANY_TIME';  
98 - };  
99 - alarmDetails: string;  
100 - dashboardId: {  
101 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
102 - entityType: 'DASHBOARD';  
103 - };  
104 - };  
105 - additionalProp3: {  
106 - condition: {  
107 - condition: [  
108 - {  
109 - key: {  
110 - type: 'TIME_SERIES';  
111 - key: 'temp';  
112 - };  
113 - valueType: 'NUMERIC';  
114 - value: {};  
115 - predicate: {};  
116 - }  
117 - ];  
118 - spec: {};  
119 - };  
120 - schedule: {  
121 - type: 'ANY_TIME';  
122 - };  
123 - alarmDetails: string;  
124 - dashboardId: {  
125 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
126 - entityType: 'DASHBOARD';  
127 - };  
128 - };  
129 - };  
130 - clearRule: {  
131 - condition: {  
132 - condition: [  
133 - {  
134 - key: {  
135 - type: 'TIME_SERIES';  
136 - key: 'temp';  
137 - };  
138 - valueType: 'NUMERIC';  
139 - value: {};  
140 - predicate: {};  
141 - }  
142 - ];  
143 - spec: {};  
144 - };  
145 - schedule: {  
146 - type: 'ANY_TIME';  
147 - };  
148 - alarmDetails: string;  
149 - dashboardId: {  
150 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
151 - entityType: 'DASHBOARD';  
152 - };  
153 - };  
154 - propagate: true;  
155 - propagateRelationTypes: [string];  
156 - }  
157 - ];  
158 - };  
159 - roleIds?: [string];  
160 - tbProfileId?: string;  
161 - tenantExpireTime?: '2021-12-15T02:17:26.645Z';  
162 - tenantId?: string;  
163 - tenantStatus?: 'DISABLED';  
164 - transportType?: string;  
165 - updateTime?: '2021-12-15T02:17:26.645Z';  
166 - updater?: string;  
167 -}  
168 -  
169 -export interface Data {  
170 - CO: number;  
171 -}  
172 -  
173 -export interface Details {  
174 - data: Data;  
175 -}  
176 -  
177 -export interface AlarmLogItem {  
178 - id: string;  
179 - tenantId: string;  
180 - creator?: any;  
181 - updater?: any;  
182 - createdTime: string;  
183 - updatedTime: string;  
184 - customerId: string;  
185 - tbDeviceId: string;  
186 - originatorType: number;  
187 - deviceId: string;  
188 - deviceName: string;  
189 - type: string;  
190 - severity: string;  
191 - status: string;  
192 - startTs: string;  
193 - endTs: string;  
194 - ackTs: string;  
195 - clearTs: string;  
196 - details: Details;  
197 - propagate: boolean;  
198 - propagateRelationTypes?: any;  
199 - organizationId: string;  
200 - organizationName: string;  
201 -}  
202 -  
203 -export interface Configuration {  
204 - type: string;  
205 -}  
206 -  
207 -export interface TransportConfiguration {  
208 - type: string;  
209 -}  
210 -  
211 -export interface ProvisionConfiguration {  
212 - type: string;  
213 - provisionDeviceSecret?: any;  
214 -}  
215 -  
216 -export interface ProfileData {  
217 - configuration: Configuration;  
218 - transportConfiguration: TransportConfiguration;  
219 - provisionConfiguration: ProvisionConfiguration;  
220 - alarms?: any;  
221 -}  
222 -  
223 -export interface ProfileRecord {  
224 - id: string;  
225 - creator: string;  
226 - createTime: string;  
227 - updater: string;  
228 - updateTime: string;  
229 - name: string;  
230 - tenantId: string;  
231 - transportType: string;  
232 - provisionType: string;  
233 - deviceType: string;  
234 - tbProfileId: string;  
235 - profileData: ProfileData;  
236 - defaultRuleChainId: string;  
237 - defaultQueueName: string;  
238 - image: string;  
239 - type: string;  
240 - default: boolean;  
241 -  
242 - checked?: boolean;  
243 -}  
244 -  
245 -export interface IDRecord {  
246 - entityType: string;  
247 - id: string;  
248 -}  
249 -  
250 -export interface RuleChainRecord {  
251 - id: IDRecord;  
252 - createdTime: number;  
253 - additionalInfo?: any;  
254 - tenantId: IDRecord;  
255 - name: string;  
256 - type: string;  
257 - firstRuleNodeId: IDRecord;  
258 - root: boolean;  
259 - debugMode: boolean;  
260 - configuration?: any;  
261 -} 1 +import { BasicPageParams } from '/@/api/model/baseModel';
  2 +
  3 +export type TDeviceConfigPageQueryParam = BasicPageParams & TDeviceConfigParams;
  4 +
  5 +export type TDeviceConfigParams = {
  6 + page?: any;
  7 + pageSize?: any;
  8 + name?: string;
  9 + transportType?: string;
  10 + orderFiled?: string;
  11 + orderType?: string;
  12 + tbDeviceId?: string;
  13 +};
  14 +
  15 +export interface IDeviceConfigAddOrEditModel {
  16 + defaultQueueName?: string; //处理队列
  17 + alarmProfile?: {
  18 + alarmContactId: string;
  19 + createTime: '2021-12-15T02:17:26.644Z';
  20 + creator: string;
  21 + defaultConfig: string;
  22 + description: string;
  23 + deviceProfileId: string;
  24 + enabled: true;
  25 + icon: string;
  26 + id: string;
  27 + messageMode: string;
  28 + name: string;
  29 + roleIds: [string];
  30 + tenantExpireTime: '2021-12-15T02:17:26.644Z';
  31 + tenantId: string;
  32 + tenantStatus: 'DISABLED';
  33 + updateTime: '2021-12-15T02:17:26.644Z';
  34 + updater: string;
  35 + };
  36 + convertJs?: string;
  37 + createTime?: '2021-12-15T02:17:26.644Z';
  38 + creator?: string;
  39 + defaultConfig?: string;
  40 + defaultRuleChainId?: string;
  41 + description?: string;
  42 + enabled?: true;
  43 + icon?: string;
  44 + id?: string;
  45 + name?: string;
  46 + profileData?: {
  47 + configuration: {};
  48 + transportConfiguration: {};
  49 + provisionConfiguration: {
  50 + provisionDeviceSecret: string;
  51 + };
  52 + //报警类型字段
  53 + alarms: [
  54 + {
  55 + id: 'highTemperatureAlarmID';
  56 + alarmType: 'High Temperature Alarm';
  57 + createRules: {
  58 + additionalProp1: {
  59 + condition: {
  60 + condition: [
  61 + {
  62 + key: {
  63 + type: 'TIME_SERIES';
  64 + key: 'temp';
  65 + };
  66 + valueType: 'NUMERIC';
  67 + value: {};
  68 + predicate: {};
  69 + }
  70 + ];
  71 + spec: {};
  72 + };
  73 + schedule: {
  74 + type: 'ANY_TIME';
  75 + };
  76 + alarmDetails: string;
  77 + dashboardId: {
  78 + id: '784f394c-42b6-435a-983c-b7beff2784f9';
  79 + entityType: 'DASHBOARD';
  80 + };
  81 + };
  82 + additionalProp2: {
  83 + condition: {
  84 + condition: [
  85 + {
  86 + key: {
  87 + type: 'TIME_SERIES';
  88 + key: 'temp';
  89 + };
  90 + valueType: 'NUMERIC';
  91 + value: {};
  92 + predicate: {};
  93 + }
  94 + ];
  95 + spec: {};
  96 + };
  97 + schedule: {
  98 + type: 'ANY_TIME';
  99 + };
  100 + alarmDetails: string;
  101 + dashboardId: {
  102 + id: '784f394c-42b6-435a-983c-b7beff2784f9';
  103 + entityType: 'DASHBOARD';
  104 + };
  105 + };
  106 + additionalProp3: {
  107 + condition: {
  108 + condition: [
  109 + {
  110 + key: {
  111 + type: 'TIME_SERIES';
  112 + key: 'temp';
  113 + };
  114 + valueType: 'NUMERIC';
  115 + value: {};
  116 + predicate: {};
  117 + }
  118 + ];
  119 + spec: {};
  120 + };
  121 + schedule: {
  122 + type: 'ANY_TIME';
  123 + };
  124 + alarmDetails: string;
  125 + dashboardId: {
  126 + id: '784f394c-42b6-435a-983c-b7beff2784f9';
  127 + entityType: 'DASHBOARD';
  128 + };
  129 + };
  130 + };
  131 + clearRule: {
  132 + condition: {
  133 + condition: [
  134 + {
  135 + key: {
  136 + type: 'TIME_SERIES';
  137 + key: 'temp';
  138 + };
  139 + valueType: 'NUMERIC';
  140 + value: {};
  141 + predicate: {};
  142 + }
  143 + ];
  144 + spec: {};
  145 + };
  146 + schedule: {
  147 + type: 'ANY_TIME';
  148 + };
  149 + alarmDetails: string;
  150 + dashboardId: {
  151 + id: '784f394c-42b6-435a-983c-b7beff2784f9';
  152 + entityType: 'DASHBOARD';
  153 + };
  154 + };
  155 + propagate: true;
  156 + propagateRelationTypes: [string];
  157 + }
  158 + ];
  159 + };
  160 + roleIds?: [string];
  161 + tbProfileId?: string;
  162 + tenantExpireTime?: '2021-12-15T02:17:26.645Z';
  163 + tenantId?: string;
  164 + tenantStatus?: 'DISABLED';
  165 + transportType?: string;
  166 + updateTime?: '2021-12-15T02:17:26.645Z';
  167 + updater?: string;
  168 +}
  169 +
  170 +export interface Data {
  171 + CO: number;
  172 +}
  173 +
  174 +export interface Details {
  175 + data: Data;
  176 +}
  177 +
  178 +export interface AlarmLogItem {
  179 + id: string;
  180 + tenantId: string;
  181 + creator?: any;
  182 + updater?: any;
  183 + createdTime: string;
  184 + updatedTime: string;
  185 + customerId: string;
  186 + tbDeviceId: string;
  187 + originatorType: number;
  188 + deviceId: string;
  189 + deviceName: string;
  190 + type: string;
  191 + severity: string;
  192 + status: string;
  193 + startTs: string;
  194 + endTs: string;
  195 + ackTs: string;
  196 + clearTs: string;
  197 + details: Details;
  198 + propagate: boolean;
  199 + propagateRelationTypes?: any;
  200 + organizationId: string;
  201 + organizationName: string;
  202 +}
  203 +
  204 +export interface Configuration {
  205 + type: string;
  206 +}
  207 +
  208 +export interface TransportConfiguration {
  209 + type: string;
  210 +}
  211 +
  212 +export interface ProvisionConfiguration {
  213 + type: string;
  214 + provisionDeviceSecret?: any;
  215 +}
  216 +
  217 +export interface ProfileData {
  218 + configuration: Configuration;
  219 + transportConfiguration: TransportConfiguration;
  220 + provisionConfiguration: ProvisionConfiguration;
  221 + alarms?: any;
  222 +}
  223 +
  224 +export interface ProfileRecord {
  225 + id: string;
  226 + creator: string;
  227 + createTime: string;
  228 + updater: string;
  229 + updateTime: string;
  230 + name: string;
  231 + tenantId: string;
  232 + transportType: string;
  233 + provisionType: string;
  234 + deviceType: string;
  235 + tbProfileId: string;
  236 + profileData: ProfileData;
  237 + defaultRuleChainId: string;
  238 + defaultQueueName: string;
  239 + image: string;
  240 + type: string;
  241 + default: boolean;
  242 +
  243 + checked?: boolean;
  244 +}
  245 +
  246 +export interface IDRecord {
  247 + entityType: string;
  248 + id: string;
  249 +}
  250 +
  251 +export interface RuleChainRecord {
  252 + id: IDRecord;
  253 + createdTime: number;
  254 + additionalInfo?: any;
  255 + tenantId: IDRecord;
  256 + name: string;
  257 + type: string;
  258 + firstRuleNodeId: IDRecord;
  259 + root: boolean;
  260 + debugMode: boolean;
  261 + configuration?: any;
  262 +}
1 -<template>  
2 - <BasicDrawer  
3 - v-bind="$attrs"  
4 - isDetail  
5 - @register="register"  
6 - destroyOnClose  
7 - @close="closeDrawer"  
8 - :title="deviceDetail.alias || deviceDetail.name"  
9 - width="80%"  
10 - >  
11 - <Tabs v-model:activeKey="activeKey" :size="size">  
12 - <TabPane key="1" tab="详情">  
13 - <Detail  
14 - ref="deviceDetailRef"  
15 - :deviceDetail="deviceDetail"  
16 - @open-gateway-device="handleOpenGatewayDevice"  
17 - />  
18 - </TabPane>  
19 - <TabPane key="modelOfMatter" tab="物模型数据">  
20 - <ModelOfMatter :deviceDetail="deviceDetail" />  
21 - </TabPane>  
22 - <!-- <TabPane key="2" tab="实时数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">  
23 - <RealTimeData :deviceDetail="deviceDetail" />  
24 - </TabPane>  
25 - <TabPane key="7" tab="历史数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">  
26 - <HistoryData :deviceDetail="deviceDetail" />  
27 - </TabPane> -->  
28 - <TabPane key="5" tab="命令下发" v-if="deviceDetail?.deviceType !== 'SENSOR'">  
29 - <CommandIssuance :deviceDetail="deviceDetail" />  
30 - </TabPane>  
31 - <TabPane key="3" tab="告警"><Alarm :id="deviceDetail.id" /></TabPane>  
32 - <TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'">  
33 - <ChildDevice  
34 - :fromId="deviceDetail?.tbDeviceId"  
35 - @openTbDeviceDetail="handleOpenTbDeviceDetail"  
36 - />  
37 - </TabPane>  
38 - <!-- 网关设备并且场家是TBox -->  
39 - <TabPane  
40 - key="6"  
41 - tab="TBox"  
42 - v-if="deviceDetail?.deviceType === 'GATEWAY' && deviceDetail?.brand == 'TBox'"  
43 - >  
44 - <TBoxDetail :deviceDetail="deviceDetail" />  
45 - </TabPane>  
46 - <!-- 网关设备并且是TBox -->  
47 - </Tabs>  
48 - </BasicDrawer>  
49 -</template>  
50 -<script lang="ts">  
51 - import { defineComponent, ref } from 'vue';  
52 - import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';  
53 -  
54 - import { Tabs } from 'ant-design-vue';  
55 - import Detail from '../tabs/Detail.vue';  
56 - // import RealTimeData from '../tabs/RealTimeData.vue';  
57 - import Alarm from '../tabs/Alarm.vue';  
58 - import ChildDevice from '../tabs/ChildDevice.vue';  
59 - import TBoxDetail from '../tabs/TBoxDetail.vue';  
60 - import CommandIssuance from '../tabs/CommandIssuance.vue';  
61 - import { getDeviceDetail } from '/@/api/device/deviceManager';  
62 - // import HistoryData from '../tabs/HistoryData.vue';  
63 - import ModelOfMatter from '../tabs/ModelOfMatter.vue';  
64 - export default defineComponent({  
65 - name: 'DeviceModal',  
66 - components: {  
67 - BasicDrawer,  
68 - Tabs,  
69 - TabPane: Tabs.TabPane,  
70 - Detail,  
71 - // RealTimeData,  
72 - Alarm,  
73 - ChildDevice,  
74 - CommandIssuance,  
75 - TBoxDetail,  
76 - // HistoryData,  
77 - ModelOfMatter,  
78 - },  
79 - emits: ['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail'],  
80 - setup(_props, { emit }) {  
81 - const activeKey = ref('1');  
82 - const size = ref('small');  
83 - const deviceDetailRef = ref();  
84 - const deviceDetail = ref<any>({});  
85 - const tbDeviceId = ref('');  
86 - // 详情回显  
87 - const [register] = useDrawerInner(async (data) => {  
88 - const { id } = data;  
89 - // 设备详情  
90 - const res = await getDeviceDetail(id);  
91 - deviceDetail.value = res;  
92 - const { latitude, longitude, address } = res.deviceInfo;  
93 - if (latitude) {  
94 - deviceDetailRef.value.initMap(longitude, latitude, address);  
95 - }  
96 - });  
97 - const closeDrawer = () => {  
98 - activeKey.value = '1';  
99 - };  
100 -  
101 - const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {  
102 - emit('openTbDeviceDetail', data);  
103 - };  
104 -  
105 - const handleOpenGatewayDevice = (data: { gatewayId: string; tbDeviceId: string }) => {  
106 - emit('openGatewayDeviceDetail', { id: data.gatewayId });  
107 - };  
108 -  
109 - return {  
110 - size,  
111 - activeKey,  
112 - register,  
113 - closeDrawer,  
114 - deviceDetail,  
115 - deviceDetailRef,  
116 - tbDeviceId,  
117 - handleOpenTbDeviceDetail,  
118 - handleOpenGatewayDevice,  
119 - };  
120 - },  
121 - });  
122 -</script> 1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + isDetail
  5 + @register="register"
  6 + destroyOnClose
  7 + @close="closeDrawer"
  8 + :title="deviceDetail.alias || deviceDetail.name"
  9 + width="80%"
  10 + >
  11 + <Tabs v-model:activeKey="activeKey" :size="size">
  12 + <TabPane key="1" tab="详情">
  13 + <Detail
  14 + ref="deviceDetailRef"
  15 + :deviceDetail="deviceDetail"
  16 + @open-gateway-device="handleOpenGatewayDevice"
  17 + />
  18 + </TabPane>
  19 + <TabPane key="modelOfMatter" tab="物模型数据">
  20 + <ModelOfMatter :deviceDetail="deviceDetail" />
  21 + </TabPane>
  22 + <!-- <TabPane key="2" tab="实时数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">
  23 + <RealTimeData :deviceDetail="deviceDetail" />
  24 + </TabPane>
  25 + <TabPane key="7" tab="历史数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">
  26 + <HistoryData :deviceDetail="deviceDetail" />
  27 + </TabPane> -->
  28 + <TabPane key="5" tab="命令下发" v-if="deviceDetail?.deviceType !== 'SENSOR'">
  29 + <CommandIssuance :deviceDetail="deviceDetail" />
  30 + </TabPane>
  31 + <TabPane key="3" tab="告警"><Alarm :id="deviceDetail.id" /></TabPane>
  32 + <TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'">
  33 + <ChildDevice
  34 + :fromId="deviceDetail?.tbDeviceId"
  35 + @openTbDeviceDetail="handleOpenTbDeviceDetail"
  36 + />
  37 + </TabPane>
  38 + <TabPane key="7" tab="命令下发记录">
  39 + <CommandRecord :fromId="deviceDetail?.tbDeviceId" />
  40 + </TabPane>
  41 + <!-- 网关设备并且场家是TBox -->
  42 + <TabPane
  43 + key="6"
  44 + tab="TBox"
  45 + v-if="deviceDetail?.deviceType === 'GATEWAY' && deviceDetail?.brand == 'TBox'"
  46 + >
  47 + <TBoxDetail :deviceDetail="deviceDetail" />
  48 + </TabPane>
  49 + <!-- 网关设备并且是TBox -->
  50 + </Tabs>
  51 + </BasicDrawer>
  52 +</template>
  53 +<script lang="ts">
  54 + import { defineComponent, ref } from 'vue';
  55 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  56 +
  57 + import { Tabs } from 'ant-design-vue';
  58 + import Detail from '../tabs/Detail.vue';
  59 + // import RealTimeData from '../tabs/RealTimeData.vue';
  60 + import Alarm from '../tabs/Alarm.vue';
  61 + import ChildDevice from '../tabs/ChildDevice.vue';
  62 + import TBoxDetail from '../tabs/TBoxDetail.vue';
  63 + import CommandIssuance from '../tabs/CommandIssuance.vue';
  64 + import { CommandRecord } from '../tabs/commandRecord/index';
  65 + import { getDeviceDetail } from '/@/api/device/deviceManager';
  66 + // import HistoryData from '../tabs/HistoryData.vue';
  67 + import ModelOfMatter from '../tabs/ModelOfMatter.vue';
  68 + export default defineComponent({
  69 + name: 'DeviceModal',
  70 + components: {
  71 + BasicDrawer,
  72 + Tabs,
  73 + TabPane: Tabs.TabPane,
  74 + Detail,
  75 + // RealTimeData,
  76 + Alarm,
  77 + ChildDevice,
  78 + CommandIssuance,
  79 + TBoxDetail,
  80 + // HistoryData,
  81 + ModelOfMatter,
  82 + CommandRecord,
  83 + },
  84 + emits: ['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail'],
  85 + setup(_props, { emit }) {
  86 + const activeKey = ref('1');
  87 + const size = ref('small');
  88 + const deviceDetailRef = ref();
  89 + const deviceDetail = ref<any>({});
  90 + const tbDeviceId = ref('');
  91 + // 详情回显
  92 + const [register] = useDrawerInner(async (data) => {
  93 + const { id } = data;
  94 + // 设备详情
  95 + const res = await getDeviceDetail(id);
  96 + deviceDetail.value = res;
  97 + const { latitude, longitude, address } = res.deviceInfo;
  98 + if (latitude) {
  99 + deviceDetailRef.value.initMap(longitude, latitude, address);
  100 + }
  101 + });
  102 + const closeDrawer = () => {
  103 + activeKey.value = '1';
  104 + };
  105 +
  106 + const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {
  107 + emit('openTbDeviceDetail', data);
  108 + };
  109 +
  110 + const handleOpenGatewayDevice = (data: { gatewayId: string; tbDeviceId: string }) => {
  111 + emit('openGatewayDeviceDetail', { id: data.gatewayId });
  112 + };
  113 +
  114 + return {
  115 + size,
  116 + activeKey,
  117 + register,
  118 + closeDrawer,
  119 + deviceDetail,
  120 + deviceDetailRef,
  121 + tbDeviceId,
  122 + handleOpenTbDeviceDetail,
  123 + handleOpenGatewayDevice,
  124 + };
  125 + },
  126 + });
  127 +</script>
  1 +import { BasicColumn } from '/@/components/Table';
  2 +import moment from 'moment';
  3 +import { Tag } from 'ant-design-vue';
  4 +import { h } from 'vue';
  5 +
  6 +export const configColumns: BasicColumn[] = [
  7 + {
  8 + title: '命令下发时间',
  9 + dataIndex: 'createTime',
  10 + format: (text) => {
  11 + return moment(text).format('YYYY-MM-DD HH:mm:ss');
  12 + },
  13 + },
  14 + {
  15 + title: '命令类型',
  16 + dataIndex: 'additionalInfo.cmdType',
  17 + },
  18 + {
  19 + title: '响应类型',
  20 + dataIndex: 'request.oneway',
  21 + format: (text) => {
  22 + return !text ? '双向' : '单向';
  23 + },
  24 + },
  25 + {
  26 + title: '命令状态',
  27 + dataIndex: 'status',
  28 + customRender: ({ text, record }) => {
  29 + return h(
  30 + Tag,
  31 + {
  32 + color:
  33 + text == 'EXPIRED'
  34 + ? 'red'
  35 + : text == 'DELIVERED'
  36 + ? 'blue'
  37 + : text == 'QUEUED'
  38 + ? '#00C9A7'
  39 + : text == 'TIMEOUT'
  40 + ? 'red'
  41 + : text == 'SENT'
  42 + ? '#00C9A7'
  43 + : text == 'FAILED'
  44 + ? 'red'
  45 + : 'green',
  46 + },
  47 + () => record?.statusName
  48 + );
  49 + },
  50 + },
  51 + {
  52 + title: '响应结果',
  53 + dataIndex: 'response',
  54 + customRender: (text) => {
  55 + return h(
  56 + Tag,
  57 + {
  58 + color: text?.status === 'SUCCESS' ? 'green' : 'red',
  59 + },
  60 + () => (text?.status === 'SUCCESS' ? '成功' : '失败')
  61 + );
  62 + },
  63 + },
  64 + {
  65 + title: '响应失败内容',
  66 + dataIndex: 'response.error',
  67 + format: (_, record) => {
  68 + return record?.response === null ? '无' : record?.response?.error;
  69 + },
  70 + },
  71 + {
  72 + title: '命令内容',
  73 + dataIndex: 'request.body',
  74 + slots: { customRender: 'recordContent' },
  75 + },
  76 +];
  1 +import CommandRecord from './index.vue';
  2 +
  3 +export { CommandRecord };
  1 +<template>
  2 + <div style="background-color: #f0f2f5">
  3 + <BasicTable @register="registerTable">
  4 + <template #recordContent="{ record }">
  5 + <a-button type="link" class="ml-2" @click="handleRecordContent(record)"> 查看 </a-button>
  6 + </template>
  7 + </BasicTable>
  8 + </div>
  9 +</template>
  10 +<script lang="ts" setup>
  11 + import { h } from 'vue';
  12 + import { configColumns } from './config';
  13 + import { deviceCommandRecordGetQuery } from '/@/api/device/deviceConfigApi';
  14 + import { BasicTable, useTable } from '/@/components/Table';
  15 + import { Modal } from 'ant-design-vue';
  16 + import { JsonPreview } from '/@/components/CodeEditor';
  17 +
  18 + const props = defineProps({
  19 + fromId: {
  20 + type: String,
  21 + default: '',
  22 + },
  23 + });
  24 + const [registerTable] = useTable({
  25 + api: deviceCommandRecordGetQuery,
  26 + columns: configColumns,
  27 + beforeFetch: (params) => {
  28 + return {
  29 + ...params,
  30 + tbDeviceId: props.fromId,
  31 + };
  32 + },
  33 + showTableSetting: true,
  34 + bordered: true,
  35 + showIndexColumn: false,
  36 + });
  37 + const commonModalInfo = (title, value) => {
  38 + Modal.info({
  39 + title,
  40 + width: 600,
  41 + content: h(JsonPreview, { data: value }),
  42 + });
  43 + };
  44 + const handleRecordContent = (record) => {
  45 + commonModalInfo('命令下发内容', JSON.parse(record?.request?.body?.params));
  46 + };
  47 +</script>
1 -<template>  
2 - <div class="card">  
3 - <Card :bordered="false" class="card">  
4 - <BasicForm @register="registerForm">  
5 - <template #logoUpload>  
6 - <Upload  
7 - name="avatar"  
8 - list-type="picture-card"  
9 - class="avatar-uploader"  
10 - :show-upload-list="false"  
11 - @preview="handlePreview"  
12 - :customRequest="customUploadLogoPic"  
13 - :before-upload="beforeUploadLogoPic"  
14 - >  
15 - <img v-if="logoPic" :src="logoPic" />  
16 - <div v-else>  
17 - <div style="margin-top: 1.875rem">  
18 - <LoadingOutlined v-if="loading" />  
19 - <PlusOutlined v-else style="font-size: 2.5rem" />  
20 - </div>  
21 - <div  
22 - class="ant-upload-text flex"  
23 - style="width: 180px; height: 100px; align-items: center; font-size: 0.5625rem"  
24 - >  
25 - 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB</div  
26 - >  
27 - </div>  
28 - </Upload>  
29 - </template>  
30 - <template #bgUpload>  
31 - <Upload  
32 - name="avatar"  
33 - list-type="picture-card"  
34 - class="avatar-uploader"  
35 - :show-upload-list="false"  
36 - :customRequest="customUploadBgPic"  
37 - :before-upload="beforeUploadBgPic"  
38 - >  
39 - <img v-if="bgPic" :src="bgPic" alt="avatar" />  
40 - <div v-else>  
41 - <div style="margin-top: 1.875rem">  
42 - <LoadingOutlined v-if="loading1" />  
43 - <PlusOutlined v-else style="font-size: 2.5rem" />  
44 - </div>  
45 - <div  
46 - class="ant-upload-text flex"  
47 - style="width: 280px; height: 100px; align-items: center; font-size: 0.5625rem"  
48 - >  
49 - 支持.PNG、.JPG格式,建议尺寸为1920*1080px,大小不超过2M</div  
50 - >  
51 - </div>  
52 - </Upload>  
53 - </template>  
54 - <template #colorInput="{ model, field }"  
55 - ><Input disabled v-model:value="model[field]">  
56 - <template #prefix> <input type="color" v-model="model[field]" /> </template  
57 - ></Input>  
58 - </template>  
59 -  
60 - <template #homeSwiper>  
61 - <Upload  
62 - v-model:file-list="fileList"  
63 - list-type="picture-card"  
64 - @preview="handlePreview"  
65 - :customRequest="customUploadHomeSwiper"  
66 - :before-upload="beforeUploadHomeSwiper"  
67 - @change="handleChange"  
68 - >  
69 - <div v-if="fileList.length < 5">  
70 - <div style="margin-top: 1.875rem">  
71 - <PlusOutlined style="font-size: 2.5rem" />  
72 - </div>  
73 - <div  
74 - class="ant-upload-text flex"  
75 - style="width: 150px; height: 70px; align-items: center; font-size: 0.5625rem"  
76 - >支持.PNG、.JPG格式,建议尺寸为800*600px,大小不超过3M</div  
77 - >  
78 - </div>  
79 - </Upload>  
80 - <Modal :visible="previewVisible" :footer="null" @cancel="handleCancel">  
81 - <img alt="example" style="width: 100%" :src="previewImage" />  
82 - </Modal>  
83 - </template>  
84 - </BasicForm>  
85 - </Card>  
86 - <Loading v-bind="compState" />  
87 - <Authority value="api:yt:appDesign:update:update">  
88 - <a-button @click="handleUpdateInfo" type="primary" class="mt-4">保存信息</a-button>  
89 - </Authority>  
90 - <Authority value="api:yt:appDesign:data_reset:reset">  
91 - <a-button @click="handleResetInfo" type="primary" class="ml-4">恢复默认设置</a-button>  
92 - </Authority>  
93 - </div>  
94 -</template>  
95 -  
96 -<script lang="ts">  
97 - import { defineComponent, ref, unref, onMounted } from 'vue';  
98 - import { BasicForm, useForm } from '/@/components/Form/index';  
99 - import { Loading } from '/@/components/Loading/index';  
100 - import { Card, Upload, Input, Modal } from 'ant-design-vue';  
101 - import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';  
102 - import { schemas } from '../config/AppDraw.config';  
103 - import { FileItem, FileInfo } from '../types/index';  
104 - import { logoUpload, bgUpload, resetAppInfo } from '/@/api/oem/index';  
105 - import { useMessage } from '/@/hooks/web/useMessage';  
106 - import { getAppDesign, updateAppDesign } from '/@/api/oem/index';  
107 - import { Authority } from '/@/components/Authority';  
108 -  
109 - export default defineComponent({  
110 - components: {  
111 - Card,  
112 - BasicForm,  
113 - Upload,  
114 - Loading,  
115 - PlusOutlined,  
116 - Input,  
117 - Modal,  
118 - Authority,  
119 - LoadingOutlined,  
120 - },  
121 - setup() {  
122 - const loading = ref(false);  
123 - const loading1 = ref(false);  
124 - const compState = ref({  
125 - absolute: false,  
126 - loading: false,  
127 - tip: '拼命加载中...',  
128 - });  
129 - const { createMessage } = useMessage();  
130 - const [registerForm, { getFieldsValue, setFieldsValue, resetFields }] = useForm({  
131 - schemas,  
132 - showSubmitButton: false,  
133 - showResetButton: false,  
134 - labelWidth: 150,  
135 - wrapperCol: {  
136 - span: 10,  
137 - },  
138 - });  
139 - const previewVisible = ref<boolean>(false);  
140 - const previewImage = ref<string | undefined>('');  
141 - function getBase64(file: File) {  
142 - return new Promise((resolve, reject) => {  
143 - const reader = new FileReader();  
144 - reader.readAsDataURL(file);  
145 - reader.onload = () => resolve(reader.result);  
146 - reader.onerror = (error) => reject(error);  
147 - });  
148 - }  
149 - const handleCancel = () => {  
150 - previewVisible.value = false;  
151 - };  
152 - const handlePreview = async (file: FileItem) => {  
153 - if (!file.url && !file.preview) {  
154 - file.preview = (await getBase64(file.originFileObj)) as string;  
155 - }  
156 - previewImage.value = file.url || file.preview;  
157 - previewVisible.value = true;  
158 - };  
159 -  
160 - // logo图片上传  
161 - const logoPic = ref();  
162 - async function customUploadLogoPic({ file }) {  
163 - if (beforeUploadLogoPic(file)) {  
164 - logoPic.value = '';  
165 - loading.value = true;  
166 - const formData = new FormData();  
167 - formData.append('file', file);  
168 - const response = await logoUpload(formData);  
169 - if (response.fileStaticUri) {  
170 - logoPic.value = response.fileStaticUri;  
171 - loading.value = false;  
172 - }  
173 - }  
174 - }  
175 - const beforeUploadLogoPic = (file) => {  
176 - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';  
177 - if (!isJpgOrPng) {  
178 - createMessage.error('只能上传图片文件!');  
179 - }  
180 - const isLt2M = (file.size as number) / 1024 < 500;  
181 - if (!isLt2M) {  
182 - createMessage.error('图片大小不能超过500KB!');  
183 - }  
184 - return isJpgOrPng && isLt2M;  
185 - };  
186 -  
187 - // 登录页背景上传  
188 - const bgPic = ref();  
189 - async function customUploadBgPic({ file }) {  
190 - if (beforeUploadBgPic(file)) {  
191 - bgPic.value = '';  
192 - loading1.value = true;  
193 - const formData = new FormData();  
194 - formData.append('file', file);  
195 - const response = await bgUpload(formData);  
196 - if (response.fileStaticUri) {  
197 - bgPic.value = response.fileStaticUri;  
198 - loading1.value = false;  
199 - }  
200 - }  
201 - }  
202 - const beforeUploadBgPic = (file) => {  
203 - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';  
204 - if (!isJpgOrPng) {  
205 - createMessage.error('只能上传图片文件!');  
206 - }  
207 - const isLt2M = (file.size as number) / 1024 / 1024 < 2;  
208 - if (!isLt2M) {  
209 - createMessage.error('图片大小不能超过2MB!');  
210 - }  
211 - return isJpgOrPng && isLt2M;  
212 - };  
213 - // 首页轮播图  
214 - const fileList = ref<FileItem[]>([]);  
215 - async function customUploadHomeSwiper({ file }) {  
216 - if (beforeUploadHomeSwiper(file)) {  
217 - const formData = new FormData();  
218 - formData.append('file', file);  
219 - const response = await bgUpload(formData);  
220 - if (response.fileStaticUri) {  
221 - fileList.value.push({  
222 - uid: -Math.random() + '',  
223 - name: response.fileName,  
224 - status: 'done',  
225 - url: response.fileStaticUri,  
226 - });  
227 - const fileArr = fileList.value.filter((item) => {  
228 - return item.percent !== 0;  
229 - });  
230 - fileList.value = fileArr;  
231 - }  
232 - }  
233 - }  
234 -  
235 - const beforeUploadHomeSwiper = (file) => {  
236 - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';  
237 - if (!isJpgOrPng) {  
238 - createMessage.error('只能上传图片文件!');  
239 - }  
240 - const isLt2M = (file.size as number) / 1024 / 1024 < 3;  
241 - if (!isLt2M) {  
242 - createMessage.error('图片大小不能超过3MB!');  
243 - }  
244 - return isJpgOrPng && isLt2M;  
245 - };  
246 - const handleChange = (info: FileInfo) => {  
247 - if (info.file.status !== 'uploading') {  
248 - fileList.value = info.fileList.filter((f: any) => !f.size);  
249 - }  
250 - };  
251 -  
252 - const handleUpdateInfo = async () => {  
253 - try {  
254 - const fieldValue = getFieldsValue();  
255 - // 做换字段  
256 - const homeSwiper = fileList.value.map((item) => item.url);  
257 - const rotation = homeSwiper.join(',');  
258 -  
259 - compState.value.loading = true;  
260 - await updateAppDesign({  
261 - ...fieldValue,  
262 - background: unref(bgPic),  
263 - icon: unref(bgPic),  
264 - logo: unref(logoPic),  
265 - rotation,  
266 - });  
267 - compState.value.loading = false;  
268 - createMessage.success('保存信息成功');  
269 - } catch (e) {  
270 - createMessage.error('保存信息失败');  
271 - }  
272 - };  
273 -  
274 - onMounted(async () => {  
275 - const res = await getAppDesign();  
276 - const rotation = res.rotation ? res.rotation.split(',') : [];  
277 - const arr: any[] = [];  
278 - for (let item of rotation) {  
279 - arr.push({  
280 - uid: -Math.random() + '',  
281 - name: '111',  
282 - url: item,  
283 - status: 'done',  
284 - });  
285 - }  
286 - setFieldsValue(res);  
287 - logoPic.value = res.logo;  
288 - bgPic.value = res.background;  
289 - if (arr[0]?.url === '') return;  
290 - fileList.value = arr;  
291 - });  
292 - const handleResetInfo = async () => {  
293 - try {  
294 - compState.value.loading = true;  
295 - await resetAppInfo();  
296 - compState.value.loading = false;  
297 - createMessage.success('恢复出厂设置成功');  
298 - resetFields();  
299 - const res = await getAppDesign();  
300 - const rotation = res.rotation ? res.rotation.split(',') : [];  
301 - const arr: any[] = [];  
302 - for (let item of rotation) {  
303 - arr.push({  
304 - uid: -Math.random() + '',  
305 - name: '111',  
306 - url: item,  
307 - status: 'done',  
308 - });  
309 - }  
310 - setFieldsValue(res);  
311 - logoPic.value = res.logo;  
312 - bgPic.value = res.background;  
313 - if (arr[0]?.url === '') return;  
314 - fileList.value = arr;  
315 - } catch (e) {  
316 - compState.value.loading = false;  
317 - createMessage.error('恢复出厂设置失败');  
318 - }  
319 - };  
320 - return {  
321 - compState,  
322 - fileList,  
323 - registerForm,  
324 - handleUpdateInfo,  
325 - handleCancel,  
326 - handlePreview,  
327 - customUploadLogoPic,  
328 - beforeUploadLogoPic,  
329 - customUploadBgPic,  
330 - beforeUploadBgPic,  
331 - customUploadHomeSwiper,  
332 - beforeUploadHomeSwiper,  
333 - handleChange,  
334 - logoPic,  
335 - bgPic,  
336 - previewVisible,  
337 - previewImage,  
338 - loading,  
339 - loading1,  
340 - handleResetInfo,  
341 - };  
342 - },  
343 - });  
344 -</script>  
345 -  
346 -<style lang="less" scoped>  
347 - .ant-upload-select-picture-card i {  
348 - font-size: 32px;  
349 - color: #999;  
350 - }  
351 -  
352 - .ant-upload-select-picture-card .ant-upload-text {  
353 - margin-top: 8px;  
354 - color: #666;  
355 - }  
356 -</style> 1 +<template>
  2 + <div class="card">
  3 + <Card :bordered="false" class="card">
  4 + <BasicForm @register="registerForm">
  5 + <template #logoUpload>
  6 + <ContentUploadText>
  7 + <template #uploadImg>
  8 + <Upload
  9 + name="avatar"
  10 + list-type="picture-card"
  11 + class="avatar-uploader"
  12 + :show-upload-list="false"
  13 + @preview="handlePreview"
  14 + :customRequest="customUploadLogoPic"
  15 + :before-upload="beforeUploadLogoPic"
  16 + >
  17 + <img v-if="logoPic" :src="logoPic" alt="avatar" />
  18 + <div v-else>
  19 + <Spin v-if="loading" tip="正在上传中..." />
  20 + <PlusOutlined v-else style="font-size: 2.5rem" /> </div
  21 + ></Upload>
  22 + </template>
  23 + <template #uploadText>
  24 + <div class="flex justify-center items-center">
  25 + 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB
  26 + </div>
  27 + </template>
  28 + </ContentUploadText>
  29 + </template>
  30 + <template #bgUpload>
  31 + <ContentUploadText>
  32 + <template #uploadImg>
  33 + <Upload
  34 + name="avatar"
  35 + list-type="picture-card"
  36 + class="avatar-uploader"
  37 + :show-upload-list="false"
  38 + :customRequest="customUploadBgPic"
  39 + :before-upload="beforeUploadBgPic"
  40 + >
  41 + <img v-if="bgPic" :src="bgPic" alt="avatar" />
  42 + <div v-else>
  43 + <Spin v-if="loading1" tip="正在上传中..." />
  44 + <PlusOutlined v-else style="font-size: 2.5rem" /> </div
  45 + ></Upload>
  46 + </template>
  47 + <template #uploadText>
  48 + <div class="flex justify-center items-center">
  49 + 支持.PNG、.JPG格式,建议尺寸为1920*1080px,大小不超过2M
  50 + </div>
  51 + </template>
  52 + </ContentUploadText>
  53 + </template>
  54 + <template #colorInput="{ model, field }"
  55 + ><Input disabled v-model:value="model[field]">
  56 + <template #prefix> <input type="color" v-model="model[field]" /> </template
  57 + ></Input>
  58 + </template>
  59 +
  60 + <template #homeSwiper>
  61 + <ContentUploadText>
  62 + <template #uploadImg>
  63 + <Upload
  64 + v-model:file-list="fileList"
  65 + list-type="picture-card"
  66 + @preview="handlePreview"
  67 + :customRequest="customUploadHomeSwiper"
  68 + :before-upload="beforeUploadHomeSwiper"
  69 + @change="handleChange"
  70 + >
  71 + <div v-if="fileList.length < 5">
  72 + <div>
  73 + <PlusOutlined style="font-size: 2.5rem" />
  74 + </div> </div
  75 + ></Upload>
  76 + </template>
  77 + <template #uploadText>
  78 + <div class="flex justify-center items-center">
  79 + 支持.PNG、.JPG格式,建议尺寸为800*600px,大小不超过3M
  80 + </div>
  81 + </template>
  82 + </ContentUploadText>
  83 + <Modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
  84 + <img alt="example" style="width: 100%" :src="previewImage" />
  85 + </Modal>
  86 + </template>
  87 + </BasicForm>
  88 + </Card>
  89 + <Loading v-bind="compState" />
  90 + <Authority value="api:yt:appDesign:update:update">
  91 + <a-button @click="handleUpdateInfo" type="primary" class="mt-4">保存信息</a-button>
  92 + </Authority>
  93 + <Authority value="api:yt:appDesign:data_reset:reset">
  94 + <a-button @click="handleResetInfo" type="primary" class="ml-4">恢复默认设置</a-button>
  95 + </Authority>
  96 + </div>
  97 +</template>
  98 +
  99 +<script lang="ts">
  100 + import { defineComponent, ref, unref, onMounted } from 'vue';
  101 + import { BasicForm, useForm } from '/@/components/Form/index';
  102 + import { Loading } from '/@/components/Loading/index';
  103 + import { Card, Upload, Input, Modal, Spin } from 'ant-design-vue';
  104 + import { PlusOutlined } from '@ant-design/icons-vue';
  105 + import { schemas } from '../config/AppDraw.config';
  106 + import { FileItem, FileInfo } from '../types/index';
  107 + import { logoUpload, bgUpload, resetAppInfo } from '/@/api/oem/index';
  108 + import { useMessage } from '/@/hooks/web/useMessage';
  109 + import { getAppDesign, updateAppDesign } from '/@/api/oem/index';
  110 + import { Authority } from '/@/components/Authority';
  111 + import ContentUploadText from './ContentUploadText.vue';
  112 +
  113 + export default defineComponent({
  114 + components: {
  115 + Card,
  116 + BasicForm,
  117 + Upload,
  118 + Loading,
  119 + PlusOutlined,
  120 + Input,
  121 + Modal,
  122 + Authority,
  123 + ContentUploadText,
  124 + Spin,
  125 + },
  126 + setup() {
  127 + const loading = ref(false);
  128 + const loading1 = ref(false);
  129 + const compState = ref({
  130 + absolute: false,
  131 + loading: false,
  132 + tip: '拼命加载中...',
  133 + });
  134 + const { createMessage } = useMessage();
  135 + const [registerForm, { getFieldsValue, setFieldsValue, resetFields }] = useForm({
  136 + schemas,
  137 + showSubmitButton: false,
  138 + showResetButton: false,
  139 + labelWidth: 150,
  140 + wrapperCol: {
  141 + span: 10,
  142 + },
  143 + });
  144 + const previewVisible = ref<boolean>(false);
  145 + const previewImage = ref<string | undefined>('');
  146 + function getBase64(file: File) {
  147 + return new Promise((resolve, reject) => {
  148 + const reader = new FileReader();
  149 + reader.readAsDataURL(file);
  150 + reader.onload = () => resolve(reader.result);
  151 + reader.onerror = (error) => reject(error);
  152 + });
  153 + }
  154 + const handleCancel = () => {
  155 + previewVisible.value = false;
  156 + };
  157 + const handlePreview = async (file: FileItem) => {
  158 + if (!file.url && !file.preview) {
  159 + file.preview = (await getBase64(file.originFileObj)) as string;
  160 + }
  161 + previewImage.value = file.url || file.preview;
  162 + previewVisible.value = true;
  163 + };
  164 +
  165 + // logo图片上传
  166 + const logoPic = ref();
  167 + async function customUploadLogoPic({ file }) {
  168 + if (beforeUploadLogoPic(file)) {
  169 + logoPic.value = '';
  170 + loading.value = true;
  171 + const formData = new FormData();
  172 + formData.append('file', file);
  173 + const response = await logoUpload(formData);
  174 + if (response.fileStaticUri) {
  175 + logoPic.value = response.fileStaticUri;
  176 + loading.value = false;
  177 + }
  178 + }
  179 + }
  180 + const beforeUploadLogoPic = (file) => {
  181 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  182 + if (!isJpgOrPng) {
  183 + createMessage.error('只能上传图片文件!');
  184 + }
  185 + const isLt2M = (file.size as number) / 1024 < 500;
  186 + if (!isLt2M) {
  187 + createMessage.error('图片大小不能超过500KB!');
  188 + }
  189 + return isJpgOrPng && isLt2M;
  190 + };
  191 +
  192 + // 登录页背景上传
  193 + const bgPic = ref();
  194 + async function customUploadBgPic({ file }) {
  195 + if (beforeUploadBgPic(file)) {
  196 + bgPic.value = '';
  197 + loading1.value = true;
  198 + const formData = new FormData();
  199 + formData.append('file', file);
  200 + const response = await bgUpload(formData);
  201 + if (response.fileStaticUri) {
  202 + bgPic.value = response.fileStaticUri;
  203 + loading1.value = false;
  204 + }
  205 + }
  206 + }
  207 + const beforeUploadBgPic = (file) => {
  208 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  209 + if (!isJpgOrPng) {
  210 + createMessage.error('只能上传图片文件!');
  211 + }
  212 + const isLt2M = (file.size as number) / 1024 / 1024 < 2;
  213 + if (!isLt2M) {
  214 + createMessage.error('图片大小不能超过2MB!');
  215 + }
  216 + return isJpgOrPng && isLt2M;
  217 + };
  218 + // 首页轮播图
  219 + const fileList = ref<FileItem[]>([]);
  220 + async function customUploadHomeSwiper({ file }) {
  221 + if (beforeUploadHomeSwiper(file)) {
  222 + const formData = new FormData();
  223 + formData.append('file', file);
  224 + const response = await bgUpload(formData);
  225 + if (response.fileStaticUri) {
  226 + fileList.value.push({
  227 + uid: -Math.random() + '',
  228 + name: response.fileName,
  229 + status: 'done',
  230 + url: response.fileStaticUri,
  231 + });
  232 + const fileArr = fileList.value.filter((item) => {
  233 + return item.percent !== 0;
  234 + });
  235 + fileList.value = fileArr;
  236 + }
  237 + }
  238 + }
  239 +
  240 + const beforeUploadHomeSwiper = (file) => {
  241 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  242 + if (!isJpgOrPng) {
  243 + createMessage.error('只能上传图片文件!');
  244 + }
  245 + const isLt2M = (file.size as number) / 1024 / 1024 < 3;
  246 + if (!isLt2M) {
  247 + createMessage.error('图片大小不能超过3MB!');
  248 + }
  249 + return isJpgOrPng && isLt2M;
  250 + };
  251 + const handleChange = (info: FileInfo) => {
  252 + if (info.file.status !== 'uploading') {
  253 + fileList.value = info.fileList.filter((f: any) => !f.size);
  254 + }
  255 + };
  256 +
  257 + const handleUpdateInfo = async () => {
  258 + try {
  259 + const fieldValue = getFieldsValue();
  260 + // 做换字段
  261 + const homeSwiper = fileList.value.map((item) => item.url);
  262 + const rotation = homeSwiper.join(',');
  263 +
  264 + compState.value.loading = true;
  265 + await updateAppDesign({
  266 + ...fieldValue,
  267 + background: unref(bgPic),
  268 + icon: unref(bgPic),
  269 + logo: unref(logoPic),
  270 + rotation,
  271 + });
  272 + compState.value.loading = false;
  273 + createMessage.success('保存信息成功');
  274 + } catch (e) {
  275 + createMessage.error('保存信息失败');
  276 + }
  277 + };
  278 +
  279 + onMounted(async () => {
  280 + const res = await getAppDesign();
  281 + const rotation = res.rotation ? res.rotation.split(',') : [];
  282 + const arr: any[] = [];
  283 + for (let item of rotation) {
  284 + arr.push({
  285 + uid: -Math.random() + '',
  286 + name: '111',
  287 + url: item,
  288 + status: 'done',
  289 + });
  290 + }
  291 + setFieldsValue(res);
  292 + logoPic.value = res.logo;
  293 + bgPic.value = res.background;
  294 + if (arr[0]?.url === '') return;
  295 + fileList.value = arr;
  296 + });
  297 + const handleResetInfo = async () => {
  298 + try {
  299 + compState.value.loading = true;
  300 + await resetAppInfo();
  301 + compState.value.loading = false;
  302 + createMessage.success('恢复出厂设置成功');
  303 + resetFields();
  304 + const res = await getAppDesign();
  305 + const rotation = res.rotation ? res.rotation.split(',') : [];
  306 + const arr: any[] = [];
  307 + for (let item of rotation) {
  308 + arr.push({
  309 + uid: -Math.random() + '',
  310 + name: '111',
  311 + url: item,
  312 + status: 'done',
  313 + });
  314 + }
  315 + setFieldsValue(res);
  316 + logoPic.value = res.logo;
  317 + bgPic.value = res.background;
  318 + if (arr[0]?.url === '') return;
  319 + fileList.value = arr;
  320 + } catch (e) {
  321 + compState.value.loading = false;
  322 + createMessage.error('恢复出厂设置失败');
  323 + }
  324 + };
  325 + return {
  326 + compState,
  327 + fileList,
  328 + registerForm,
  329 + handleUpdateInfo,
  330 + handleCancel,
  331 + handlePreview,
  332 + customUploadLogoPic,
  333 + beforeUploadLogoPic,
  334 + customUploadBgPic,
  335 + beforeUploadBgPic,
  336 + customUploadHomeSwiper,
  337 + beforeUploadHomeSwiper,
  338 + handleChange,
  339 + logoPic,
  340 + bgPic,
  341 + previewVisible,
  342 + previewImage,
  343 + loading,
  344 + loading1,
  345 + handleResetInfo,
  346 + };
  347 + },
  348 + });
  349 +</script>
  350 +
  351 +<style lang="less" scoped>
  352 + .ant-upload-select-picture-card i {
  353 + font-size: 32px;
  354 + color: #999;
  355 + }
  356 +
  357 + .ant-upload-select-picture-card .ant-upload-text {
  358 + margin-top: 8px;
  359 + color: #666;
  360 + }
  361 +</style>
@@ -3,81 +3,82 @@ @@ -3,81 +3,82 @@
3 <Card :bordered="false" class="card"> 3 <Card :bordered="false" class="card">
4 <BasicForm @register="registerForm"> 4 <BasicForm @register="registerForm">
5 <template #logoUpload> 5 <template #logoUpload>
6 - <Upload  
7 - name="avatar"  
8 - list-type="picture-card"  
9 - class="avatar-uploader"  
10 - :show-upload-list="false"  
11 - :customRequest="customUploadLogoPic"  
12 - :before-upload="beforeUploadLogoPic"  
13 - >  
14 - <img v-if="logoPic" :src="logoPic" />  
15 - <div v-else>  
16 - <div style="margin-top: 1.875rem">  
17 - <LoadingOutlined v-if="loading" />  
18 - <PlusOutlined v-else style="font-size: 2.5rem" />  
19 - </div>  
20 - <div  
21 - class="ant-upload-text flex"  
22 - style="width: 180px; height: 100px; align-items: center; font-size: 0.5625rem"  
23 - >  
24 - 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB</div 6 + <ContentUploadText>
  7 + <template #uploadImg>
  8 + <Upload
  9 + name="avatar"
  10 + list-type="picture-card"
  11 + class="avatar-uploader"
  12 + :show-upload-list="false"
  13 + :customRequest="customUploadLogoPic"
  14 + :before-upload="beforeUploadLogoPic"
25 > 15 >
26 - </div>  
27 - </Upload> 16 + <img v-if="logoPic" :src="logoPic" alt="avatar" />
  17 + <div v-else>
  18 + <Spin v-if="loading" tip="正在上传中..." />
  19 + <PlusOutlined v-else style="font-size: 2.5rem" /> </div
  20 + ></Upload>
  21 + </template>
  22 + <template #uploadText>
  23 + <div class="flex justify-center items-center">
  24 + 支持.PNG、.JPG格式,建议尺寸为32*32px,大小不超过500KB
  25 + </div>
  26 + </template>
  27 + </ContentUploadText>
28 </template> 28 </template>
29 <template #iconUpload> 29 <template #iconUpload>
30 - <Upload  
31 - name="avatar"  
32 - list-type="picture-card"  
33 - class="avatar-uploader"  
34 - :show-upload-list="false"  
35 - :customRequest="customUploadIconPic"  
36 - :before-upload="beforeUploadIconPic"  
37 - >  
38 - <div v-if="iconPic">  
39 - <img :src="iconPic" class="m-auto" />  
40 - <div style="background-color: #ccc; margin-top: 20px">重新上传</div>  
41 - </div>  
42 - <div v-else>  
43 - <div style="margin-top: 20px">  
44 - <LoadingOutlined v-if="loading1" />  
45 - <PlusOutlined v-else style="font-size: 30px" />  
46 - </div>  
47 - <div  
48 - class="ant-upload-text flex"  
49 - style="width: 130px; height: 70px; align-items: center; font-size: 0.5625rem"  
50 - >  
51 - 支持.ICON格式,建议尺寸为16*16px</div 30 + <ContentUploadText>
  31 + <template #uploadImg>
  32 + <Upload
  33 + name="avatar"
  34 + list-type="picture-card"
  35 + class="avatar-uploader"
  36 + :show-upload-list="false"
  37 + :customRequest="customUploadIconPic"
  38 + :before-upload="beforeUploadIconPic"
52 > 39 >
53 - </div>  
54 - </Upload> 40 + <div v-if="iconPic">
  41 + <img :src="iconPic" class="m-auto" />
  42 + <div style="background-color: #ccc; margin-top: 20px">重新上传</div>
  43 + </div>
  44 + <div v-else>
  45 + <div>
  46 + <Spin v-if="loading1" tip="正在上传中..." />
  47 + <PlusOutlined v-else style="font-size: 2.5rem" />
  48 + </div> </div
  49 + ></Upload>
  50 + </template>
  51 + <template #uploadText>
  52 + <div class="flex justify-center items-center"> 支持.ICON格式,建议尺寸为16*16px </div>
  53 + </template>
  54 + </ContentUploadText>
55 </template> 55 </template>
56 <template #bgUpload> 56 <template #bgUpload>
57 - <Upload  
58 - name="avatar"  
59 - list-type="picture-card"  
60 - class="avatar-uploader"  
61 - :show-upload-list="false"  
62 - :customRequest="customUploadBgPic"  
63 - :before-upload="beforeUploadBgPic"  
64 - >  
65 - <img v-if="bgPic" :src="bgPic" alt="avatar" />  
66 - <div v-else>  
67 - <div style="margin-top: 1.875rem">  
68 - <LoadingOutlined v-if="loading2" />  
69 - <PlusOutlined v-else style="font-size: 2.5rem" />  
70 - </div>  
71 - <div  
72 - class="ant-upload-text flex"  
73 - style="width: 280px; height: 130px; align-items: center; font-size: 0.5625rem"  
74 - >  
75 - 支持.PNG、.JPG格式,建议尺寸为1920*1080px以上,大小不超过5M</div 57 + <ContentUploadText>
  58 + <template #uploadImg>
  59 + <Upload
  60 + name="avatar"
  61 + list-type="picture-card"
  62 + class="avatar-uploader"
  63 + :show-upload-list="false"
  64 + :customRequest="customUploadBgPic"
  65 + :before-upload="beforeUploadBgPic"
76 > 66 >
77 - </div>  
78 - </Upload> 67 + <img v-if="bgPic" :src="bgPic" alt="avatar" />
  68 + <div v-else>
  69 + <div>
  70 + <Spin v-if="loading2" tip="正在上传中..." />
  71 + <PlusOutlined v-else style="font-size: 2.5rem" />
  72 + </div> </div
  73 + ></Upload>
  74 + </template>
  75 + <template #uploadText>
  76 + <div class="flex justify-center items-center">
  77 + 支持.PNG、.JPG格式,建议尺寸为1920*1080px以上,大小不超过5M
  78 + </div>
  79 + </template>
  80 + </ContentUploadText>
79 </template> 81 </template>
80 -  
81 <template #colorInput="{ model, field }" 82 <template #colorInput="{ model, field }"
82 ><Input disabled v-model:value="model[field]"> 83 ><Input disabled v-model:value="model[field]">
83 <template #prefix> <input type="color" v-model="model[field]" /> </template 84 <template #prefix> <input type="color" v-model="model[field]" /> </template
@@ -97,7 +98,7 @@ @@ -97,7 +98,7 @@
97 98
98 <script lang="ts"> 99 <script lang="ts">
99 import { defineComponent, ref, onMounted, unref } from 'vue'; 100 import { defineComponent, ref, onMounted, unref } from 'vue';
100 - import { Card, Upload, Input } from 'ant-design-vue'; 101 + import { Card, Upload, Input, Spin } from 'ant-design-vue';
101 import { BasicForm, useForm } from '/@/components/Form/index'; 102 import { BasicForm, useForm } from '/@/components/Form/index';
102 import { schemas } from '../config/CVIDraw.config'; 103 import { schemas } from '../config/CVIDraw.config';
103 import { Loading } from '/@/components/Loading/index'; 104 import { Loading } from '/@/components/Loading/index';
@@ -111,10 +112,11 @@ @@ -111,10 +112,11 @@
111 updatePlatForm, 112 updatePlatForm,
112 resetPlateInfo, 113 resetPlateInfo,
113 } from '/@/api/oem/index'; 114 } from '/@/api/oem/index';
114 - import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue'; 115 + import { PlusOutlined } from '@ant-design/icons-vue';
115 import { useUserStore } from '/@/store/modules/user'; 116 import { useUserStore } from '/@/store/modules/user';
116 import { createLocalStorage } from '/@/utils/cache/index'; 117 import { createLocalStorage } from '/@/utils/cache/index';
117 import { Authority } from '/@/components/Authority'; 118 import { Authority } from '/@/components/Authority';
  119 + import ContentUploadText from './ContentUploadText.vue';
118 120
119 export default defineComponent({ 121 export default defineComponent({
120 components: { 122 components: {
@@ -125,7 +127,8 @@ @@ -125,7 +127,8 @@
125 Input, 127 Input,
126 PlusOutlined, 128 PlusOutlined,
127 Authority, 129 Authority,
128 - LoadingOutlined, 130 + ContentUploadText,
  131 + Spin,
129 }, 132 },
130 setup() { 133 setup() {
131 const loading = ref(false); 134 const loading = ref(false);
  1 +<template>
  2 + <a-row type="flex" align="middle" justify="start">
  3 + <a-col :span="12">
  4 + <slot name="uploadImg"></slot>
  5 + </a-col>
  6 + <a-col :span="12">
  7 + <slot name="uploadText"></slot>
  8 + </a-col>
  9 + </a-row>
  10 +</template>
  11 +
  12 +<script lang="ts" setup></script>
  13 +
  14 +<style lang="less" scoped></style>
1 -<template>  
2 - <div class="card">  
3 - <Card :bordered="false" class="card">  
4 - <BasicForm @register="registerForm">  
5 - <template #qrcode>  
6 - <Upload  
7 - name="avatar"  
8 - list-type="picture-card"  
9 - class="avatar-uploader"  
10 - :show-upload-list="false"  
11 - :customRequest="customUploadqrcodePic"  
12 - :before-upload="beforeUploadqrcodePic"  
13 - >  
14 - <img v-if="qrcodePic" :src="qrcodePic" alt="avatar" />  
15 - <div v-else>  
16 - <div style="margin-top: 1.875rem">  
17 - <LoadingOutlined v-if="loading" />  
18 - <PlusOutlined v-else style="font-size: 2.5rem" />  
19 - </div>  
20 - <div  
21 - class="ant-upload-text flex"  
22 - style="width: 180px; height: 100px; align-items: center; font-size: 0.5625rem"  
23 - >  
24 - 支持.PNG、.JPG格式,建议尺寸为300*300px,大小不超过5M</div  
25 - >  
26 - </div>  
27 - </Upload>  
28 - </template>  
29 - <template #customProv>  
30 - <BasicForm @register="registerCustomForm" />  
31 - </template>  
32 - </BasicForm>  
33 - </Card>  
34 - <Loading v-bind="compState" />  
35 - <Authority value="api:yt:enterprise:update:update">  
36 - <a-button  
37 - v-if="isWhereAdmin !== 'CUSTOMER_USER'"  
38 - @click="handleUpdateInfo"  
39 - type="primary"  
40 - class="mt-4"  
41 - >更新基本信息</a-button  
42 - >  
43 - </Authority>  
44 - </div>  
45 -</template>  
46 -  
47 -<script lang="ts">  
48 - import { defineComponent, onMounted, ref, computed } from 'vue';  
49 - import { Card, Upload } from 'ant-design-vue';  
50 - import { BasicForm, useForm } from '/@/components/Form/index';  
51 - import { schemas, provSchemas } from '../config/enterPriseInfo.config';  
52 - import { getAreaList, getEnterPriseDetail, updateEnterPriseDetail } from '/@/api/oem/index';  
53 - import { Loading } from '/@/components/Loading';  
54 - import { useMessage } from '/@/hooks/web/useMessage';  
55 - import { useUserStore } from '/@/store/modules/user';  
56 - import { createLocalStorage } from '/@/utils/cache';  
57 - import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';  
58 - import { qrcodeUpload } from '/@/api/oem/index';  
59 - import type { FileItem } from '/@/components/Upload/src/typing';  
60 - import type { CityItem, Code } from '../types';  
61 - import { Authority } from '/@/components/Authority';  
62 - import { USER_INFO_KEY } from '/@/enums/cacheEnum';  
63 - import { getAuthCache } from '/@/utils/auth';  
64 -  
65 - export default defineComponent({  
66 - components: {  
67 - Card,  
68 - BasicForm,  
69 - Loading,  
70 - Upload,  
71 - PlusOutlined,  
72 - Authority,  
73 - LoadingOutlined,  
74 - },  
75 - setup() {  
76 - const userInfo: any = getAuthCache(USER_INFO_KEY);  
77 - const isWhereAdmin: any = computed(() => {  
78 - if (userInfo.roles.includes('TENANT_ADMIN')) {  
79 - return 'TENANT_ADMIN';  
80 - } else if (userInfo.roles.includes('CUSTOMER_USER')) {  
81 - return 'CUSTOMER_USER';  
82 - } else {  
83 - return 'SYS_ADMIN';  
84 - }  
85 - });  
86 -  
87 - const loading = ref(false);  
88 - const compState = ref({  
89 - absolute: false,  
90 - loading: false,  
91 - tip: '拼命加载中...',  
92 - });  
93 - const [registerForm, { getFieldsValue, setFieldsValue, validate, clearValidate }] = useForm({  
94 - labelWidth: 80,  
95 - schemas,  
96 - showResetButton: false,  
97 - showSubmitButton: false,  
98 - wrapperCol: {  
99 - span: 12,  
100 - },  
101 - });  
102 -  
103 - const [  
104 - registerCustomForm,  
105 - { getFieldsValue: getNameTown, updateSchema, setFieldsValue: setNameTown },  
106 - ] = useForm({  
107 - labelWidth: 80,  
108 - schemas: provSchemas,  
109 - showResetButton: false,  
110 - showSubmitButton: false,  
111 - compact: true,  
112 - actionColOptions: {  
113 - span: 0,  
114 - },  
115 - });  
116 -  
117 - const { createMessage } = useMessage();  
118 -  
119 - const qrcodePic = ref();  
120 - const customUploadqrcodePic = async ({ file }) => {  
121 - clearValidate('qrcode');  
122 - if (beforeUploadqrcodePic(file)) {  
123 - qrcodePic.value = '';  
124 - loading.value = true;  
125 - const formData = new FormData();  
126 - formData.append('file', file);  
127 - const response = await qrcodeUpload(formData);  
128 - if (response.fileStaticUri) {  
129 - qrcodePic.value = response.fileStaticUri;  
130 - loading.value = false;  
131 - }  
132 - }  
133 - };  
134 - const beforeUploadqrcodePic = (file: FileItem) => {  
135 - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';  
136 - if (!isJpgOrPng) {  
137 - createMessage.error('只能上传图片文件!');  
138 - }  
139 - const isLt2M = (file.size as number) / 1024 / 1024 < 5;  
140 - if (!isLt2M) {  
141 - createMessage.error('图片大小不能超过5MB!');  
142 - }  
143 - return isJpgOrPng && isLt2M;  
144 - };  
145 - // 更新  
146 - const handleUpdateInfo = async () => {  
147 - try {  
148 - const fieldsValue = getFieldsValue();  
149 - const { nameTown } = getNameTown();  
150 - const newFieldValue: any = {  
151 - ...fieldsValue,  
152 - codeTown: nameTown,  
153 - qrCode: qrcodePic.value,  
154 - };  
155 - delete newFieldValue.nameProv;  
156 - delete newFieldValue.nameCity;  
157 - delete newFieldValue.nameCoun;  
158 - delete newFieldValue.nameTown;  
159 - // 表单校验  
160 - let validateArray = [  
161 - 'name',  
162 - 'abbreviation',  
163 - 'officialWebsite',  
164 - 'email',  
165 - 'synopsis',  
166 - 'nameCountry',  
167 - 'address',  
168 - 'contacts',  
169 - 'tel',  
170 - 'id',  
171 - ];  
172 - if (newFieldValue.qrCode == undefined || newFieldValue.qrCode == '') {  
173 - validateArray.push('qrcode');  
174 - } else {  
175 - const findExistIndex = validateArray.findIndex((o) => o == 'qrcode');  
176 - if (findExistIndex !== -1) {  
177 - validateArray.splice(findExistIndex, 1);  
178 - }  
179 - }  
180 - if (newFieldValue.codeTown == undefined) {  
181 - validateArray.push('prov');  
182 - console.log(validateArray);  
183 - } else {  
184 - const findExistIndex1 = validateArray.findIndex((o) => o == 'prov');  
185 - if (findExistIndex1 !== -1) {  
186 - validateArray.splice(findExistIndex1, 1);  
187 - }  
188 - clearValidate('prov');  
189 - }  
190 - const values = await validate(validateArray);  
191 - if (!values) return;  
192 - compState.value.loading = true;  
193 - await updateEnterPriseDetail(newFieldValue);  
194 - createMessage.success('更新信息成功');  
195 - setEnterPriseInfo(newFieldValue);  
196 - } finally {  
197 - compState.value.loading = false;  
198 - }  
199 - };  
200 -  
201 - const userStore = useUserStore();  
202 - const storage = createLocalStorage();  
203 -  
204 - // 设置企业信息  
205 - function setEnterPriseInfo(newFieldValue) {  
206 - // 保存store  
207 - userStore.setEnterPriseInfo(newFieldValue);  
208 - // 保存本地缓存  
209 - storage.set('enterpriseInfo', newFieldValue);  
210 - }  
211 -  
212 - // 地区显示回显和数据联动  
213 - async function updateCityData(  
214 - cities: CityItem[],  
215 - couns: CityItem[],  
216 - towns: CityItem[],  
217 - code: Code  
218 - ) {  
219 - // 加工后端返回字段  
220 -  
221 - cities.forEach((item) => {  
222 - item.label = item.name;  
223 - item.value = item.code;  
224 - });  
225 -  
226 - couns.forEach((item) => {  
227 - item.label = item.name;  
228 - item.value = item.code;  
229 - });  
230 - towns.forEach((item) => {  
231 - item.label = item.name;  
232 - item.value = item.code;  
233 - });  
234 - const { codeProv, codeCity, codeCoun, codeTown } = code;  
235 - updateSchema([  
236 - {  
237 - field: 'nameCity',  
238 - componentProps: ({ formModel }) => {  
239 - return {  
240 - options: cities,  
241 - async onChange(value) {  
242 - if (value === undefined) {  
243 - formModel.nameCoun = undefined; // reset city value  
244 - formModel.nameTown = undefined;  
245 - updateSchema([  
246 - {  
247 - field: 'nameCoun',  
248 - componentProps: {  
249 - options: [],  
250 - },  
251 - },  
252 - {  
253 - field: 'nameTown',  
254 - componentProps: {  
255 - options: [],  
256 - },  
257 - },  
258 - ]);  
259 - } else {  
260 - let couns: CityItem[] = await getAreaList({ parentId: value });  
261 - couns.forEach((item) => {  
262 - item.label = item.name;  
263 - item.value = item.code;  
264 - });  
265 - formModel.nameCoun = undefined; // reset city value  
266 - formModel.nameTown = undefined;  
267 - updateSchema({  
268 - field: 'nameCoun',  
269 - componentProps: {  
270 - // 请选择区  
271 - options: couns,  
272 - async onChange(value) {  
273 - if (value === undefined) {  
274 - formModel.nameTown = undefined;  
275 - } else {  
276 - let towns: CityItem[] = await getAreaList({ parentId: value });  
277 - towns.forEach((item) => {  
278 - item.label = item.name;  
279 - item.value = item.code;  
280 - });  
281 - formModel.nameTown = undefined;  
282 - updateSchema({  
283 - field: 'nameTown',  
284 - componentProps: {  
285 - placeholder: '城镇/街道',  
286 - options: towns,  
287 - },  
288 - });  
289 - }  
290 - },  
291 - },  
292 - });  
293 - }  
294 - },  
295 - };  
296 - },  
297 - },  
298 - {  
299 - field: 'nameCoun',  
300 - componentProps: {  
301 - options: couns,  
302 - async onChange(value) {  
303 - if (value === undefined) {  
304 - setNameTown({  
305 - nameTown: undefined,  
306 - });  
307 - updateSchema({  
308 - field: 'nameTown',  
309 - componentProps: {  
310 - placeholder: '城镇/街道',  
311 - options: [],  
312 - },  
313 - });  
314 - } else {  
315 - let towns = await getAreaList({ parentId: value });  
316 - towns.forEach((item) => {  
317 - item.label = item.name;  
318 - item.value = item.code;  
319 - });  
320 - setNameTown({  
321 - nameTown: undefined,  
322 - });  
323 - updateSchema({  
324 - field: 'nameTown',  
325 - componentProps: {  
326 - placeholder: '城镇/街道',  
327 - options: towns,  
328 - },  
329 - });  
330 - }  
331 - },  
332 - },  
333 - },  
334 - {  
335 - field: 'nameTown',  
336 - componentProps: {  
337 - options: towns,  
338 - },  
339 - },  
340 - ]);  
341 - setNameTown({  
342 - nameProv: codeProv,  
343 - nameCity: codeCity,  
344 - nameCoun: codeCoun,  
345 - nameTown: codeTown,  
346 - });  
347 - }  
348 -  
349 - onMounted(async () => {  
350 - const res = await getEnterPriseDetail();  
351 - if (res.sysTown) {  
352 - const { cities, couns, towns, codeCountry, codeProv, codeCity, codeCoun, codeTown } =  
353 - res.sysTown;  
354 - const code = {  
355 - codeCountry,  
356 - codeProv,  
357 - codeCity,  
358 - codeCoun,  
359 - codeTown,  
360 - };  
361 - updateCityData(cities, couns, towns, code);  
362 - setFieldsValue({ nameCountry: codeCountry });  
363 - }  
364 - setFieldsValue(res);  
365 - qrcodePic.value = res.qrCode;  
366 - });  
367 -  
368 - return {  
369 - registerForm,  
370 - compState,  
371 - qrcodePic,  
372 - handleUpdateInfo,  
373 - customUploadqrcodePic,  
374 - beforeUploadqrcodePic,  
375 - registerCustomForm,  
376 - loading,  
377 - isWhereAdmin,  
378 - };  
379 - },  
380 - });  
381 -</script> 1 +<template>
  2 + <div class="card">
  3 + <Card :bordered="false" class="card">
  4 + <BasicForm @register="registerForm">
  5 + <template #qrcode>
  6 + <ContentUploadText>
  7 + <template #uploadImg>
  8 + <Upload
  9 + name="avatar"
  10 + list-type="picture-card"
  11 + class="avatar-uploader"
  12 + :show-upload-list="false"
  13 + :customRequest="customUploadqrcodePic"
  14 + :before-upload="beforeUploadqrcodePic"
  15 + >
  16 + <img v-if="qrcodePic" :src="qrcodePic" alt="avatar" />
  17 + <div v-else>
  18 + <Spin v-if="loading" tip="正在上传中..." />
  19 + <PlusOutlined v-else style="font-size: 2.5rem" /> </div
  20 + ></Upload>
  21 + </template>
  22 + <template #uploadText>
  23 + <div class="flex justify-center items-center">
  24 + 支持.PNG、.JPG格式,建议尺寸为300*300px,大小不超过5M
  25 + </div>
  26 + </template>
  27 + </ContentUploadText>
  28 + </template>
  29 + <template #customProv>
  30 + <BasicForm @register="registerCustomForm" />
  31 + </template>
  32 + </BasicForm>
  33 + </Card>
  34 + <Loading v-bind="compState" />
  35 + <Authority value="api:yt:enterprise:update:update">
  36 + <a-button
  37 + v-if="isWhereAdmin !== 'CUSTOMER_USER'"
  38 + @click="handleUpdateInfo"
  39 + type="primary"
  40 + class="mt-4"
  41 + >更新基本信息</a-button
  42 + >
  43 + </Authority>
  44 + </div>
  45 +</template>
  46 +
  47 +<script lang="ts">
  48 + import { defineComponent, onMounted, ref, computed } from 'vue';
  49 + import { Card, Upload, Spin } from 'ant-design-vue';
  50 + import { BasicForm, useForm } from '/@/components/Form/index';
  51 + import { schemas, provSchemas } from '../config/enterPriseInfo.config';
  52 + import { getAreaList, getEnterPriseDetail, updateEnterPriseDetail } from '/@/api/oem/index';
  53 + import { Loading } from '/@/components/Loading';
  54 + import { useMessage } from '/@/hooks/web/useMessage';
  55 + import { useUserStore } from '/@/store/modules/user';
  56 + import { createLocalStorage } from '/@/utils/cache';
  57 + import { PlusOutlined } from '@ant-design/icons-vue';
  58 + import { qrcodeUpload } from '/@/api/oem/index';
  59 + import type { FileItem } from '/@/components/Upload/src/typing';
  60 + import type { CityItem, Code } from '../types';
  61 + import { Authority } from '/@/components/Authority';
  62 + import { USER_INFO_KEY } from '/@/enums/cacheEnum';
  63 + import { getAuthCache } from '/@/utils/auth';
  64 + import ContentUploadText from './ContentUploadText.vue';
  65 +
  66 + export default defineComponent({
  67 + components: {
  68 + Card,
  69 + BasicForm,
  70 + Loading,
  71 + Upload,
  72 + PlusOutlined,
  73 + Authority,
  74 + ContentUploadText,
  75 + Spin,
  76 + },
  77 + setup() {
  78 + const userInfo: any = getAuthCache(USER_INFO_KEY);
  79 + const isWhereAdmin: any = computed(() => {
  80 + if (userInfo.roles.includes('TENANT_ADMIN')) {
  81 + return 'TENANT_ADMIN';
  82 + } else if (userInfo.roles.includes('CUSTOMER_USER')) {
  83 + return 'CUSTOMER_USER';
  84 + } else {
  85 + return 'SYS_ADMIN';
  86 + }
  87 + });
  88 +
  89 + const loading = ref(false);
  90 + const compState = ref({
  91 + absolute: false,
  92 + loading: false,
  93 + tip: '拼命加载中...',
  94 + });
  95 + const [registerForm, { getFieldsValue, setFieldsValue, validate, clearValidate }] = useForm({
  96 + labelWidth: 80,
  97 + schemas,
  98 + showResetButton: false,
  99 + showSubmitButton: false,
  100 + wrapperCol: {
  101 + span: 12,
  102 + },
  103 + });
  104 +
  105 + const [
  106 + registerCustomForm,
  107 + { getFieldsValue: getNameTown, updateSchema, setFieldsValue: setNameTown },
  108 + ] = useForm({
  109 + labelWidth: 80,
  110 + schemas: provSchemas,
  111 + showResetButton: false,
  112 + showSubmitButton: false,
  113 + compact: true,
  114 + actionColOptions: {
  115 + span: 0,
  116 + },
  117 + });
  118 +
  119 + const { createMessage } = useMessage();
  120 +
  121 + const qrcodePic = ref();
  122 + const customUploadqrcodePic = async ({ file }) => {
  123 + clearValidate('qrcode');
  124 + if (beforeUploadqrcodePic(file)) {
  125 + qrcodePic.value = '';
  126 + loading.value = true;
  127 + const formData = new FormData();
  128 + formData.append('file', file);
  129 + const response = await qrcodeUpload(formData);
  130 + if (response.fileStaticUri) {
  131 + qrcodePic.value = response.fileStaticUri;
  132 + loading.value = false;
  133 + }
  134 + }
  135 + };
  136 + const beforeUploadqrcodePic = (file: FileItem) => {
  137 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  138 + if (!isJpgOrPng) {
  139 + createMessage.error('只能上传图片文件!');
  140 + }
  141 + const isLt2M = (file.size as number) / 1024 / 1024 < 5;
  142 + if (!isLt2M) {
  143 + createMessage.error('图片大小不能超过5MB!');
  144 + }
  145 + return isJpgOrPng && isLt2M;
  146 + };
  147 + // 更新
  148 + const handleUpdateInfo = async () => {
  149 + try {
  150 + const fieldsValue = getFieldsValue();
  151 + const { nameTown } = getNameTown();
  152 + const newFieldValue: any = {
  153 + ...fieldsValue,
  154 + codeTown: nameTown,
  155 + qrCode: qrcodePic.value,
  156 + };
  157 + delete newFieldValue.nameProv;
  158 + delete newFieldValue.nameCity;
  159 + delete newFieldValue.nameCoun;
  160 + delete newFieldValue.nameTown;
  161 + // 表单校验
  162 + let validateArray = [
  163 + 'name',
  164 + 'abbreviation',
  165 + 'officialWebsite',
  166 + 'email',
  167 + 'synopsis',
  168 + 'nameCountry',
  169 + 'address',
  170 + 'contacts',
  171 + 'tel',
  172 + 'id',
  173 + ];
  174 + if (newFieldValue.qrCode == undefined || newFieldValue.qrCode == '') {
  175 + validateArray.push('qrcode');
  176 + } else {
  177 + const findExistIndex = validateArray.findIndex((o) => o == 'qrcode');
  178 + if (findExistIndex !== -1) {
  179 + validateArray.splice(findExistIndex, 1);
  180 + }
  181 + }
  182 + if (newFieldValue.codeTown == undefined) {
  183 + validateArray.push('prov');
  184 + console.log(validateArray);
  185 + } else {
  186 + const findExistIndex1 = validateArray.findIndex((o) => o == 'prov');
  187 + if (findExistIndex1 !== -1) {
  188 + validateArray.splice(findExistIndex1, 1);
  189 + }
  190 + clearValidate('prov');
  191 + }
  192 + const values = await validate(validateArray);
  193 + if (!values) return;
  194 + compState.value.loading = true;
  195 + await updateEnterPriseDetail(newFieldValue);
  196 + createMessage.success('更新信息成功');
  197 + setEnterPriseInfo(newFieldValue);
  198 + } finally {
  199 + compState.value.loading = false;
  200 + }
  201 + };
  202 +
  203 + const userStore = useUserStore();
  204 + const storage = createLocalStorage();
  205 +
  206 + // 设置企业信息
  207 + function setEnterPriseInfo(newFieldValue) {
  208 + // 保存store
  209 + userStore.setEnterPriseInfo(newFieldValue);
  210 + // 保存本地缓存
  211 + storage.set('enterpriseInfo', newFieldValue);
  212 + }
  213 +
  214 + // 地区显示回显和数据联动
  215 + async function updateCityData(
  216 + cities: CityItem[],
  217 + couns: CityItem[],
  218 + towns: CityItem[],
  219 + code: Code
  220 + ) {
  221 + // 加工后端返回字段
  222 +
  223 + cities.forEach((item) => {
  224 + item.label = item.name;
  225 + item.value = item.code;
  226 + });
  227 +
  228 + couns.forEach((item) => {
  229 + item.label = item.name;
  230 + item.value = item.code;
  231 + });
  232 + towns.forEach((item) => {
  233 + item.label = item.name;
  234 + item.value = item.code;
  235 + });
  236 + const { codeProv, codeCity, codeCoun, codeTown } = code;
  237 + updateSchema([
  238 + {
  239 + field: 'nameCity',
  240 + componentProps: ({ formModel }) => {
  241 + return {
  242 + options: cities,
  243 + async onChange(value) {
  244 + if (value === undefined) {
  245 + formModel.nameCoun = undefined; // reset city value
  246 + formModel.nameTown = undefined;
  247 + updateSchema([
  248 + {
  249 + field: 'nameCoun',
  250 + componentProps: {
  251 + options: [],
  252 + },
  253 + },
  254 + {
  255 + field: 'nameTown',
  256 + componentProps: {
  257 + options: [],
  258 + },
  259 + },
  260 + ]);
  261 + } else {
  262 + let couns: CityItem[] = await getAreaList({ parentId: value });
  263 + couns.forEach((item) => {
  264 + item.label = item.name;
  265 + item.value = item.code;
  266 + });
  267 + formModel.nameCoun = undefined; // reset city value
  268 + formModel.nameTown = undefined;
  269 + updateSchema({
  270 + field: 'nameCoun',
  271 + componentProps: {
  272 + // 请选择区
  273 + options: couns,
  274 + async onChange(value) {
  275 + if (value === undefined) {
  276 + formModel.nameTown = undefined;
  277 + } else {
  278 + let towns: CityItem[] = await getAreaList({ parentId: value });
  279 + towns.forEach((item) => {
  280 + item.label = item.name;
  281 + item.value = item.code;
  282 + });
  283 + formModel.nameTown = undefined;
  284 + updateSchema({
  285 + field: 'nameTown',
  286 + componentProps: {
  287 + placeholder: '城镇/街道',
  288 + options: towns,
  289 + },
  290 + });
  291 + }
  292 + },
  293 + },
  294 + });
  295 + }
  296 + },
  297 + };
  298 + },
  299 + },
  300 + {
  301 + field: 'nameCoun',
  302 + componentProps: {
  303 + options: couns,
  304 + async onChange(value) {
  305 + if (value === undefined) {
  306 + setNameTown({
  307 + nameTown: undefined,
  308 + });
  309 + updateSchema({
  310 + field: 'nameTown',
  311 + componentProps: {
  312 + placeholder: '城镇/街道',
  313 + options: [],
  314 + },
  315 + });
  316 + } else {
  317 + let towns = await getAreaList({ parentId: value });
  318 + towns.forEach((item) => {
  319 + item.label = item.name;
  320 + item.value = item.code;
  321 + });
  322 + setNameTown({
  323 + nameTown: undefined,
  324 + });
  325 + updateSchema({
  326 + field: 'nameTown',
  327 + componentProps: {
  328 + placeholder: '城镇/街道',
  329 + options: towns,
  330 + },
  331 + });
  332 + }
  333 + },
  334 + },
  335 + },
  336 + {
  337 + field: 'nameTown',
  338 + componentProps: {
  339 + options: towns,
  340 + },
  341 + },
  342 + ]);
  343 + setNameTown({
  344 + nameProv: codeProv,
  345 + nameCity: codeCity,
  346 + nameCoun: codeCoun,
  347 + nameTown: codeTown,
  348 + });
  349 + }
  350 +
  351 + onMounted(async () => {
  352 + const res = await getEnterPriseDetail();
  353 + if (res.sysTown) {
  354 + const { cities, couns, towns, codeCountry, codeProv, codeCity, codeCoun, codeTown } =
  355 + res.sysTown;
  356 + const code = {
  357 + codeCountry,
  358 + codeProv,
  359 + codeCity,
  360 + codeCoun,
  361 + codeTown,
  362 + };
  363 + updateCityData(cities, couns, towns, code);
  364 + setFieldsValue({ nameCountry: codeCountry });
  365 + }
  366 + setFieldsValue(res);
  367 + qrcodePic.value = res.qrCode;
  368 + });
  369 +
  370 + return {
  371 + registerForm,
  372 + compState,
  373 + qrcodePic,
  374 + handleUpdateInfo,
  375 + customUploadqrcodePic,
  376 + beforeUploadqrcodePic,
  377 + registerCustomForm,
  378 + loading,
  379 + isWhereAdmin,
  380 + };
  381 + },
  382 + });
  383 +</script>