Commit 925126add19fcb3ad8636899b5fc161bb286f62f

Authored by gesilong
1 parent 3a325d8b

commit:移动端列表页面开发联调

  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum'
  3 +
  4 +export function salesmanQuotationQueryApi(params) {
  5 + return request({
  6 + url: '/procurement/salesmanQuotation/query',
  7 + method: 'get',
  8 + params
  9 + })
  10 +}
... ...
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum'
  3 +
  4 +export function salesmanQuotationPeerQueryApi(params) {
  5 + return request({
  6 + url: '/procurement/salesmanQuotationPeer/query',
  7 + method: 'get',
  8 + params
  9 + })
  10 +}
... ...
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum'
  3 +
  4 +export function supplierQuotationDealQueryApi(params) {
  5 + return request({
  6 + url: '/procurement/supplierQuotationDeal/query',
  7 + method: 'get',
  8 + params
  9 + })
  10 +}
... ...
  1 +import request from '@/utils/request'
  2 +import { ContentTypeEnum } from '@/utils/httpEnum'
  3 +
  4 +export function supplierQuotationProjectQueryApi(params) {
  5 + return request({
  6 + url: '/procurement/supplierQuotationProject/query',
  7 + method: 'get',
  8 + params
  9 + })
  10 +}
... ...
... ... @@ -4,8 +4,8 @@ module.exports = {
4 4 themeColor: '#3d48a3',
5 5
6 6 // baseUrl: 'http://ft.wecando21cn.com/api',
7   - baseUrl: 'http://gjtd.ahcjxc.com:81/api',
8   - // baseUrl: 'http://erp.qgutech.com/api',
  7 + // baseUrl: 'http://gjtd.ahcjxc.com:81/api',
  8 + baseUrl: 'http://erp.qgutech.com/api',
9 9 // baseUrl: 'http://10.9.5.246:8081',
10 10 // 应用信息
11 11 appInfo: {
... ...
... ... @@ -276,6 +276,63 @@
276 276 }
277 277 },
278 278 {
  279 + "path": "pages/sales-price/index",
  280 + "style": {
  281 + "navigationBarTitleText": "业务员报价单",
  282 + "navigationBarBackgroundColor": "#ffffff",
  283 + "navigationBarTextStyle": "black"
  284 + }
  285 + },
  286 + // {
  287 + // "path": "pages/sales-price/add",
  288 + // "style": {
  289 + // "navigationBarTitleText": "新增业务员报价单",
  290 + // "navigationBarBackgroundColor": "#ffffff",
  291 + // "navigationBarTextStyle": "black"
  292 + // }
  293 + // },
  294 + // {
  295 + // "path": "pages/sales-price/modify",
  296 + // "style": {
  297 + // "navigationBarTitleText": "编辑业务员报价单",
  298 + // "navigationBarBackgroundColor": "#ffffff",
  299 + // "navigationBarTextStyle": "black"
  300 + // }
  301 + // },
  302 + // {
  303 + // "path": "pages/sales-price/detail",
  304 + // "style": {
  305 + // "navigationBarTitleText": "查看业务员报价单",
  306 + // "navigationBarBackgroundColor": "#ffffff",
  307 + // "navigationBarTextStyle": "black"
  308 + // }
  309 + // },
  310 +
  311 + {
  312 + "path": "pages/supplier-price/index",
  313 + "style": {
  314 + "navigationBarTitleText": "报价项目",
  315 + "navigationBarBackgroundColor": "#ffffff",
  316 + "navigationBarTextStyle": "black"
  317 + }
  318 + },
  319 + {
  320 + "path": "pages/quote-manage/index",
  321 + "style": {
  322 + "navigationBarTitleText": "报价管理",
  323 + "navigationBarBackgroundColor": "#ffffff",
  324 + "navigationBarTextStyle": "black"
  325 + }
  326 + },
  327 + {
  328 + "path": "pages/peer-info/index",
  329 + "style": {
  330 + "navigationBarTitleText": "同行信息",
  331 + "navigationBarBackgroundColor": "#ffffff",
  332 + "navigationBarTextStyle": "black"
  333 + }
  334 + },
  335 + {
279 336 "path": "pages/order_list/index",
280 337 "style": {
281 338 "navigationBarTitleText": "订货单列表",
... ...
... ... @@ -152,12 +152,35 @@ export default {
152 152 },
153 153 {
154 154 text: '外贸客户资信管理',
155   - icon: '/static/images/index/order_list.png',
  155 + icon: '/static/images/index/change_list.png',
156 156 link: '/pages/foreign_trade/index',
157 157 name: 'ForeignTrade'
  158 + },
  159 + {
  160 + text: '业务员报价单',
  161 + icon: '/static/images/index/revoke_list.png',
  162 + link: '/pages/sales-price/index',
  163 + name: 'SalesPrice'
  164 + },
  165 + {
  166 + text: '报价项目',
  167 + icon: '/static/images/index/invoice.png',
  168 + link: '/pages/supplier-price/index',
  169 + name: 'SupplierPrice'
  170 + },
  171 + {
  172 + text: '同行信息',
  173 + icon: '/static/images/index/draft_order.png',
  174 + link: '/pages/peer-info/index',
  175 + name: 'PeerInfo'
  176 + },
  177 + {
  178 + text: '报价管理',
  179 + icon: '/static/images/index/delay_invoice.png',
  180 + link: '/pages/quote-manage/index',
  181 + name: 'QuoteManage'
158 182 }
159 183 ]
160   -
161 184 },
162 185 {
163 186 title: '订货单管理',
... ...
  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 class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
  10 + </view>
  11 + </view>
  12 + </view>
  13 +
  14 + <view class="list-box">
  15 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  16 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  17 + <template v-slot="{ item }">
  18 + <view class="card" @click.stop="onCardClick(item)">
  19 + <view class="card-header">
  20 + <text class="title omit2">{{ item.peerName || '-' }}</text>
  21 + </view>
  22 + <view class="info-row">
  23 + <text>同行品种</text><text>{{ item.peerProductName || '-' }}</text>
  24 + </view>
  25 + <view class="info-row">
  26 + <text>同行报价</text><text>{{ item.peerPrice != null ? item.peerPrice : '-' }}</text>
  27 + </view>
  28 + <view class="info-row">
  29 + <text>创建人</text><text>{{ item.createBy || '-' }}</text>
  30 + </view>
  31 + <view class="info-row">
  32 + <text>创建时间</text><text>{{ formatDateTime(item.createTime) }}</text>
  33 + </view>
  34 + </view>
  35 + </template>
  36 + </card-list>
  37 + </view>
  38 +
  39 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  40 + @confirm="onFilterConfirm">
  41 + <template v-slot="{ model }">
  42 + <view class="filter-form">
  43 + <view class="form-item">
  44 + <view class="label">同行名称</view>
  45 + <uni-easyinput v-model="model.peerName" placeholder="请输入同行名称" :inputBorder="false"
  46 + placeholderStyle="font-size:14px" @input="onPeerNameInput" />
  47 + </view>
  48 + <view class="form-item">
  49 + <view class="label">同行品种名称</view>
  50 + <uni-easyinput v-model="model.peerProductName" placeholder="请输入同行品种名称" :inputBorder="false"
  51 + placeholderStyle="font-size:14px" @input="onPeerProductNameInput" />
  52 + </view>
  53 + <view class="form-item">
  54 + <view class="label">创建日期</view>
  55 + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" />
  56 + </view>
  57 + </view>
  58 + </template>
  59 + </filter-modal>
  60 + </view>
  61 +</template>
  62 +
  63 +<script>
  64 +import CardList from '@/components/card/index.vue'
  65 +import FilterModal from '@/components/filter/index.vue'
  66 +import { salesmanQuotationPeerQueryApi } from '@/api/procure-manage/salesmanQuotationPeer.js'
  67 +
  68 +export default {
  69 + name: 'PeerInfoList',
  70 + components: { CardList, FilterModal },
  71 + data() {
  72 + return {
  73 + searchKeyword: '',
  74 + searchKeywordDebounced: '',
  75 + searchDebounceTimer: null,
  76 + query: {
  77 + peerName: '',
  78 + peerProductName: '',
  79 + dateRange: []
  80 + },
  81 + extraParams: {},
  82 + currentItems: [],
  83 + filterVisible: false,
  84 + filterForm: {
  85 + peerName: '',
  86 + peerProductName: '',
  87 + dateRange: []
  88 + }
  89 + }
  90 + },
  91 + watch: {
  92 + searchKeywordDebounced(v) {
  93 + this.query = { ...this.query, peerName: v || '' }
  94 + }
  95 + },
  96 + onShow() {
  97 + let needRefresh = ''
  98 + try { needRefresh = uni.getStorageSync('PEER_INFO_LIST_NEED_REFRESH') } catch (e) {}
  99 + if (!needRefresh) return
  100 + try { uni.removeStorageSync('PEER_INFO_LIST_NEED_REFRESH') } catch (e) {}
  101 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) {
  102 + this.$refs.cardRef.reload()
  103 + }
  104 + },
  105 + onReachBottom() {
  106 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  107 + this.$refs.cardRef.onLoadMore()
  108 + }
  109 + },
  110 + beforeDestroy() {
  111 + if (this.searchDebounceTimer) {
  112 + clearTimeout(this.searchDebounceTimer)
  113 + this.searchDebounceTimer = null
  114 + }
  115 + },
  116 + methods: {
  117 + formatDateTime(v) {
  118 + const s = v == null ? '' : String(v).trim()
  119 + if (!s) return '-'
  120 + if (s.length >= 16) return s.slice(0, 16)
  121 + if (s.length >= 10) return s.slice(0, 10)
  122 + return s
  123 + },
  124 + onCardLoaded({ items }) {
  125 + this.currentItems = items
  126 + },
  127 + onCardError() {
  128 + uni.showToast({ title: '列表加载失败', icon: 'none' })
  129 + },
  130 + onSearchInput() {
  131 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  132 + this.searchDebounceTimer = setTimeout(() => {
  133 + this.searchKeywordDebounced = this.searchKeyword
  134 + this.searchDebounceTimer = null
  135 + }, 1200)
  136 + },
  137 + search(e) {
  138 + const val = e && e.value != null ? e.value : this.searchKeyword
  139 + this.searchKeyword = val
  140 + this.searchKeywordDebounced = val
  141 + },
  142 + openFilter() {
  143 + this.filterForm = {
  144 + peerName: this.query.peerName || '',
  145 + peerProductName: this.query.peerProductName || '',
  146 + dateRange: Array.isArray(this.query.dateRange) ? this.query.dateRange.slice(0) : []
  147 + }
  148 + this.filterVisible = true
  149 + },
  150 + onFilterReset(payload) {
  151 + this.filterForm = payload
  152 + },
  153 + onFilterConfirm(payload) {
  154 + this.query = {
  155 + peerName: this.searchKeywordDebounced || payload.peerName || '',
  156 + peerProductName: payload.peerProductName || '',
  157 + dateRange: Array.isArray(payload.dateRange) ? payload.dateRange : []
  158 + }
  159 + },
  160 + onPeerNameInput(val) {
  161 + this.filterForm.peerName = val
  162 + },
  163 + onPeerProductNameInput(val) {
  164 + this.filterForm.peerProductName = val
  165 + },
  166 + fetchList({ pageIndex, pageSize, query }) {
  167 + const q = query || {}
  168 + const range = Array.isArray(q.dateRange) ? q.dateRange : []
  169 + const params = {
  170 + pageIndex,
  171 + pageSize,
  172 + peerName: q.peerName || '',
  173 + peerProductName: q.peerProductName || '',
  174 + createDateStart: (range && range.length === 2) ? range[0] : '',
  175 + createDateEnd: (range && range.length === 2) ? range[1] : ''
  176 + }
  177 + return salesmanQuotationPeerQueryApi(params).then(res => {
  178 + const _data = res && res.data ? res.data : {}
  179 + let records = _data.datas || _data.list || _data.records || []
  180 + const totalCount = _data.totalCount || _data.count || 0
  181 + const hasNext = _data.hasNext || false
  182 + records = records.map(it => ({ ...it }))
  183 + return { records, totalCount, hasNext }
  184 + }).catch(() => {
  185 + this.onCardError()
  186 + return { records: [], totalCount: 0, hasNext: false }
  187 + })
  188 + },
  189 + onCardClick(item) {
  190 + // 暂无详情页
  191 + }
  192 + }
  193 +}
  194 +</script>
  195 +
  196 +<style lang="scss" scoped>
  197 +.page {
  198 + display: flex;
  199 + flex-direction: column;
  200 + height: 100vh;
  201 +}
  202 +
  203 +.dev-list-fixed {
  204 + position: fixed;
  205 + top: 96rpx;
  206 + left: 0;
  207 + right: 0;
  208 + z-index: 2;
  209 + background: #fff;
  210 +
  211 + .search-row {
  212 + display: flex;
  213 + align-items: center;
  214 + padding: 16rpx 32rpx;
  215 +
  216 + .uni-searchbar {
  217 + padding: 0;
  218 + flex: 1;
  219 + }
  220 +
  221 + .tool-icons {
  222 + display: flex;
  223 +
  224 + .tool-icon {
  225 + width: 48rpx;
  226 + height: 48rpx;
  227 + display: block;
  228 + margin-left: 32rpx;
  229 + }
  230 + }
  231 + }
  232 +}
  233 +
  234 +::v-deep .uni-searchbar__box {
  235 + height: 80rpx !important;
  236 + justify-content: start;
  237 +
  238 + .uni-searchbar__box-search-input {
  239 + font-size: 32rpx !important;
  240 + }
  241 +}
  242 +
  243 +.list-box {
  244 + flex: 1;
  245 + padding-top: 140rpx;
  246 +
  247 + .card {
  248 + position: relative;
  249 + }
  250 +
  251 + .card-header {
  252 + margin-bottom: 28rpx;
  253 + position: relative;
  254 +
  255 + .title {
  256 + font-size: 36rpx;
  257 + font-weight: 600;
  258 + line-height: 50rpx;
  259 + color: rgba(0, 0, 0, 0.9);
  260 + width: 100%;
  261 + }
  262 + }
  263 +
  264 + .info-row {
  265 + display: flex;
  266 + align-items: center;
  267 + color: rgba(0, 0, 0, 0.6);
  268 + font-size: 28rpx;
  269 + margin-bottom: 24rpx;
  270 + height: 32rpx;
  271 +
  272 + &:last-child {
  273 + margin-bottom: 0;
  274 + }
  275 +
  276 + text {
  277 + width: 50%;
  278 +
  279 + &:last-child {
  280 + color: rgba(0, 0, 0, 0.9);
  281 + width: 50%;
  282 + }
  283 + }
  284 + }
  285 +}
  286 +
  287 +.filter-form {
  288 + .form-item {
  289 + margin-bottom: 24rpx;
  290 + }
  291 +
  292 + .label {
  293 + margin-bottom: 20rpx;
  294 + color: rgba(0, 0, 0, 0.9);
  295 + height: 44rpx;
  296 + line-height: 44rpx;
  297 + font-size: 30rpx;
  298 + }
  299 +
  300 + .uni-easyinput {
  301 + border: 1rpx solid #f3f3f3;
  302 + }
  303 +}
  304 +</style>
