business_tms_program 0.0.0

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.
Files changed (136) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintrc-auto-import.json +113 -0
  3. package/.eslintrc.js +121 -0
  4. package/.prettierrc.js +9 -0
  5. package/.stylelintignore +4 -0
  6. package/README.md +43 -0
  7. package/components.d.ts +23 -0
  8. package/index.html +20 -0
  9. package/package.json +70 -0
  10. package/shims-uni.d.ts +10 -0
  11. package/src/App.vue +81 -0
  12. package/src/api/afterSale.ts +184 -0
  13. package/src/api/context.ts +26 -0
  14. package/src/api/device.ts +134 -0
  15. package/src/api/index.ts +80 -0
  16. package/src/api/installtion.ts +155 -0
  17. package/src/api/model/index.ts +15 -0
  18. package/src/api/model/userModel.ts +62 -0
  19. package/src/api/order.ts +49 -0
  20. package/src/api/system.ts +19 -0
  21. package/src/api/user.ts +171 -0
  22. package/src/auto-imports.d.ts +108 -0
  23. package/src/components/ConfirmDialog.vue +101 -0
  24. package/src/components/DaySelect.vue +212 -0
  25. package/src/components/Drawer.vue +104 -0
  26. package/src/components/DrawerSelect.vue +105 -0
  27. package/src/components/DropMenu.vue +144 -0
  28. package/src/components/Empty.vue +49 -0
  29. package/src/components/Loading.vue +41 -0
  30. package/src/components/RippleBtn.vue +159 -0
  31. package/src/components/SinglePick.vue +120 -0
  32. package/src/components/Skeleton.vue +43 -0
  33. package/src/components/Timeline.vue +85 -0
  34. package/src/components/Upload.vue +217 -0
  35. package/src/config/app.ts +32 -0
  36. package/src/config/env.ts +29 -0
  37. package/src/dict/afterSale.ts +161 -0
  38. package/src/dict/device.ts +29 -0
  39. package/src/dict/installtion.ts +141 -0
  40. package/src/dict/systems.ts +4 -0
  41. package/src/env.d.ts +8 -0
  42. package/src/hooks/useForm.ts +222 -0
  43. package/src/hooks/useUpload.ts +80 -0
  44. package/src/main.ts +8 -0
  45. package/src/manifest.json +39 -0
  46. package/src/pages/acceptance/DeviceInfo.vue +132 -0
  47. package/src/pages/acceptance/list.vue +276 -0
  48. package/src/pages/afterSale/DeviceInfo.vue +128 -0
  49. package/src/pages/afterSale/Step.vue +0 -0
  50. package/src/pages/afterSale/faultReport.vue +552 -0
  51. package/src/pages/afterSale/orderDetail.vue +327 -0
  52. package/src/pages/afterSale/orderFinish.vue +517 -0
  53. package/src/pages/afterSale/orderList.vue +305 -0
  54. package/src/pages/afterSale/returnVisit.vue +288 -0
  55. package/src/pages/afterSale/searchDeviceList.vue +148 -0
  56. package/src/pages/device/Search.vue +201 -0
  57. package/src/pages/device/acceptance.vue +270 -0
  58. package/src/pages/device/detail.vue +165 -0
  59. package/src/pages/device/index.vue +322 -0
  60. package/src/pages/device/info.vue +140 -0
  61. package/src/pages/device/list.vue +219 -0
  62. package/src/pages/device/materialTowerCode.vue +589 -0
  63. package/src/pages/device/searchList.vue +224 -0
  64. package/src/pages/installtion/Record.vue +145 -0
  65. package/src/pages/installtion/StatusTimeline.vue +85 -0
  66. package/src/pages/installtion/addAcceptance.vue +409 -0
  67. package/src/pages/installtion/addRecord.vue +338 -0
  68. package/src/pages/installtion/orderDetail.vue +220 -0
  69. package/src/pages/installtion/orderList.vue +100 -0
  70. package/src/pages/user/component/PersonAgree.vue +226 -0
  71. package/src/pages/user/component/PrivayAgree.vue +221 -0
  72. package/src/pages/user/component/SliderCode.vue +173 -0
  73. package/src/pages/user/forgetPassword.vue +249 -0
  74. package/src/pages/user/index.vue +139 -0
  75. package/src/pages/user/login.vue +342 -0
  76. package/src/pages/user/register.vue +348 -0
  77. package/src/pages/user/repassword.vue +329 -0
  78. package/src/pages/user/utils/mcaptcha.js +75 -0
  79. package/src/pages/user/utils/verifyCode.ts +41 -0
  80. package/src/pages/workspace/index.vue +225 -0
  81. package/src/pages.json +203 -0
  82. package/src/shime-uni.d.ts +6 -0
  83. package/src/static/icon/system/breeder_icon.png +0 -0
  84. package/src/static/icon/system/check.png +0 -0
  85. package/src/static/icon/system/factory_icon.png +0 -0
  86. package/src/static/icon/system/plus.png +0 -0
  87. package/src/static/icon/system/right.png +0 -0
  88. package/src/static/icon/system/unCheck.png +0 -0
  89. package/src/static/icon/tab/search.png +0 -0
  90. package/src/static/icon/tab/user.png +0 -0
  91. package/src/static/icon/tab/user_active.png +0 -0
  92. package/src/static/icon/tab/workspace.png +0 -0
  93. package/src/static/icon/tab/workspace_active.png +0 -0
  94. package/src/static/img/active_dot.png +0 -0
  95. package/src/static/img/afterSale_icon.png +0 -0
  96. package/src/static/img/check.png +0 -0
  97. package/src/static/img/close.png +0 -0
  98. package/src/static/img/confirm.png +0 -0
  99. package/src/static/img/empty.png +0 -0
  100. package/src/static/img/equipment_icon.png +0 -0
  101. package/src/static/img/fault_icon.png +0 -0
  102. package/src/static/img/install_icon.png +0 -0
  103. package/src/static/img/login_bg2.png +0 -0
  104. package/src/static/img/movable_right.png +0 -0
  105. package/src/static/img/navigation.png +0 -0
  106. package/src/static/img/psw_off.png +0 -0
  107. package/src/static/img/psw_on.png +0 -0
  108. package/src/static/img/scan.png +0 -0
  109. package/src/static/img/scan_icon.png +0 -0
  110. package/src/static/img/search.png +0 -0
  111. package/src/static/img/turn_right.png +0 -0
  112. package/src/static/img/unActive_dot.png +0 -0
  113. package/src/static/img/verifyBg.png +0 -0
  114. package/src/stores/index.ts +11 -0
  115. package/src/stores/modules/customer.ts +146 -0
  116. package/src/stores/modules/installtion.ts +30 -0
  117. package/src/stores/modules/system.ts +56 -0
  118. package/src/stores/modules/user.ts +133 -0
  119. package/src/stores/types.ts +16 -0
  120. package/src/stores/utils.ts +6 -0
  121. package/src/styles/index.less +63 -0
  122. package/src/types/chengyiApi.d.ts +36 -0
  123. package/src/types/index.d.ts +95 -0
  124. package/src/utils/address.ts +17 -0
  125. package/src/utils/cipher.ts +61 -0
  126. package/src/utils/form.ts +155 -0
  127. package/src/utils/httpEnum.ts +31 -0
  128. package/src/utils/image.ts +21 -0
  129. package/src/utils/index.ts +111 -0
  130. package/src/utils/request.ts +139 -0
  131. package/src/utils/requestCancelHandle.ts +67 -0
  132. package/stylelint.config.js +87 -0
  133. package/tsconfig.docs.json +11 -0
  134. package/tsconfig.json +30 -0
  135. package/typedoc.json +6 -0
  136. package/vite.config.ts +55 -0
