Commit cf7d32a59efa6f50d42083dca0897260c2d79bd7

Authored by 史婷婷
1 parent f6d6c842

feat: 发货单-列表&筛选 --100%

  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum';
  3 +
  4 +const baseUrl = '/shipments/order';
  5 +// 查询列表
  6 +export function queryApi(params) {
  7 + return request({
  8 + url: baseUrl + `/query`,
  9 + method: 'get',
  10 + params
  11 + })
  12 +}
  13 +
  14 +// 根据ID查询详情数据
  15 +export function getDetailApi(id) {
  16 + return request({
  17 + url: baseUrl,
  18 + method: 'get',
  19 + params: { id }
  20 + })
  21 +}
  22 +
  23 +// 新增保存
  24 +export function createApi(params) {
  25 + return request({
  26 + url: baseUrl,
  27 + method: 'post',
  28 + data: params,
  29 + contentType: ContentTypeEnum.FORM_URLENCODED
  30 + })
  31 +}
  32 +
  33 +
  34 +// 修改保存
  35 +export function updateApi(params) {
  36 + return request({
  37 + url: baseUrl,
  38 + method: 'put',
  39 + data: params,
  40 + contentType: ContentTypeEnum.FORM_URLENCODED
  41 + })
  42 +}
  43 +
  44 +
  45 +// 检查发货计划是否可以填写实发数
  46 +export function checkApi(ids) {
  47 + return request({
  48 + url: baseUrl + '/check',
  49 + method: 'post',
  50 + data: ids,
  51 + contentType: ContentTypeEnum.JSON
  52 + })
  53 +}
  54 +
  55 +// 根据发货计划ID查询发货订单列表
  56 +export function listByShipmentOrderId(shipmentsOrderId) {
  57 + return request({
  58 + url: baseUrl + '/listByShipmentOrderId',
  59 + method: 'get',
  60 + params: { shipmentsOrderId }
  61 + })
  62 +}
  63 +
  64 +// 根据发货计划ID查询发货订单列表
  65 +// {
  66 +// id,
  67 +// detailList,
  68 +// type,
  69 +// }
  70 +export function dataReplenishInput(params) {
  71 + return request({
  72 + url: baseUrl + '/dataReplenishInput',
  73 + method: 'post',
  74 + data: params,
  75 + contentType: ContentTypeEnum.JSON
  76 + })
  77 +}
  78 +
  79 +// 保存签收单
  80 +// {
  81 +// fileId: String;
  82 +// fileName: String;
  83 +// shipmentsOrderId: String;
  84 +// }
  85 +export function saveSignInTicket(params) {
  86 + return request({
  87 + url: baseUrl + '/saveSignInTicket',
  88 + method: 'get',
  89 + params: params,
  90 + })
  91 +}
  92 +
  93 +// 查询发货计划详情
  94 +export function queryDetail(params) {
  95 + return request({
  96 + url: '/shipments/plan/detail/query',
  97 + method: 'get',
  98 + params: params,
  99 + })
  100 +}
