Commit 8f02816dd3612ca27e05d29fbf2563aaa60daf7d

Authored by gesilong
1 parent 84cf5663

commit:同行信息联调

... ... @@ -8,3 +8,37 @@ export function salesmanQuotationPeerQueryApi(params) {
8 8 params
9 9 })
10 10 }
  11 +
  12 +export function salesmanQuotationPeerSaveApi(data) {
  13 + return request({
  14 + url: '/procurement/salesmanQuotationPeer',
  15 + method: 'post',
  16 + data,
  17 + contentType: ContentTypeEnum.JSON
  18 + })
  19 +}
  20 +
  21 +export function salesmanQuotationPeerGetApi(id) {
  22 + return request({
  23 + url: '/procurement/salesmanQuotationPeer',
  24 + method: 'get',
  25 + params: { id }
  26 + })
  27 +}
  28 +
  29 +export function salesmanQuotationPeerUpdateApi(data) {
  30 + return request({
  31 + url: '/procurement/salesmanQuotationPeer',
  32 + method: 'put',
  33 + data,
  34 + contentType: ContentTypeEnum.JSON
  35 + })
  36 +}
  37 +
  38 +export function salesmanQuotationPeerDeleteApi(id) {
  39 + return request({
  40 + url: '/procurement/salesmanQuotationPeer',
  41 + method: 'delete',
  42 + params: { id }
  43 + })
  44 +}