... ...
  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 class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
  10 + </view>
  11 + </view>
  12 + </view>
  13 +
  14 + <view class="list-box">
  15 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  16 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  17 + <template v-slot="{ item }">
  18 + <view class="card">
  19 + <view class="card-header">
  20 + <text class="title omit2">{{ item.projectName || '-' }}</text>
  21 + </view>
  22 + <view class="info-row">
  23 + <text>项目编号</text><text>{{ item.projectCode || '-' }}</text>
  24 + </view>
  25 + <view class="info-row">
  26 + <text>品种</text><text>{{ item.productName || '-' }}</text>
  27 + </view>
  28 + <view class="info-row">
  29 + <text>供应商名称</text><text>{{ item.supplierName || '-' }}</text>
  30 + </view>
  31 + <view class="info-row">
  32 + <text>价格</text><text>{{ item.price != null ? item.price : '-' }}</text>
  33 + </view>
  34 + </view>
  35 + </template>
  36 + </card-list>
  37 + </view>
  38 +
  39 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  40 + @confirm="onFilterConfirm">
  41 + <template v-slot="{ model }">
  42 + <view class="filter-form">
  43 + <view class="form-item">
  44 + <view class="label">项目编号</view>
  45 + <uni-easyinput v-model="model.projectCode" placeholder="请输入项目编号" :inputBorder="true" />
  46 + </view>
  47 + <view class="form-item">
  48 + <view class="label">供应商名称</view>
  49 + <uni-easyinput v-model="model.supplierName" placeholder="请输入供应商名称" :inputBorder="true" />
  50 + </view>
  51 + </view>
  52 + </template>
  53 + </filter-modal>
  54 + </view>
  55 +</template>
  56 +
  57 +<script>
  58 +import CardList from '@/components/card/index.vue'
  59 +import FilterModal from '@/components/filter/index.vue'
  60 +import { supplierQuotationDealQueryApi } from '@/api/procure-manage/supplierQuotationDeal.js'
  61 +
  62 +export default {
  63 + name: 'QuoteManageList',
  64 + components: { CardList, FilterModal },
  65 + data() {
  66 + return {
  67 + searchKeyword: '',
  68 + searchKeywordDebounced: '',
  69 + searchDebounceTimer: null,
  70 + query: {
  71 + projectName: '',
  72 + projectCode: '',
  73 + supplierName: ''
  74 + },
  75 + extraParams: {},
  76 + currentItems: [],
  77 + filterVisible: false,
  78 + filterForm: {
  79 + projectCode: '',
  80 + supplierName: ''
  81 + }
  82 + }
  83 + },
  84 + watch: {
  85 + searchKeywordDebounced(v) {
  86 + this.query = { ...this.query, projectName: v || '' }
  87 + }
  88 + },
  89 + onShow() {
  90 + let needRefresh = ''
  91 + try { needRefresh = uni.getStorageSync('QUOTE_MANAGE_LIST_NEED_REFRESH') } catch (e) {}
  92 + if (!needRefresh) return
  93 + try { uni.removeStorageSync('QUOTE_MANAGE_LIST_NEED_REFRESH') } catch (e) {}
  94 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) {
  95 + this.$refs.cardRef.reload()
  96 + }
  97 + },
  98 + onReachBottom() {
  99 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  100 + this.$refs.cardRef.onLoadMore()
  101 + }
  102 + },
  103 + beforeDestroy() {
  104 + if (this.searchDebounceTimer) {
  105 + clearTimeout(this.searchDebounceTimer)
  106 + this.searchDebounceTimer = null
  107 + }
  108 + },
  109 + methods: {
  110 + onCardLoaded({ items }) {
  111 + this.currentItems = items
  112 + },
  113 + onCardError() {
  114 + uni.showToast({ title: '列表加载失败', icon: 'none' })
  115 + },
  116 + onSearchInput() {
  117 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  118 + this.searchDebounceTimer = setTimeout(() => {
  119 + this.searchKeywordDebounced = this.searchKeyword
  120 + this.searchDebounceTimer = null
  121 + }, 1200)
  122 + },
  123 + search(e) {
  124 + const val = e && e.value != null ? e.value : this.searchKeyword
  125 + this.searchKeyword = val
  126 + this.searchKeywordDebounced = val
  127 + },
  128 + openFilter() {
  129 + this.filterForm = {
  130 + projectCode: this.query.projectCode || '',
  131 + supplierName: this.query.supplierName || ''
  132 + }
  133 + this.filterVisible = true
  134 + },
  135 + onFilterReset(payload) {
  136 + this.filterForm = payload
  137 + },
  138 + onFilterConfirm(payload) {
  139 + this.query = {
  140 + projectName: this.query.projectName || '',
  141 + projectCode: payload.projectCode || '',
  142 + supplierName: payload.supplierName || ''
  143 + }
  144 + },
  145 + fetchList({ pageIndex, pageSize, query }) {
  146 + const q = query || {}
  147 + const params = {
  148 + pageIndex,
  149 + pageSize,
  150 + projectName: q.projectName || '',
  151 + projectCode: q.projectCode || '',
  152 + supplierName: q.supplierName || ''
  153 + }
  154 + return supplierQuotationDealQueryApi(params).then(res => {
  155 + const _data = res && res.data ? res.data : {}
  156 + let records = _data.datas || _data.list || _data.records || []
  157 + const totalCount = _data.totalCount || _data.count || 0
  158 + const hasNext = _data.hasNext || false
  159 + records = records.map(it => ({ ...it }))
  160 + return { records, totalCount, hasNext }
  161 + }).catch(() => {
  162 + this.onCardError()
  163 + return { records: [], totalCount: 0, hasNext: false }
  164 + })
  165 + }
  166 + }
  167 +}
  168 +</script>
  169 +
  170 +<style lang="scss" scoped>
  171 +.page {
  172 + display: flex;
  173 + flex-direction: column;
  174 + height: 100vh;
  175 +}
  176 +
  177 +.dev-list-fixed {
  178 + position: fixed;
  179 + top: 96rpx;
  180 + left: 0;
  181 + right: 0;
  182 + z-index: 2;
  183 + background: #fff;
  184 +
  185 + .search-row {
  186 + display: flex;
  187 + align-items: center;
  188 + padding: 16rpx 32rpx;
  189 +
  190 + .uni-searchbar {
  191 + padding: 0;
  192 + flex: 1;
  193 + }
  194 +
  195 + .tool-icons {
  196 + display: flex;
  197 +
  198 + .tool-icon {
  199 + width: 48rpx;
  200 + height: 48rpx;
  201 + display: block;
  202 + margin-left: 32rpx;
  203 + }
  204 + }
  205 + }
  206 +}
  207 +
  208 +::v-deep .uni-searchbar__box {
  209 + height: 80rpx !important;
  210 + justify-content: start;
  211 +
  212 + .uni-searchbar__box-search-input {
  213 + font-size: 32rpx !important;
  214 + }
  215 +}
  216 +
  217 +.list-box {
  218 + flex: 1;
  219 + padding-top: 140rpx;
  220 +
  221 + .card {
  222 + position: relative;
  223 + }
  224 +
  225 + .card-header {
  226 + margin-bottom: 28rpx;
  227 + position: relative;
  228 +
  229 + .title {
  230 + font-size: 36rpx;
  231 + font-weight: 600;
  232 + line-height: 50rpx;
  233 + color: rgba(0, 0, 0, 0.9);
  234 + width: 578rpx;
  235 + }
  236 + }
  237 +
  238 + .info-row {
  239 + display: flex;
  240 + align-items: center;
  241 + color: rgba(0, 0, 0, 0.6);
  242 + font-size: 28rpx;
  243 + margin-bottom: 24rpx;
  244 + height: 32rpx;
  245 +
  246 + &:last-child {
  247 + margin-bottom: 0;
  248 + }
  249 +
  250 + text {
  251 + width: 50%;
  252 +
  253 + &:last-child {
  254 + color: rgba(0, 0, 0, 0.9);
  255 + width: 50%;
  256 + }
  257 + }
  258 + }
  259 +}
  260 +
  261 +.filter-form {
  262 + .form-item {
  263 + margin-bottom: 24rpx;
  264 + }
  265 +
  266 + .label {
  267 + margin-bottom: 20rpx;
  268 + color: rgba(0, 0, 0, 0.9);
  269 + height: 44rpx;
  270 + line-height: 44rpx;
  271 + font-size: 30rpx;
  272 + }
  273 +}
  274 +</style>
