@dhccmobile/vue3-lo-form 2.0.55 → 2.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -7
- package/dist/vue3-lo-form.common.js +191 -154
- package/dist/vue3-lo-form.common.js.map +1 -1
- package/dist/vue3-lo-form.css +1 -1
- package/dist/vue3-lo-form.umd.js +191 -154
- package/dist/vue3-lo-form.umd.js.map +1 -1
- package/dist/vue3-lo-form.umd.min.js +1 -1
- package/dist/vue3-lo-form.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/App.vue +16 -4
- package/src/components/form/DvForm.vue +8 -10
- package/src/components/form/DvFormLayout.vue +88 -54
- package/src/core/FormApi.ts +15 -2
- package/src/domain/DesFormControl.ts +3 -0
- package/src/domain/FormConfig.ts +1 -0
- package/src/index.ts +1 -0
- package/src/main.ts +2 -4
- package/src/services/api.service.ts +4 -1
- package/src/services/form-tools.service.ts +1 -28
- package/src/styles/index.scss +0 -6
- package/src/styles/themes.scss +2 -10
- package/types/core/FormApi.d.ts +3 -0
- package/types/domain/DesFormControl.d.ts +2 -0
- package/types/domain/FormConfig.d.ts +1 -0
- package/types/services/api.service.d.ts +2 -2
- package/types/services/form-tools.service.d.ts +0 -1
- package/src/styles/theme-3.scss +0 -371
- package/src/styles/theme-4.scss +0 -395
package/package.json
CHANGED
package/src/App.vue
CHANGED
|
@@ -101,8 +101,8 @@
|
|
|
101
101
|
</div>
|
|
102
102
|
</div>
|
|
103
103
|
<div class="lo-input">
|
|
104
|
-
<!--styleMode="credit-rd" :formId="'
|
|
105
|
-
<dy-form v-if="showForm" :formId="'
|
|
104
|
+
<!--styleMode="credit-rd" :formId="'773549593606574080'"-->
|
|
105
|
+
<dy-form v-if="showForm" :formId="'984119606230257664'" v-model:edit="formApi.edit" :formApi="formApi" @change="onChange($event)" @click="onClick($event)" @focus="onFocus($event)" @blur="onBlur($event)" @addon-before="onAddonBeforeHandler($event)" @addon-after="onAddonAfterHandler($event)" @add-item="selectAddItem($event)">
|
|
106
106
|
<template #combinationSelector="{ control, onChange }">
|
|
107
107
|
<div class="lo-custom-control-box">
|
|
108
108
|
<a-input v-model:value="control.formControl.value" @input="onChange(control.formControl)" v-if="control && control.formControl" />
|
|
@@ -188,7 +188,12 @@ export default class App extends Vue {
|
|
|
188
188
|
],
|
|
189
189
|
};
|
|
190
190
|
formApi: FormApi = new FormApi({
|
|
191
|
-
edit:
|
|
191
|
+
edit: false,
|
|
192
|
+
desParams: {
|
|
193
|
+
businessId: "123", // 业务编号
|
|
194
|
+
bizType: "project", // 业务对象类型
|
|
195
|
+
formLabel: "项目管理", //表单中文
|
|
196
|
+
},
|
|
192
197
|
});
|
|
193
198
|
dictionaryFormatCollection: DictionaryFormatCollection = {
|
|
194
199
|
sysDictDetailOptions: [],
|
|
@@ -268,13 +273,20 @@ export default class App extends Vue {
|
|
|
268
273
|
this.srcDesForm = formToolsService.formatDesForm(desForm);
|
|
269
274
|
this.$formToolsService.init().then((res: FormRestfulResponse) => {
|
|
270
275
|
this.showForm = true;
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
this.formApi.setFormData({ phoneNo: "138****0000", phoneNoEnc: "13800000000" });
|
|
278
|
+
}, 1000);
|
|
271
279
|
// this.formApi.setAttribute("testx1-1-1", Attribute.TextFold, true);
|
|
272
280
|
// this.formApi.setAttribute("testx1-1-1", Attribute.HiddenDropdown, true);
|
|
273
281
|
});
|
|
274
282
|
// this.dictLocalcConvert();
|
|
275
283
|
}
|
|
276
284
|
|
|
277
|
-
created() {
|
|
285
|
+
created() {
|
|
286
|
+
setTimeout(() => {
|
|
287
|
+
// this.formApi.setFormData({ liubo: "1000w", email: "100@dhcc.com.cn" });
|
|
288
|
+
}, 2000);
|
|
289
|
+
}
|
|
278
290
|
|
|
279
291
|
onChange(e: any): void {
|
|
280
292
|
if (e instanceof FormControl) {
|
|
@@ -45,7 +45,7 @@ export type NfFormTheme = "default" | "gray";
|
|
|
45
45
|
},
|
|
46
46
|
})
|
|
47
47
|
export default class DyForm extends Vue {
|
|
48
|
-
@Prop() formId: string | undefined;
|
|
48
|
+
@Prop({ default: "刘波", type: String }) formId: string | undefined;
|
|
49
49
|
@Prop() mode: NfFormMode | undefined;
|
|
50
50
|
@Prop({ type: String, default: "default" }) styleMode!: NfStyleMode;
|
|
51
51
|
@Prop() srcDesForm: DesForm | undefined;
|
|
@@ -99,7 +99,7 @@ export default class DyForm extends Vue {
|
|
|
99
99
|
* @date 2022/4/6 14:17
|
|
100
100
|
*/
|
|
101
101
|
@Watch("formValidateStateResetMark")
|
|
102
|
-
onPropFormValidateStateResetHandler(): void {
|
|
102
|
+
onPropFormValidateStateResetHandler(newVal: any): void {
|
|
103
103
|
if ((this as any)._provided) {
|
|
104
104
|
((this as any)._provided as any).provideInjectData.formValidateStateResetMark = this.formValidateStateResetMark;
|
|
105
105
|
}
|
|
@@ -116,7 +116,7 @@ export default class DyForm extends Vue {
|
|
|
116
116
|
@Watch("metaRefresh")
|
|
117
117
|
@Watch("refreshCheckFeedbackFlag")
|
|
118
118
|
@Watch("widthCompatibleMode")
|
|
119
|
-
onPropHandler(): void {
|
|
119
|
+
onPropHandler(newVal: any): void {
|
|
120
120
|
if (this) {
|
|
121
121
|
this.provideInjectData.edit = this.edit;
|
|
122
122
|
this.provideInjectData.labelSpan = this.labelSpan;
|
|
@@ -129,8 +129,7 @@ export default class DyForm extends Vue {
|
|
|
129
129
|
|
|
130
130
|
get loFormTheme(): string {
|
|
131
131
|
const win: any = window;
|
|
132
|
-
|
|
133
|
-
const themes = ["default", "gray", "nitic", "labelWrap"];
|
|
132
|
+
const themes = ["default", "gray"];
|
|
134
133
|
const formTheme = themes.indexOf(this.formTheme) > -1 ? this.formTheme : win.$loFormTheme;
|
|
135
134
|
return themes.indexOf(formTheme) > -1 ? formTheme : themes[0];
|
|
136
135
|
}
|
|
@@ -184,10 +183,8 @@ export default class DyForm extends Vue {
|
|
|
184
183
|
*/
|
|
185
184
|
private initDesForm(): void {
|
|
186
185
|
if (this.formId != null && this.formId !== "") {
|
|
187
|
-
formToolsService.
|
|
188
|
-
|
|
189
|
-
this.formatDesForm();
|
|
190
|
-
});
|
|
186
|
+
this.desForm = formToolsService.loadResource(this.formId);
|
|
187
|
+
this.formatDesForm();
|
|
191
188
|
}
|
|
192
189
|
}
|
|
193
190
|
|
|
@@ -458,8 +455,9 @@ export default class DyForm extends Vue {
|
|
|
458
455
|
* @date 2020/11/23 11:19
|
|
459
456
|
*/
|
|
460
457
|
private initControlForm(controls: Control[], formGroup: FormGroup): void {
|
|
461
|
-
controls.forEach((control) => {
|
|
458
|
+
controls.forEach((control: any) => {
|
|
462
459
|
if (control.type === FormFieldClass.Base.code || control.type === FormFieldClass.Senior.code) {
|
|
460
|
+
control.formApi = this.formApi; // 表单控制类对象
|
|
463
461
|
const boundProperty: string = (control.controlAttr as DesFormControl)?.boundProperty;
|
|
464
462
|
if (boundProperty) {
|
|
465
463
|
const propertys: string[] = boundProperty.split(".");
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
:class="{
|
|
17
17
|
['form-model-item-' + controlAttr.boundProperty]: true,
|
|
18
18
|
['form-model-item-' + control.code]: true,
|
|
19
|
-
'lo-form-model-item-textarea-box
|
|
19
|
+
'lo-form-model-item-textarea-box': control.code === formFieldType.Textarea.code,
|
|
20
20
|
'lo-form-item-mobile': isMobileBrowser(),
|
|
21
21
|
}"
|
|
22
22
|
>
|
|
@@ -319,6 +319,12 @@
|
|
|
319
319
|
<template v-if="controlAttr.unit">
|
|
320
320
|
<span class="addon-readonly">{{ controlAttr.unit }}</span>
|
|
321
321
|
</template>
|
|
322
|
+
<template v-if="controlAttr.isDesensitize">
|
|
323
|
+
<div @click="handlerMasking(formControl)">
|
|
324
|
+
<eye-outlined v-if="!isAfterClick" class="addon-icon" />
|
|
325
|
+
<eye-invisible-outlined v-else class="addon-icon" />
|
|
326
|
+
</div>
|
|
327
|
+
</template>
|
|
322
328
|
</template>
|
|
323
329
|
</a-form-item>
|
|
324
330
|
</div>
|
|
@@ -338,7 +344,6 @@
|
|
|
338
344
|
@focus="onFocus($event)"
|
|
339
345
|
@blur="onBlur($event)"
|
|
340
346
|
@addon-before="onAddonBeforeHandler($event)"
|
|
341
|
-
@addon-after="onAddonAfterHandler($event)"
|
|
342
347
|
@add-item="selectAddItem($event)"
|
|
343
348
|
@fixFormLayout="onHideControl"
|
|
344
349
|
>
|
|
@@ -372,36 +377,31 @@
|
|
|
372
377
|
</template>
|
|
373
378
|
|
|
374
379
|
<script lang="ts">
|
|
375
|
-
import {
|
|
376
|
-
import { Control } from "@/domain";
|
|
377
|
-
import {
|
|
378
|
-
import { FormFieldClass } from "@/constants";
|
|
379
|
-
import { FormFieldType } from "@/constants";
|
|
380
|
+
import { Inject, Options, Prop, Vue, Watch } from "vue-property-decorator";
|
|
381
|
+
import { Control, DesFormControl, DesFormLayout, FormEnum } from "@/domain";
|
|
382
|
+
import { FormFieldClass, FormFieldType, ValidateRules, VerticalArrangement, ZoomType } from "@/constants";
|
|
380
383
|
import generateGridTemplateColumns from "../../filtres/generate-grid-template-columns.filter";
|
|
381
384
|
import generateGridColumnEnd from "../../filtres/generate-grid-column-end.filter";
|
|
382
|
-
import { DesFormLayout } from "@/domain";
|
|
383
|
-
import { DesFormControl } from "@/domain";
|
|
384
385
|
|
|
385
|
-
import { AutoComplete, Cascader, Checkbox,
|
|
386
|
-
import {
|
|
387
|
-
import { formBeanUtilsService } from "@/services";
|
|
386
|
+
import { AutoComplete, Button, Cascader, Checkbox, CheckboxGroup, Col, DatePicker, Divider, Dropdown, Form, FormItem, Input, InputNumber, InputPassword, Menu, Popconfirm, Popover, Radio, RadioGroup, Rate, Row, Select, Slider, Switch, Textarea, Timeline, TimelineItem, TimePicker, Tooltip, TreeSelect, Upload, notification } from "ant-design-vue";
|
|
387
|
+
import { apiService, formBeanUtilsService } from "@/services";
|
|
388
388
|
import { ProvideInjectData } from "@/domain/ProvideInjectData";
|
|
389
389
|
|
|
390
390
|
import amountCapitalization from "../../filtres/amount-capitalization.filter";
|
|
391
|
-
import { FormControl, ValidateResult
|
|
392
|
-
import {
|
|
393
|
-
import { ValidateRules } from "@/constants";
|
|
394
|
-
import { ZoomType } from "@/constants";
|
|
391
|
+
import { CustomFormat, FormControl, ValidateResult } from "../../domain";
|
|
392
|
+
import { BuiltLabel, ControlFormatType, FormBusAttr, MoneyUnit, SubmittedType, SupportUploadType } from "../../constants/enum";
|
|
395
393
|
import { extractOptions } from "@/filtres/extract-options.filter";
|
|
396
394
|
import zoomMultiple from "../../filtres/zoom-multiple.filter";
|
|
397
395
|
import switchEnumConvert from "../../filtres/switch-enum-convert.filter";
|
|
398
396
|
import StretchText from "./StretchText.vue";
|
|
399
|
-
import {
|
|
400
|
-
import {
|
|
397
|
+
import { HISTORY_SVG_XML, SUBMITTED_SVG_XML } from "../../constants/encode-assets/svg";
|
|
398
|
+
import { ClockCircleOutlined, DownOutlined, EyeInvisibleOutlined, EyeOutlined, PlusOutlined, QuestionCircleOutlined, SearchOutlined, UploadOutlined, ExclamationCircleOutlined } from "@ant-design/icons-vue";
|
|
399
|
+
import { h } from "vue";
|
|
401
400
|
|
|
402
401
|
import dayjs from "dayjs";
|
|
403
402
|
import locale from "ant-design-vue/es/date-picker/locale/zh_CN";
|
|
404
403
|
import pinYin from "../../../public/js/pinyin";
|
|
404
|
+
import { FormApi } from "@/core";
|
|
405
405
|
|
|
406
406
|
@Options({
|
|
407
407
|
name: "DvFormLayout",
|
|
@@ -450,6 +450,8 @@ import pinYin from "../../../public/js/pinyin";
|
|
|
450
450
|
[StretchText.name]: StretchText,
|
|
451
451
|
[Row.name]: Row,
|
|
452
452
|
[Col.name]: Col,
|
|
453
|
+
EyeOutlined,
|
|
454
|
+
EyeInvisibleOutlined,
|
|
453
455
|
VNodes: (_, { attrs }) => {
|
|
454
456
|
return attrs.vnodes;
|
|
455
457
|
},
|
|
@@ -476,6 +478,7 @@ export default class DvFormLayout extends Vue {
|
|
|
476
478
|
workdayList: any = localStorage.getItem("workdayList") || JSON.stringify([]); // 工作日集合
|
|
477
479
|
amountCapitalization = amountCapitalization; // 大写转换
|
|
478
480
|
zoomMultiple = zoomMultiple; // 缩放
|
|
481
|
+
isAfterClick = false; // 后缀图标是否被点击了 2026年4月17日 15:21:53
|
|
479
482
|
filterOption(value: any, item: any) {
|
|
480
483
|
if (!item.title) {
|
|
481
484
|
return false;
|
|
@@ -484,7 +487,7 @@ export default class DvFormLayout extends Vue {
|
|
|
484
487
|
}
|
|
485
488
|
|
|
486
489
|
@Prop() index: number | undefined;
|
|
487
|
-
@Prop() control: Control |
|
|
490
|
+
@Prop() control: Control | any;
|
|
488
491
|
@Prop() parentControl: Control | undefined;
|
|
489
492
|
@Prop({ type: Object, default: () => ({}) }) customFormats: { [key: string]: CustomFormat } | undefined;
|
|
490
493
|
@Prop({ type: Array, default: () => [] }) linkList: any | undefined; // 需要添加超链接点击事件数组 例:['cifNo', 'prodBaseNo']
|
|
@@ -782,7 +785,7 @@ export default class DvFormLayout extends Vue {
|
|
|
782
785
|
} else if (this.provideInjectData.controlSpan) {
|
|
783
786
|
return this.provideInjectData.controlSpan;
|
|
784
787
|
} else {
|
|
785
|
-
return
|
|
788
|
+
return 0;
|
|
786
789
|
}
|
|
787
790
|
}
|
|
788
791
|
|
|
@@ -957,7 +960,6 @@ export default class DvFormLayout extends Vue {
|
|
|
957
960
|
for (let i = 0; i < index; i++) {
|
|
958
961
|
data += "0";
|
|
959
962
|
}
|
|
960
|
-
data = this.countDecimalPlaces(data, controlAttr.decimalPlaces);
|
|
961
963
|
}
|
|
962
964
|
// 金额后缀不依赖于是否设置了小数位
|
|
963
965
|
if (controlAttr.zoomType !== ZoomType.automatic.code && data != null && data != "" && controlAttr.unit) {
|
|
@@ -1034,39 +1036,6 @@ export default class DvFormLayout extends Vue {
|
|
|
1034
1036
|
return data;
|
|
1035
1037
|
}
|
|
1036
1038
|
|
|
1037
|
-
/**
|
|
1038
|
-
* 数字小数位数计算
|
|
1039
|
-
* @author JiangTao
|
|
1040
|
-
* @since 2026-04-16 16:40:23
|
|
1041
|
-
*/
|
|
1042
|
-
countDecimalPlaces(data: string | number, decimalPlaces: number | undefined): string {
|
|
1043
|
-
// 1. 安全处理
|
|
1044
|
-
const digits = decimalPlaces ?? 0;
|
|
1045
|
-
const str = String(data).trim();
|
|
1046
|
-
if (!str) return digits > 0 ? `0.${"0".repeat(digits)}` : "0";
|
|
1047
|
-
|
|
1048
|
-
// 2. 判断是否有小数
|
|
1049
|
-
const hasDot = str.includes(".");
|
|
1050
|
-
const intPart = hasDot ? str.split(".")[0] : str;
|
|
1051
|
-
const decimalPart = hasDot ? str.split(".")[1] : "";
|
|
1052
|
-
|
|
1053
|
-
// 3. 拼接成纯数字用于四舍五入计算
|
|
1054
|
-
const pureNumStr = intPart.replace(/,/g, "") + (hasDot ? "." + decimalPart : "");
|
|
1055
|
-
const num = parseFloat(pureNumStr);
|
|
1056
|
-
if (isNaN(num)) return intPart + (digits > 0 ? `.${"0".repeat(digits)}` : "");
|
|
1057
|
-
|
|
1058
|
-
// 4. 四舍五入保留 digits 位
|
|
1059
|
-
const factor = Math.pow(10, digits);
|
|
1060
|
-
const rounded = (Math.round(num * factor) / factor).toFixed(digits);
|
|
1061
|
-
|
|
1062
|
-
// 5. 拆分四舍五入后的整数与小数
|
|
1063
|
-
const [, roundedDecimal = ""] = rounded.split(".");
|
|
1064
|
-
|
|
1065
|
-
// 6. 最终结果:原始整数部分 + 处理后的小数部分
|
|
1066
|
-
if (digits <= 0) return intPart;
|
|
1067
|
-
return `${intPart}.${roundedDecimal}`;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
1039
|
/**
|
|
1071
1040
|
* @description: 支持的上传类型
|
|
1072
1041
|
* @author ChenRui
|
|
@@ -1521,7 +1490,61 @@ export default class DvFormLayout extends Vue {
|
|
|
1521
1490
|
onAddonAfterHandler(event: any): void {
|
|
1522
1491
|
this.$emit("addon-after", event);
|
|
1523
1492
|
}
|
|
1493
|
+
/**
|
|
1494
|
+
*
|
|
1495
|
+
* @param formControl 表单控制器
|
|
1496
|
+
* @private 私有方法
|
|
1497
|
+
*/
|
|
1498
|
+
handlerMasking(formControl: any): void {
|
|
1499
|
+
const path = this.$qlForm.desApiAddr;
|
|
1500
|
+
if (!path) {
|
|
1501
|
+
notification.open({
|
|
1502
|
+
message: "解密接口未配置,请联系管理员",
|
|
1503
|
+
duration: 5,
|
|
1504
|
+
icon: () => h(ExclamationCircleOutlined, { style: "color: #FBBC05" }),
|
|
1505
|
+
});
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
// 调用解密函数
|
|
1509
|
+
this.isAfterClick = !this.isAfterClick;
|
|
1510
|
+
const formApi: FormApi = this.control.formApi;
|
|
1511
|
+
if (this.isAfterClick) {
|
|
1512
|
+
const encData = formApi.formData[formControl.key + "Enc"];
|
|
1513
|
+
if (!formControl.oldValue) {
|
|
1514
|
+
// 保存原始脱敏值
|
|
1515
|
+
formControl.oldValue = formApi.formData[formControl.key]; // 脱敏数据
|
|
1516
|
+
}
|
|
1517
|
+
// 接口获取解密值
|
|
1518
|
+
const params: any = { ...formApi.desParams };
|
|
1519
|
+
params.ciphertext = encData; // 密文
|
|
1520
|
+
params.desensField = formControl.key; // 脱敏的字段
|
|
1521
|
+
console.error(params);
|
|
1522
|
+
this.getFieldPlaintext(path, params).then((res: any) => {
|
|
1523
|
+
if (res.code === 1) {
|
|
1524
|
+
formControl.value = res.data;
|
|
1525
|
+
} else {
|
|
1526
|
+
notification.open({
|
|
1527
|
+
message: res.msg || "解密失败,请重试",
|
|
1528
|
+
duration: 5,
|
|
1529
|
+
icon: () => h(ExclamationCircleOutlined, { style: "color: #FBBC05" }),
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
});
|
|
1533
|
+
} else {
|
|
1534
|
+
formControl.value = formControl.oldValue;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1524
1537
|
|
|
1538
|
+
/**
|
|
1539
|
+
* @desc 解密字段
|
|
1540
|
+
* @param path 解密接口地址
|
|
1541
|
+
* @param params 解密需要的参数
|
|
1542
|
+
* @private
|
|
1543
|
+
*/
|
|
1544
|
+
private getFieldPlaintext(path: string, params: any): Promise<any> {
|
|
1545
|
+
const headers = apiService.createAuthHeaders();
|
|
1546
|
+
return apiService.fetch(path, {}, JSON.stringify(params), "POST", headers);
|
|
1547
|
+
}
|
|
1525
1548
|
/**
|
|
1526
1549
|
* @description: 数字框失焦点
|
|
1527
1550
|
* @author ChenRui
|
|
@@ -1637,4 +1660,15 @@ export default class DvFormLayout extends Vue {
|
|
|
1637
1660
|
flex: 3 !important;
|
|
1638
1661
|
}
|
|
1639
1662
|
}
|
|
1663
|
+
.addon-icon {
|
|
1664
|
+
width: 40px !important;
|
|
1665
|
+
user-select: none;
|
|
1666
|
+
}
|
|
1667
|
+
.addon-icon:hover {
|
|
1668
|
+
color: #429eff !important;
|
|
1669
|
+
font-weight: bold;
|
|
1670
|
+
}
|
|
1671
|
+
.addon-icon:active {
|
|
1672
|
+
opacity: 0.7;
|
|
1673
|
+
}
|
|
1640
1674
|
</style>
|
package/src/core/FormApi.ts
CHANGED
|
@@ -91,8 +91,9 @@ export class FormApi {
|
|
|
91
91
|
formatType: FormatType; // 数据格式化模式
|
|
92
92
|
apiMetaRefresh: any; // api内部刷新标识
|
|
93
93
|
[key: string]: any; // 任一扩展属性
|
|
94
|
-
oldVal: any;
|
|
95
|
-
|
|
94
|
+
oldVal: any; // 修改前数据
|
|
95
|
+
private srcData: any; // 表单原始数据
|
|
96
|
+
desParams: any; // 脱敏参数 包括【业务编号、业务对象类型、表单中文等】
|
|
96
97
|
/**
|
|
97
98
|
* @description: 获取表单对象
|
|
98
99
|
* @author ChenRui
|
|
@@ -104,12 +105,14 @@ export class FormApi {
|
|
|
104
105
|
dvForm?: Vue;
|
|
105
106
|
edit?: boolean;
|
|
106
107
|
formatType?: FormatType;
|
|
108
|
+
desParams?: any;
|
|
107
109
|
} = {}
|
|
108
110
|
) {
|
|
109
111
|
this.id = options.id || this.getUuid();
|
|
110
112
|
this.dvForm = options.dvForm || new Vue(DvForm);
|
|
111
113
|
this.edit = options.edit;
|
|
112
114
|
this.formatType = options.formatType || "default";
|
|
115
|
+
this.desParams = options.desParams || {}; // 脱敏所需参数
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
get mathjs(): MathJsStatic {
|
|
@@ -134,6 +137,15 @@ export class FormApi {
|
|
|
134
137
|
obj = null;
|
|
135
138
|
}
|
|
136
139
|
}
|
|
140
|
+
// 追加表单中没有的字段 2026年5月13日 20:39:24 用于处理字段脱敏
|
|
141
|
+
if (this.srcData) {
|
|
142
|
+
for (const key in this.srcData) {
|
|
143
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
144
|
+
if (obj && !obj.hasOwnProperty(key)) {
|
|
145
|
+
obj[key] = this.srcData[key];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
137
149
|
return obj;
|
|
138
150
|
}
|
|
139
151
|
return null;
|
|
@@ -181,6 +193,7 @@ export class FormApi {
|
|
|
181
193
|
});
|
|
182
194
|
}
|
|
183
195
|
if (oldVal) this.oldVal = oldVal;
|
|
196
|
+
this.srcData = srcData; // 记录赋值时的原始数据,这里面有非表单字段
|
|
184
197
|
}
|
|
185
198
|
|
|
186
199
|
/**
|
|
@@ -77,6 +77,7 @@ export class DesFormControl {
|
|
|
77
77
|
isTreeOpen: string | boolean; // 树形选择框是否展开
|
|
78
78
|
changeOnSelect: string | boolean; // 是否允许级联选择框只选中父级选项
|
|
79
79
|
textareaRows: number | undefined; // 设置textarea组件默认展示行数
|
|
80
|
+
isDesensitize: string | boolean; // 是否脱敏 2026年5月13日 13:48:28
|
|
80
81
|
constructor(
|
|
81
82
|
options: {
|
|
82
83
|
formFieldId?: string;
|
|
@@ -157,6 +158,7 @@ export class DesFormControl {
|
|
|
157
158
|
itemWidth?: string | boolean;
|
|
158
159
|
changeOnSelect?: string | boolean;
|
|
159
160
|
textareaRows?: number | undefined;
|
|
161
|
+
isDesensitize?: string; // 是否脱敏 2026年5月13日 13:48:28
|
|
160
162
|
} = {}
|
|
161
163
|
) {
|
|
162
164
|
this.formFieldId = options.formFieldId || "";
|
|
@@ -237,5 +239,6 @@ export class DesFormControl {
|
|
|
237
239
|
this.itemWidth = options.itemWidth || "";
|
|
238
240
|
this.changeOnSelect = options.changeOnSelect || "";
|
|
239
241
|
this.textareaRows = options.textareaRows || 3;
|
|
242
|
+
this.isDesensitize = options.isDesensitize || "0";
|
|
240
243
|
}
|
|
241
244
|
}
|
package/src/domain/FormConfig.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ const install: any = function (app: App, options: any) {
|
|
|
46
46
|
onlySimpleLoadConfig: options && options.onlySimpleLoadConfig ? options.onlySimpleLoadConfig : false,
|
|
47
47
|
urls: options?.urls,
|
|
48
48
|
dictUrls: options?.dictUrls,
|
|
49
|
+
desApiAddr: options?.desApiAddr || "",
|
|
49
50
|
};
|
|
50
51
|
app.config.globalProperties.$formToolsService = formToolsService;
|
|
51
52
|
(window as any).$app = app;
|
package/src/main.ts
CHANGED
|
@@ -10,11 +10,9 @@ app.config.performance = true;
|
|
|
10
10
|
app
|
|
11
11
|
.use(VueLoForm, {
|
|
12
12
|
url: "http://82.156.213.34:8080",
|
|
13
|
-
|
|
14
|
-
appId: "1461652844787691520",
|
|
13
|
+
appId: "1009549397931601920",
|
|
15
14
|
onlySimpleLoadConfig: false,
|
|
16
15
|
loadMode: "dynamic",
|
|
16
|
+
desApiAddr: "http://82.156.213.34:8080/ms-loong/api/v1/des-cache-info/xxx-yyy-zzz",
|
|
17
17
|
})
|
|
18
18
|
.mount("#app");
|
|
19
|
-
const win: any = window;
|
|
20
|
-
win.$loFormTheme = "labelWrap"; // 指定主题
|
|
@@ -6,7 +6,10 @@ class ApiService {
|
|
|
6
6
|
};
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
createAuthHeaders(
|
|
9
|
+
createAuthHeaders() {
|
|
10
|
+
const data = JSON.parse(localStorage.getItem("core:token") || sessionStorage.getItem("core:token") || "{}");
|
|
11
|
+
const accessToken = data.accessToken || "";
|
|
12
|
+
const jti = data.jti || "";
|
|
10
13
|
return {
|
|
11
14
|
Authorization: "bearer " + accessToken,
|
|
12
15
|
"user-identity": jti,
|
|
@@ -632,6 +632,7 @@ class FormToolsService {
|
|
|
632
632
|
controlAttr.hiddenDropdown = desFormControl.hiddenDropdown === Switch.Enable.code;
|
|
633
633
|
controlAttr.textFold = desFormControl.textFold === Switch.Enable.code;
|
|
634
634
|
controlAttr.verificationRules = formBeanUtilsService.parse(desFormControl.verificationRules);
|
|
635
|
+
controlAttr.isDesensitize = desFormControl.isDesensitize === Switch.Enable.code; // 是否脱敏2026年5月13日 15:43:17
|
|
635
636
|
controls.push(control);
|
|
636
637
|
});
|
|
637
638
|
}
|
|
@@ -702,34 +703,6 @@ class FormToolsService {
|
|
|
702
703
|
}
|
|
703
704
|
}
|
|
704
705
|
|
|
705
|
-
initResource(formId: string): Promise<void | DesForm> {
|
|
706
|
-
if (this.desForms.length === 0) {
|
|
707
|
-
return new Promise((resolve, reject) => {
|
|
708
|
-
Promise.all([dictStore.getDicts(), dictStore.getTreeDicts(), dictStore.getMapDicts(), dictStore.getMapTreeDicts(), formStore.getForms()]).then(([dicts, treeDicts, mapDicts, mapTreeDicts, forms]: any[]) => {
|
|
709
|
-
this.desForms = forms;
|
|
710
|
-
this.sysDictDetailOptions = dicts;
|
|
711
|
-
this.sysDictTreeDetailOptions = treeDicts;
|
|
712
|
-
this.mapSysDictDetailOptions = mapDicts;
|
|
713
|
-
this.mapSysDictTreeDetailOptions = mapTreeDicts;
|
|
714
|
-
const desForm: DesForm | undefined = this.desForms.find((item) => item.formId === formId);
|
|
715
|
-
if (desForm != null) {
|
|
716
|
-
resolve(formBeanUtilsService.copy(desForm));
|
|
717
|
-
return formBeanUtilsService.copy(desForm);
|
|
718
|
-
} else {
|
|
719
|
-
reject(new DesForm({ formId: formId }));
|
|
720
|
-
}
|
|
721
|
-
});
|
|
722
|
-
});
|
|
723
|
-
} else {
|
|
724
|
-
const desForm: DesForm | undefined = this.desForms.find((item) => item.formId === formId);
|
|
725
|
-
if (desForm != null) {
|
|
726
|
-
return Promise.resolve(formBeanUtilsService.copy(desForm));
|
|
727
|
-
} else {
|
|
728
|
-
return Promise.reject(new DesForm({ formId: formId }));
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
706
|
/**
|
|
734
707
|
* @description: rest客户端
|
|
735
708
|
* @author ChenRui
|
package/src/styles/index.scss
CHANGED
package/src/styles/themes.scss
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
.lo-form-container.lo-form-theme-default {
|
|
2
3
|
@import "theme2";
|
|
3
4
|
}
|
|
@@ -6,13 +7,4 @@
|
|
|
6
7
|
@import "theme1";
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
@import "theme-3";
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.lo-form-container.lo-form-theme-labelWrap {
|
|
14
|
-
@import "theme-4";
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@import "datePicker";
|
|
10
|
+
@import "datePicker";
|
package/types/core/FormApi.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ export declare class FormApi {
|
|
|
81
81
|
apiMetaRefresh: any;
|
|
82
82
|
[key: string]: any;
|
|
83
83
|
oldVal: any;
|
|
84
|
+
private srcData;
|
|
85
|
+
desParams: any;
|
|
84
86
|
/**
|
|
85
87
|
* @description: 获取表单对象
|
|
86
88
|
* @author ChenRui
|
|
@@ -91,6 +93,7 @@ export declare class FormApi {
|
|
|
91
93
|
dvForm?: Vue;
|
|
92
94
|
edit?: boolean;
|
|
93
95
|
formatType?: FormatType;
|
|
96
|
+
desParams?: any;
|
|
94
97
|
});
|
|
95
98
|
get mathjs(): MathJsStatic;
|
|
96
99
|
/**
|
|
@@ -77,6 +77,7 @@ export declare class DesFormControl {
|
|
|
77
77
|
isTreeOpen: string | boolean;
|
|
78
78
|
changeOnSelect: string | boolean;
|
|
79
79
|
textareaRows: number | undefined;
|
|
80
|
+
isDesensitize: string | boolean;
|
|
80
81
|
constructor(options?: {
|
|
81
82
|
formFieldId?: string;
|
|
82
83
|
formId?: string;
|
|
@@ -156,5 +157,6 @@ export declare class DesFormControl {
|
|
|
156
157
|
itemWidth?: string | boolean;
|
|
157
158
|
changeOnSelect?: string | boolean;
|
|
158
159
|
textareaRows?: number | undefined;
|
|
160
|
+
isDesensitize?: string;
|
|
159
161
|
});
|
|
160
162
|
}
|
|
@@ -3,9 +3,9 @@ declare class ApiService {
|
|
|
3
3
|
"Content-Type": string;
|
|
4
4
|
Accept: string;
|
|
5
5
|
};
|
|
6
|
-
createAuthHeaders(
|
|
6
|
+
createAuthHeaders(): {
|
|
7
7
|
Authorization: string;
|
|
8
|
-
"user-identity":
|
|
8
|
+
"user-identity": any;
|
|
9
9
|
"Content-Type": string;
|
|
10
10
|
Accept: string;
|
|
11
11
|
};
|