n20-common-lib 3.3.2 → 3.3.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n20-common-lib",
3
- "version": "3.3.2",
3
+ "version": "3.3.4",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -10,8 +10,6 @@ const DYNAMIC_CONFIG_QUERY = {
10
10
  configKeys: []
11
11
  }
12
12
 
13
- let backendConfigPromise
14
-
15
13
  function parseConfigValue(value) {
16
14
  if (typeof value !== 'string') return value
17
15
  try {
@@ -51,27 +49,19 @@ function mergeConfigList(configList) {
51
49
  }
52
50
 
53
51
  async function getBackendConfig() {
54
- if (!backendConfigPromise) {
55
- backendConfigPromise = (async () => {
56
- const { data } = await axios.post(DYNAMIC_CONFIG_URL, DYNAMIC_CONFIG_QUERY, {
57
- loading: false,
58
- noMsg: true
59
- })
60
- const config = mergeConfigList(decodeConfigList(data))
61
- return {
62
- ...config,
63
- ...(config.nstc && config.nstc.activiti ? config.nstc.activiti : {})
64
- }
65
- })()
52
+ const { data } = await axios.post(DYNAMIC_CONFIG_URL, DYNAMIC_CONFIG_QUERY, {
53
+ loading: false,
54
+ noMsg: true
55
+ })
56
+ const config = mergeConfigList(decodeConfigList(data))
57
+ return {
58
+ ...config,
59
+ ...(config.nstc && config.nstc.activiti ? config.nstc.activiti : {})
66
60
  }
61
+ }
67
62
 
68
- try {
69
- return await backendConfigPromise
70
- } catch (error) {
71
- // 接口不可用时不缓存失败结果,后续组件实例仍可重新探测新配置接口。
72
- backendConfigPromise = undefined
73
- throw error
74
- }
63
+ export function isApprovalRequired(value) {
64
+ return value === true || value === 1 || value === '1' || value === 'true'
75
65
  }
76
66
 
77
67
  /**
@@ -2,20 +2,24 @@
2
2
  <template>
3
3
  <div :class="prefixCls">
4
4
  <!-- 自定义项 -->
5
- <ExpandablePane
6
- v-if="taskId && showBtn && authList.includes('isShowOtherAtt')"
7
- :title="$lc('自定义项')"
8
- :default-expand="otherExpand"
9
- >
10
- <el-form ref="approveBtnGroup" label-position="right" :label-width="_lang === 'zh' ? '12em' : '12em'">
11
- <div
12
- class="p-b-lg p-t-lg p-r-lg"
13
- style="max-height: 150px; overflow-y: auto; border: 1px dashed var(--border-color-base); border-radius: 5px"
14
- >
15
- <show-other-att-new ref="showOtherAttNew" :task-id="taskId" :form="customizationDtos" :required="true" />
16
- </div>
17
- </el-form>
18
- </ExpandablePane>
5
+ <template v-if="taskId && showBtn">
6
+ <ExpandablePane v-show="shouldShowCustomization" :title="$lc('自定义项')" :default-expand="otherExpand">
7
+ <el-form ref="approveBtnGroup" label-position="right" :label-width="_lang === 'zh' ? '12em' : '12em'">
8
+ <div
9
+ class="p-b-lg p-t-lg p-r-lg"
10
+ style="max-height: 150px; overflow-y: auto; border: 1px dashed var(--border-color-base); border-radius: 5px"
11
+ >
12
+ <show-other-att-new
13
+ ref="showOtherAttNew"
14
+ :task-id="taskId"
15
+ :form="customizationDtos"
16
+ :required="true"
17
+ @loaded="showCustomItem = $event"
18
+ />
19
+ </div>
20
+ </el-form>
21
+ </ExpandablePane>
22
+ </template>
19
23
 
20
24
  <div class="n20-form-expandable-pane n20-approve-title">
21
25
  <div class="n20-title flex-box flex-lr flex-v" :class="titleClass">
@@ -349,7 +353,7 @@ import ShowAppOpi from './showAppOpi.vue'
349
353
  import ShowOtherAtt from './showOtherAttr.vue'
350
354
  import ShowOtherAttNew from './showOtherAttrNew.vue'
351
355
  import { toExaminePath } from './specialHandle'
352
- import getApprovalConfig from './getApprovalConfig'
356
+ import getApprovalConfig, { isApprovalRequired } from './getApprovalConfig'
353
357
 
354
358
  import getJsonc from '../../assets/getJsonc.js'
355
359
  import { closeTagsForBackPage } from '../../plugins/CompatibleOld'
@@ -532,6 +536,10 @@ export default {
532
536
  }
533
537
  },
534
538
  computed: {
539
+ // 兼容历史流程:权限标识缺失时,以任务实际返回的自定义项作为展示和提交依据
540
+ shouldShowCustomization() {
541
+ return this.authList.includes('isShowOtherAtt') || this.showCustomItem
542
+ },
535
543
  messageC: {
536
544
  get() {
537
545
  return this.msgisSync ? this.message : this.messageIn
@@ -567,6 +575,13 @@ export default {
567
575
  this.getConfiguration()
568
576
  this.getIsShowUploadWidget()
569
577
  },
578
+ activated() {
579
+ if (!this._canRefreshConfiguration) return
580
+ this.getConfiguration()
581
+ },
582
+ deactivated() {
583
+ this._canRefreshConfiguration = true
584
+ },
570
585
  methods: {
571
586
  // 查询选择审批人
572
587
  async showAdvancePop() {
@@ -646,18 +661,19 @@ export default {
646
661
  },
647
662
  // 意见是否必填
648
663
  async getConfiguration() {
664
+ let opinionRequired = false
649
665
  try {
650
- const { opinionRequired, showApproveTo } = await getApprovalConfig()
651
- this.requiredC = opinionRequired ?? this.required
666
+ const approvalConfig = await getApprovalConfig()
667
+ opinionRequired = approvalConfig.opinionRequired
668
+ const { showApproveTo } = approvalConfig
652
669
  this.showApproveTo = showApproveTo ?? true
653
670
  } catch (error) {
654
- this.requiredC = this.required
655
- } finally {
656
- // 工作流节点配置优先于全局审批意见必填配置。
657
- if (this.$route.query.remarkIsMust !== undefined) {
658
- this.requiredC = this.$route.query.remarkIsMust === '1'
659
- }
671
+ // 配置接口与 JSONC 均不可用时沿用组件默认值。
660
672
  }
673
+ // 业务属性、全局配置、工作流节点配置任一开启时,审批意见均为必填。
674
+ this.requiredC = Boolean(
675
+ this.required || isApprovalRequired(opinionRequired) || this.$route.query.remarkIsMust === '1'
676
+ )
661
677
  },
662
678
  getTodoList() {
663
679
  return new Promise((resolve, reject) => {
@@ -789,7 +805,7 @@ export default {
789
805
  getParam() {
790
806
  let { typeCode, taskId, groupNo, isAgentcy, isCheck } = this.$route.query
791
807
  let customizationDtos
792
- if (this.authList.includes('isShowOtherAtt')) {
808
+ if (this.shouldShowCustomization) {
793
809
  customizationDtos = this.$refs['showOtherAttNew']?.getOtherAttData()
794
810
  }
795
811
  return [
@@ -2,20 +2,24 @@
2
2
  <template>
3
3
  <div :class="prefixCls">
4
4
  <!-- 自定义项 -->
5
- <ExpandablePane
6
- v-if="taskId && showBtn && authList.includes('isShowOtherAtt')"
7
- :title="$lc('自定义项')"
8
- :default-expand="false"
9
- >
10
- <el-form ref="approveBtnGroup" label-position="right" :label-width="_lang === 'zh' ? '12em' : '12em'">
11
- <div
12
- class="p-b-lg p-t-lg p-r-lg"
13
- style="max-height: 150px; overflow-y: auto; border: 1px dashed var(--border-color-base); border-radius: 5px"
14
- >
15
- <show-other-att-new ref="showOtherAttNew" :task-id="taskId" :form="customizationDtos" :required="true" />
16
- </div>
17
- </el-form>
18
- </ExpandablePane>
5
+ <template v-if="taskId && showBtn">
6
+ <ExpandablePane v-show="shouldShowCustomization" :title="$lc('自定义项')" :default-expand="false">
7
+ <el-form ref="approveBtnGroup" label-position="right" :label-width="_lang === 'zh' ? '12em' : '12em'">
8
+ <div
9
+ class="p-b-lg p-t-lg p-r-lg"
10
+ style="max-height: 150px; overflow-y: auto; border: 1px dashed var(--border-color-base); border-radius: 5px"
11
+ >
12
+ <show-other-att-new
13
+ ref="showOtherAttNew"
14
+ :task-id="taskId"
15
+ :form="customizationDtos"
16
+ :required="true"
17
+ @loaded="showCustomItem = $event"
18
+ />
19
+ </div>
20
+ </el-form>
21
+ </ExpandablePane>
22
+ </template>
19
23
  <!-- <div class="n20-form-expandable-pane">
20
24
  <div class="n20-title flex-box flex-lr flex-v" :class="titleClass">
21
25
  <span class="n20-tips flex-item">
@@ -326,6 +330,7 @@
326
330
  <script>
327
331
  import selectSpr from './selectSpr.vue'
328
332
  import getJsonc from '../../assets/getJsonc.js'
333
+ import getApprovalConfig, { isApprovalRequired } from './getApprovalConfig'
329
334
  import { closeTagsForBackPage } from '../../plugins/CompatibleOld'
330
335
  import axios from '../../utils/axios'
331
336
  import { $lc } from '../../utils/i18n/index'
@@ -507,6 +512,10 @@ export default {
507
512
  }
508
513
  },
509
514
  computed: {
515
+ // 兼容历史流程:权限标识缺失时,以任务实际返回的自定义项作为展示和提交依据
516
+ shouldShowCustomization() {
517
+ return this.authList.includes('isShowOtherAtt') || this.showCustomItem
518
+ },
510
519
  messageC: {
511
520
  get() {
512
521
  return this.msgisSync ? this.message : this.messageIn
@@ -539,9 +548,16 @@ export default {
539
548
  this.getShowApprovalTo()
540
549
  this.getHasQueryAppOpiAndUser()
541
550
  this.nextApproval && this.getTodoList()
542
- //this.getConfiguration()
551
+ this.getConfiguration()
543
552
  this.getIsShowUploadWidget()
544
553
  },
554
+ activated() {
555
+ if (!this._canRefreshConfiguration) return
556
+ this.getConfiguration()
557
+ },
558
+ deactivated() {
559
+ this._canRefreshConfiguration = true
560
+ },
545
561
  methods: {
546
562
  // 查询选择审批人
547
563
  async showAdvancePop() {
@@ -576,22 +592,18 @@ export default {
576
592
  console.log(code, data)
577
593
  },
578
594
  // 意见是否必填
579
- getConfiguration() {
580
- getJsonc('portal/server-config.jsonc', null, true)
581
- .then(({ opinionRequired }) => {
582
- this.requiredC = opinionRequired ?? this.required
583
- // 读取该工作流是否意见必填
584
- if (this.$route.query.remarkIsMust !== undefined) {
585
- this.requiredC = this.$route.query.remarkIsMust === '1'
586
- }
587
- })
588
- .catch(() => {
589
- this.requiredC = this.required
590
- // 读取该工作流是否意见必填
591
- if (this.$route.query.remarkIsMust !== undefined) {
592
- this.requiredC = this.$route.query.remarkIsMust === '1'
593
- }
594
- })
595
+ async getConfiguration() {
596
+ let opinionRequired = false
597
+ try {
598
+ const approvalConfig = await getApprovalConfig()
599
+ opinionRequired = approvalConfig.opinionRequired
600
+ } catch (error) {
601
+ // 配置接口与 JSONC 均不可用时沿用组件默认值。
602
+ }
603
+ // 业务属性、全局配置、工作流节点配置任一开启时,审批意见均为必填。
604
+ this.requiredC = Boolean(
605
+ this.required || isApprovalRequired(opinionRequired) || this.$route.query.remarkIsMust === '1'
606
+ )
595
607
  },
596
608
  getTodoList() {
597
609
  return new Promise((resolve, reject) => {
@@ -721,7 +733,7 @@ export default {
721
733
  getParam() {
722
734
  let { typeCode, taskId, groupNo, isAgentcy, isCheck } = this.$route.query
723
735
  let customizationDtos
724
- if (this.authList.includes('isShowOtherAtt')) {
736
+ if (this.shouldShowCustomization) {
725
737
  customizationDtos = this.$refs['showOtherAttNew']?.getOtherAttData()
726
738
  }
727
739
  return [
@@ -143,22 +143,30 @@ export default {
143
143
  if (data.length) {
144
144
  this.otherAttData = data
145
145
  }
146
+ this.$emit('loaded', this.otherAttData.length > 0)
146
147
  if (this.taskId) {
147
- axios.post(`/bems/admin/customization/${this.taskId}`, null, { loading: false }).then(({ data }) => {
148
- if (data && data.length) {
149
- this.otherAttData =
150
- data?.map((item) => {
151
- if (['32'].includes(item.cfgType)) {
152
- item.checkList = item.checkList ? item.checkList : []
153
- }
154
- if (['31'].includes(item.cfgType)) {
155
- item.selectList = item.selectList ? item.selectList : []
156
- }
157
- this.setDefaultValue(item)
158
- return item
159
- }) || []
160
- }
161
- })
148
+ axios
149
+ .post(`/bems/admin/customization/${this.taskId}`, null, { loading: false })
150
+ .then(({ data }) => {
151
+ if (data && data.length) {
152
+ this.otherAttData =
153
+ data?.map((item) => {
154
+ if (['32'].includes(item.cfgType)) {
155
+ item.checkList = item.checkList ? item.checkList : []
156
+ }
157
+ if (['31'].includes(item.cfgType)) {
158
+ item.selectList = item.selectList ? item.selectList : []
159
+ }
160
+ this.setDefaultValue(item)
161
+ return item
162
+ }) || []
163
+ }
164
+ this.$emit('loaded', this.otherAttData.length > 0)
165
+ })
166
+ .catch(() => {
167
+ // 接口不可用时保留传入数据和原权限标识逻辑,不阻断普通审批
168
+ this.$emit('loaded', this.otherAttData.length > 0)
169
+ })
162
170
  }
163
171
  },
164
172
  changeFn(val, item) {
@@ -113,7 +113,7 @@
113
113
  :action="apiPrefix ? apiPrefix + action : action"
114
114
  :multiple="multiple"
115
115
  :headers="headers"
116
- :disabled="!row[keys.type] || row._typeDisabled || row._uploadDisabled"
116
+ :disabled="row._typeDisabled || row._uploadDisabled"
117
117
  :accept="row[keys.type] | acceptFilter(typeOptions, fileAccept)"
118
118
  :size="row[keys.type] | sizeFilter(typeOptions, fileSize)"
119
119
  :http-request="uploadHttpRequest ? (options) => uploadHttpRequest(options, row) : undefined"
@@ -960,6 +960,10 @@ export default {
960
960
  if (!type || row._originalType === type) {
961
961
  return
962
962
  }
963
+ // 未上传的临时行没有后端附件 ID,只保留本地类型选择,不调用更新接口。
964
+ if (!row.beid) {
965
+ return
966
+ }
963
967
  // 未识别类型的行手动选中类型后,删除该类型对应的占位行
964
968
  if (!row._originalType) {
965
969
  let placeholderIndex = this.tableData.findIndex(
@@ -1232,6 +1236,11 @@ export default {
1232
1236
  }
1233
1237
  },
1234
1238
  beforeUploadFn(file, row) {
1239
+ if (!row[this.keys.type]) {
1240
+ this.$message.warning($lc('请先选择附件类型'))
1241
+ return false
1242
+ }
1243
+
1235
1244
  this.$set(row, '_percent', 0)
1236
1245
  this.$set(row, '_status', undefined)
1237
1246
 
@@ -1243,7 +1252,7 @@ export default {
1243
1252
  this.$set(row, '_percent', percent <= 99 ? Math.round(percent) : 99)
1244
1253
  },
1245
1254
  onSuccessFn(response, file, fileList, row) {
1246
- this.$set(row, '_typeDisabled', true)
1255
+ this.$set(row, '_typeDisabled', false)
1247
1256
  this.$set(row, '_name', file.name)
1248
1257
 
1249
1258
  this.$set(row, [this.keys.rowKey], response.data)
@@ -1259,6 +1268,42 @@ export default {
1259
1268
  row[this.keys.url] = response.data
1260
1269
  row[this.keys.name] = file.name
1261
1270
 
1271
+ // 从上传参数中提取后续 updateFlieBuss 需要的业务字段,合并到行上,
1272
+ // 避免上传后修改附件类型时因 row 缺字段导致后端报“参数缺失”
1273
+ let fileDataObj = row['_fileData'] || this.fileData
1274
+ if (fileDataObj) {
1275
+ let dto = {}
1276
+ try {
1277
+ dto = JSON.parse(fileDataObj.data || '{}') || {}
1278
+ } catch (e) {
1279
+ dto = {}
1280
+ }
1281
+ ;['syscode', 'appno', 'bussId', 'bussValue', 'bussName', 'reid', 'fmid'].forEach((k) => {
1282
+ if (dto[k] !== undefined && row[k] === undefined) {
1283
+ this.$set(row, k, dto[k])
1284
+ }
1285
+ })
1286
+ if (fileDataObj.bussId !== undefined && row.bussId === undefined) {
1287
+ this.$set(row, 'bussId', fileDataObj.bussId)
1288
+ }
1289
+ }
1290
+ let currType = row[this.keys.type] || this.bathType
1291
+ let currTypeOption = this.typeOptions.find((item) => item.type === currType)
1292
+ let currTypeName = currTypeOption?.attname || currTypeOption?.label || ''
1293
+ this.$set(row, 'beid', response.data)
1294
+ this.$set(row, 'filePath', row.filePath || response.data)
1295
+ this.$set(row, 'fileName', file.name)
1296
+ this.$set(row, 'attno', currType)
1297
+ this.$set(row, 'attname', currTypeName)
1298
+ if (currTypeOption?.bussValue !== undefined && row.bussValue === undefined) {
1299
+ this.$set(row, 'bussValue', currTypeOption.bussValue)
1300
+ }
1301
+ // 标记为“已存在后端”的行,使 handleTypeChange 可正常进入 updateFileBuss
1302
+ this.$set(row, '_originalType', currType || '')
1303
+ this.$set(row, '_lastFileType', currType)
1304
+ this.$set(row, '_lastFileTypeName', currTypeName)
1305
+ this.$set(row, '_lastBussValue', row.bussValue)
1306
+
1262
1307
  this.$emit('on-success', file, row)
1263
1308
  },
1264
1309
  MultipleSUccessFn(response, file, fileList, row) {
@@ -1286,7 +1331,7 @@ export default {
1286
1331
  [this.keys.url]: response.data,
1287
1332
  [this.keys.name]: file.name,
1288
1333
  _status,
1289
- _typeDisabled: true,
1334
+ _typeDisabled: false,
1290
1335
  [this.keys.user]: deepRow[this.keys.user],
1291
1336
  [this.keys.type]: deepRow[this.keys.type]
1292
1337
  })