... ...
  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 class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
  10 + </view>
  11 + </view>
  12 + </view>
  13 +
  14 + <view class="list-box">
  15 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  16 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  17 + <template v-slot="{ item }">
  18 + <view class="card" @click.stop="onCardClick(item)">
  19 + <view class="card-header">
  20 + <text class="title omit2">{{ item.supplierName || '-' }}</text>
  21 + <text :class="['status', `status_${item.approvalStatus}`]">{{ getAuditStatusText(item.approvalStatus) }}</text>
  22 + </view>
  23 + <view class="info-row">
  24 + <text>编号</text><text>{{ item.code || '-' }}</text>
  25 + </view>
  26 + <view class="info-row">
  27 + <text>采购处</text><text>{{ item.purchaseDepartmentName || '-' }}</text>
  28 + </view>
  29 + <view class="info-row">
  30 + <text>区域</text><text>{{ item.regionName || '-' }}</text>
  31 + </view>
  32 + <view class="info-row">
  33 + <text>日期</text><text>{{ formatDateOnly(item.quoteTime) }}</text>
  34 + </view>
  35 + </view>
  36 + </template>
  37 + </card-list>
  38 + </view>
  39 +
  40 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  41 + @confirm="onFilterConfirm">
  42 + <template v-slot="{ model }">
  43 + <view class="filter-form">
  44 + <view class="form-item">
  45 + <view class="label">编号</view>
  46 + <uni-easyinput v-model="model.code" placeholder="请输入编号" :inputBorder="false"
  47 + placeholderStyle="font-size:14px" @input="onCodeInput" />
  48 + </view>
  49 + <view class="form-item">
  50 + <view class="label">报价时间</view>
  51 + <uni-datetime-picker type="daterange" v-model="model.dateRange" start="2023-01-01" />
  52 + </view>
  53 + </view>
  54 + </template>
  55 + </filter-modal>
  56 + </view>
  57 +</template>
  58 +
  59 +<script>
  60 +import CardList from '@/components/card/index.vue'
  61 +import FilterModal from '@/components/filter/index.vue'
  62 +import { getDicByCodes, getDicName } from '@/utils/dic.js'
  63 +import { salesmanQuotationQueryApi } from '@/api/procure-manage/salesmanQuotation.js'
  64 +
  65 +export default {
  66 + name: 'SalesPriceList',
  67 + components: { CardList, FilterModal },
  68 + data() {
  69 + return {
  70 + searchKeyword: '',
  71 + searchKeywordDebounced: '',
  72 + searchDebounceTimer: null,
  73 + query: {
  74 + supplierName: '',
  75 + code: '',
  76 + dateRange: []
  77 + },
  78 + extraParams: {},
  79 + currentItems: [],
  80 + filterVisible: false,
  81 + filterForm: {
  82 + code: '',
  83 + dateRange: []
  84 + },
  85 + dicOptions: {
  86 + AUDIT_STATUS: []
  87 + },
  88 + }
  89 + },
  90 + watch: {
  91 + searchKeywordDebounced(v) {
  92 + this.query = { ...this.query, supplierName: v || '' }
  93 + }
  94 + },
  95 + created() {
  96 + this.loadDicData()
  97 + },
  98 + onShow() {
  99 + let needRefresh = ''
  100 + try { needRefresh = uni.getStorageSync('SALES_PRICE_LIST_NEED_REFRESH') } catch (e) {}
  101 + if (!needRefresh) return
  102 + try { uni.removeStorageSync('SALES_PRICE_LIST_NEED_REFRESH') } catch (e) {}
  103 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) {
  104 + this.$refs.cardRef.reload()
  105 + }
  106 + },
  107 + onReachBottom() {
  108 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  109 + this.$refs.cardRef.onLoadMore()
  110 + }
  111 + },
  112 + beforeDestroy() {
  113 + if (this.searchDebounceTimer) {
  114 + clearTimeout(this.searchDebounceTimer)
  115 + this.searchDebounceTimer = null
  116 + }
  117 + },
  118 + methods: {
  119 + async loadDicData() {
  120 + try {
  121 + const results = await getDicByCodes(['AUDIT_STATUS'])
  122 + this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || []
  123 + } catch (e) {
  124 + this.dicOptions.AUDIT_STATUS = []
  125 + }
  126 + },
  127 + formatDateOnly(v) {
  128 + const s = v == null ? '' : String(v).trim()
  129 + if (!s) return '-'
  130 + if (s.length >= 10) return s.slice(0, 10)
  131 + return s
  132 + },
  133 + onCardLoaded({ items }) {
  134 + this.currentItems = items
  135 + },
  136 + onCardError() {
  137 + uni.showToast({ title: '列表加载失败', icon: 'none' })
  138 + },
  139 + onSearchInput() {
  140 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  141 + this.searchDebounceTimer = setTimeout(() => {
  142 + this.searchKeywordDebounced = this.searchKeyword
  143 + this.searchDebounceTimer = null
  144 + }, 1200)
  145 + },
  146 + search(e) {
  147 + const val = e && e.value != null ? e.value : this.searchKeyword
  148 + this.searchKeyword = val
  149 + this.searchKeywordDebounced = val
  150 + },
  151 + openFilter() {
  152 + this.filterForm = {
  153 + code: this.query.code || '',
  154 + dateRange: Array.isArray(this.query.dateRange) ? this.query.dateRange.slice(0) : []
  155 + }
  156 + this.filterVisible = true
  157 + },
  158 + onFilterReset(payload) {
  159 + this.filterForm = payload
  160 + },
  161 + onFilterConfirm(payload) {
  162 + this.query = {
  163 + supplierName: this.query.supplierName || '',
  164 + code: payload.code || '',
  165 + dateRange: Array.isArray(payload.dateRange) ? payload.dateRange : []
  166 + }
  167 + },
  168 + onCodeInput(val) {
  169 + this.filterForm.code = val
  170 + },
  171 + getAuditStatusText(status) {
  172 + const v = status == null ? '' : String(status)
  173 + if (!v) return '-'
  174 + return getDicName('AUDIT_STATUS', v, this.dicOptions.AUDIT_STATUS) || v
  175 + },
  176 + fetchList({ pageIndex, pageSize, query }) {
  177 + const q = query || {}
  178 + const range = Array.isArray(q.dateRange) ? q.dateRange : []
  179 + const params = {
  180 + pageIndex,
  181 + pageSize,
  182 + supplierName: q.supplierName || '',
  183 + code: q.code || '',
  184 + quoteDateStart: (range && range.length === 2) ? range[0] : '',
  185 + quoteDateEnd: (range && range.length === 2) ? range[1] : ''
  186 + }
  187 + return salesmanQuotationQueryApi(params).then(res => {
  188 + const _data = res && res.data ? res.data : {}
  189 + let records = _data.datas || _data.list || _data.records || []
  190 + const totalCount = _data.totalCount || _data.count || 0
  191 + const hasNext = _data.hasNext || false
  192 + records = records.map(it => ({ ...it }))
  193 + return { records, totalCount, hasNext }
  194 + }).catch(() => {
  195 + this.onCardError()
  196 + return { records: [], totalCount: 0, hasNext: false }
  197 + })
  198 + },
  199 + onCardClick(item) {
  200 + uni.navigateTo({ url: '/pages/sales-price/detail?id=' + item.id })
  201 + },
  202 + }
  203 +}
  204 +</script>
  205 +
  206 +<style lang="scss" scoped>
  207 +.page {
  208 + display: flex;
  209 + flex-direction: column;
  210 + height: 100vh;
  211 +}
  212 +
  213 +.dev-list-fixed {
  214 + position: fixed;
  215 + top: 96rpx;
  216 + left: 0;
  217 + right: 0;
  218 + z-index: 2;
  219 + background: #fff;
  220 +
  221 + .search-row {
  222 + display: flex;
  223 + align-items: center;
  224 + padding: 16rpx 32rpx;
  225 +
  226 + .uni-searchbar {
  227 + padding: 0;
  228 + flex: 1;
  229 + }
  230 +
  231 + .tool-icons {
  232 + display: flex;
  233 +
  234 + .tool-icon {
  235 + width: 48rpx;
  236 + height: 48rpx;
  237 + display: block;
  238 + margin-left: 32rpx;
  239 + }
  240 + }
  241 + }
  242 +}
  243 +
  244 +::v-deep .uni-searchbar__box {
  245 + height: 80rpx !important;
  246 + justify-content: start;
  247 +
  248 + .uni-searchbar__box-search-input {
  249 + font-size: 32rpx !important;
  250 + }
  251 +}
  252 +
  253 +.list-box {
  254 + flex: 1;
  255 + padding-top: 140rpx;
  256 +
  257 + .card {
  258 + position: relative;
  259 + }
  260 +
  261 + .card-header {
  262 + margin-bottom: 28rpx;
  263 + position: relative;
  264 +
  265 + .title {
  266 + font-size: 36rpx;
  267 + font-weight: 600;
  268 + line-height: 50rpx;
  269 + color: rgba(0, 0, 0, 0.9);
  270 + width: 578rpx;
  271 + }
  272 +
  273 + .status {
  274 + position: absolute;
  275 + top: -32rpx;
  276 + right: -12rpx;
  277 + height: 48rpx;
  278 + line-height: 48rpx;
  279 + font-weight: 600;
  280 + color: #fff;
  281 + font-size: 24rpx;
  282 + padding: 0 14rpx;
  283 + border-radius: 6rpx;
  284 +
  285 + &.status_AUDIT {
  286 + background: $theme-primary;
  287 + }
  288 +
  289 + &.status_PASS {
  290 + background: #2BA471;
  291 + }
  292 +
  293 + &.status_REFUSE {
  294 + background: #D54941;
  295 + }
  296 +
  297 + &.status_CANCEL {
  298 + background: #E7E7E7;
  299 + color: rgba(0, 0, 0, 0.9);
  300 + }
  301 + }
  302 + }
  303 +
  304 + .info-row {
  305 + display: flex;
  306 + align-items: center;
  307 + color: rgba(0, 0, 0, 0.6);
  308 + font-size: 28rpx;
  309 + margin-bottom: 24rpx;
  310 + height: 32rpx;
  311 +
  312 + &:last-child {
  313 + margin-bottom: 0;
  314 + }
  315 +
  316 + text {
  317 + width: 50%;
  318 +
  319 + &:last-child {
  320 + color: rgba(0, 0, 0, 0.9);
  321 + width: 50%;
  322 + }
  323 + }
  324 + }
  325 +}
  326 +
  327 +.filter-form {
  328 + .form-item {
  329 + margin-bottom: 24rpx;
  330 + }
  331 +
  332 + .label {
  333 + margin-bottom: 20rpx;
  334 + color: rgba(0, 0, 0, 0.9);
  335 + height: 44rpx;
  336 + line-height: 44rpx;
  337 + font-size: 30rpx;
  338 + }
  339 +
  340 + .uni-easyinput {
  341 + border: 1rpx solid #f3f3f3;
  342 + }
  343 +}
  344 +</style>
