@dhccmobile/vue3-lo-form 2.0.53 → 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 -4
- package/dist/vue3-lo-form.common.js +196 -162
- 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 +196 -162
- 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 +89 -57
- 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 -401
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
|
>
|
|
@@ -302,9 +302,7 @@
|
|
|
302
302
|
</a-upload>
|
|
303
303
|
</template>
|
|
304
304
|
<template v-if="control.code === formFieldType.Custom.code && controlAttr.customFieldName">
|
|
305
|
-
<
|
|
306
|
-
<slot :control="control" :onChange="onChange" :name="controlAttr.customFieldName"></slot>
|
|
307
|
-
</div>
|
|
305
|
+
<slot :control="control" :onChange="onChange" :name="controlAttr.customFieldName"></slot>
|
|
308
306
|
</template>
|
|
309
307
|
</template>
|
|
310
308
|
<template v-else>
|
|
@@ -321,6 +319,12 @@
|
|
|
321
319
|
<template v-if="controlAttr.unit">
|
|
322
320
|
<span class="addon-readonly">{{ controlAttr.unit }}</span>
|
|
323
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>
|
|
324
328
|
</template>
|
|
325
329
|
</a-form-item>
|
|
326
330
|
</div>
|
|
@@ -340,7 +344,6 @@
|
|
|
340
344
|
@focus="onFocus($event)"
|
|
341
345
|
@blur="onBlur($event)"
|
|
342
346
|
@addon-before="onAddonBeforeHandler($event)"
|
|
343
|
-
@addon-after="onAddonAfterHandler($event)"
|
|
344
347
|
@add-item="selectAddItem($event)"
|
|
345
348
|
@fixFormLayout="onHideControl"
|
|
346
349
|
>
|
|
@@ -374,36 +377,31 @@
|
|
|
374
377
|
</template>
|
|
375
378
|
|
|
376
379
|
<script lang="ts">
|
|
377
|
-
import {
|
|
378
|
-
import { Control } from "@/domain";
|
|
379
|
-
import {
|
|
380
|
-
import { FormFieldClass } from "@/constants";
|
|
381
|
-
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";
|
|
382
383
|
import generateGridTemplateColumns from "../../filtres/generate-grid-template-columns.filter";
|
|
383
384
|
import generateGridColumnEnd from "../../filtres/generate-grid-column-end.filter";
|
|
384
|
-
import { DesFormLayout } from "@/domain";
|
|
385
|
-
import { DesFormControl } from "@/domain";
|
|
386
385
|
|
|
387
|
-
import { AutoComplete, Cascader, Checkbox,
|
|
388
|
-
import {
|
|
389
|
-
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";
|
|
390
388
|
import { ProvideInjectData } from "@/domain/ProvideInjectData";
|
|
391
389
|
|
|
392
390
|
import amountCapitalization from "../../filtres/amount-capitalization.filter";
|
|
393
|
-
import { FormControl, ValidateResult
|
|
394
|
-
import {
|
|
395
|
-
import { ValidateRules } from "@/constants";
|
|
396
|
-
import { ZoomType } from "@/constants";
|
|
391
|
+
import { CustomFormat, FormControl, ValidateResult } from "../../domain";
|
|
392
|
+
import { BuiltLabel, ControlFormatType, FormBusAttr, MoneyUnit, SubmittedType, SupportUploadType } from "../../constants/enum";
|
|
397
393
|
import { extractOptions } from "@/filtres/extract-options.filter";
|
|
398
394
|
import zoomMultiple from "../../filtres/zoom-multiple.filter";
|
|
399
395
|
import switchEnumConvert from "../../filtres/switch-enum-convert.filter";
|
|
400
396
|
import StretchText from "./StretchText.vue";
|
|
401
|
-
import {
|
|
402
|
-
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";
|
|
403
400
|
|
|
404
401
|
import dayjs from "dayjs";
|
|
405
402
|
import locale from "ant-design-vue/es/date-picker/locale/zh_CN";
|
|
406
403
|
import pinYin from "../../../public/js/pinyin";
|
|
404
|
+
import { FormApi } from "@/core";
|
|
407
405
|
|
|
408
406
|
@Options({
|
|
409
407
|
name: "DvFormLayout",
|
|
@@ -452,6 +450,8 @@ import pinYin from "../../../public/js/pinyin";
|
|
|
452
450
|
[StretchText.name]: StretchText,
|
|
453
451
|
[Row.name]: Row,
|
|
454
452
|
[Col.name]: Col,
|
|
453
|
+
EyeOutlined,
|
|
454
|
+
EyeInvisibleOutlined,
|
|
455
455
|
VNodes: (_, { attrs }) => {
|
|
456
456
|
return attrs.vnodes;
|
|
457
457
|
},
|
|
@@ -478,6 +478,7 @@ export default class DvFormLayout extends Vue {
|
|
|
478
478
|
workdayList: any = localStorage.getItem("workdayList") || JSON.stringify([]); // 工作日集合
|
|
479
479
|
amountCapitalization = amountCapitalization; // 大写转换
|
|
480
480
|
zoomMultiple = zoomMultiple; // 缩放
|
|
481
|
+
isAfterClick = false; // 后缀图标是否被点击了 2026年4月17日 15:21:53
|
|
481
482
|
filterOption(value: any, item: any) {
|
|
482
483
|
if (!item.title) {
|
|
483
484
|
return false;
|
|
@@ -486,7 +487,7 @@ export default class DvFormLayout extends Vue {
|
|
|
486
487
|
}
|
|
487
488
|
|
|
488
489
|
@Prop() index: number | undefined;
|
|
489
|
-
@Prop() control: Control |
|
|
490
|
+
@Prop() control: Control | any;
|
|
490
491
|
@Prop() parentControl: Control | undefined;
|
|
491
492
|
@Prop({ type: Object, default: () => ({}) }) customFormats: { [key: string]: CustomFormat } | undefined;
|
|
492
493
|
@Prop({ type: Array, default: () => [] }) linkList: any | undefined; // 需要添加超链接点击事件数组 例:['cifNo', 'prodBaseNo']
|
|
@@ -784,7 +785,7 @@ export default class DvFormLayout extends Vue {
|
|
|
784
785
|
} else if (this.provideInjectData.controlSpan) {
|
|
785
786
|
return this.provideInjectData.controlSpan;
|
|
786
787
|
} else {
|
|
787
|
-
return
|
|
788
|
+
return 0;
|
|
788
789
|
}
|
|
789
790
|
}
|
|
790
791
|
|
|
@@ -959,7 +960,6 @@ export default class DvFormLayout extends Vue {
|
|
|
959
960
|
for (let i = 0; i < index; i++) {
|
|
960
961
|
data += "0";
|
|
961
962
|
}
|
|
962
|
-
data = this.countDecimalPlaces(data, controlAttr.decimalPlaces);
|
|
963
963
|
}
|
|
964
964
|
// 金额后缀不依赖于是否设置了小数位
|
|
965
965
|
if (controlAttr.zoomType !== ZoomType.automatic.code && data != null && data != "" && controlAttr.unit) {
|
|
@@ -1036,39 +1036,6 @@ export default class DvFormLayout extends Vue {
|
|
|
1036
1036
|
return data;
|
|
1037
1037
|
}
|
|
1038
1038
|
|
|
1039
|
-
/**
|
|
1040
|
-
* 数字小数位数计算
|
|
1041
|
-
* @author JiangTao
|
|
1042
|
-
* @since 2026-04-16 16:40:23
|
|
1043
|
-
*/
|
|
1044
|
-
countDecimalPlaces(data: string | number, decimalPlaces: number | undefined): string {
|
|
1045
|
-
// 1. 安全处理
|
|
1046
|
-
const digits = decimalPlaces ?? 0;
|
|
1047
|
-
const str = String(data).trim();
|
|
1048
|
-
if (!str) return digits > 0 ? `0.${"0".repeat(digits)}` : "0";
|
|
1049
|
-
|
|
1050
|
-
// 2. 判断是否有小数
|
|
1051
|
-
const hasDot = str.includes(".");
|
|
1052
|
-
const intPart = hasDot ? str.split(".")[0] : str;
|
|
1053
|
-
const decimalPart = hasDot ? str.split(".")[1] : "";
|
|
1054
|
-
|
|
1055
|
-
// 3. 拼接成纯数字用于四舍五入计算
|
|
1056
|
-
const pureNumStr = intPart.replace(/,/g, "") + (hasDot ? "." + decimalPart : "");
|
|
1057
|
-
const num = parseFloat(pureNumStr);
|
|
1058
|
-
if (isNaN(num)) return intPart + (digits > 0 ? `.${"0".repeat(digits)}` : "");
|
|
1059
|
-
|
|
1060
|
-
// 4. 四舍五入保留 digits 位
|
|
1061
|
-
const factor = Math.pow(10, digits);
|
|
1062
|
-
const rounded = (Math.round(num * factor) / factor).toFixed(digits);
|
|
1063
|
-
|
|
1064
|
-
// 5. 拆分四舍五入后的整数与小数
|
|
1065
|
-
const [, roundedDecimal = ""] = rounded.split(".");
|
|
1066
|
-
|
|
1067
|
-
// 6. 最终结果:原始整数部分 + 处理后的小数部分
|
|
1068
|
-
if (digits <= 0) return intPart;
|
|
1069
|
-
return `${intPart}.${roundedDecimal}`;
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
1039
|
/**
|
|
1073
1040
|
* @description: 支持的上传类型
|
|
1074
1041
|
* @author ChenRui
|
|
@@ -1523,7 +1490,61 @@ export default class DvFormLayout extends Vue {
|
|
|
1523
1490
|
onAddonAfterHandler(event: any): void {
|
|
1524
1491
|
this.$emit("addon-after", event);
|
|
1525
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
|
+
}
|
|
1526
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
|
+
}
|
|
1527
1548
|
/**
|
|
1528
1549
|
* @description: 数字框失焦点
|
|
1529
1550
|
* @author ChenRui
|
|
@@ -1639,4 +1660,15 @@ export default class DvFormLayout extends Vue {
|
|
|
1639
1660
|
flex: 3 !important;
|
|
1640
1661
|
}
|
|
1641
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
|
+
}
|
|
1642
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
|
};
|