@@ -0,0 +1,224 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import DropMenu from '@/components/DropMenu.vue'
4
+ import { isCheckStatusEnum } from '@/dict/device'
5
+ import { debounce } from 'lodash-es';
6
+ import Skeleton from '@/components/Skeleton.vue';
7
+ import LoadingView from '@/components/Loading.vue';
8
+ import Empty from '@/components/Empty.vue';
9
+ import { queryCustomerCode, queryDevicePageList } from '@/api/device'
10
+
11
+ defineOptions({
12
+ name: "searchList"
13
+ });
14
+ const selectedValue = ref('customerCode')
15
+ const state = reactive({
16
+ customerCode: '',
17
+ searchList: [] as any[],
18
+ itemDatas: [] as any[],
19
+ searchLoading: false,
20
+ deviceLoading: false,
21
+ hasSearch: false, // 是否有搜索过
22
+ searchValue: ''
23
+ });
24
+ const options = [
25
+ { value: 'customerCode', name: '客户名称' },
26
+ { value: 'deviceCode', name: '设备编号' }
27
+ ]
28
+ const toDeviceDetail = (item: any) => {
29
+ uni.navigateTo({ url: `/pages/device/detail?deviceCode=${item.deviceCode}` })
30
+ }
31
+ const searchCustomer = debounce(async (value: string) => {
32
+ state.searchLoading = true;
33
+ state.searchList = [];
34
+ const res = await queryCustomerCode({
35
+ customerName: value, // 假设搜索字段为customerName
36
+ })
37
+ state.searchLoading = false;
38
+ if (!res) {
39
+ return; // 搜索失败时不更新数据
40
+ }
41
+ state.searchList = res;
42
+ })
43
+ const searchDevice = async (value: string) => {
44
+ if (!value) {
45
+ return; // 输入为空时不进行搜索
46
+ }
47
+ state.hasSearch = false;
48
+ state.deviceLoading = true;
49
+ const res = await queryDevicePageList({
50
+ size: 10,
51
+ current: 1,
52
+ customerCode: value, // 假设搜索字段为deviceCode
53
+ })
54
+ state.deviceLoading = false;
55
+ if (!res) {
56
+ return; // 搜索失败时不更新数据
57
+ }
58
+ state.itemDatas = res.records;
59
+ }
60
+ const handleSearchInput = debounce((e: any) => {
61
+ const { value } = e.detail
62
+ if (value === state.searchValue) {
63
+ return; // 输入为空时不进行搜索
64
+ }
65
+ state.searchValue = value; // 更新搜索框的值
66
+ searchCustomer(value); // 刷新数据
67
+ if (!state.hasSearch) {
68
+ state.hasSearch = true; // 标记为已搜索
69
+ }
70
+ }, 300)
71
+ </script>
72
+
73
+ <template>
74
+ <view class="content">
75
+ <view class="header">
76
+ <DropMenu v-model="selectedValue" :options="options" />
77
+ <view class="input-wrapper">
78
+ <input class="search-input" @change="handleSearchInput" />
79
+ </view>
80
+ <image class="uni-icon" src="/static/img/search.png" />
81
+ </view>
82
+ <view class="searchist" v-if="state.hasSearch">
83
+ <view class="skeleton-box" v-if="state.searchLoading">
84
+ <Skeleton class="skeleton-container"></Skeleton>
85
+ <Skeleton class="skeleton-container"></Skeleton>
86
+ <Skeleton class="skeleton-container"></Skeleton>
87
+ <Skeleton class="skeleton-container"></Skeleton>
88
+ <Skeleton class="skeleton-container"></Skeleton>
89
+ </view>
90
+ <view class="search-item"
91
+ v-else
92
+ v-for="item in state.searchList" :key="item.customerCode"
93
+ @click="searchDevice(item.customerCode)"
94
+ >
95
+ {{ item.customerName }}<view class="code">{{ item.customerCode }}</view>
96
+ </view>
97
+ </view>
98
+ <view class="deviceBox" v-else>
99
+ <view class="record-box"
100
+ v-for="item in state.itemDatas" :key="item.deviceCode"
101
+ @click="toDeviceDetail(item)"
102
+ >
103
+ <view class="img"></view>
104
+ <view class="info">
105
+ <view class="inlineBox">
106
+ <view class="code">{{ item.deviceCode }}</view>
107
+ <view class="status" :class="{ 'unCheck': item.isCheckStatus === isCheckStatusEnum.NO }">
108
+ {{ item.isCheckStatus === isCheckStatusEnum.YES ? '已验收' : '未验收' }}
109
+ </view>
110
+ </view>
111
+ <view class="contact">客户:{{ item.customerName }}</view>
112
+ </view>
113
+ </view>
114
+ <view class="skeleton-box" v-if="state.deviceLoading">
115
+ <Skeleton class="skeleton-container"></Skeleton>
116
+ <Skeleton class="skeleton-container"></Skeleton>
117
+ <Skeleton class="skeleton-container"></Skeleton>
118
+ <Skeleton class="skeleton-container"></Skeleton>
119
+ <Skeleton class="skeleton-container"></Skeleton>
120
+ </view>
121
+ <Empty v-else-if="state.itemDatas.length === 0" />
122
+ </view>
123
+ </view>
124
+ </template>
125
+ <style scoped lang="less">
126
+ .content {
127
+ background-color: #F5F5F5;
128
+ min-height: 100vh;
129
+ }
130
+ .header {
131
+ padding: 12rpx 18rpx;
132
+ background-color: #fff;
133
+ display: flex;
134
+ align-items: center;
135
+ position: relative;
136
+ .input-wrapper{
137
+ flex: 1;
138
+ margin-left: 4rpx;
139
+ padding: 0 24rpx;
140
+ background: rgba(0,0,0,0.04);
141
+ border-radius: 8rpx;
142
+ display: flex;
143
+ align-items: center;
144
+ }
145
+ .search-input {
146
+ flex: 1;
147
+ font-size: 24rpx;
148
+ padding: 12rpx 0;
149
+ }
150
+ .uni-icon {
151
+ position: absolute;
152
+ right: 36rpx;
153
+ top: 28rpx;
154
+ width: 36rpx;
155
+ height: 36rpx;
156
+ }
157
+ }
158
+ .scroll-box {
159
+ padding: 16rpx 32rpx;
160
+ box-sizing: border-box;
161
+ }
162
+ .record-box{
163
+ display: flex;
164
+ margin-bottom: 16rpx;
165
+ padding: 36rpx;
166
+ background: #FFFFFF;
167
+ border-radius: 16rpx;
168
+ .img{
169
+ margin-right: 16rpx;
170
+ width: 96rpx;
171
+ height: 96rpx;
172
+ background: #E8E8E8;
173
+ border-radius: 8rpx;
174
+ }
175
+ .inlineBox{
176
+ display: flex;
177
+ margin-bottom: 6rpx;
178
+ .code{
179
+ margin-right: 16rpx;
180
+ font-weight: bold;
181
+ font-size: 32rpx;
182
+ color: #000000;
183
+ line-height: 38rpx;
184
+ }
185
+ .status{
186
+ padding: 6rpx 16rpx 8rpx 16rpx;
187
+ font-weight: 400;
188
+ font-size: 24rpx;
189
+ color: #1D6FE9;
190
+ line-height: 34rpx;
191
+ border-radius: 24rpx;
192
+ background: rgba(29,111,233,0.1);
193
+ border: 1rpx solid #1D6FE9;
194
+ }
195
+ .unCheck {
196
+ color: #F5894E;
197
+ border: 1rpx solid #F5894E;
198
+ background: rgba(245,137,78,0.1);
199
+ }
200
+ }
201
+ .contact{
202
+ font-size: 28rpx;
203
+ color: rgba(0,0,0, 0.6);
204
+ line-height: 40rpx;
205
+ }
206
+ }
207
+ .searchist, .deviceBox{
208
+ margin-top: 24rpx;
209
+ }
210
+ .search-item{
211
+ display: flex;
212
+ align-items: flex-end;
213
+ background-color: #fff;
214
+ padding: 18rpx 16rpx 18rpx 42rpx;
215
+ font-size: 28rpx;
216
+ margin-bottom: 1rpx;
217
+ color: rgba(0,0,0,0.6);
218
+ .code{
219
+ margin-left: 24rpx;
220
+ font-size: 24rpx;
221
+ color: rgba(0,0,0,0.4);
222
+ }
223
+ }
224
+ </style>
@@ -0,0 +1,145 @@
1
+ <script setup lang="ts">
2
+ import StatusTimeline from './StatusTimeline.vue'
3
+ const props = defineProps({
4
+ data: {
5
+ type: Object,
6
+ default: {}
7
+ },
8
+ type: {
9
+ type: String,
10
+ default: ''
11
+ }
12
+ })
13
+ const emit = defineEmits(['clickDevice']);
14
+ const handleClickDevice = (item: any) => {
15
+ emit('clickDevice', {
16
+ ...item,
17
+ workOrderCode: props.data.workOrderCode,
18
+ });
19
+ }
20
+ const chooseAddress = () => {
21
+ const { latitude, longitude } = props.data;
22
+ if (!latitude || !longitude) {
23
+ uni.showToast({ title: '暂无位置信息', icon: 'error' })
24
+ return;
25
+ }
26
+ uni.openLocation({
27
+ latitude: Number(latitude),
28
+ longitude: Number(longitude),
29
+ success: (res) => {
30
+ console.log(res);
31
+ },
32
+ fail: (err) => {
33
+ uni.showToast({ title: '获取位置失败', icon: 'error' })
34
+ }
35
+ })
36
+ }
37
+ </script>
38
+ <template>
39
+ <view class="record-box">
40
+ <view class="customerName">{{ data.customerName }}</view>
41
+ <view class="orderCode">{{ data.workOrderCode }}</view>
42
+ <view class="contact">
43
+ <view class="name">联系人姓名:{{ data.contactsName }}</view>
44
+ <view class="mobile">联系电话:{{ data.contactsMobile || '--' }}</view>
45
+ </view>
46
+ <view class="deviceBox" v-for="dItem in data.deviceList"
47
+ :key="dItem.id" @click="handleClickDevice(dItem)">
48
+ <view class="name">{{ dItem.deviceName }}</view>
49
+ <view class="code">{{ dItem.deviceCode }}</view>
50
+ <view v-if="type==='positioning'" class="address">
51
+ <view class="label">设备地址:</view><view class="address-detail">
52
+ {{ (data?.provinceName !== null && data?.provinceName) ?
53
+ `${data?.provinceName} ${data?.cityName} ${data?.areaName} ${dItem?.address}`
54
+ : `空`}}
55
+ </view>
56
+ <!-- <image class="address-icon" src="/static/img/navigation.png" /> -->
57
+ </view>
58
+ <view v-else class="address">设备地址:<view class="address-detail">
59
+ {{ (dItem?.provinceName !== null && dItem?.provinceName) ?
60
+ `${dItem?.provinceName} ${dItem?.cityName} ${dItem?.areaName} ${dItem?.address}`
61
+ : `空` }}
62
+ </view>
63
+ </view>
64
+ <StatusTimeline :status="dItem.status" />
65
+ </view>
66
+ </view>
67
+ </template>
68
+
69
+ <style scoped>
70
+ .record-box {
71
+ background-color: #fff;
72
+ padding: 32rpx;
73
+ .customerName {
74
+ font-weight: bold;
75
+ font-size: 32rpx;
76
+ color: #000000;
77
+ line-height: 48rpx;
78
+ }
79
+
80
+ .orderCode {
81
+ margin-top: 16rpx;
82
+ font-size: 14px;
83
+ color: rgba(0, 0, 0, 0.4);
84
+ line-height: 34rpx;
85
+ }
86
+
87
+ .contact {
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: space-between;
91
+ margin-top: 16rpx;
92
+ margin-bottom: 32rpx;
93
+ font-size: 28rpx;
94
+ line-height: 40rpx;
95
+ }
96
+
97
+ .deviceBox {
98
+ margin-bottom: 32rpx;
99
+ padding: 16rpx;
100
+ background-color: rgba(0, 0, 0, 0.02);
101
+ border-radius: 8rpx;
102
+
103
+ .name {
104
+ margin-bottom: 16rpx;
105
+ font-weight: bold;
106
+ font-size: 28rpx;
107
+ color: #000000;
108
+ line-height: 40rpx;
109
+ }
110
+
111
+ .code {
112
+ margin-bottom: 16rpx;
113
+ font-size: 14px;
114
+ color: rgba(0, 0, 0, 0.4);
115
+ line-height: 34rpx;
116
+ }
117
+
118
+ .address {
119
+ display: flex;
120
+ justify-content: center;
121
+ font-size: 28rpx;
122
+ line-height: 42rpx;
123
+ margin-bottom: 16rpx;
124
+ color: rgba(0,0,0,0.9);
125
+ .label{
126
+ min-width: 132rpx;
127
+ }
128
+ .address-detail{
129
+ flex: 1;
130
+ width: 380rpx;
131
+ color: rgba(0,0,0,0.65);
132
+ font-size: 26rpx;
133
+ line-height: 42rpx;
134
+ }
135
+ .address-icon {
136
+ width: 48rpx;
137
+ height: 48rpx;
138
+ image-rendering: -webkit-optimize-contrast; /* 优化图片渲染 */
139
+ image-rendering: pixelated; /* 像素化渲染 */
140
+ transform: translateZ(0); /* 开启GPU加速 */
141
+ }
142
+ }
143
+ }
144
+ }
145
+ </style>
@@ -0,0 +1,85 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps({
3
+ data: {
4
+ type: Object,
5
+ default: {}
6
+ },
7
+ status: {
8
+ type: Number,
9
+ default: 0
10
+ }
11
+ })
12
+ const items = [
13
+ { text: '齐料清点', value: '1' },
14
+ { text: '安装完成', value: '2' },
15
+ { text: '验收完成', value: '3' },
16
+ ]
17
+ const timelineWidth = computed(() => {
18
+ if (props.status === 0) {
19
+ return '0%'
20
+ }
21
+ if (props.status == 1) {
22
+ return '23%'
23
+ }
24
+ if (props.status == 2) {
25
+ return '65%'
26
+ }
27
+ return `88%`
28
+ })
29
+ </script>
30
+ <template>
31
+ <view class="timeline-box">
32
+ <view class="timeline" :style="{ width: timelineWidth }"></view>
33
+ <view class="unactive-timeline"></view>
34
+ <view class="dot-box" v-for="(item, index) in items" :key="item.value">
35
+ <img class="dot" :src="index < status ? '/static/img/active_dot.png': '/static/img/unActive_dot.png'" />
36
+ <view class="text" :style="{ color: index < status ? '#1D6FE9': 'rgba(0,0,0,0.4)'}">
37
+ {{ item.text }}
38
+ </view>
39
+ </view>
40
+ </view>
41
+ </template>
42
+
43
+ <style scoped>
44
+ .timeline-box {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: space-between;
48
+ position: relative;
49
+ .dot-box{
50
+ text-align: center;
51
+ .text{
52
+ font-size: 24rpx;
53
+ color: #1D6FE9;
54
+ line-height: 34rpx;
55
+ }
56
+ }
57
+ .dot {
58
+ position: relative;
59
+ z-index: 4;
60
+ margin: 0 auto;
61
+ width: 32rpx;
62
+ height: 32rpx;
63
+ }
64
+ .unactive-timeline {
65
+ position: absolute;
66
+ z-index: 1;
67
+ top: 17rpx;
68
+ left: 34rpx;
69
+ width: 88%;
70
+ height: 8rpx;
71
+ background: #E7E7E7;
72
+ border-radius: 4rpx;
73
+ }
74
+ .timeline {
75
+ position: absolute;
76
+ z-index: 2;
77
+ top: 17rpx;
78
+ left: 34rpx;
79
+ width: 88%;
80
+ height: 8rpx;
81
+ background: #1D6FE9;
82
+ border-radius: 4rpx;
83
+ }
84
+ }
85
+ </style>