... ...
  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 class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
  10 + </view>
  11 + </view>
  12 + </view>
  13 +
  14 + <view class="list-box">
  15 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  16 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  17 + <template v-slot="{ item }">
  18 + <view class="card" @click.stop="onCardClick(item)">
  19 + <view class="card-header">
  20 + <text class="title omit2">{{ item.name || '-' }}</text>
  21 + </view>
  22 + <view class="info-row">
  23 + <text>项目编号</text><text>{{ item.code || '-' }}</text>
  24 + </view>
  25 + <view class="info-row">
  26 + <text>品种</text><text>{{ item.productName || '-' }}</text>
  27 + </view>
  28 + <view class="info-row">
  29 + <text>开始时间</text><text>{{ formatDateTimeMinute(item.startTime) }}</text>
  30 + </view>
  31 + <view class="info-row">
  32 + <text>截止时间</text><text>{{ formatDateTimeMinute(item.endTime) }}</text>
  33 + </view>
  34 + </view>
  35 + </template>
  36 + </card-list>
  37 + </view>
  38 +
  39 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  40 + @confirm="onFilterConfirm">
  41 + <template v-slot="{ model }">
  42 + <view class="filter-form">
  43 + <view class="form-item">
  44 + <view class="label">开始时间</view>
  45 + <uni-datetime-picker type="datetimerange" v-model="model.startTimeRange" start="2023-01-01" />
  46 + </view>
  47 + <view class="form-item">
  48 + <view class="label">截止时间</view>
  49 + <uni-datetime-picker type="datetimerange" v-model="model.endTimeRange" start="2023-01-01" />
  50 + </view>
  51 + <view class="form-item">
  52 + <view class="label">开标时间</view>
  53 + <uni-datetime-picker type="datetimerange" v-model="model.bidTimeRange" start="2023-01-01" />
  54 + </view>
  55 + </view>
  56 + </template>
  57 + </filter-modal>
  58 + </view>
  59 +</template>
  60 +
  61 +<script>
  62 +import CardList from '@/components/card/index.vue'
  63 +import FilterModal from '@/components/filter/index.vue'
  64 +import { supplierQuotationProjectQueryApi } from '@/api/procure-manage/supplierQuotationProject.js'
  65 +
  66 +export default {
  67 + name: 'SupplierPriceList',
  68 + components: { CardList, FilterModal },
  69 + data() {
  70 + return {
  71 + searchKeyword: '',
  72 + searchKeywordDebounced: '',
  73 + searchDebounceTimer: null,
  74 + query: {
  75 + name: '',
  76 + startTimeRange: [],
  77 + endTimeRange: [],
  78 + bidTimeRange: []
  79 + },
  80 + extraParams: {},
  81 + currentItems: [],
  82 + filterVisible: false,
  83 + filterForm: {
  84 + startTimeRange: [],
  85 + endTimeRange: [],
  86 + bidTimeRange: []
  87 + }
  88 + }
  89 + },
  90 + watch: {
  91 + searchKeywordDebounced(v) {
  92 + this.query = { ...this.query, name: v || '' }
  93 + }
  94 + },
  95 + onShow() {
  96 + let needRefresh = ''
  97 + try { needRefresh = uni.getStorageSync('SUPPLIER_PRICE_LIST_NEED_REFRESH') } catch (e) {}
  98 + if (!needRefresh) return
  99 + try { uni.removeStorageSync('SUPPLIER_PRICE_LIST_NEED_REFRESH') } catch (e) {}
  100 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.reload) {
  101 + this.$refs.cardRef.reload()
  102 + }
  103 + },
  104 + onReachBottom() {
  105 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  106 + this.$refs.cardRef.onLoadMore()
  107 + }
  108 + },
  109 + beforeDestroy() {
  110 + if (this.searchDebounceTimer) {
  111 + clearTimeout(this.searchDebounceTimer)
  112 + this.searchDebounceTimer = null
  113 + }
  114 + },
  115 + methods: {
  116 + formatDateTimeMinute(v) {
  117 + const s = v == null ? '' : String(v).trim()
  118 + if (!s) return '-'
  119 + // 截取到分钟 (yyyy-MM-dd HH:mm)
  120 + if (s.length >= 16) return s.slice(0, 16)
  121 + if (s.length >= 10) return s.slice(0, 10)
  122 + return s
  123 + },
  124 + onCardLoaded({ items }) {
  125 + this.currentItems = items
  126 + },
  127 + onCardError() {
  128 + uni.showToast({ title: '列表加载失败', icon: 'none' })
  129 + },
  130 + onSearchInput() {
  131 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  132 + this.searchDebounceTimer = setTimeout(() => {
  133 + this.searchKeywordDebounced = this.searchKeyword
  134 + this.searchDebounceTimer = null
  135 + }, 1200)
  136 + },
  137 + search(e) {
  138 + const val = e && e.value != null ? e.value : this.searchKeyword
  139 + this.searchKeyword = val
  140 + this.searchKeywordDebounced = val
  141 + },
  142 + openFilter() {
  143 + this.filterForm = {
  144 + startTimeRange: Array.isArray(this.query.startTimeRange) ? this.query.startTimeRange.slice(0) : [],
  145 + endTimeRange: Array.isArray(this.query.endTimeRange) ? this.query.endTimeRange.slice(0) : [],
  146 + bidTimeRange: Array.isArray(this.query.bidTimeRange) ? this.query.bidTimeRange.slice(0) : []
  147 + }
  148 + this.filterVisible = true
  149 + },
  150 + onFilterReset(payload) {
  151 + this.filterForm = payload
  152 + },
  153 + onFilterConfirm(payload) {
  154 + this.query = {
  155 + name: this.query.name || '',
  156 + startTimeRange: Array.isArray(payload.startTimeRange) ? payload.startTimeRange : [],
  157 + endTimeRange: Array.isArray(payload.endTimeRange) ? payload.endTimeRange : [],
  158 + bidTimeRange: Array.isArray(payload.bidTimeRange) ? payload.bidTimeRange : []
  159 + }
  160 + },
  161 + fetchList({ pageIndex, pageSize, query }) {
  162 + const q = query || {}
  163 + const sRange = Array.isArray(q.startTimeRange) ? q.startTimeRange : []
  164 + const eRange = Array.isArray(q.endTimeRange) ? q.endTimeRange : []
  165 + const bRange = Array.isArray(q.bidTimeRange) ? q.bidTimeRange : []
  166 + const params = {
  167 + pageIndex,
  168 + pageSize,
  169 + name: q.name || '',
  170 + startTimeStart: (sRange && sRange.length === 2) ? sRange[0] : '',
  171 + startTimeEnd: (sRange && sRange.length === 2) ? sRange[1] : '',
  172 + endTimeStart: (eRange && eRange.length === 2) ? eRange[0] : '',
  173 + endTimeEnd: (eRange && eRange.length === 2) ? eRange[1] : '',
  174 + bidTimeStart: (bRange && bRange.length === 2) ? bRange[0] : '',
  175 + bidTimeEnd: (bRange && bRange.length === 2) ? bRange[1] : ''
  176 + }
  177 + return supplierQuotationProjectQueryApi(params).then(res => {
  178 + const _data = res && res.data ? res.data : {}
  179 + let records = _data.datas || _data.list || _data.records || []
  180 + const totalCount = _data.totalCount || _data.count || 0
  181 + const hasNext = _data.hasNext || false
  182 + records = records.map(it => ({ ...it }))
  183 + return { records, totalCount, hasNext }
  184 + }).catch(() => {
  185 + this.onCardError()
  186 + return { records: [], totalCount: 0, hasNext: false }
  187 + })
  188 + },
  189 + onCardClick(item) {
  190 + uni.navigateTo({ url: '/pages/supplier-price/detail?id=' + item.id })
  191 + }
  192 + }
  193 +}
  194 +</script>
  195 +
  196 +<style lang="scss" scoped>
  197 +.page {
  198 + display: flex;
  199 + flex-direction: column;
  200 + height: 100vh;
  201 +}
  202 +
  203 +.dev-list-fixed {
  204 + position: fixed;
  205 + top: 96rpx;
  206 + left: 0;
  207 + right: 0;
  208 + z-index: 2;
  209 + background: #fff;
  210 +
  211 + .search-row {
  212 + display: flex;
  213 + align-items: center;
  214 + padding: 16rpx 32rpx;
  215 +
  216 + .uni-searchbar {
  217 + padding: 0;
  218 + flex: 1;
  219 + }
  220 +
  221 + .tool-icons {
  222 + display: flex;
  223 +
  224 + .tool-icon {
  225 + width: 48rpx;
  226 + height: 48rpx;
  227 + display: block;
  228 + margin-left: 32rpx;
  229 + }
  230 + }
  231 + }
  232 +}
  233 +
  234 +::v-deep .uni-searchbar__box {
  235 + height: 80rpx !important;
  236 + justify-content: start;
  237 +
  238 + .uni-searchbar__box-search-input {
  239 + font-size: 32rpx !important;
  240 + }
  241 +}
  242 +
  243 +.list-box {
  244 + flex: 1;
  245 + padding-top: 140rpx;
  246 +
  247 + .card {
  248 + position: relative;
  249 + }
  250 +
  251 + .card-header {
  252 + margin-bottom: 28rpx;
  253 + position: relative;
  254 +
  255 + .title {
  256 + font-size: 36rpx;
  257 + font-weight: 600;
  258 + line-height: 50rpx;
  259 + color: rgba(0, 0, 0, 0.9);
  260 + width: 578rpx;
  261 + }
  262 + }
  263 +
  264 + .info-row {
  265 + display: flex;
  266 + align-items: center;
  267 + color: rgba(0, 0, 0, 0.6);
  268 + font-size: 28rpx;
  269 + margin-bottom: 24rpx;
  270 + height: 32rpx;
  271 +
  272 + &:last-child {
  273 + margin-bottom: 0;
  274 + }
  275 +
  276 + text {
  277 + width: 50%;
  278 +
  279 + &:last-child {
  280 + color: rgba(0, 0, 0, 0.9);
  281 + width: 50%;
  282 + }
  283 + }
  284 + }
  285 +}
  286 +
  287 +.filter-form {
  288 + .form-item {
  289 + margin-bottom: 24rpx;
  290 + }
  291 +
  292 + .label {
  293 + margin-bottom: 20rpx;
  294 + color: rgba(0, 0, 0, 0.9);
  295 + height: 44rpx;
  296 + line-height: 44rpx;
  297 + font-size: 30rpx;
  298 + }
  299 +}
  300 +</style>
... ...