Commit d26a220b85570bf763652095086a88be9ab14242

Authored by 史婷婷
1 parent 2171bcc2

feat: 客户开发列表-批量审批

@@ -93,6 +93,7 @@ export function batchApproveApi(params) { @@ -93,6 +93,7 @@ export function batchApproveApi(params) {
93 url: `/flow/task/approve/batch`, 93 url: `/flow/task/approve/batch`,
94 method: 'post', 94 method: 'post',
95 data: params, 95 data: params,
  96 + contentType: ContentTypeEnum.JSON
96 }) 97 })
97 } 98 }
98 99
1 -/**  
2 - * @description: Request result set  
3 - */  
4 -export enum ResultEnum {  
5 - SUCCESS = 200,  
6 - ERROR = -1,  
7 - TIMEOUT = 401,  
8 - TYPE = 'success',  
9 -}  
10 -  
11 -export enum ResponseEnum {  
12 - BLOB = 'BLOB',  
13 -}  
14 -/**  
15 - * @description: request method  
16 - */  
17 -export enum RequestEnum {  
18 - GET = 'GET',  
19 - POST = 'POST',  
20 - PUT = 'PUT',  
21 - DELETE = 'DELETE',  
22 -}  
23 -  
24 -/**  
25 - * @description: contentType  
26 - */  
27 -export enum ContentTypeEnum {  
28 - // json  
29 - JSON = 'application/json;charset=UTF-8',  
30 - // form-data qs  
31 - FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',  
32 - // form-data upload  
33 - BLOB = 'multipart/form-data;charset=UTF-8',  
34 -}  
@@ -135,6 +135,29 @@ @@ -135,6 +135,29 @@
135 title="科办" 135 title="科办"
136 @confirm="onOfficeConfirm" 136 @confirm="onOfficeConfirm"
137 /> 137 />
  138 + <!-- 批量:统一弹框(通过/驳回) -->
  139 + <uni-popup ref="approvePopup" type="center" :mask-click="false">
  140 + <view class="action-modal">
  141 + <view class="header">{{ approveType === 'PASS' ? '通过' : '驳回' }}</view>
  142 + <view class="body">
  143 + <text class="tip">
  144 + {{ approveType === 'PASS' ? '您将通过该信息的审核' : '您将驳回该信息的审核' }}
  145 + </text>
  146 + <uni-easyinput
  147 + v-model="approveComment"
  148 + :placeholder="approveType === 'PASS' ? '请输入通过原因' : '请输入驳回原因'"
  149 + />
  150 + </view>
  151 + <view class="footer">
  152 + <button class="btn cancel" @click="cancelApprove">取消</button>
  153 + <button
  154 + class="btn confirm"
  155 + type="primary"
  156 + @click="confirmApprove"
  157 + >{{ approveType === 'PASS' ? '通过' : '驳回' }}</button>
  158 + </view>
  159 + </view>
  160 + </uni-popup>