... ...
... ... @@ -341,6 +341,30 @@
341 341 }
342 342 },
343 343 {
  344 + "path": "pages/peer-info/add",
  345 + "style": {
  346 + "navigationBarTitleText": "新增同行信息",
  347 + "navigationBarBackgroundColor": "#ffffff",
  348 + "navigationBarTextStyle": "black"
  349 + }
  350 + },
  351 + {
  352 + "path": "pages/peer-info/modify",
  353 + "style": {
  354 + "navigationBarTitleText": "编辑同行信息",
  355 + "navigationBarBackgroundColor": "#ffffff",
  356 + "navigationBarTextStyle": "black"
  357 + }
  358 + },
  359 + {
  360 + "path": "pages/peer-info/detail",
  361 + "style": {
  362 + "navigationBarTitleText": "查看同行信息",
  363 + "navigationBarBackgroundColor": "#ffffff",
  364 + "navigationBarTextStyle": "black"
  365 + }
  366 + },
  367 + {
344 368 "path": "pages/order_list/index",
345 369 "style": {
346 370 "navigationBarTitleText": "订货单列表",
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item>
  6 + <template v-slot:body>
  7 + <view class="item-title"><text class="required">*</text><text>同行名称</text></view>
  8 + </template>
  9 + <template v-slot:footer>
  10 + <uni-easyinput v-model="form.peerName" placeholder="请输入同行名称" :inputBorder="false" />
  11 + </template>
  12 + </uni-list-item>
  13 +
  14 + <uni-list-item class="select-item" :class="form.peerProductName ? 'is-filled' : 'is-empty'" clickable
  15 + @click="openSheet('peerProductId')" :rightText="displayLabel('peerProductName')" showArrow>
  16 + <template v-slot:body>
  17 + <view class="item-title"><text class="required">*</text><text>同行品种</text></view>
  18 + </template>
  19 + </uni-list-item>
  20 +
  21 + <uni-list-item>
  22 + <template v-slot:body>
  23 + <view class="item-title"><text class="required">*</text><text>同行报价</text></view>
  24 + </template>
  25 + <template v-slot:footer>
  26 + <uni-easyinput type="digit" v-model="form.peerPrice" placeholder="请输入同行报价" :inputBorder="false" />
  27 + </template>
  28 + </uni-list-item>
  29 + </uni-list>
  30 + </scroll-view>
  31 +
  32 + <view class="footer">
  33 + <button class="btn submit" type="primary" :disabled="submitting" @click="onSubmit">{{ submitting ? '提交中...' : '提交' }}</button>
  34 + </view>
  35 +
  36 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  37 + @confirm="onSheetConfirm" />
  38 + </view>
  39 +</template>
  40 +
  41 +<script>
  42 +import SingleSelectSheet from '@/components/single-select/index.vue'
  43 +import { breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js'
  44 +import { salesmanQuotationPeerSaveApi } from '@/api/procure-manage/salesmanQuotationPeer.js'
  45 +
  46 +export default {
  47 + name: 'PeerInfoAdd',
  48 + components: { SingleSelectSheet },
  49 + data() {
  50 + return {
  51 + submitting: false,
  52 + productVarietyList: [],
  53 + sheet: { visible: false, title: '请选择', options: [], field: '', value: '' },
  54 + form: {
  55 + peerName: '',
  56 + peerProductId: '',
  57 + peerProductName: '',
  58 + peerPrice: ''
  59 + }
  60 + }
  61 + },
  62 + created() {
  63 + this.loadProductVariety()
  64 + },
  65 + methods: {
  66 + async loadProductVariety() {
  67 + try {
  68 + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 })
  69 + const _data = res && res.data ? res.data : {}
  70 + const list = _data.datas || _data.list || _data.records || []
  71 + this.productVarietyList = list.map(it => ({
  72 + label: it.productName || it.name || '',
  73 + value: it.productId || it.id || ''
  74 + })).filter(it => it.value)
  75 + } catch (e) {
  76 + this.productVarietyList = []
  77 + }
  78 + },
  79 + displayLabel(field) {
  80 + const map = { peerProductName: '请选择同行品种' }
  81 + const val = this.form[field]
  82 + return val ? String(val) : (map[field] || '请选择')
  83 + },
  84 + openSheet(field) {
  85 + if (field === 'peerProductId') {
  86 + const current = this.form.peerProductId
  87 + const match = (this.productVarietyList || []).find(o => String(o.value) === String(current))
  88 + this.sheet = {
  89 + visible: true,
  90 + title: '同行品种',
  91 + options: this.productVarietyList || [],
  92 + field,
  93 + value: match ? match.value : ''
  94 + }
  95 + }
  96 + },
  97 + onSheetConfirm({ value, label }) {
  98 + const field = this.sheet.field
  99 + if (!field) return
  100 + if (field === 'peerProductId') {
  101 + this.form.peerProductId = value || ''
  102 + this.form.peerProductName = label || ''
  103 + }
  104 + },
  105 + validate() {
  106 + const checks = [
  107 + { key: 'peerName', label: '同行名称' },
  108 + { key: 'peerProductId', label: '同行品种' },
  109 + { key: 'peerPrice', label: '同行报价' }
  110 + ]
  111 + for (const it of checks) {
  112 + const val = this.form[it.key]
  113 + const empty = (val === undefined || val === null || (typeof val === 'string' && String(val).trim() === ''))
  114 + if (empty) {
  115 + uni.showToast({ title: `${it.label}必填`, icon: 'none' })
  116 + return false
  117 + }
  118 + }
  119 + return true
  120 + },
  121 + buildPayload() {
  122 + return {
  123 + peerName: this.form.peerName,
  124 + peerProductId: this.form.peerProductId,
  125 + peerPrice: this.form.peerPrice
  126 + }
  127 + },
  128 + async onSubmit() {
  129 + if (this.submitting) return
  130 + if (!this.validate()) return
  131 + this.submitting = true
  132 + const payload = this.buildPayload()
  133 + try {
  134 + await salesmanQuotationPeerSaveApi(payload)
  135 + uni.showToast({ title: '保存成功', icon: 'success' })
  136 + try { uni.setStorageSync('PEER_INFO_LIST_NEED_REFRESH', '1') } catch (e) {}
  137 + setTimeout(() => { uni.redirectTo({ url: '/pages/peer-info/index' }) }, 300)
  138 + } catch (e) {
  139 + uni.showToast({ title: (e && e.msg) || '保存失败', icon: 'none' })
  140 + } finally {
  141 + this.submitting = false
  142 + }
  143 + }
  144 + }
  145 +}
  146 +</script>
  147 +
  148 +<style lang="scss" scoped>
  149 +.page {
  150 + display: flex;
  151 + flex-direction: column;
  152 + height: 100%;
  153 +}
  154 +
  155 +.scroll {
  156 + flex: 1;
  157 + padding: 0rpx 0 160rpx;
  158 + background-color: #f3f3f3;
  159 +}
  160 +
  161 +.footer {
  162 + position: fixed;
  163 + left: 0;
  164 + right: 0;
  165 + bottom: 0;
  166 + padding: 32rpx;
  167 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  168 + background: #fff;
  169 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  170 + z-index: 10;
  171 +
  172 + .btn {
  173 + height: 80rpx;
  174 + line-height: 80rpx;
  175 + border-radius: 12rpx;
  176 + font-size: 32rpx;
  177 + }
  178 +
  179 + .submit {
  180 + background: $theme-primary;
  181 + color: #fff;
  182 + }
  183 +}
  184 +
  185 +.title-header {
  186 + display: flex;
  187 + align-items: center;
  188 + padding: 24rpx 32rpx 12rpx;
  189 + background-color: #ffffff;
  190 +
  191 + .title-header_icon {
  192 + width: 36rpx;
  193 + height: 36rpx;
  194 + margin-right: 12rpx;
  195 + }
  196 +
  197 + span {
  198 + font-size: 34rpx;
  199 + font-weight: 600;
  200 + color: rgba(0, 0, 0, 0.9);
  201 + }
  202 +}
  203 +
  204 +.mgb10 {
  205 + margin-bottom: 20rpx;
  206 +}
  207 +
  208 +::v-deep .uni-list {
  209 + .uni-easyinput {
  210 + display: flex;
  211 +
  212 + .uni-input-input {
  213 + color: rgba(0, 0, 0, 0.9);
  214 + }
  215 + }
  216 +
  217 + .uni-input-placeholder {
  218 + z-index: 1;
  219 + }
  220 +
  221 + .uni-input-input {
  222 + background-color: #ffffff;
  223 + }
  224 +
  225 + background: transparent;
  226 +
  227 + &-item {
  228 + &__extra-text {
  229 + font-size: 32rpx;
  230 + }
  231 +
  232 + &__content-title {
  233 + font-size: 32rpx;
  234 + color: rgba(0, 0, 0, 0.9);
  235 + }
  236 +
  237 + &__container {
  238 + padding: 32rpx;
  239 +
  240 + .uni-easyinput {
  241 + &__placeholder-class {
  242 + font-size: 32rpx;
  243 + color: rgba(0, 0, 0, 0.4);
  244 + }
  245 +
  246 + &__content {
  247 + border: none;
  248 + background-color: #ffffff !important;
  249 +
  250 + &-input {
  251 + padding-left: 0 !important;
  252 + height: 48rpx;
  253 + line-height: 48rpx;
  254 + font-size: 32rpx;
  255 + }
  256 +
  257 + .content-clear-icon {
  258 + font-size: 44rpx !important;
  259 + }
  260 + }
  261 + }
  262 +
  263 + .item-title,
  264 + .uni-list-item__content {
  265 + flex: none;
  266 + min-height: 48rpx;
  267 + line-height: 48rpx;
  268 + font-size: 32rpx;
  269 + position: relative;
  270 + width: 210rpx;
  271 + margin-right: 32rpx;
  272 + color: rgba(0, 0, 0, 0.9);
  273 +
  274 + .required {
  275 + color: red;
  276 + position: absolute;
  277 + top: 50%;
  278 + transform: translateY(-50%);
  279 + left: -16rpx;
  280 + }
  281 + }
  282 + }
  283 +
  284 + &.select-item {
  285 + &.is-empty {
  286 + .uni-list-item__extra-text {
  287 + color: rgba(0, 0, 0, 0.4) !important;
  288 + }
  289 + }
  290 +
  291 + &.is-filled {
  292 + .uni-list-item__extra-text {
  293 + color: rgba(0, 0, 0, 0.9) !important;
  294 + }
  295 + }
  296 + }
  297 +
  298 + &.mgb10 {
  299 + margin-bottom: 20rpx;
  300 + }
  301 + }
  302 +}
  303 +</style>
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <view class="detail-page">
  5 + <view class="section">
  6 + <text class="row company">{{ safeText(form.peerName) }}</text>
  7 + <view class="row"><text class="label">同行品种</text><text class="value">{{ safeText(form.peerProductName) }}</text></view>
  8 + <view class="row"><text class="label">同行报价</text><text class="value">{{ safeText(form.peerPrice) }}</text></view>
  9 + <view class="row"><text class="label">创建人</text><text class="value">{{ safeText(form.createBy) }}</text></view>
  10 + <view class="row"><text class="label">创建时间</text><text class="value">{{ formatDateTime(form.createTime) }}</text></view>
  11 + </view>
  12 + </view>
  13 + </scroll-view>
  14 + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" />
  15 + </view>
  16 +</template>
  17 +
  18 +<script>
  19 +import DetailButtons from '@/components/detail-buttons/index.vue'
  20 +import { salesmanQuotationPeerGetApi, salesmanQuotationPeerDeleteApi } from '@/api/procure-manage/salesmanQuotationPeer.js'
  21 +
  22 +export default {
  23 + name: 'PeerInfoDetail',
  24 + components: { DetailButtons },
  25 + data() {
  26 + return {
  27 + id: '',
  28 + loading: false,
  29 + form: {},
  30 + buttons: [
  31 + { text: '编辑', visible: true, variant: 'outline', event: 'edit' },
  32 + { text: '删除', visible: true, variant: 'danger', event: 'delete' }
  33 + ]
  34 + }
  35 + },
  36 + computed: {
  37 + displayButtons() {
  38 + const isToday = this.isToday(this.form.createTime);
  39 + return [
  40 + { ...this.buttons[0], visible: isToday && this.$auth.hasPermi('procure-manage:peer-info:modify') },
  41 + { ...this.buttons[1], visible: isToday && this.$auth.hasPermi('procure-manage:peer-info:delete') }
  42 + ]
  43 + }
  44 + },
  45 + onShow() {
  46 + const options = (this.$route && this.$route.query) ? this.$route.query : {}
  47 + const id = options && options.id ? String(options.id) : ''
  48 + if (id && id !== this.id) {
  49 + this.id = id
  50 + }
  51 + if (this.id) this.loadDetail()
  52 + },
  53 + methods: {
  54 + isToday(dateStr) {
  55 + if (!dateStr) return false;
  56 + const date = new Date(dateStr);
  57 + const today = new Date();
  58 + return (
  59 + date.getFullYear() === today.getFullYear() &&
  60 + date.getMonth() === today.getMonth() &&
  61 + date.getDate() === today.getDate()
  62 + );
  63 + },
  64 + safeText(v) {
  65 + const s = v == null ? '' : String(v)
  66 + return s.trim() ? s : ''
  67 + },
  68 + formatDateTime(v) {
  69 + const s = v == null ? '' : String(v).trim()
  70 + if (!s) return '-'
  71 + if (s.length >= 16) return s.slice(0, 16)
  72 + if (s.length >= 10) return s.slice(0, 10)
  73 + return s
  74 + },
  75 + handleButtonClick(btn) {
  76 + if (!btn || btn.disabled) return
  77 + const e = btn.event || ''
  78 + if (e === 'edit') return this.onEdit()
  79 + if (e === 'delete') return this.onDelete()
  80 + },
  81 + onEdit() {
  82 + uni.navigateTo({ url: '/pages/peer-info/modify?id=' + this.id })
  83 + },
  84 + onDelete() {
  85 + const id = this.id || (this.form && this.form.id) || ''
  86 + if (!id) return
  87 + uni.showModal({
  88 + title: '系统提示',
  89 + content: '是否确定删除该同行信息?',
  90 + confirmText: '确定',
  91 + cancelText: '取消',
  92 + success: (res) => {
  93 + if (res && res.confirm) {
  94 + salesmanQuotationPeerDeleteApi(id).then(() => {
  95 + uni.showToast({ title: '已删除', icon: 'none' })
  96 + try { uni.setStorageSync('PEER_INFO_LIST_NEED_REFRESH', '1') } catch (e) {}
  97 + setTimeout(() => { uni.redirectTo({ url: '/pages/peer-info/index' }) }, 300)
  98 + }).catch((e) => {
  99 + uni.showToast({ title: (e && e.msg) || '删除失败', icon: 'none' })
  100 + })
  101 + }
  102 + }
  103 + })
  104 + },
  105 + async loadDetail() {
  106 + this.loading = true
  107 + try {
  108 + const res = await salesmanQuotationPeerGetApi(this.id)
  109 + this.form = (res && res.data) ? res.data : {}
  110 + } catch (e) {
  111 + this.form = {}
  112 + uni.showToast({ title: '详情加载失败', icon: 'none' })
  113 + } finally {
  114 + this.loading = false
  115 + }
  116 + }
  117 + }
  118 +}
  119 +</script>
  120 +
  121 +<style lang="scss" scoped>
  122 +.page {
  123 + display: flex;
  124 + flex-direction: column;
  125 + height: 100%;
  126 +}
  127 +
  128 +.scroll {
  129 + flex: 1;
  130 + padding: 8rpx 0 144rpx;
  131 +}
  132 +
  133 +.detail-page {
  134 + background: #f3f3f3;
  135 +}
  136 +
  137 +.section {
  138 + padding: 32rpx;
  139 + background: #fff;
  140 + margin-bottom: 20rpx;
  141 +}
  142 +
  143 +.row {
  144 + display: flex;
  145 + margin-bottom: 28rpx;
  146 +
  147 + &:last-child {
  148 + margin-bottom: 0;
  149 + }
  150 +
  151 + &.company {
  152 + font-size: 36rpx;
  153 + font-weight: 600;
  154 + color: rgba(0, 0, 0, 0.9);
  155 + padding-top: 8rpx;
  156 + line-height: 50rpx;
  157 + margin-bottom: 28rpx;
  158 + }
  159 +
  160 + .label {
  161 + max-width: 420rpx;
  162 + margin-right: 20rpx;
  163 + line-height: 32rpx;
  164 + font-size: 28rpx;
  165 + color: rgba(0, 0, 0, 0.6);
  166 + }
  167 +
  168 + .value {
  169 + flex: 1;
  170 + line-height: 32rpx;
  171 + font-size: 28rpx;
  172 + color: rgba(0, 0, 0, 0.9);
  173 + text-align: right;
  174 + word-break: break-all;
  175 +
  176 + &.pre {
  177 + white-space: pre-wrap;
  178 + }
  179 + }
  180 +}
  181 +</style>
... ...
... ... @@ -6,6 +6,7 @@
6 6 cancelButton="none" bgColor="#F3F3F3" textColor="rgba(0,0,0,0.4)" @confirm="search"
7 7 @input="onSearchInput" />
8 8 <view class="tool-icons">
  9 + <image class="tool-icon" src="/static/images/dev_manage/add_icon.png" @click="onAdd" />
9 10 <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
10 11 </view>
11 12 </view>
... ... @@ -121,6 +122,9 @@ export default {
121 122 if (s.length >= 10) return s.slice(0, 10)
122 123 return s
123 124 },
  125 + onAdd() {
  126 + uni.navigateTo({ url: '/pages/peer-info/add' })
  127 + },
124 128 onCardLoaded({ items }) {
125 129 this.currentItems = items
126 130 },
... ... @@ -187,7 +191,7 @@ export default {
187 191 })
188 192 },
189 193 onCardClick(item) {
190   - // 暂无详情页
  194 + uni.navigateTo({ url: '/pages/peer-info/detail?id=' + item.id })
191 195 }
192 196 }
193 197 }
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <view class="title-header">
  6 + <image class="title-header_icon" src="/static/images/title.png" />
  7 + <span>同行信息</span>
  8 + </view>
  9 +
  10 + <uni-list-item>
  11 + <template v-slot:body>
  12 + <view class="item-title"><text class="required">*</text><text>同行名称</text></view>
  13 + </template>
  14 + <template v-slot:footer>
  15 + <uni-easyinput v-model="form.peerName" placeholder="请输入同行名称" :inputBorder="false" />
  16 + </template>
  17 + </uni-list-item>
  18 +
  19 + <uni-list-item class="select-item" :class="form.peerProductName ? 'is-filled' : 'is-empty'" clickable
  20 + @click="openSheet('peerProductId')" :rightText="displayLabel('peerProductName')" showArrow>
  21 + <template v-slot:body>
  22 + <view class="item-title"><text class="required">*</text><text>同行品种</text></view>
  23 + </template>
  24 + </uni-list-item>
  25 +
  26 + <uni-list-item>
  27 + <template v-slot:body>
  28 + <view class="item-title"><text class="required">*</text><text>同行报价</text></view>
  29 + </template>
  30 + <template v-slot:footer>
  31 + <uni-easyinput type="digit" v-model="form.peerPrice" placeholder="请输入同行报价" :inputBorder="false" />
  32 + </template>
  33 + </uni-list-item>
  34 + </uni-list>
  35 + </scroll-view>
  36 +
  37 + <view class="footer">
  38 + <button class="btn submit" type="primary" :disabled="submitting" @click="onSubmit">{{ submitting ? '提交中...' : '提交' }}</button>
  39 + </view>
  40 +
  41 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  42 + @confirm="onSheetConfirm" />
  43 + </view>
  44 +</template>
  45 +
  46 +<script>
  47 +import SingleSelectSheet from '@/components/single-select/index.vue'
  48 +import { breedRelationshipQueryApi } from '@/api/procure-manage/salesmanQuotation.js'
  49 +import { salesmanQuotationPeerGetApi, salesmanQuotationPeerUpdateApi } from '@/api/procure-manage/salesmanQuotationPeer.js'
  50 +
  51 +export default {
  52 + name: 'PeerInfoModify',
  53 + components: { SingleSelectSheet },
  54 + data() {
  55 + return {
  56 + id: '',
  57 + submitting: false,
  58 + loading: false,
  59 + productVarietyList: [],
  60 + sheet: { visible: false, title: '请选择', options: [], field: '', value: '' },
  61 + form: {
  62 + id: '',
  63 + peerName: '',
  64 + peerProductId: '',
  65 + peerProductName: '',
  66 + peerPrice: ''
  67 + }
  68 + }
  69 + },
  70 + onLoad(query) {
  71 + this.id = (query && query.id) ? String(query.id) : ''
  72 + },
  73 + created() {
  74 + this.loadProductVariety()
  75 + if (this.id) this.loadDetail()
  76 + },
  77 + methods: {
  78 + async loadProductVariety() {
  79 + try {
  80 + const res = await breedRelationshipQueryApi({ pageIndex: 1, pageSize: 9999 })
  81 + const _data = res && res.data ? res.data : {}
  82 + const list = _data.datas || _data.list || _data.records || []
  83 + this.productVarietyList = list.map(it => ({
  84 + label: it.productName || it.name || '',
  85 + value: it.productId || it.id || ''
  86 + })).filter(it => it.value)
  87 + } catch (e) {
  88 + this.productVarietyList = []
  89 + }
  90 + },
  91 + async loadDetail() {
  92 + this.loading = true
  93 + try {
  94 + const res = await salesmanQuotationPeerGetApi(this.id)
  95 + const data = (res && res.data) ? res.data : {}
  96 + this.form = {
  97 + id: data.id || this.id,
  98 + peerName: data.peerName || '',
  99 + peerProductId: data.peerProductId || '',
  100 + peerProductName: data.peerProductName || this.getOptionLabel(this.productVarietyList, data.peerProductId),
  101 + peerPrice: data.peerPrice != null ? String(data.peerPrice) : ''
  102 + }
  103 + } catch (e) {
  104 + uni.showToast({ title: '加载失败', icon: 'none' })
  105 + } finally {
  106 + this.loading = false
  107 + }
  108 + },
  109 + getOptionLabel(options, value) {
  110 + const v = value != null ? String(value) : ''
  111 + if (!v) return ''
  112 + const match = (options || []).find(o => String(o.value) === v)
  113 + return match ? String(match.label || '') : ''
  114 + },
  115 + displayLabel(field) {
  116 + const map = { peerProductName: '请选择同行品种' }
  117 + const val = this.form[field]
  118 + return val ? String(val) : (map[field] || '请选择')
  119 + },
  120 + openSheet(field) {
  121 + if (field === 'peerProductId') {
  122 + const current = this.form.peerProductId
  123 + const match = (this.productVarietyList || []).find(o => String(o.value) === String(current))
  124 + this.sheet = {
  125 + visible: true,
  126 + title: '同行品种',
  127 + options: this.productVarietyList || [],
  128 + field,
  129 + value: match ? match.value : ''
  130 + }
  131 + }
  132 + },
  133 + onSheetConfirm({ value, label }) {
  134 + const field = this.sheet.field
  135 + if (!field) return
  136 + if (field === 'peerProductId') {
  137 + this.form.peerProductId = value || ''
  138 + this.form.peerProductName = label || ''
  139 + }
  140 + },
  141 + validate() {
  142 + const checks = [
  143 + { key: 'peerName', label: '同行名称' },
  144 + { key: 'peerProductId', label: '同行品种' },
  145 + { key: 'peerPrice', label: '同行报价' }
  146 + ]
  147 + for (const it of checks) {
  148 + const val = this.form[it.key]
  149 + const empty = (val === undefined || val === null || (typeof val === 'string' && String(val).trim() === ''))
  150 + if (empty) {
  151 + uni.showToast({ title: `${it.label}必填`, icon: 'none' })
  152 + return false
  153 + }
  154 + }
  155 + return true
  156 + },
  157 + buildPayload() {
  158 + return {
  159 + id: this.form.id,
  160 + peerName: this.form.peerName,
  161 + peerProductId: this.form.peerProductId,
  162 + peerPrice: this.form.peerPrice
  163 + }
  164 + },
  165 + async onSubmit() {
  166 + if (this.submitting) return
  167 + if (!this.validate()) return
  168 + this.submitting = true
  169 + const payload = this.buildPayload()
  170 + try {
  171 + await salesmanQuotationPeerUpdateApi(payload)
  172 + uni.showToast({ title: '保存成功', icon: 'success' })
  173 + try { uni.setStorageSync('PEER_INFO_LIST_NEED_REFRESH', '1') } catch (e) {}
  174 + setTimeout(() => { uni.redirectTo({ url: '/pages/peer-info/index' }) }, 300)
  175 + } catch (e) {
  176 + uni.showToast({ title: (e && e.msg) || '保存失败', icon: 'none' })
  177 + } finally {
  178 + this.submitting = false
  179 + }
  180 + }
  181 + }
  182 +}
  183 +</script>
  184 +
  185 +<style lang="scss" scoped>
  186 +.page {
  187 + display: flex;
  188 + flex-direction: column;
  189 + height: 100%;
  190 +}
  191 +
  192 +.scroll {
  193 + flex: 1;
  194 + padding: 0rpx 0 160rpx;
  195 + background-color: #f3f3f3;
  196 +}
  197 +
  198 +.footer {
  199 + position: fixed;
  200 + left: 0;
  201 + right: 0;
  202 + bottom: 0;
  203 + padding: 32rpx;
  204 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  205 + background: #fff;
  206 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  207 + z-index: 10;
  208 +
  209 + .btn {
  210 + height: 80rpx;
  211 + line-height: 80rpx;
  212 + border-radius: 12rpx;
  213 + font-size: 32rpx;
  214 + }
  215 +
  216 + .submit {
  217 + background: $theme-primary;
  218 + color: #fff;
  219 + }
  220 +}
  221 +
  222 +.title-header {
  223 + display: flex;
  224 + align-items: center;
  225 + padding: 24rpx 32rpx 12rpx;
  226 + background-color: #ffffff;
  227 +
  228 + .title-header_icon {
  229 + width: 36rpx;
  230 + height: 36rpx;
  231 + margin-right: 12rpx;
  232 + }
  233 +
  234 + span {
  235 + font-size: 34rpx;
  236 + font-weight: 600;
  237 + color: rgba(0, 0, 0, 0.9);
  238 + }
  239 +}
  240 +
  241 +.mgb10 {
  242 + margin-bottom: 20rpx;
  243 +}
  244 +
  245 +::v-deep .uni-list {
  246 + .uni-easyinput {
  247 + display: flex;
  248 +
  249 + .uni-input-input {
  250 + color: rgba(0, 0, 0, 0.9);
  251 + }
  252 + }
  253 +
  254 + .uni-input-placeholder {
  255 + z-index: 1;
  256 + }
  257 +
  258 + .uni-input-input {
  259 + background-color: #ffffff;
  260 + }
  261 +
  262 + background: transparent;
  263 +
  264 + &-item {
  265 + &__extra-text {
  266 + font-size: 32rpx;
  267 + }
  268 +
  269 + &__content-title {
  270 + font-size: 32rpx;
  271 + color: rgba(0, 0, 0, 0.9);
  272 + }
  273 +
  274 + &__container {
  275 + padding: 32rpx;
  276 +
  277 + .uni-easyinput {
  278 + &__placeholder-class {
  279 + font-size: 32rpx;
  280 + color: rgba(0, 0, 0, 0.4);
  281 + }
  282 +
  283 + &__content {
  284 + border: none;
  285 + background-color: #ffffff !important;
  286 +
  287 + &-input {
  288 + padding-left: 0 !important;
  289 + height: 48rpx;
  290 + line-height: 48rpx;
  291 + font-size: 32rpx;
  292 + }
  293 +
  294 + .content-clear-icon {
  295 + font-size: 44rpx !important;
  296 + }
  297 + }
  298 + }
  299 +
  300 + .item-title,
  301 + .uni-list-item__content {
  302 + flex: none;
  303 + min-height: 48rpx;
  304 + line-height: 48rpx;
  305 + font-size: 32rpx;
  306 + position: relative;
  307 + width: 210rpx;
  308 + margin-right: 32rpx;
  309 + color: rgba(0, 0, 0, 0.9);
  310 +
  311 + .required {
  312 + color: red;
  313 + position: absolute;
  314 + top: 50%;
  315 + transform: translateY(-50%);
  316 + left: -16rpx;
  317 + }
  318 + }
  319 + }
  320 +
  321 + &.select-item {
  322 + &.is-empty {
  323 + .uni-list-item__extra-text {
  324 + color: rgba(0, 0, 0, 0.4) !important;
  325 + }
  326 + }
  327 +
  328 + &.is-filled {
  329 + .uni-list-item__extra-text {
  330 + color: rgba(0, 0, 0, 0.9) !important;
  331 + }
  332 + }
  333 + }
  334 +
  335 + &.mgb10 {
  336 + margin-bottom: 20rpx;
  337 + }
  338 + }
  339 +}
  340 +</style>
... ...