\ No newline at end of file
... ...
... ... @@ -624,6 +624,14 @@
624 624 "navigationBarBackgroundColor": "#ffffff",
625 625 "navigationBarTextStyle": "black"
626 626 }
  627 + },
  628 + {
  629 + "path": "pages/invoice/index",
  630 + "style": {
  631 + "navigationBarTitleText": "发货单",
  632 + "navigationBarBackgroundColor": "#ffffff",
  633 + "navigationBarTextStyle": "black"
  634 + }
627 635 }
628 636 ],
629 637 "subPackages": [
... ...
... ... @@ -100,7 +100,7 @@
100 100 computed: {
101 101 extraCombined() {
102 102 return {
103   - searchKey: this.searchKeywordDebounced || undefined
  103 + keyword: this.searchKeywordDebounced || undefined
104 104 }
105 105 }
106 106 },
... ... @@ -204,7 +204,7 @@
204 204 delete params.dateRange
205 205 }
206 206 if (this.searchKeywordDebounced) {
207   - params.searchKey = this.searchKeywordDebounced
  207 + params.keyword = this.searchKeywordDebounced
208 208 }
209 209 return queryApi(params)
210 210 .then(res => {
... ...
  1 +<template>
  2 + <view class="page">
  3 + <view class="dev-list-fixed">
  4 + <view class="search-row">
  5 + <uni-search-bar v-model="searchKeyword" radius="6" placeholder="请输入购货单位" clearButton="auto"
  6 + cancelButton="none" bgColor="#F3F3F3" textColor="rgba(0,0,0,0.4)" @confirm="search"
  7 + @input="onSearchInput" />
  8 + <view class="tool-icons">
  9 + <image v-if="$auth.hasPermi('customer-credit-manage:customer-credit-plan:add')" class="tool-icon"
  10 + src="/static/images/dev_manage/add_icon.png" @click="onAdd" />
  11 + <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
  12 + </view>
  13 + </view>
  14 + </view>
  15 +
  16 +
  17 + <!-- 列表卡片组件 -->
  18 + <view class="list-box">
  19 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  20 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  21 + <template v-slot="{ item, selected }">
  22 + <view class="card" @click.stop="onCardClick(item)">
  23 + <view class="card-header">
  24 + <text class="title omit2">{{ item.customerName }}</text>
  25 + <view class="status-box">
  26 + <text :class="['status', `status_${item.status}`]">{{ getDicName('SHIP_ORDER_STATUS',
  27 + item.status, dicOptions.SHIP_ORDER_STATUS) }}</text>
  28 + </view>
  29 + </view>
  30 + <view class="info-row">
  31 + <text>生产厂</text><text>{{ item.workshopName || '-' }}</text>
  32 + </view>
  33 + <view class="info-row">
  34 + <text>办事处</text><text>{{ item.deptName || '-' }}</text>
  35 + </view>
  36 + <view class="info-row">
  37 + <text>交货方式</text><text>{{ item.deliveryType || '-' }}</text>
  38 + </view>
  39 + <view class="info-row">
  40 + <text>发货日期</text><text>{{ item.shipmentsDate || '-' }}</text>
  41 + </view>
  42 + </view>
  43 + </template>
  44 + </card-list>
  45 + </view>
  46 +
  47 +
  48 +
  49 + <!-- 筛选弹框 -->
  50 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  51 + @confirm="onFilterConfirm">
  52 + <template v-slot="{ model }">
  53 + <view class="filter-form">
  54 + <view class="form-item">
  55 + <view class="label">办事处</view>
  56 + <uni-easyinput v-model="model.deptName" placeholder="请输入办事处" :inputBorder="false"
  57 + placeholderStyle="font-size:14px" />
  58 + </view>
  59 +
  60 + <view class="form-item">
  61 + <view class="label">生产厂</view>
  62 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  63 + v-model="model.workshopId" @change="onWorkshopChange" :localdata="workshopOptions" />
  64 + </view>
  65 +
  66 + <view class="form-item">
  67 + <view class="label">状态</view>
  68 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  69 + v-model="model.status" @change="onStatusChange" :localdata="statusLocal" />
  70 + </view>
  71 +
  72 + <view class="form-item">
  73 + <view class="label">订货日期</view>
  74 + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" />
  75 + </view>
  76 + </view>
  77 + </template>
  78 + </filter-modal>
  79 + </view>
  80 +</template>
  81 +
  82 +<script>
  83 +import CardList from '@/components/card/index.vue'
  84 +import FilterModal from '@/components/filter/index.vue'
  85 +import { workshopQueryApi } from '@/api/devManage.js'
  86 +import SingleSelectSheet from '@/components/single-select/index.vue'
  87 +import {
  88 + queryApi
  89 +} from '@/api/invoice.js'
  90 +import {
  91 + getDicByCodes
  92 +} from '@/utils/dic'
  93 +import {
  94 + getDicName
  95 +} from '@/utils/dic.js'
  96 +
  97 +export default {
  98 + components: {
  99 + CardList,
  100 + FilterModal,
  101 + SingleSelectSheet
  102 + },
  103 + data() {
  104 + return {
  105 + searchKeyword: '',
  106 + searchKeywordDebounced: '',
  107 + tabs: [],
  108 + // 给到 card 的筛选值
  109 + query: {
  110 + status: '',
  111 + companySuggestedCategory: '',
  112 + dateRange: []
  113 + },
  114 + extraParams: {},
  115 +
  116 + // 批量选择
  117 + rowKey: 'id',
  118 + currentItems: [],
  119 +
  120 + // 筛选弹框
  121 + filterVisible: false,
  122 + filterForm: {
  123 + status: '',
  124 + companySuggestedCategory: '',
  125 + dateRange: []
  126 + },
  127 + dicOptions: {
  128 + SHIP_ORDER_STATUS: [],
  129 + },
  130 + statusLocal: [],
  131 + workshopOptions: [],
  132 + }
  133 + },
  134 + computed: {
  135 + extraCombined() {
  136 + return {
  137 + customerName: this.searchKeywordDebounced || undefined
  138 + }
  139 + }
  140 + },
  141 + watch: {
  142 + extraCombined: {
  143 + deep: true,
  144 + handler(v) {
  145 + this.extraParams = v
  146 + },
  147 + immediate: true
  148 + },
  149 +
  150 + },
  151 + created() {
  152 + this.loadAllDicData()
  153 + this.loadWorkshopOptions()
  154 + },
  155 + onLoad() { },
  156 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  157 + onReachBottom() {
  158 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  159 + this.$refs.cardRef.onLoadMore()
  160 + }
  161 + },
  162 + beforeDestroy() {
  163 + if (this.searchDebounceTimer) {
  164 + clearTimeout(this.searchDebounceTimer)
  165 + this.searchDebounceTimer = null
  166 + }
  167 + },
  168 + methods: {
  169 + async loadWorkshopOptions() {
  170 + try {
  171 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  172 + const list = (res && res.data && res.data.datas) || []
  173 + this.workshopOptions = list.map(it => ({ text: it.name || it.workshopName || '', value: it.id || it.workshopId || '' }))
  174 + } catch (e) {
  175 + this.workshopOptions = []
  176 + }
  177 + },
  178 + onCardLoaded({
  179 + items
  180 + }) {
  181 + this.currentItems = items
  182 + },
  183 + onCardError() {
  184 + uni.showToast({
  185 + title: '列表加载失败',
  186 + icon: 'none'
  187 + })
  188 + },
  189 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  190 + onSearchInput(val) {
  191 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  192 + this.searchDebounceTimer = setTimeout(() => {
  193 + this.searchKeywordDebounced = this.searchKeyword
  194 + this.searchDebounceTimer = null
  195 + }, 1200)
  196 + },
  197 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  198 + search(e) {
  199 + const val = e && e.value != null ? e.value : this.searchKeyword
  200 + this.searchKeyword = val
  201 + this.searchKeywordDebounced = val
  202 + },
  203 + onAdd() {
  204 + uni.navigateTo({
  205 + url: '/pages/credit_manage/add'
  206 + })
  207 + },
  208 + openFilter() {
  209 + this.filterVisible = true
  210 + },
  211 + onFilterReset(payload) {
  212 + this.filterForm = payload
  213 + },
  214 + onFilterConfirm(payload) {
  215 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  216 + payload.status = this.filterForm.status
  217 + }
  218 + if ((payload.companySuggestedCategory === '' || payload.companySuggestedCategory == null) && this
  219 + .filterForm
  220 + .companySuggestedCategory !== '') {
  221 + payload.companySuggestedCategory = this.filterForm.companySuggestedCategory
  222 + }
  223 + this.query = {
  224 + ...payload
  225 + }
  226 + },
  227 + onStatusChange(e) {
  228 + const raw = e && e.detail && e.detail.value !== undefined ?
  229 + e.detail.value :
  230 + (e && e.value !== undefined ? e.value : '')
  231 + this.filterForm.status = raw
  232 + },
  233 + onCategoryChange(e) {
  234 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ?
  235 + e.value : '')
  236 + this.filterForm.companySuggestedCategory = raw
  237 + },
  238 +
  239 + // 列表接口(真实请求)
  240 + fetchList({
  241 + pageIndex,
  242 + pageSize,
  243 + query,
  244 + extra
  245 + }) {
  246 + const params = {
  247 + pageIndex,
  248 + pageSize,
  249 + ...extra,
  250 + ...query
  251 + }
  252 + if (Array.isArray(params.dateRange) && params.dateRange.length === 2) {
  253 + params.shipmentsDateStart = params.dateRange[0]
  254 + params.shipmentsDateEnd = params.dateRange[1]
  255 + delete params.dateRange
  256 + }
  257 + if (this.searchKeywordDebounced) {
  258 + params.customerName = this.searchKeywordDebounced
  259 + }
  260 + return queryApi(params)
  261 + .then(res => {
  262 + const _data = res.data || {};
  263 + const records = _data.datas || [];
  264 + const totalCount = _data.totalCount || 0;
  265 + const hasNext = _data.hasNext || false
  266 + return {
  267 + records,
  268 + totalCount,
  269 + hasNext
  270 + }
  271 + })
  272 + .catch(err => {
  273 + console.error('fetchList error', err)
  274 + this.onCardError()
  275 + return {
  276 + records: [],
  277 + totalCount: 0,
  278 + hasNext: false
  279 + }
  280 + })
  281 + },
  282 + loadAllDicData() {
  283 + const dicCodes = ['SHIP_ORDER_STATUS']
  284 + return getDicByCodes(dicCodes).then(results => {
  285 + this.dicOptions.SHIP_ORDER_STATUS = results.SHIP_ORDER_STATUS.data || []
  286 + this.statusLocal = (this.dicOptions.SHIP_ORDER_STATUS || []).map(it => ({
  287 + value: it.code,
  288 + text: it.name
  289 + }))
  290 + }).catch(() => {
  291 + this.dicOptions = {
  292 + SHIP_ORDER_STATUS: [],
  293 + }
  294 + this.statusLocal = []
  295 + })
  296 + },
  297 + onCardClick(item) {
  298 + const id = (item && (item.id || item.code)) || ''
  299 + if (!id) return
  300 + const query = '?id=' + encodeURIComponent(id)
  301 + uni.navigateTo({
  302 + url: '/pages/credit_manage/detail' + query
  303 + })
  304 + },
  305 + getDicName: getDicName,
  306 + getCategoryClass(categoryName) {
  307 + if (!categoryName) return ''
  308 + if (categoryName.includes('A') || categoryName.includes('a')) {
  309 + return 'category_A'
  310 + } else if (categoryName.includes('B') || categoryName.includes('b')) {
  311 + return 'category_B'
  312 + } else if (categoryName.includes('C') || categoryName.includes('c')) {
  313 + return 'category_C'
  314 + } else if (categoryName.includes('D') || categoryName.includes('d')) {
  315 + return 'category_D'
  316 + }
  317 + },
  318 + onWorkshopChange(e) {
  319 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
  320 + this.filterForm.workshopId = raw
  321 + const match = (this.workshopOptions || []).find(o => String(o.value) === String(raw))
  322 + this.filterForm.workshopIdName = match ? (match.text || '') : ''
  323 + },
  324 +
  325 + }
  326 +}
  327 +</script>
  328 +
  329 +<style lang="scss" scoped>
  330 +.page {
  331 + display: flex;
  332 + flex-direction: column;
  333 + height: 100vh;
  334 +}
  335 +
  336 +.dev-list-fixed {
  337 + position: fixed;
  338 + top: 96rpx;
  339 + left: 0;
  340 + right: 0;
  341 + z-index: 2;
  342 + background: #fff;
  343 +
  344 + .search-row {
  345 + display: flex;
  346 + align-items: center;
  347 + padding: 16rpx 32rpx;
  348 +
  349 + .uni-searchbar {
  350 + padding: 0;
  351 + flex: 1;
  352 + }
  353 +
  354 + .tool-icons {
  355 + display: flex;
  356 +
  357 + .tool-icon {
  358 + width: 48rpx;
  359 + height: 48rpx;
  360 + display: block;
  361 + margin-left: 32rpx;
  362 + }
  363 + }
  364 + }
  365 +
  366 +}
  367 +
  368 +/* 仅当前页覆盖 uni-search-bar 盒子高度 */
  369 +::v-deep .uni-searchbar__box {
  370 + height: 80rpx !important;
  371 + justify-content: start;
  372 +
  373 + .uni-searchbar__box-search-input {
  374 + font-size: 32rpx !important;
  375 + }
  376 +}
  377 +
  378 +.list-box {
  379 + flex: 1;
  380 + padding-top: 132rpx;
  381 +
  382 + &.pad-batch {
  383 + padding-bottom: 144rpx;
  384 + }
  385 +
  386 + .card {
  387 + position: relative;
  388 + }
  389 +
  390 + .card-header {
  391 + margin-bottom: 28rpx;
  392 + position: relative;
  393 +
  394 + .title {
  395 + font-size: 36rpx;
  396 + font-weight: 600;
  397 + line-height: 50rpx;
  398 + color: rgba(0, 0, 0, 0.9);
  399 + width: 578rpx;
  400 + }
  401 +
  402 + .status-box {
  403 + position: absolute;
  404 + top: -32rpx;
  405 + right: -32rpx;
  406 +
  407 + .status {
  408 + display: block;
  409 + height: 48rpx;
  410 + line-height: 48rpx;
  411 + font-weight: 600;
  412 + color: #fff;
  413 + font-size: 24rpx;
  414 + padding: 0 14rpx;
  415 + border-radius: 6rpx;
  416 + margin-bottom: 8rpx;
  417 +
  418 + // 已签收
  419 + &.status_DELIVERED {
  420 + background: #E7E7E7;
  421 + color: rgba(0, 0, 0, 0.9);
  422 + }
  423 +
  424 + // 已发货
  425 + &.status_SHIPMENTS {
  426 + background: #2BA471;
  427 + }
  428 +
  429 + // 未发货
  430 + &.status_UN_SHIPMENTS {
  431 + background: #D54941;
  432 + }
  433 + }
  434 +
  435 + .status2 {
  436 + display: block;
  437 + font-weight: 600;
  438 + line-height: 48rpx;
  439 + height: 48rpx;
  440 + color: #fff;
  441 + font-size: 24rpx;
  442 + padding: 0 14rpx;
  443 + border-radius: 6rpx;
  444 + background: #E7E7E7;
  445 + color: rgba(0, 0, 0, 0.9);
  446 +
  447 + }
  448 +
  449 + }
  450 +
  451 + }
  452 +
  453 + .info-row {
  454 + display: flex;
  455 + align-items: center;
  456 + color: rgba(0, 0, 0, 0.6);
  457 + font-size: 28rpx;
  458 + margin-bottom: 24rpx;
  459 +
  460 + &:last-child {
  461 + margin-bottom: 0;
  462 + }
  463 +
  464 + text {
  465 + width: 60%;
  466 + line-height: 32rpx;
  467 +
  468 + &:last-child {
  469 + color: rgba(0, 0, 0, 0.9);
  470 + width: 40%;
  471 + }
  472 +
  473 + &.category {
  474 + display: inline-block;
  475 + padding: 4rpx 12rpx;
  476 + border-radius: 6rpx;
  477 + font-size: 24rpx;
  478 + width: auto;
  479 +
  480 + &.category_A {
  481 + background: #FFF0ED;
  482 + color: #D54941;
  483 + }
  484 +
  485 + &.category_B {
  486 + background: #FFF1E9;
  487 + color: #E37318;
  488 + }
  489 +
  490 + &.category_C {
  491 + background: #F2F3FF;
  492 + color: $theme-primary;
  493 + }
  494 +
  495 + &.category_D {
  496 + background: #E3F9E9;
  497 + color: #2BA471;
  498 + }
  499 + }
  500 + }
  501 +
  502 + }
  503 +}
  504 +
  505 +.filter-form {
  506 + .form-item {
  507 + margin-bottom: 24rpx;
  508 + }
  509 +
  510 + .label {
  511 + margin-bottom: 20rpx;
  512 + color: rgba(0, 0, 0, 0.9);
  513 + height: 44rpx;
  514 + line-height: 44rpx;
  515 + font-size: 30rpx;
  516 + }
  517 +
  518 + .uni-easyinput {
  519 + border: 1rpx solid #f3f3f3;
  520 + }
  521 +
  522 +}
  523 +
  524 +/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  525 +::v-deep .filter-form .uni-data-checklist .checklist-group {
  526 + .checklist-box {
  527 + &.is--tag {
  528 + width: 212rpx;
  529 + margin-top: 0;
  530 + margin-bottom: 24rpx;
  531 + margin-right: 24rpx;
  532 + height: 80rpx;
  533 + padding: 0;
  534 + border-radius: 12rpx;
  535 + background-color: #f3f3f3;
  536 + border-color: #f3f3f3;
  537 +
  538 + &:nth-child(3n) {
  539 + margin-right: 0;
  540 + }
  541 +
  542 + .checklist-content {
  543 + display: flex;
  544 + justify-content: center;
  545 + }
  546 +
  547 + .checklist-text {
  548 + color: rgba(0, 0, 0, 0.9);
  549 + font-size: 28rpx;
  550 + }
  551 + }
  552 +
  553 + &.is-checked {
  554 + background-color: $theme-primary-plain-bg !important;
  555 + border-color: $theme-primary-plain-bg !important;
  556 +
  557 + .checklist-text {
  558 + color: $theme-primary !important;
  559 + }
  560 + }
  561 + }
  562 +
  563 +}
  564 +</style>
\ No newline at end of file
... ...