af-mobile-client-vue3 1.1.32 → 1.1.34

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,100 +1,111 @@
1
- {
2
- "name": "af-mobile-client-vue3",
3
- "type": "module",
4
- "version": "1.1.32",
5
- "description": "Vue + Vite component lib",
6
- "license": "MIT",
7
- "engines": {
8
- "node": ">=18.12.0",
9
- "pnpm": ">=8.15.0"
10
- },
11
- "dependencies": {
12
- "@micro-zoe/micro-app": "1.0.0-rc.24",
13
- "@vant/area-data": "^2.0.0",
14
- "@unhead/vue": "^2.0.5",
15
- "@vant/touch-emulator": "^1.4.0",
16
- "@vant/use": "^1.6.0",
17
- "@vueuse/core": "^13.1.0",
18
- "@iconify/vue": "4.3.0",
19
- "animate.css": "^4.1.1",
20
- "axios": "^1.8.4",
21
- "crypto-js": "^4.2.0",
22
- "echarts": "^5.6.0",
23
- "lodash-es": "^4.17.21",
24
- "nprogress": "^0.2.0",
25
- "ol": "^10.5.0",
26
- "pinia": "^3.0.2",
27
- "pinia-plugin-persistedstate": "^4.2.0",
28
- "qs": "^6.14.0",
29
- "resize-detector": "^0.3.0",
30
- "store": "^2.0.12",
31
- "vant": "^4.9.18",
32
- "vconsole": "^3.15.1",
33
- "vue": "^3.5.13",
34
- "vue-router": "^4.5.0"
35
- },
36
- "devDependencies": {
37
- "@antfu/eslint-config": "^4.12.0",
38
- "@iconify/json": "2.2.318",
39
- "@types/crypto-js": "^4.2.2",
40
- "@types/lodash-es": "^4.17.12",
41
- "@types/node": "^22.14.1",
42
- "@types/nprogress": "^0.2.3",
43
- "@types/store": "^2.0.5",
44
- "@unocss/eslint-plugin": "^66.1.0-beta.11",
45
- "@unocss/preset-rem-to-px": "66.1.0-beta.11",
46
- "@vitejs/plugin-legacy": "^6.0.2",
47
- "@vitejs/plugin-vue": "^5.2.3",
48
- "autoprefixer": "^10.4.21",
49
- "bumpp": "^10.1.0",
50
- "commitizen": "^4.3.1",
51
- "consola": "^3.4.2",
52
- "cross-env": "^7.0.3",
53
- "cz-emoji-chinese": "^0.3.1",
54
- "eslint": "^9.24.0",
55
- "eslint-ts-patch": "^8.57.0-0",
56
- "husky": "^9.1.7",
57
- "less": "^4.3.0",
58
- "mockjs": "^1.1.0",
59
- "postcss-mobile-forever": "^5.0.0",
60
- "rollup": "^4.40.0",
61
- "terser": "^5.39.0",
62
- "typescript": "^5.8.3",
63
- "unocss": "^66.1.0-beta.11",
64
- "unplugin-auto-import": "^19.1.2",
65
- "unplugin-vue-components": "^28.4.1",
66
- "unplugin-vue-router": "^0.12.0",
67
- "vite": "^6.2.6",
68
- "vite-plugin-compression": "^0.5.1",
69
- "vite-plugin-mock-dev-server": "^1.8.5",
70
- "vite-plugin-pwa": "^1.0.0",
71
- "vite-plugin-sitemap": "^0.7.1",
72
- "vite-plugin-svg-icons": "^2.0.1",
73
- "vite-plugin-vconsole": "^2.1.1",
74
- "vite-plugin-vue-devtools": "^7.7.2",
75
- "vite-plugin-vue-layouts": "^0.11.0",
76
- "vitest": "^3.1.1",
77
- "vue-tsc": "^2.2.8"
78
- },
79
- "config": {
80
- "commitizen": {
81
- "path": "./node_modules/cz-emoji-chinese"
82
- },
83
- "cz-emoji-chinese": {
84
- "skipQuestions": [
85
- "body",
86
- "scope"
87
- ]
88
- }
89
- },
90
- "scripts": {
91
- "dev": "cross-env MOCK_SERVER_PORT=8086 vite",
92
- "build": "vue-tsc --noEmit && vite build",
93
- "build:dev": "vue-tsc --noEmit && vite build --mode=development",
94
- "preview": "vite preview",
95
- "lint": "eslint . && vue-tsc --noEmit",
96
- "lint:fix": "eslint . --fix",
97
- "test": "vitest",
98
- "release": "bumpp --commit --push --tag"
99
- }
100
- }
1
+ {
2
+ "name": "af-mobile-client-vue3",
3
+ "type": "module",
4
+ "version": "1.1.34",
5
+ "description": "Vue + Vite component lib",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=18.12.0",
9
+ "pnpm": ">=8.15.0"
10
+ },
11
+ "scripts": {
12
+ "dev": "cross-env MOCK_SERVER_PORT=8086 vite",
13
+ "build": "vue-tsc --noEmit && vite build",
14
+ "build:dev": "vue-tsc --noEmit && vite build --mode=development",
15
+ "preview": "vite preview",
16
+ "lint": "eslint . && vue-tsc --noEmit",
17
+ "lint:fix": "eslint . --fix",
18
+ "test": "vitest",
19
+ "release": "bumpp --commit --push --tag"
20
+ },
21
+ "dependencies": {
22
+ "@micro-zoe/micro-app": "1.0.0-rc.24",
23
+ "@vant/area-data": "^2.0.0",
24
+ "@unhead/vue": "^2.0.5",
25
+ "@vant/touch-emulator": "^1.4.0",
26
+ "@vant/use": "^1.6.0",
27
+ "@vueuse/core": "^13.1.0",
28
+ "@iconify/vue": "4.3.0",
29
+ "animate.css": "^4.1.1",
30
+ "axios": "^1.8.4",
31
+ "crypto-js": "^4.2.0",
32
+ "echarts": "^5.6.0",
33
+ "lodash-es": "^4.17.21",
34
+ "nprogress": "^0.2.0",
35
+ "ol": "^10.5.0",
36
+ "pinia": "^3.0.2",
37
+ "pinia-plugin-persistedstate": "^4.2.0",
38
+ "qs": "^6.14.0",
39
+ "resize-detector": "^0.3.0",
40
+ "store": "^2.0.12",
41
+ "vant": "^4.9.18",
42
+ "vconsole": "^3.15.1",
43
+ "vue": "^3.5.13",
44
+ "vue-router": "^4.5.0"
45
+ },
46
+ "devDependencies": {
47
+ "@antfu/eslint-config": "^4.12.0",
48
+ "@iconify/json": "2.2.318",
49
+ "@types/crypto-js": "^4.2.2",
50
+ "@types/lodash-es": "^4.17.12",
51
+ "@types/node": "^22.14.1",
52
+ "@types/nprogress": "^0.2.3",
53
+ "@types/store": "^2.0.5",
54
+ "@unocss/eslint-plugin": "^66.1.0-beta.11",
55
+ "@unocss/preset-rem-to-px": "66.1.0-beta.11",
56
+ "@vitejs/plugin-legacy": "^6.0.2",
57
+ "@vitejs/plugin-vue": "^5.2.3",
58
+ "autoprefixer": "^10.4.21",
59
+ "bumpp": "^10.1.0",
60
+ "commitizen": "^4.3.1",
61
+ "consola": "^3.4.2",
62
+ "cross-env": "^7.0.3",
63
+ "cz-emoji-chinese": "^0.3.1",
64
+ "eslint": "^9.24.0",
65
+ "eslint-ts-patch": "^8.57.0-0",
66
+ "husky": "^9.1.7",
67
+ "less": "^4.3.0",
68
+ "mockjs": "^1.1.0",
69
+ "postcss-mobile-forever": "^5.0.0",
70
+ "rollup": "^4.40.0",
71
+ "terser": "^5.39.0",
72
+ "typescript": "^5.8.3",
73
+ "unocss": "^66.1.0-beta.11",
74
+ "unplugin-auto-import": "^19.1.2",
75
+ "unplugin-vue-components": "^28.4.1",
76
+ "unplugin-vue-router": "^0.12.0",
77
+ "vite": "^6.2.6",
78
+ "vite-plugin-compression": "^0.5.1",
79
+ "vite-plugin-mock-dev-server": "^1.8.5",
80
+ "vite-plugin-pwa": "^1.0.0",
81
+ "vite-plugin-sitemap": "^0.7.1",
82
+ "vite-plugin-svg-icons": "^2.0.1",
83
+ "vite-plugin-vconsole": "^2.1.1",
84
+ "vite-plugin-vue-devtools": "^7.7.2",
85
+ "vite-plugin-vue-layouts": "^0.11.0",
86
+ "vitest": "^3.1.1",
87
+ "vue-tsc": "^2.2.8"
88
+ },
89
+ "pnpm": {
90
+ "peerDependencyRules": {
91
+ "ignoreMissing": [
92
+ "postcss",
93
+ "esbuild"
94
+ ],
95
+ "allowedVersions": {
96
+ "rollup": "^4.x"
97
+ }
98
+ }
99
+ },
100
+ "config": {
101
+ "commitizen": {
102
+ "path": "./node_modules/cz-emoji-chinese"
103
+ },
104
+ "cz-emoji-chinese": {
105
+ "skipQuestions": [
106
+ "body",
107
+ "scope"
108
+ ]
109
+ }
110
+ }
111
+ }
@@ -30,7 +30,6 @@ function triggerCamera() {
30
30
  funcName: 'takePicture',
31
31
  param: {},
32
32
  callbackFunc: (result: any) => {
33
- console.log('>>>> 拍照 后 上传', result)
34
33
  if (result.status === 'success') {
35
34
  handlePhotoUpload(result.data)
36
35
  }
@@ -50,7 +49,7 @@ function handlePhotoUpload(photoData: any) {
50
49
  formData.append('filesize', (photoData.size / 1024 / 1024).toFixed(4))
51
50
  formData.append('f_operator', 'server')
52
51
  formData.append('imgPath', photoData.filePath)
53
- formData.append('urlPath', '/api/af-revenue/resource/upload')
52
+ formData.append('urlPath', `/api/${import.meta.env.VITE_APP_SYSTEM_NAME}/resource/upload`)
54
53
 
55
54
  // 添加临时预览
56
55
  const tempFile = {
@@ -78,15 +77,13 @@ function handlePhotoUpload(photoData: any) {
78
77
  filesize: photoData.size,
79
78
  f_operator: 'server',
80
79
  imgPath: photoData.filePath,
81
- urlPath: '/api/af-revenue/resource/upload',
80
+ urlPath: `/api/${import.meta.env.VITE_APP_SYSTEM_NAME}/resource/upload`,
82
81
  }
83
- console.log('>>>> 上传 param: ', JSON.stringify(param))
84
82
  // 上传到服务器
85
83
  mobileUtil.execute({
86
84
  funcName: 'uploadResource',
87
85
  param,
88
86
  callbackFunc: (result: any) => {
89
- console.log('>>>> 上传结果: ', result)
90
87
  if (result.status === 'success') {
91
88
  const index = imageList.value.findIndex(item => item.uid === tempFile.uid)
92
89
  if (index !== -1) {
@@ -481,21 +481,17 @@ function evaluateCustomFunction(funcString: string | undefined, record: any, ind
481
481
  }
482
482
  }
483
483
 
484
- // 更新查询条件并刷新
484
+ /**
485
+ * 函数描述: 传入自定义条件进行查询(传入字段必须在琉璃中配置生成查询项才会生效)
486
+ * @param {string} params - 查询条件map 例: { os_id:1 }
487
+ * // 小提示:此处传入的条件会覆盖掉fixQueryForm(固定查询条件参数)
488
+ */
485
489
  function updateConditionAndRefresh(params: any) {
486
- // 更新 conditionParams
487
- if (!conditionParams.value) {
488
- conditionParams.value = {}
489
- }
490
490
  if (params) {
491
491
  // 遍历参数,更新对应的表单值
492
492
  Object.entries(params).forEach(([key, value]) => {
493
493
  // 找到对应的表单项
494
- const formItem = formQueryList.value.find(item => item.model === key)
495
- if (formItem) {
496
- // 更新表单项的值
497
- conditionParams.value[key] = value
498
- }
494
+ conditionParams.value[key] = value
499
495
  })
500
496
  }
501
497
 
@@ -647,7 +643,12 @@ defineExpose({
647
643
  </div>
648
644
  </VanCol>
649
645
  </VanRow>
650
- <VanRow gutter="20" class="card_item_footer" @click="emit('toDetail', item)">
646
+ <VanRow
647
+ v-if="footColumns && footColumns.length > 0"
648
+ gutter="20"
649
+ class="card_item_footer"
650
+ @click="emit('toDetail', item)"
651
+ >
651
652
  <VanCol v-for="column of footColumns" :key="`foot_${column.dataIndex}`" :span="12">
652
653
  <p>
653
654
  <span :style="handleFunctionStyle(column.styleFunctionForTitle, item)">
@@ -665,13 +666,13 @@ defineExpose({
665
666
  <VanCol span="4">
666
667
  <VanPopover
667
668
  v-model:show="showPopover[index]"
669
+ v-if="otherActions && otherActions.length !== 0 && otherActions.some(action => evaluateCustomFunction(action.customFunction, item, index))"
668
670
  placement="bottom-start"
669
671
  :actions="otherActions.filter(action => evaluateCustomFunction(action.customFunction, item, index))"
670
672
  @select="onSelectMenu(item, $event)"
671
673
  >
672
674
  <template #reference>
673
675
  <div
674
- v-show="otherActions && otherActions.length !== 0 && otherActions.some(action => evaluateCustomFunction(action.customFunction, item, index))"
675
676
  class="more-button"
676
677
  >
677
678
  <span>⋯</span>
@@ -733,6 +734,14 @@ defineExpose({
733
734
  border-radius: var(--van-radius-lg);
734
735
  margin: 0 0 var(--van-padding-xs) 0;
735
736
  padding: var(--van-padding-sm);
737
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
738
+ transition: all 0.3s ease;
739
+ border: 1px solid rgba(0, 0, 0, 0.04);
740
+
741
+ &:active {
742
+ transform: scale(0.98);
743
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.02);
744
+ }
736
745
 
737
746
  .card_item_header {
738
747
  margin-bottom: var(--van-padding-base);
@@ -740,7 +749,7 @@ defineExpose({
740
749
  .title-row {
741
750
  display: flex;
742
751
  align-items: center;
743
- margin-bottom: 8px;
752
+ margin-bottom: 2px;
744
753
  width: 100%;
745
754
 
746
755
  .main-title {
@@ -748,6 +757,8 @@ defineExpose({
748
757
  align-items: center;
749
758
  .card_item_title {
750
759
  font-size: var(--van-font-size-lg);
760
+ font-weight: 500;
761
+ color: var(--van-text-color);
751
762
  margin: 0;
752
763
  }
753
764
  }
@@ -755,7 +766,7 @@ defineExpose({
755
766
  .sub-title {
756
767
  display: inline-flex;
757
768
  align-items: center;
758
- margin-left: 4px;
769
+ margin-left: 8px;
759
770
  .card_item_subtitle {
760
771
  font-size: var(--van-font-size-xs);
761
772
  color: var(--van-text-color-2);
@@ -768,21 +779,23 @@ defineExpose({
768
779
  align-items: center;
769
780
  margin-left: auto;
770
781
  .action-button {
771
- margin-left: 4px;
772
- width: 36px;
773
- height: 36px;
782
+ margin-left: 6px;
783
+ width: 32px;
784
+ height: 32px;
774
785
  padding: 0;
775
786
  border: none;
776
787
  color: var(--van-primary-color);
777
- background-color: rgba(25, 137, 250, 0.3);
778
- border-radius: 4px;
779
- font-size: 20px;
788
+ background-color: rgba(25, 137, 250, 0.1);
789
+ border-radius: 6px;
790
+ font-size: 18px;
780
791
  display: flex;
781
792
  align-items: center;
782
793
  justify-content: center;
794
+ transition: all 0.2s ease;
783
795
  &:active {
784
796
  opacity: 0.7;
785
- background-color: rgba(25, 137, 250, 0.5);
797
+ background-color: rgba(25, 137, 250, 0.2);
798
+ transform: scale(0.95);
786
799
  }
787
800
  }
788
801
  }
@@ -801,13 +814,13 @@ defineExpose({
801
814
  padding: 0 !important;
802
815
  align-items: center;
803
816
  width: 100%;
804
- margin: 0 -8px;
817
+ margin: 0 -4px;
805
818
 
806
819
  .tag-col {
807
820
  display: flex;
808
821
  align-items: center;
809
- padding: 0 8px;
810
- min-height: 32px;
822
+ padding: 0 4px;
823
+ min-height: 28px;
811
824
  }
812
825
 
813
826
  .tag-item {
@@ -816,12 +829,14 @@ defineExpose({
816
829
  font-size: var(--van-font-size-xs);
817
830
  display: flex;
818
831
  align-items: center;
819
- margin: 4px 0;
832
+ margin: 2px 0;
820
833
  justify-content: center;
821
834
  :deep(.van-tag) {
822
835
  width: fit-content;
823
836
  display: inline-flex;
824
837
  align-items: center;
838
+ padding: 2px 8px;
839
+ border-radius: 4px;
825
840
  }
826
841
  .tag-content {
827
842
  display: flex;
@@ -842,19 +857,38 @@ defineExpose({
842
857
  }
843
858
 
844
859
  .card_item_details {
845
- margin-bottom: var(--van-padding-base);
846
860
  font-size: var(--van-font-size-sm);
847
- color: #666;
861
+ color: var(--van-text-color-2);
862
+ padding: 8px 0;
848
863
 
849
864
  .van-col {
850
- margin-bottom: 2px;
865
+ margin-bottom: 4px;
866
+ p {
867
+ display: flex;
868
+ align-items: center;
869
+ gap: 4px;
870
+
871
+ span {
872
+ flex: 1;
873
+ min-width: 0;
874
+ overflow: hidden;
875
+ text-overflow: ellipsis;
876
+ white-space: nowrap;
877
+ }
878
+
879
+ :deep(.van-badge) {
880
+ flex-shrink: 0;
881
+ }
882
+ }
851
883
  }
852
884
  }
853
885
 
854
886
  .card_item_footer {
855
887
  font-size: var(--van-font-size-sm);
856
888
  color: var(--van-text-color-2);
857
- margin-bottom: 15px;
889
+ margin-bottom: 12px;
890
+ padding: 8px 0;
891
+ border-top: 1px solid rgba(0, 0, 0, 0.04);
858
892
 
859
893
  .van-col:last-child {
860
894
  text-align: right;
@@ -864,6 +898,45 @@ defineExpose({
864
898
  text-align: left;
865
899
  }
866
900
  }
901
+
902
+ .card_item_bottom {
903
+ margin-top: 4px;
904
+
905
+ .more-button {
906
+ width: 28px;
907
+ height: 28px;
908
+ display: flex;
909
+ align-items: center;
910
+ justify-content: center;
911
+ color: var(--van-text-color-2);
912
+ cursor: pointer;
913
+ font-size: 18px;
914
+ background-color: var(--van-background);
915
+ border-radius: 6px;
916
+ transition: all 0.2s ease;
917
+ border: 1px solid rgba(0, 0, 0, 0.06);
918
+ span {
919
+ line-height: 1;
920
+ margin-top: -2px;
921
+ }
922
+ &:active {
923
+ opacity: 0.7;
924
+ background-color: var(--van-background-2);
925
+ transform: scale(0.95);
926
+ }
927
+ }
928
+
929
+ .action-btn {
930
+ min-width: 76px;
931
+ height: 32px;
932
+ border-radius: 16px;
933
+ font-size: 14px;
934
+ transition: all 0.2s ease;
935
+ &:active {
936
+ transform: scale(0.95);
937
+ }
938
+ }
939
+ }
867
940
  }
868
941
  }
869
942
 
@@ -872,25 +945,30 @@ defineExpose({
872
945
  align-items: center;
873
946
  padding: 8px 12px;
874
947
  background-color: #fff;
875
- gap: 5px;
948
+ gap: 8px;
949
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.02);
950
+ position: sticky;
951
+ top: 0;
952
+ z-index: 10;
876
953
  :deep(.van-search) {
877
954
  width: 100%;
878
955
  padding: var(--van-search-padding);
879
956
  background-color: transparent;
880
957
  }
881
958
  :deep(.van-search__content) {
882
- border-radius: 5px;
883
- background-color: #f5f5f5;
884
- padding: 4px 8px;
959
+ border-radius: 8px;
960
+ background-color: var(--van-background);
961
+ padding: 4px 12px;
962
+ border: 1px solid rgba(0, 0, 0, 0.01);
885
963
  }
886
964
  :deep(.van-field__left-icon) {
887
- color: #999;
965
+ color: var(--van-text-color-2);
888
966
  }
889
967
  :deep(.van-cell) {
890
968
  background-color: transparent;
891
969
  }
892
970
  :deep(.van-field__control::placeholder) {
893
- color: #999;
971
+ color: var(--van-text-color-2);
894
972
  font-size: 14px;
895
973
  }
896
974
  .van-col {
@@ -909,48 +987,20 @@ defineExpose({
909
987
  display: flex;
910
988
  align-items: center;
911
989
  justify-content: center;
912
- width: 40px;
913
- height: 40px;
914
- border-radius: 10px;
915
- background-color: rgba(245,245,245);
990
+ width: 36px;
991
+ height: 36px;
992
+ border-radius: 8px;
993
+ background-color: var(--van-background);
916
994
  cursor: pointer;
917
995
  position: relative;
918
996
  z-index: 1;
997
+ border: 1px solid rgba(0, 0, 0, 0.06);
998
+ transition: all 0.2s ease;
919
999
  &:active {
920
1000
  opacity: 0.7;
1001
+ transform: scale(0.95);
921
1002
  }
922
1003
  }
923
1004
  }
924
-
925
- .custom-button {
926
- border: none !important;
927
- box-shadow: none !important;
928
- }
929
-
930
- .more-button {
931
- width: 24px;
932
- height: 24px;
933
- display: flex;
934
- align-items: center;
935
- justify-content: center;
936
- color: #666;
937
- cursor: pointer;
938
- font-size: 20px;
939
- background-color: #f7f8fa;
940
- border-radius: 4px;
941
- span {
942
- line-height: 1;
943
- margin-top: -2px;
944
- }
945
- &:active {
946
- opacity: 0.7;
947
- background-color: #ebedf0;
948
- }
949
- }
950
- .action-btn {
951
- min-width: 80px;
952
- border-radius: 20px;
953
- font-size: 14px;
954
- }
955
1005
  }
956
1006
  </style>
@@ -501,7 +501,7 @@ function handleCloseScanButton() {
501
501
  font-size: 13px;
502
502
  font-weight: 600;
503
503
  line-height: 2rem;
504
- margin: 5px 5px 1px 8px;
504
+ margin: 5px 5px 1px 0px;
505
505
  color: black;
506
506
  }
507
507
  .range-picker-list {
@@ -1,108 +1,428 @@
1
1
  <script setup lang="ts">
2
2
  import XCellList from '@af-mobile-client-vue3/components/data/XCellList/index.vue'
3
- import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
4
- import { defineEmits, ref } from 'vue'
5
- import { useRouter } from 'vue-router'
3
+ import { getConfigByName } from '@af-mobile-client-vue3/services/api/common'
4
+ import { post } from '@af-mobile-client-vue3/services/restTools'
5
+ import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
6
+ import {
7
+ showDialog,
8
+ showNotify,
9
+ Badge as VanBadge,
10
+ Dialog as VanDialog,
11
+ Field as VanField,
12
+ Icon as VanIcon,
13
+ Radio as VanRadio,
14
+ RadioGroup as VanRadioGroup,
15
+ } from 'vant'
16
+ import { defineEmits, onMounted, onUnmounted, reactive, ref } from 'vue'
6
17
 
7
18
  // 定义事件
8
19
  const emit = defineEmits(['deleteRow'])
9
- // 访问路由
10
- const router = useRouter()
11
- // 获取默认值
12
- const idKey = ref('o_id')
13
-
14
- // 简易crud表单测试
15
- const configName = ref('crud_oper_log_manage')
16
- const serviceName = ref('af-system')
17
-
18
- // 资源权限测试
19
- // const configName = ref('crud_sources_test')
20
- // const serviceName = ref('af-system')
21
-
22
- // 实际业务测试
23
- // const configName = ref('lngChargeAuditMobileCRUD')
24
- // const serviceName = ref('af-gaslink')
25
-
26
- // 跳转到详情页面
27
- // function toDetail(item) {
28
- // router.push({
29
- // name: 'XCellDetailView',
30
- // params: { id: item[idKey.value] }, // 如果使用命名路由,推荐使用路由参数而不是直接构建 URL
31
- // query: {
32
- // operName: item[operNameKey.value],
33
- // method:item[methodKey.value],
34
- // requestMethod:item[requestMethodKey.value],
35
- // operatorType:item[operatorTypeKey.value],
36
- // operUrl:item[operUrlKey.value],
37
- // operIp:item[operIpKey.value],
38
- // costTime:item[costTimeKey.value],
39
- // operTime:item[operTimeKey.value],
40
- //
41
- // title: item[titleKey.value],
42
- // businessType: item[businessTypeKey.value],
43
- // status:item[statusKey.value]
44
- // }
45
- // })
46
- // }
47
-
48
- // 跳转到表单——以表单组来渲染纯表单
49
- function toDetail(item) {
50
- router.push({
51
- name: 'XFormGroupView',
52
- query: {
53
- id: item[idKey.value],
54
- // id: item.rr_id,
55
- // o_id: item.o_id,
56
- },
20
+ const userState = useUserStore().getLogin()
21
+ let timer: number | null = null
22
+ const configName = ref('ReservationOrderCRUD')
23
+ const serviceName = ref('af-safecheck')
24
+
25
+ // 获取组件引用
26
+ const cellListRef = ref()
27
+ const statistics = reactive({
28
+ awaiting_security: 0,
29
+ pending: 0,
30
+ })
31
+
32
+ const fixQueryForm = { }
33
+
34
+ // 处理公告点击
35
+ function handleBadgeClick(opt) {
36
+ const condition = {}
37
+ if (opt === 'backlog') {
38
+ condition.os_f_accept_status = '待受理'
39
+ condition.os_f_accept_user_id = null
40
+ }
41
+ else {
42
+ condition.os_f_accept_status = '待安检'
43
+ condition.os_f_accept_user_id = userState.f.resources.id
44
+ }
45
+ cellListRef.value?.updateConditionAndRefresh(condition)
46
+ }
47
+
48
+ // 获取待办数据
49
+ function fetchTodoData() {
50
+ post(`/af-safecheck/logic/getToDoSafeOrder`, { params: { userid: userState.f.resources.id, f_urban_area: userState.f.resources.orgs } }).then((res) => {
51
+ console.log('res====', res)
52
+ if (res && res.length > 0) {
53
+ statistics.awaiting_security = res[0].awaiting_security || 0
54
+ statistics.pending = res[0].pending || 0
55
+ }
56
+ })
57
+ }
58
+
59
+ onMounted(() => {
60
+ // 立即执行一次
61
+ fetchTodoData()
62
+ getConfig()
63
+ // 设置定时器,每10秒执行一次
64
+ timer = window.setInterval(() => {
65
+ fetchTodoData()
66
+ }, 10000)
67
+ window.addEventListener('appstate-change', (e: any) => {
68
+ if (e.detail.appState === 'afterhidden') {
69
+ if (timer) {
70
+ clearInterval(timer)
71
+ timer = null
72
+ }
73
+ }
74
+ })
75
+ })
76
+
77
+ // 组件销毁时清理定时器
78
+ onUnmounted(() => {
79
+ if (timer) {
80
+ clearInterval(timer)
81
+ timer = null
82
+ }
83
+ })
84
+
85
+ // 添加新的状态变量
86
+ const showCompleteDialog = ref(false)
87
+ const showInvalidateDialog = ref(false)
88
+ const currentItem = ref(null)
89
+ const completeForm = reactive({
90
+ result: '',
91
+ problemDesc: '',
92
+ remark: '',
93
+ })
94
+ const invalidateForm = reactive({
95
+ reason: '',
96
+ remark: '',
97
+ })
98
+
99
+ // 安检结果选项
100
+ const inspectionResults = ref([])
101
+
102
+ // 作废原因选项
103
+ const invalidateReasons = ref([])
104
+
105
+ // 开始安检
106
+ function accept(item) {
107
+ currentItem.value = item
108
+ showCompleteDialog.value = true
109
+ }
110
+ // 作废安检
111
+ function showInvalidated(item) {
112
+ currentItem.value = item
113
+ showInvalidateDialog.value = true
114
+ }
115
+ // 完成安检
116
+ function completed() {
117
+ if (!completeForm.result) {
118
+ showNotify({
119
+ type: 'warning',
120
+ message: '请选择安检结果',
121
+ duration: 2000,
122
+ })
123
+ return false
124
+ }
125
+
126
+ const currentResult = inspectionResults.value.find(item => item.value === completeForm.result)
127
+ if (currentResult?.showProblemDesc && !completeForm.problemDesc) {
128
+ showNotify({
129
+ type: 'warning',
130
+ message: '请填写问题描述',
131
+ duration: 2000,
132
+ })
133
+ return false
134
+ }
135
+
136
+ // TODO: 调用后端API保存安检结果
137
+ post('/af-safecheck/entity/save/t_order_safecheck', {
138
+ id: currentItem.value.os_id,
139
+ f_accept_status: '已安检',
140
+ f_check_result: completeForm.result,
141
+ f_problem_desc: completeForm.problemDesc || null,
142
+ f_remark: completeForm.remark || null,
143
+ version: currentItem.value.os_version,
144
+ }).then(() => {
145
+ showNotify({
146
+ type: 'success',
147
+ message: '安检完成',
148
+ duration: 2000,
149
+ })
150
+ // 刷新列表
151
+ cellListRef.value?.updateConditionAndRefresh()
152
+ fetchTodoData()
153
+ // 关闭弹窗并重置表单
154
+ showCompleteDialog.value = false
155
+ resetCompleteForm()
156
+ })
157
+ return true
158
+ }
159
+
160
+ // 作废安检
161
+ function invalidated() {
162
+ if (!invalidateForm.reason) {
163
+ showNotify({
164
+ type: 'warning',
165
+ message: '请选择作废原因',
166
+ duration: 2000,
167
+ })
168
+ return false
169
+ }
170
+
171
+ // TODO: 调用后端API保存作废信息
172
+ post('/af-safecheck/entity/save/t_order_safecheck', {
173
+ id: currentItem.value.os_id,
174
+ f_accept_status: '已作废',
175
+ f_problem_desc: `${invalidateForm.reason}-${invalidateForm.remark}`,
176
+ version: currentItem.value.os_version,
177
+ }).then(() => {
178
+ showNotify({
179
+ type: 'success',
180
+ message: '安检已作废',
181
+ duration: 2000,
182
+ })
183
+ // 刷新列表
184
+ cellListRef.value?.updateConditionAndRefresh()
185
+ fetchTodoData()
186
+ // 关闭弹窗并重置表单
187
+ showInvalidateDialog.value = false
188
+ resetInvalidateForm()
189
+ })
190
+ return true
191
+ }
192
+
193
+ function accepted(item) {
194
+ // TODO: 调用后端API保存作废信息
195
+ post('/af-safecheck/entity/save/t_order_safecheck', {
196
+ id: item.os_id,
197
+ f_accept_status: '待安检',
198
+ f_accept_user_id: userState.f.resources.id,
199
+ f_accept_user_name: userState.f.resources.name,
200
+ version: item.os_version,
201
+ }).then(() => {
202
+ showNotify({
203
+ type: 'success',
204
+ message: '已成功受理,请及时安检!',
205
+ duration: 2000,
206
+ })
207
+ // 刷新列表
208
+ cellListRef.value?.updateConditionAndRefresh()
209
+ fetchTodoData()
57
210
  })
211
+ return true
58
212
  }
59
213
 
60
- // 新增功能
61
- // function addOption(totalCount) {
62
- // router.push({
63
- // name: 'XFormView',
64
- // params: { id: totalCount, openid: totalCount },
65
- // query: {
66
- // configName: configName.value,
67
- // serviceName: serviceName.value,
68
- // mode: '新增',
69
- // },
70
- // })
71
- // }
72
-
73
- // 修改功能
74
- // function updateRow(result) {
75
- // router.push({
76
- // name: 'XFormView',
77
- // params: { id: result.o_id, openid: result.o_id },
78
- // query: {
79
- // configName: configName.value,
80
- // serviceName: serviceName.value,
81
- // mode: '修改',
82
- // },
83
- // })
84
- // }
85
-
86
- // 删除功能
87
- function deleteRow(result) {
88
- emit('deleteRow', result.o_id)
214
+ function getConfig() {
215
+ getConfigByName('invalidateReasonsConfig', (result) => {
216
+ if (result?.value)
217
+ invalidateReasons.value = result.value
218
+ }, 'af-safecheck')
219
+ getConfigByName('inspectionResultsConfig', (result) => {
220
+ if (result?.value)
221
+ inspectionResults.value = result.value
222
+ }, 'af-safecheck')
223
+ }
224
+ // 重置完成安检表单
225
+ function resetCompleteForm() {
226
+ completeForm.result = ''
227
+ completeForm.problemDesc = ''
228
+ completeForm.remark = ''
229
+ }
230
+
231
+ // 重置作废安检表单
232
+ function resetInvalidateForm() {
233
+ invalidateForm.reason = ''
234
+ invalidateForm.remark = ''
235
+ }
236
+ // 退出登录
237
+ async function exit_login() {
238
+ showDialog({
239
+ title: '提示',
240
+ message: '确定要退出登录吗?',
241
+ confirmButtonText: '确定',
242
+ cancelButtonText: '取消',
243
+ showCancelButton: true,
244
+ }).then(async () => {
245
+ await useUserStore().logout()
246
+ }).catch(() => {
247
+ // 用户点击取消,不做任何操作
248
+ })
89
249
  }
90
250
  </script>
91
251
 
92
252
  <template>
93
- <NormalDataLayout id="XCellListView" title="工作计划">
94
- <template #layout_content>
95
- <XCellList
96
- :config-name="configName"
97
- :service-name="serviceName"
98
- :fix-query-form="{ o_f_oper_name: 'edu_test' }"
99
- :id-key="idKey"
100
- @to-detail="toDetail"
101
- @delete-row="deleteRow"
102
- />
103
- </template>
104
- </NormalDataLayout>
253
+ <div class="xlv_t">
254
+ <XCellList
255
+ ref="cellListRef"
256
+ :config-name="configName"
257
+ :service-name="serviceName"
258
+ :fix-query-form="fixQueryForm"
259
+ @accept="accepted"
260
+ @completed="accept"
261
+ @invalidated="showInvalidated"
262
+ >
263
+ <!-- <template #search-left-loginout>
264
+ <VanBadge @click="exit_login()">
265
+ <VanIcon name="arrow-left" size="24" />
266
+ </VanBadge>
267
+ </template>-->
268
+ <template #search-right-bad>
269
+ <VanBadge :content="statistics.pending" @click="handleBadgeClick('backlog')">
270
+ <VanIcon name="bullhorn-o" size="24" />
271
+ </VanBadge>
272
+ </template>
273
+ <template #search-right-my>
274
+ <VanBadge :content="statistics.awaiting_security" @click="handleBadgeClick('my')">
275
+ <VanIcon name="description-o" size="24" />
276
+ </VanBadge>
277
+ </template>
278
+ </XCellList>
279
+
280
+ <!-- 完成安检弹窗 -->
281
+ <VanDialog
282
+ v-model:show="showCompleteDialog"
283
+ title="完成安检"
284
+ show-cancel-button
285
+ :close-on-click-overlay="false"
286
+ :close-on-popstate="false"
287
+ :before-close="(action) => action === 'confirm' ? completed() : true"
288
+ class="inspection-dialog"
289
+ @cancel="resetCompleteForm"
290
+ >
291
+ <div class="dialog-content">
292
+ <div class="form-item">
293
+ <div class="form-label">
294
+ 安检结果
295
+ </div>
296
+ <VanRadioGroup v-model="completeForm.result" class="radio-group">
297
+ <VanRadio
298
+ v-for="item in inspectionResults"
299
+ :key="item.value"
300
+ :name="item.value"
301
+ class="radio-item"
302
+ >
303
+ {{ item.label }}
304
+ </VanRadio>
305
+ </VanRadioGroup>
306
+ </div>
307
+
308
+ <div v-if="inspectionResults.find(item => item.value === completeForm.result)?.showProblemDesc" class="form-item">
309
+ <div class="form-label">
310
+ 问题描述
311
+ </div>
312
+ <VanField
313
+ v-model="completeForm.problemDesc"
314
+ type="textarea"
315
+ rows="3"
316
+ placeholder="请详细描述发现的问题"
317
+ class="field-item"
318
+ />
319
+ </div>
320
+
321
+ <div class="form-item">
322
+ <div class="form-label">
323
+ 备注信息
324
+ </div>
325
+ <VanField
326
+ v-model="completeForm.remark"
327
+ type="textarea"
328
+ rows="3"
329
+ placeholder="请输入其他备注信息(选填)"
330
+ class="field-item"
331
+ />
332
+ </div>
333
+ </div>
334
+ </VanDialog>
335
+
336
+ <!-- 作废安检弹窗 -->
337
+ <VanDialog
338
+ v-model:show="showInvalidateDialog"
339
+ title="作废安检"
340
+ show-cancel-button
341
+ :close-on-click-overlay="false"
342
+ :close-on-popstate="false"
343
+ :before-close="(action) => action === 'confirm' ? invalidated() : true"
344
+ class="inspection-dialog"
345
+ @cancel="resetInvalidateForm"
346
+ >
347
+ <div class="dialog-content">
348
+ <div class="form-item">
349
+ <div class="form-label">
350
+ 作废原因
351
+ </div>
352
+ <VanRadioGroup v-model="invalidateForm.reason" class="radio-group">
353
+ <VanRadio
354
+ v-for="item in invalidateReasons"
355
+ :key="item.value"
356
+ :name="item.value"
357
+ class="radio-item"
358
+ >
359
+ {{ item.label }}
360
+ </VanRadio>
361
+ </VanRadioGroup>
362
+ </div>
363
+
364
+ <div class="form-item">
365
+ <div class="form-label">
366
+ 补充说明
367
+ </div>
368
+ <VanField
369
+ v-model="invalidateForm.remark"
370
+ type="textarea"
371
+ rows="3"
372
+ placeholder="请详细说明作废原因(选填)"
373
+ class="field-item"
374
+ />
375
+ </div>
376
+ </div>
377
+ </VanDialog>
378
+ </div>
105
379
  </template>
106
380
 
107
381
  <style scoped lang="less">
382
+ .xlv_t{
383
+ --van-cell-horizontal-padding: 0;
384
+ --van-cell-vertical-padding: 0;
385
+ .dialog-content {
386
+ padding: 8%;
387
+ .form-item {
388
+ margin-bottom: 20px;
389
+
390
+ &:last-child {
391
+ margin-bottom: 0;
392
+ }
393
+ }
394
+
395
+ .form-label {
396
+ font-size: 14px;
397
+ color: #323233;
398
+ margin-bottom: 12px;
399
+ font-weight: 500;
400
+ }
401
+
402
+ .radio-group {
403
+ display: flex;
404
+ flex-direction: column;
405
+ gap: 12px;
406
+ }
407
+
408
+ .radio-item {
409
+ font-size: 14px;
410
+ color: #323233;
411
+ }
412
+
413
+ .field-item {
414
+ :deep(.van-field__control) {
415
+ min-height: 80px;
416
+ border: 1px solid #ebedf0;
417
+ border-radius: 4px;
418
+ padding: 8px 12px;
419
+ background-color: #f7f8fa;
420
+ }
421
+
422
+ :deep(.van-field__placeholder) {
423
+ color: #969799;
424
+ }
425
+ }
426
+ }
427
+ }
108
428
  </style>