138 </view> 161 </view>
139 </template> 162 </template>
140 163
@@ -142,7 +165,7 @@ @@ -142,7 +165,7 @@
142 import CardList from '@/components/card/index.vue' 165 import CardList from '@/components/card/index.vue'
143 import FilterModal from '@/components/filter/index.vue' 166 import FilterModal from '@/components/filter/index.vue'
144 import SingleSelectSheet from '@/components/single-select/index.vue' 167 import SingleSelectSheet from '@/components/single-select/index.vue'
145 -import { queryApi, officeQueryApi, statusOptions, getTodoTypeStatisticsApi } from '@/api/devManage.js' 168 +import { queryApi, officeQueryApi, statusOptions, getTodoTypeStatisticsApi, batchApproveApi } from '@/api/devManage.js'
146 import {getDicByCodes, getDicName} from '@/utils/dic'; 169 import {getDicByCodes, getDicName} from '@/utils/dic';
147 170
148 export default { 171 export default {
@@ -150,6 +173,7 @@ export default { @@ -150,6 +173,7 @@ export default {
150 data() { 173 data() {
151 return { 174 return {
152 searchKeyword: '', 175 searchKeyword: '',
  176 + searchKeywordDebounced: '',
153 officeList: [], // 科办列表下拉选 177 officeList: [], // 科办列表下拉选
154 tabs: [], 178 tabs: [],
155 todoType: '', 179 todoType: '',
@@ -180,7 +204,9 @@ export default { @@ -180,7 +204,9 @@ export default {
180 // 批量选择 204 // 批量选择
181 batchMode: false, 205 batchMode: false,
182 selectedKeys: [], 206 selectedKeys: [],
183 - rowKey: 'customerId', 207 + rowKey: 'id',
  208 + selectedRows: [],
  209 + currentItems: [],
184 210
185 // 筛选弹框 211 // 筛选弹框
186 filterVisible: false, 212 filterVisible: false,
@@ -188,12 +214,15 @@ export default { @@ -188,12 +214,15 @@ export default {
188 officeSelectVisible: false, 214 officeSelectVisible: false,
189 // 审核状态枚举(来自 api/devManage.js) 215 // 审核状态枚举(来自 api/devManage.js)
190 statusOptions, 216 statusOptions,
  217 + // 批量操作弹框数据
  218 + approveType: 'PASS', // PASS:通过;REFUSE:驳回
  219 + approveComment: ''
191 } 220 }
192 }, 221 },
193 computed: { 222 computed: {
194 extraCombined() { 223 extraCombined() {
195 return { 224 return {
196 - keyword: this.searchKeyword, 225 + customerName: this.searchKeywordDebounced || undefined,
197 todoType: this.todoType || undefined, 226 todoType: this.todoType || undefined,
198 workshopType: this.workshopType || undefined 227 workshopType: this.workshopType || undefined
199 } 228 }
@@ -206,6 +235,13 @@ export default { @@ -206,6 +235,13 @@ export default {
206 this.extraParams = v 235 this.extraParams = v
207 }, 236 },
208 immediate: true 237 immediate: true
  238 + },
  239 + // 勾选变化时同步 selectedRows
  240 + selectedKeys: {
  241 + deep: true,
  242 + handler() {
  243 + this.updateSelectedRows()
  244 + }
209 } 245 }
210 }, 246 },
211 created() { 247 created() {
@@ -229,42 +265,36 @@ export default { @@ -229,42 +265,36 @@ export default {
229 methods: { 265 methods: {
230 onCardLoaded({ items }) { 266 onCardLoaded({ items }) {
231 this.currentItems = items 267 this.currentItems = items
  268 + this.updateSelectedRows()
232 }, 269 },
233 onCardError() { 270 onCardError() {
234 uni.showToast({ title: '列表加载失败', icon: 'none' }) 271 uni.showToast({ title: '列表加载失败', icon: 'none' })
235 }, 272 },
236 - onSearch() {  
237 - this.extraParams = { ...this.extraParams, keyword: this.searchKeyword }  
238 - },  
239 - // 输入实时搜索:300ms 防抖更新关键字并触发 CardList 刷新 273 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
240 onSearchInput(val) { 274 onSearchInput(val) {
241 - this.searchKeyword = typeof val === 'string' ? val : (val && val.value) ? val.value : this.searchKeyword  
242 if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer) 275 if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
243 this.searchDebounceTimer = setTimeout(() => { 276 this.searchDebounceTimer = setTimeout(() => {
244 - this.extraParams = { ...this.extraParams, keyword: this.searchKeyword } 277 + this.searchKeywordDebounced = this.searchKeyword
245 this.searchDebounceTimer = null 278 this.searchDebounceTimer = null
246 - }, 300) 279 + }, 1200)
247 }, 280 },
248 // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新 281 // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
249 search(e) { 282 search(e) {
250 const val = e && e.value != null ? e.value : this.searchKeyword 283 const val = e && e.value != null ? e.value : this.searchKeyword
251 this.searchKeyword = val 284 this.searchKeyword = val
252 - this.extraParams = { ...this.extraParams, keyword: val } 285 + this.searchKeywordDebounced = val
253 }, 286 },
254 switchTab(item) { 287 switchTab(item) {
255 this.todoType = item.value; 288 this.todoType = item.value;
256 - this.extraParams = { ...this.extraParams, todoType: item.value }  
257 }, 289 },
258 switchWorkshopType(item, i) { 290 switchWorkshopType(item, i) {
259 this.workshopType = item.value; 291 this.workshopType = item.value;
260 this.currentWorkshopTypeIndex = i; 292 this.currentWorkshopTypeIndex = i;
261 - this.extraParams = { ...this.extraParams, workshopType: item.value }  
262 }, 293 },
263 openFilter() { 294 openFilter() {
264 this.filterVisible = true 295 this.filterVisible = true
265 }, 296 },
266 onFilterReset(payload) { 297 onFilterReset(payload) {
267 - console.log('onFilterReset',payload)  
268 // 保持弹框不关闭,仅同步表单 298 // 保持弹框不关闭,仅同步表单
269 this.filterForm = payload 299 this.filterForm = payload
270 }, 300 },
@@ -297,13 +327,45 @@ export default { @@ -297,13 +327,45 @@ export default {
297 this.batchMode = !this.batchMode 327 this.batchMode = !this.batchMode
298 if (!this.batchMode) this.selectedKeys = [] 328 if (!this.batchMode) this.selectedKeys = []
299 }, 329 },
  330 + // 根据 selectedKeys 与当前页 items 计算选中行对象
  331 + updateSelectedRows() {
  332 + const key = this.rowKey || 'id'
  333 + const keys = Array.isArray(this.selectedKeys) ? this.selectedKeys : []
  334 + const items = Array.isArray(this.currentItems) ? this.currentItems : []
  335 + this.selectedRows = items.filter(it => keys.includes(it && it[key]))
  336 + },
300 batchReject() { 337 batchReject() {
301 if (this.selectedKeys.length === 0) return uni.showToast({ title: '请选择记录', icon: 'none' }) 338 if (this.selectedKeys.length === 0) return uni.showToast({ title: '请选择记录', icon: 'none' })
302 - uni.showToast({ title: '已发起驳回', icon: 'none' }) 339 + this.approveType = 'REFUSE'
  340 + this.approveComment = ''
  341 + this.$refs.approvePopup && this.$refs.approvePopup.open()
303 }, 342 },
304 batchPass() { 343 batchPass() {
305 if (this.selectedKeys.length === 0) return uni.showToast({ title: '请选择记录', icon: 'none' }) 344 if (this.selectedKeys.length === 0) return uni.showToast({ title: '请选择记录', icon: 'none' })
306 - uni.showToast({ title: '已发起通过', icon: 'none' }) 345 + this.approveType = 'PASS'
  346 + this.approveComment = ''
  347 + this.$refs.approvePopup && this.$refs.approvePopup.open()
  348 + },
  349 + cancelApprove() {
  350 + this.$refs.approvePopup && this.$refs.approvePopup.close()
  351 + this.approveComment = ''
  352 + },
  353 + async confirmApprove() {
  354 + this.flowTaskIds = this.selectedRows.map((item) => item.flowTaskId || '' + "");
  355 + batchApproveApi({ taskIds: this.flowTaskIds, approveType: this.approveType, message: this.approveComment }).then((res) => {
  356 + console.log('batchApproveApi_res', res)
  357 + uni.showToast({ title: this.approveType === 'PASS' ? '已通过' : '已驳回', icon: 'none' })
  358 + this.$refs.approvePopup && this.$refs.approvePopup.close()
  359 + this.approveComment = '';
  360 + this.selectedKeys = [];
  361 + this.selectedRows = [];
  362 + this.batchMode = false;
  363 + this.$refs.cardRef && this.$refs.cardRef.reload && this.$refs.cardRef.reload();
  364 + this.getTodoTypeStatisticsFun()
  365 + }).catch(() => {
  366 + console.error('confirmApprove error', e)
  367 + uni.showToast({ title: '操作失败', icon: 'none' })
  368 + })
307 }, 369 },
308 onAdd() { 370 onAdd() {
309 uni.showToast({ title: '点击新增', icon: 'none' }) 371 uni.showToast({ title: '点击新增', icon: 'none' })
@@ -317,9 +379,9 @@ export default { @@ -317,9 +379,9 @@ export default {
317 params.createEndTime = params.dateRange[1] + ' 23:59:59' 379 params.createEndTime = params.dateRange[1] + ' 23:59:59'
318 delete params.dateRange 380 delete params.dateRange
319 } 381 }
320 - // 关键字  
321 - if (this.searchKeyword) {  
322 - params.keyword = this.searchKeyword 382 + // 关键字(使用去抖后的值避免频繁触发)
  383 + if (this.searchKeywordDebounced) {
  384 + params.customerName = this.searchKeywordDebounced
323 } 385 }
324 return queryApi(params) 386 return queryApi(params)
325 .then(res => { 387 .then(res => {
@@ -633,4 +695,55 @@ export default { @@ -633,4 +695,55 @@ export default {
633 695
634 } 696 }
635 697
  698 +.action-modal {
  699 + width: 560rpx;
  700 + padding: 32rpx 28rpx 20rpx;
  701 + background: #fff;
  702 + border-radius: 20rpx;
  703 + .header {
  704 + text-align: center;
  705 + font-size: 34rpx;
  706 + font-weight: 600;
  707 + margin-bottom: 12rpx;
  708 + color: rgba(0,0,0,0.9);
  709 + }
  710 + .body {
  711 + padding: 12rpx 4rpx 24rpx;
  712 + .tip {
  713 + display: block;
  714 + text-align: center;
  715 + font-size: 32rpx;
  716 + color: rgba(0,0,0,0.6);
  717 + margin-bottom: 32rpx;
  718 + }
  719 + ::v-deep .uni-easyinput {
  720 + width: 100%;
  721 + }
  722 + }
  723 + .footer {
  724 + display: flex;
  725 + justify-content: space-between;
  726 + gap: 16rpx;
  727 + .btn {
  728 + flex: 1;
  729 + height: 80rpx;
  730 + line-height: 80rpx;
  731 + border-radius: 12rpx;
  732 + font-size: 30rpx;
  733 + font-size: 32rpx;
  734 + &::after {
  735 + border: none;
  736 + }
  737 + }
  738 + .cancel {
  739 + background: #fff;
  740 + color: rgba(0,0,0,0.9);
  741 + }
  742 + .confirm {
  743 + background: #fff !important;
  744 + color: $theme-primary !important;
  745 + }
  746 + }
  747 +}
  748 +
636 </style> 749 </style>
@@ -44,7 +44,10 @@ config.responseType = 'blob'; @@ -44,7 +44,10 @@ config.responseType = 'blob';
44 header: config.header, 44 header: config.header,
45 dataType: 'json' 45 dataType: 'json'
46 }).then(response => { 46 }).then(response => {
47 - let [error, res] = response 47 + let [error, res] = response;
  48 + console.log('request__response', response)
  49 + console.log('request__error', error)
  50 + console.log('request__res', res)
48 if (error) { 51 if (error) {
49 toast('后端接口连接异常') 52 toast('后端接口连接异常')
50 reject('后端接口连接异常') 53 reject('后端接口连接异常')