Commit 3d87892b675d69e477e70a660c03cbd312b7bcfb

Authored by 史婷婷
1 parent 9e15aba8

feat: 产品试样结果反馈单-列表&详情

  1 +import request from '@/utils/request'
  2 +
  3 +const baseUrl = '/sample/feedback';
  4 +// 查询列表
  5 +export function queryApi(params) {
  6 + return request({
  7 + url: baseUrl + `/query`,
  8 + method: 'get',
  9 + params
  10 + })
  11 +}
  12 +
  13 +// 根据ID查询详情数据
  14 +export function getDetailApi(id) {
  15 + return request({
  16 + url: baseUrl,
  17 + method: 'get',
  18 + params: { id }
  19 + })
  20 +}
... ...
... ... @@ -832,6 +832,22 @@
832 832 "navigationBarBackgroundColor": "#ffffff",
833 833 "navigationBarTextStyle": "black"
834 834 }
  835 + },
  836 + {
  837 + "path": "pages/feedback_form/index",
  838 + "style": {
  839 + "navigationBarTitleText": "产品试样结果反馈单",
  840 + "navigationBarBackgroundColor": "#ffffff",
  841 + "navigationBarTextStyle": "black"
  842 + }
  843 + },
  844 + {
  845 + "path": "pages/feedback_form/detail",
  846 + "style": {
  847 + "navigationBarTitleText": "产品试样结果反馈单详情",
  848 + "navigationBarBackgroundColor": "#ffffff",
  849 + "navigationBarTextStyle": "black"
  850 + }
835 851 }
836 852 ],
837 853 "subPackages": [
... ...
  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">{{ form.customerName }}</text>
  7 + <view class="row"><text class="label">订单编号</text><text class="value">{{ form.orderNo }}</text></view>
  8 + <view class="row"><text class="label">生产厂</text><text class="value">{{ form.workshopName }}</text></view>
  9 + </view>
  10 +
  11 + <!-- 产品 -->
  12 + <view class="section2">
  13 + <Product mode="view" :list="form.detailList" />
  14 + </view>
  15 +
  16 + </view>
  17 + </scroll-view>
  18 + <!-- <detail-buttons :buttons="displayButtons" @click="handleButtonClick" /> -->
  19 + </view>
  20 +</template>
  21 +
  22 +<script>
  23 +import { getDetailApi } from '@/api/feedback_form.js'
  24 +import Product from './product.vue'
  25 +import DetailButtons from '@/components/detail-buttons/index.vue'
  26 +import { downloadFile } from '@/utils/downloadFile.js'
  27 +import {
  28 + getDicByCodes
  29 +} from '@/utils/dic'
  30 +import {
  31 + getDicName
  32 +} from '@/utils/dic.js'
  33 +
  34 +export default {
  35 + name: 'FeedbackFormDetail',
  36 + components: { Product, DetailButtons },
  37 + data() {
  38 + return {
  39 + form: {},
  40 + buttons: [
  41 + // { text: '编辑', visible: true, variant: 'outline', event: 'edit' },
  42 + // { text: '审核详情', visible: true, variant: 'outline', event: 'auditDetail' },
  43 + // { text: '审核', visible: true, variant: 'primary', event: 'audit' },
  44 + ],
  45 + dicOptions: {
  46 + SAMPLE_RESULT: [],
  47 + SAMPLE_RESULT_SUB: []
  48 + },
  49 + sampleResultLocal: [],
  50 + sampleResultSubLocal: []
  51 + }
  52 + },
  53 + computed: {
  54 + // statusFlags() {
  55 + // const m = this.form || {}
  56 + // const e = String(m.status || '')
  57 + // return {
  58 + // // 跟踪单编辑:1:审核状态为空、已驳回 2:showAudit为true 3:需要加角色权限
  59 + // canEdit: (!e || e === 'REFUSE') && m.showAudit || false,
  60 + // canAudit: e === 'AUDIT' && m.showExamine || false,
  61 + // canAuditDetail: !!e || false,
  62 + // }
  63 + // },
  64 + // displayButtons() {
  65 + // const f = this.statusFlags;
  66 + // console.log('displayButtons_f', f)
  67 + // return [
  68 + // { ...this.buttons[0], visible: f.canEdit && this.$auth.hasPermi('sample-order:follow-up-form:modify') },
  69 + // { ...this.buttons[1], visible: f.canAuditDetail && this.$auth.hasPermi('sample-order:follow-up-form:review') },
  70 + // { ...this.buttons[2], visible: f.canAudit && this.$auth.hasPermi('sample-order:follow-up-form:approve') },
  71 + // ]
  72 + // }
  73 + },
  74 + onLoad(query) {
  75 + const id = (query && (query.id || query.code)) || ''
  76 + if (id) {
  77 + this.loadDetail(id)
  78 + // this.loadAllDicData()
  79 + }
  80 + },
  81 + methods: {
  82 + async loadDetail(id) {
  83 + try {
  84 + const res = await getDetailApi(id)
  85 + this.form = res.data || {}
  86 + } catch (e) {
  87 + this.form = {}
  88 + }
  89 + },
  90 + handleButtonClick(btn) {
  91 + if (!btn || btn.disabled) return
  92 + const map = {
  93 + edit: () => this.onEdit(),
  94 + auditDetail: () => this.onAuditDetail(),
  95 + audit: () => this.onAudit(),
  96 + }
  97 + const fn = map[btn.event]
  98 + if (typeof fn === 'function') fn()
  99 + },
  100 + onEdit() {
  101 + const id = this.form.id || this.form.code
  102 + if (id) uni.navigateTo({ url: `/pages/follow_up_form/modify?id=${id}` })
  103 + },
  104 + onAuditDetail() {
  105 + uni.setStorageSync('sourceBusinessId', this.form.id)
  106 + uni.navigateTo({ url: '/pages/flow/audit_detail' })
  107 + },
  108 + onAudit() {
  109 + uni.setStorageSync('sourceBusinessId', this.form.id)
  110 + uni.navigateTo({ url: '/pages/flow/audit' })
  111 + },
  112 + downloadFile,
  113 + getDicName,
  114 + loadAllDicData() {
  115 + const dicCodes = ['SAMPLE_RESULT', 'SAMPLE_RESULT_SUB']
  116 + return getDicByCodes(dicCodes).then(results => {
  117 + this.dicOptions.SAMPLE_RESULT = results.SAMPLE_RESULT.data || []
  118 + this.dicOptions.SAMPLE_RESULT_SUB = results.SAMPLE_RESULT_SUB.data || []
  119 + this.sampleResultLocal = (this.dicOptions.SAMPLE_RESULT || []).map(it => ({
  120 + value: it.code,
  121 + text: it.name
  122 + }))
  123 + this.sampleResultSubLocal = (this.dicOptions.SAMPLE_RESULT_SUB || []).map(it => ({
  124 + value: it.code,
  125 + text: it.name
  126 + }))
  127 + }).catch(() => {
  128 + this.dicOptions = {
  129 + SAMPLE_RESULT: [],
  130 + SAMPLE_RESULT_SUB: []
  131 + }
  132 + this.sampleResultLocal = []
  133 + this.sampleResultSubLocal = []
  134 + })
  135 + },
  136 + }
  137 +}
  138 +</script>
  139 +
  140 +<style lang="scss" scoped>
  141 +.page {
  142 + display: flex;
  143 + flex-direction: column;
  144 + height: 100vh;
  145 +}
  146 +
  147 +.scroll {
  148 + flex: 1;
  149 + background: #f3f3f3;
  150 +}
  151 +
  152 +.detail-page {
  153 + padding-bottom: 20rpx;
  154 +}
  155 +
  156 +.section {
  157 + padding: 32rpx;
  158 + background: #fff;
  159 + margin-bottom: 20rpx;
  160 + position: relative;
  161 +
  162 + .status {
  163 + position: absolute;
  164 + top: 16rpx;
  165 + right: 52rpx;
  166 + width: 180rpx;
  167 + height: 146rpx;
  168 + background-repeat: no-repeat;
  169 + background-size: 100% 100%;
  170 + background-position: center;
  171 +
  172 + &_AUDIT {
  173 + background-image: url('~@/static/images/dev_manage/status_1.png');
  174 + }
  175 +
  176 + &_PASS {
  177 + background-image: url('~@/static/images/dev_manage/status_2.png');
  178 + }
  179 +
  180 + &_REFUSE {
  181 + background-image: url('~@/static/images/dev_manage/status_3.png');
  182 + }
  183 +
  184 + &_CANCEL {
  185 + background-image: url('~@/static/images/dev_manage/status_4.png');
  186 + }
  187 +
  188 + }
  189 +}
  190 +
  191 +.row {
  192 + display: flex;
  193 + margin-bottom: 28rpx;
  194 +
  195 + &:last-child {
  196 + margin-bottom: 0;
  197 + }
  198 +
  199 + &.company {
  200 + font-size: 36rpx;
  201 + font-weight: 600;
  202 + color: rgba(0, 0, 0, 0.9);
  203 + padding-top: 10rpx;
  204 + margin-bottom: 32rpx;
  205 + line-height: 50rpx;
  206 + }
  207 +
  208 + .label {
  209 + max-width: 400rpx;
  210 + margin-right: 20rpx;
  211 + line-height: 32rpx;
  212 + font-size: 28rpx;
  213 + color: rgba(0, 0, 0, 0.6);
  214 + }
  215 +
  216 + .value {
  217 + flex: 1;
  218 + line-height: 32rpx;
  219 + font-size: 28rpx;
  220 + color: rgba(0, 0, 0, 0.9);
  221 + text-align: right;
  222 + word-break: break-all;
  223 +
  224 + &.act {
  225 + color: $theme-primary;
  226 + }
  227 +
  228 + }
  229 +}
  230 +
  231 +.title-header {
  232 + background-color: #fff;
  233 + display: flex;
  234 + align-items: center;
  235 + padding: 32rpx 32rpx 22rpx;
  236 + border-bottom: 1rpx dashed #f0f0f0;
  237 +
  238 + &_icon {
  239 + width: 32rpx;
  240 + height: 28rpx;
  241 + margin-right: 16rpx;
  242 + }
  243 +
  244 + span {
  245 + color: rgba(0, 0, 0, 0.9);
  246 + font-size: 32rpx;
  247 + line-height: 44rpx;
  248 + font-weight: 600;
  249 + }
  250 +}
  251 +
  252 +.section2 {
  253 + background: #f1f1f1;
  254 + margin-bottom: 20rpx;
  255 +}
  256 +
  257 +
  258 +.section3 {
  259 + padding: 0 32rpx;
  260 + background-color: #fff;
  261 + margin: 20rpx 0;
  262 +}
  263 +
  264 +.view-total {
  265 + padding-bottom: 20rpx;
  266 +
  267 + .head {
  268 + font-size: 32rpx;
  269 + font-weight: 600;
  270 + line-height: 50rpx;
  271 + color: rgba(0, 0, 0, 0.9);
  272 + padding-bottom: 16rpx;
  273 + margin-bottom: 24rpx;
  274 + border-bottom: 1px dashed #E7E7E7;
  275 + }
  276 +
  277 + .row {
  278 + display: flex;
  279 + margin-bottom: 24rpx;
  280 + line-height: 32rpx;
  281 +
  282 + .row2 {
  283 + width: 50%;
  284 + }
  285 +
  286 + .label {
  287 + width: 180rpx;
  288 + margin-right: 14rpx;
  289 + color: rgba(0, 0, 0, 0.6);
  290 + font-size: 28rpx;
  291 + }
  292 +
  293 + .value {
  294 + flex: 1;
  295 + color: rgba(0, 0, 0, 0.9);
  296 + font-size: 28rpx;
  297 + white-space: pre-wrap;
  298 + word-break: break-all;
  299 + }
  300 + }
  301 +}
  302 +</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 +
  15 + <!-- 列表卡片组件 -->
  16 + <view class="list-box">
  17 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" row-key="id"
  18 + :enable-refresh="true" :enable-load-more="true" @loaded="onCardLoaded" @error="onCardError">
  19 + <template v-slot="{ item, selected }">
  20 + <view class="card" @click.stop="onCardClick(item)">
  21 + <view class="card-header">
  22 + <text class="title omit2">{{ item.customerName }}</text>
  23 + <!-- <text :class="['status', `status_${item.status}`]">{{ filterStatus(item.status) }}</text> -->
  24 + </view>
  25 + <view class="info-row">
  26 + <text>订单编号</text><text>{{ item.orderNo || '-' }}</text>
  27 + </view>
  28 + <view class="info-row">
  29 + <text>生产厂</text><text>{{ item.workshopName || '-' }}</text>
  30 + </view>
  31 + </view>
  32 + </template>
  33 + </card-list>
  34 + </view>
  35 +
  36 +
  37 +
  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-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  46 + v-model="model.workshopId" @change="onWorkshopChange" :localdata="workshopOptions" />
  47 + </view>
  48 + <!-- <view class="form-item">
  49 + <view class="label">审核状态</view>
  50 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  51 + v-model="model.status" @change="onStatusChange" :localdata="statusLocal" />
  52 + </view> -->
  53 + <!-- <view class="form-item">
  54 + <view class="label">试样种类</view>
  55 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  56 + v-model="model.sampleType" @change="onSampleTypeChange" :localdata="sampleTypeLocal" />
  57 + </view>
  58 + <view class="form-item">
  59 + <view class="label">客户类型</view>
  60 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  61 + v-model="model.customerType" @change="onEnterpriseTypeChange" :localdata="enterpriseTypeLocal" />
  62 + </view> -->
  63 + </view>
  64 + </template>
  65 + </filter-modal>
  66 + </view>
  67 +</template>
  68 +
  69 +<script>
  70 +import CardList from '@/components/card/index.vue'
  71 +import FilterModal from '@/components/filter/index.vue'
  72 +import { workshopQueryApi } from '@/api/devManage.js'
  73 +import SingleSelectSheet from '@/components/single-select/index.vue'
  74 +import {
  75 + queryApi
  76 +} from '@/api/feedback_form.js'
  77 +import {
  78 + getDicByCodes
  79 +} from '@/utils/dic'
  80 +
  81 +export default {
  82 + components: {
  83 + CardList,
  84 + FilterModal,
  85 + SingleSelectSheet
  86 + },
  87 + data() {
  88 + return {
  89 + searchKeyword: '',
  90 + searchKeywordDebounced: '',
  91 + tabs: [],
  92 + // 给到 card 的筛选值
  93 + query: {
  94 + status: '',
  95 + workshopId: '',
  96 + },
  97 + extraParams: {},
  98 +
  99 + // 批量选择
  100 + rowKey: 'id',
  101 + currentItems: [],
  102 +
  103 + // 筛选弹框
  104 + filterVisible: false,
  105 + filterForm: {
  106 + status: '',
  107 + workshopId: '',
  108 + },
  109 + dicOptions: {
  110 + AUDIT_STATUS: [], // 审核
  111 + },
  112 + statusLocal: [],
  113 + workshopOptions: [],
  114 + }
  115 + },
  116 + computed: {
  117 + extraCombined() {
  118 + return {
  119 + searchKey: this.searchKeywordDebounced || undefined
  120 + }
  121 + }
  122 + },
  123 + watch: {
  124 + extraCombined: {
  125 + deep: true,
  126 + handler(v) {
  127 + this.extraParams = v
  128 + },
  129 + immediate: true
  130 + },
  131 +
  132 + },
  133 + created() {
  134 + // this.loadAllDicData()
  135 + this.loadWorkshopOptions()
  136 + },
  137 + onLoad() { },
  138 + // 页面触底兜底:当页面自身滚动到底部时,转调卡片组件加载更多
  139 + onReachBottom() {
  140 + if (this.$refs && this.$refs.cardRef && this.$refs.cardRef.onLoadMore) {
  141 + this.$refs.cardRef.onLoadMore()
  142 + }
  143 + },
  144 + beforeDestroy() {
  145 + if (this.searchDebounceTimer) {
  146 + clearTimeout(this.searchDebounceTimer)
  147 + this.searchDebounceTimer = null
  148 + }
  149 + },
  150 + methods: {
  151 + async loadWorkshopOptions() {
  152 + try {
  153 + const res = await workshopQueryApi({ pageIndex: 1, pageSize: 9999 })
  154 + const list = (res && res.data && res.data.datas) || []
  155 + this.workshopOptions = list.map(it => ({ text: it.name || it.workshopName || '', value: it.id || it.workshopId || '' }))
  156 + } catch (e) {
  157 + this.workshopOptions = []
  158 + }
  159 + },
  160 + onCardLoaded({
  161 + items
  162 + }) {
  163 + this.currentItems = items
  164 + },
  165 + onCardError() {
  166 + uni.showToast({
  167 + title: '列表加载失败',
  168 + icon: 'none'
  169 + })
  170 + },
  171 + // 输入实时搜索:1200ms 防抖,仅在停止输入超过阈值后刷新
  172 + onSearchInput(val) {
  173 + if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer)
  174 + this.searchDebounceTimer = setTimeout(() => {
  175 + this.searchKeywordDebounced = this.searchKeyword
  176 + this.searchDebounceTimer = null
  177 + }, 1200)
  178 + },
  179 + // uni-search-bar 确认搜索:更新关键字并触发 CardList 刷新
  180 + search(e) {
  181 + const val = e && e.value != null ? e.value : this.searchKeyword
  182 + this.searchKeyword = val
  183 + this.searchKeywordDebounced = val
  184 + },
  185 + onAdd() {
  186 + uni.navigateTo({
  187 + url: '/pages/follow_up_form/add'
  188 + })
  189 + },
  190 + openFilter() {
  191 + this.filterVisible = true
  192 + },
  193 + onFilterReset(payload) {
  194 + this.filterForm = payload
  195 + },
  196 + onFilterConfirm(payload) {
  197 + if ((payload.status === '' || payload.status == null) && this.filterForm.status !== '') {
  198 + payload.status = this.filterForm.status
  199 + }
  200 + this.query = {
  201 + ...payload
  202 + }
  203 + },
  204 + onStatusChange(e) {
  205 + const raw = e && e.detail && e.detail.value !== undefined ?
  206 + e.detail.value :
  207 + (e && e.value !== undefined ? e.value : '')
  208 + this.filterForm.status = raw
  209 + },
  210 +
  211 + onSampleTypeChange(e) {
  212 + const raw = e && e.detail && e.detail.value !== undefined ?
  213 + e.detail.value :
  214 + (e && e.value !== undefined ? e.value : '')
  215 + this.filterForm.sampleType = raw
  216 + },
  217 +
  218 + onEnterpriseTypeChange(e) {
  219 + const raw = e && e.detail && e.detail.value !== undefined ?
  220 + e.detail.value :
  221 + (e && e.value !== undefined ? e.value : '')
  222 + this.filterForm.customerType = raw
  223 + },
  224 +
  225 + // 列表接口(真实请求)
  226 + fetchList({
  227 + pageIndex,
  228 + pageSize,
  229 + query,
  230 + extra
  231 + }) {
  232 + const params = {
  233 + pageIndex,
  234 + pageSize,
  235 + ...extra,
  236 + ...query
  237 + }
  238 + if (this.searchKeywordDebounced) {
  239 + params.searchKey = this.searchKeywordDebounced
  240 + }
  241 + return queryApi(params)
  242 + .then(res => {
  243 + const _data = res.data || {};
  244 + const records = _data.datas || [];
  245 + const totalCount = _data.totalCount || 0;
  246 + const hasNext = _data.hasNext || false
  247 + return {
  248 + records,
  249 + totalCount,
  250 + hasNext
  251 + }
  252 + })
  253 + .catch(err => {
  254 + console.error('fetchList error', err)
  255 + this.onCardError()
  256 + return {
  257 + records: [],
  258 + totalCount: 0,
  259 + hasNext: false
  260 + }
  261 + })
  262 + },
  263 + loadAllDicData() {
  264 + const dicCodes = ['AUDIT_STATUS']
  265 + return getDicByCodes(dicCodes).then(results => {
  266 + this.dicOptions.AUDIT_STATUS = results.AUDIT_STATUS.data || []
  267 + this.statusLocal = (this.dicOptions.AUDIT_STATUS || []).map(it => ({
  268 + value: it.code,
  269 + text: it.name
  270 + }))
  271 + }).catch(() => {
  272 + this.dicOptions = {
  273 + AUDIT_STATUS: [],
  274 + }
  275 + this.statusLocal = []
  276 + })
  277 + },
  278 + onCardClick(item) {
  279 + const id = (item && (item.id || item.code)) || ''
  280 + if (!id) return
  281 + const query = '?id=' + encodeURIComponent(id)
  282 + uni.navigateTo({
  283 + url: '/pages/feedback_form/detail' + query
  284 + })
  285 + },
  286 + onWorkshopChange(e) {
  287 + const raw = e && e.detail && e.detail.value !== undefined ? e.detail.value : (e && e.value !== undefined ? e.value : '')
  288 + this.filterForm.workshopId = raw
  289 + const match = (this.workshopOptions || []).find(o => String(o.value) === String(raw))
  290 + this.filterForm.workshopIdName = match ? (match.text || '') : ''
  291 + },
  292 + filterStatus(status) {
  293 + const _item = this.statusLocal.filter(item => item.value === status)[0] || {};
  294 + return _item.text || '';
  295 + },
  296 + }
  297 +}
  298 +</script>
  299 +
  300 +<style lang="scss" scoped>
  301 +.page {
  302 + display: flex;
  303 + flex-direction: column;
  304 + height: 100vh;
  305 +}
  306 +
  307 +.dev-list-fixed {
  308 + position: fixed;
  309 + top: 96rpx;
  310 + left: 0;
  311 + right: 0;
  312 + z-index: 2;
  313 + background: #fff;
  314 +
  315 + .search-row {
  316 + display: flex;
  317 + align-items: center;
  318 + padding: 16rpx 32rpx;
  319 +
  320 + .uni-searchbar {
  321 + padding: 0;
  322 + flex: 1;
  323 + }
  324 +
  325 + .tool-icons {
  326 + display: flex;
  327 +
  328 + .tool-icon {
  329 + width: 48rpx;
  330 + height: 48rpx;
  331 + display: block;
  332 + margin-left: 32rpx;
  333 + }
  334 + }
  335 + }
  336 +
  337 +}
  338 +
  339 +/* 仅当前页覆盖 uni-search-bar 盒子高度 */
  340 +::v-deep .uni-searchbar__box {
  341 + height: 80rpx !important;
  342 + justify-content: start;
  343 +
  344 + .uni-searchbar__box-search-input {
  345 + font-size: 32rpx !important;
  346 + }
  347 +}
  348 +
  349 +.list-box {
  350 + flex: 1;
  351 + padding-top: 140rpx;
  352 +
  353 + &.pad-batch {
  354 + padding-bottom: 144rpx;
  355 + }
  356 +
  357 + .card {
  358 + position: relative;
  359 + }
  360 +
  361 + .card-header {
  362 + margin-bottom: 28rpx;
  363 + position: relative;
  364 +
  365 + .title {
  366 + font-size: 36rpx;
  367 + font-weight: 600;
  368 + line-height: 50rpx;
  369 + color: rgba(0, 0, 0, 0.9);
  370 + width: 578rpx;
  371 + }
  372 +
  373 + .status {
  374 + font-weight: 600;
  375 + position: absolute;
  376 + top: -32rpx;
  377 + right: -12rpx;
  378 + height: 48rpx;
  379 + line-height: 48rpx;
  380 + color: #fff;
  381 + font-size: 24rpx;
  382 + padding: 0 14rpx;
  383 + border-radius: 6rpx;
  384 +
  385 + // 审核中
  386 + &.status_AUDIT {
  387 + background: $theme-primary;
  388 + }
  389 +
  390 + // 审核通过
  391 + &.status_PASS {
  392 + background: #2BA471;
  393 + }
  394 +
  395 + // 已驳回
  396 + &.status_REFUSE {
  397 + background: #d54941;
  398 + }
  399 +
  400 + // 已取消
  401 + &.status_CANCEL {
  402 + background: #e7e7e7;
  403 + color: rgba(0, 0, 0, 0.6);
  404 + }
  405 +
  406 + }
  407 +
  408 + }
  409 +
  410 + .info-row {
  411 + display: flex;
  412 + align-items: center;
  413 + color: rgba(0, 0, 0, 0.6);
  414 + font-size: 28rpx;
  415 + margin-bottom: 24rpx;
  416 +
  417 + &:last-child {
  418 + margin-bottom: 0;
  419 + }
  420 +
  421 + text {
  422 + width: 60%;
  423 + line-height: 32rpx;
  424 +
  425 + &:last-child {
  426 + color: rgba(0, 0, 0, 0.9);
  427 + width: 40%;
  428 + }
  429 +
  430 + &.category {
  431 + display: inline-block;
  432 + padding: 4rpx 12rpx;
  433 + border-radius: 6rpx;
  434 + font-size: 24rpx;
  435 + width: auto;
  436 +
  437 + &.category_A {
  438 + background: #FFF0ED;
  439 + color: #D54941;
  440 + }
  441 +
  442 + &.category_B {
  443 + background: #FFF1E9;
  444 + color: #E37318;
  445 + }
  446 +
  447 + &.category_C {
  448 + background: #F2F3FF;
  449 + color: $theme-primary;
  450 + }
  451 +
  452 + &.category_D {
  453 + background: #E3F9E9;
  454 + color: #2BA471;
  455 + }
  456 + }
  457 + }
  458 +
  459 + }
  460 +}
  461 +
  462 +.filter-form {
  463 + .form-item {
  464 + margin-bottom: 24rpx;
  465 + }
  466 +
  467 + .label {
  468 + margin-bottom: 20rpx;
  469 + color: rgba(0, 0, 0, 0.9);
  470 + height: 44rpx;
  471 + line-height: 44rpx;
  472 + font-size: 30rpx;
  473 + }
  474 +
  475 + .uni-easyinput {
  476 + border: 1rpx solid #f3f3f3;
  477 + }
  478 +
  479 +}
  480 +
  481 +/* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
  482 +::v-deep .filter-form .uni-data-checklist .checklist-group {
  483 + .checklist-box {
  484 + &.is--tag {
  485 + width: 212rpx;
  486 + margin-top: 0;
  487 + margin-bottom: 24rpx;
  488 + margin-right: 24rpx;
  489 + height: 80rpx;
  490 + padding: 0 20rpx;
  491 + border-radius: 12rpx;
  492 + background-color: #f3f3f3;
  493 + border-color: #f3f3f3;
  494 +
  495 + &:nth-child(3n) {
  496 + margin-right: 0;
  497 + }
  498 +
  499 + .checklist-content {
  500 + display: flex;
  501 + justify-content: center;
  502 + }
  503 +
  504 + .checklist-text {
  505 + color: rgba(0, 0, 0, 0.9);
  506 + font-size: 28rpx;
  507 + text-align: center;
  508 + }
  509 + }
  510 +
  511 + &.is-checked {
  512 + background-color: $theme-primary-plain-bg !important;
  513 + border-color: $theme-primary-plain-bg !important;
  514 +
  515 + .checklist-text {
  516 + color: $theme-primary !important;
  517 + }
  518 + }
  519 + }
  520 +
  521 +}
  522 +</style>
... ...
  1 +<template>
  2 + <view class="product">
  3 +
  4 + <!-- 新增&详情-产品 -->
  5 + <view class="header bp">
  6 + <image class="opCollapse" src="/static/images/title.png" />
  7 + <text class="title">{{ title || '产品' }}</text>
  8 + <view class="ops">
  9 + <!-- <image v-if="mode === 'add'" class="opAdd" @click="onAdd" src="/static/images/plus.png" /> -->
  10 + <view v-if="mode === 'view'" class="op1" @click="toggleViewCollapse">
  11 + <image class="opAdd" :src="collapsedView ? '/static/images/down.png' : '/static/images/up.png'" />
  12 + <text class="op">{{ collapsedView ? '展开' : '收起' }} </text>
  13 + </view>
  14 +
  15 + </view>
  16 + </view>
  17 +
  18 + <view v-if="mode === 'add'" class="section">
  19 + <view v-for="(item, idx) in items" :key="'a-' + idx" class="block">
  20 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  21 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  22 + <view class="row row-spec"><text class="label">规格(mm)</text>
  23 + <view class="value value-spec">
  24 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  25 + <view v-if="item.thickness" class="value-spec_box">
  26 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+' + item.thicknessTolPos : item.thicknessTolPos }}
  27 + </view>
  28 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+' + item.thicknessTolNeg : item.thicknessTolNeg }}
  29 + </view>
  30 + </view>
  31 + <view v-if="item.width" class="value-spec_val p12">*</view>
  32 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  33 + <view v-if="item.width" class="value-spec_box">
  34 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  35 + item.widthTolPos : item.widthTolPos }}</view>
  36 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  37 + item.widthTolNeg : item.widthTolNeg }}</view>
  38 + </view>
  39 + <view v-if="item.length" class="value-spec_val p12">*</view>
  40 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  41 + <view v-if="item.length" class="value-spec_box">
  42 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  43 + item.lengthTolPos : item.lengthTolPos }}</view>
  44 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  45 + item.lengthTolNeg : item.lengthTolNeg }}</view>
  46 + </view>
  47 + </view>
  48 + </view>
  49 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  50 + <view v-show="!item.collapsed">
  51 +
  52 + <view class="row" :class="{ 'noneStyle': !item.showSalesPrice }"><text
  53 + class="label">数量kg</text><text class="value">{{ item.quantity }}</text>
  54 + </view>
  55 +
  56 + <uni-list class="edit-list">
  57 + <uni-list-item class="select-item"
  58 + :class="item.provideSamplesName ? 'is-filled' : 'is-empty'" clickable
  59 + @click="openProductSheet(idx, 'provideSamples')"
  60 + :rightText="item.provideSamplesName || '请选择是否提供样品'" showArrow>
  61 + <template v-slot:body>
  62 + <view class="item-title"><text>是否提供样品</text></view>
  63 + </template>
  64 + </uni-list-item>
  65 + <uni-list-item class="select-item"
  66 + :class="item.clearParametersName ? 'is-filled' : 'is-empty'" clickable
  67 + @click="openProductSheet(idx, 'clearParameters')"
  68 + :rightText="item.clearParametersName || '请选择是否提供明确参数'" showArrow>
  69 + <template v-slot:body>
  70 + <view class="item-title"><text>是否提供明确参数</text></view>
  71 + </template>
  72 + </uni-list-item>
  73 + </uni-list>
  74 + </view>
  75 +
  76 + <view class="block-ops">
  77 + <div class="toggle" @click="toggleItem(idx)">
  78 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'"
  79 + class="icon" />
  80 + {{ item.collapsed ? '展开' : '收起' }}
  81 + </div>
  82 + </view>
  83 + </view>
  84 + </view>
  85 +
  86 + <view v-else-if="mode === 'view'" class="view-list" v-show="!collapsedView">
  87 + <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
  88 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  89 + <!-- 厚(公差) * 宽(公差) * 长(公差) -->
  90 + <view class="row row-spec"><text class="label">规格(mm)</text>
  91 + <view class="value value-spec">
  92 + <view v-if="item.thickness" class="value-spec_val">{{ item.thickness }}</view>
  93 + <view v-if="item.thickness" class="value-spec_box">
  94 + <view v-if="item.thicknessTolPos" class="value-spec_box_1">{{ item.thicknessTolPos > 0 ? '+'
  95 + +
  96 + item.thicknessTolPos : item.thicknessTolPos }}
  97 + </view>
  98 + <view v-if="item.thicknessTolNeg" class="value-spec_box_2">{{ item.thicknessTolNeg > 0 ? '+'
  99 + +
  100 + item.thicknessTolNeg : item.thicknessTolNeg }}
  101 + </view>
  102 + </view>
  103 + <view v-if="item.width" class="value-spec_val p12">*</view>
  104 + <view v-if="item.width" class="value-spec_val">{{ item.width }}</view>
  105 + <view v-if="item.width" class="value-spec_box">
  106 + <view v-if="item.widthTolPos" class="value-spec_box_1">{{ item.widthTolPos > 0 ? '+' +
  107 + item.widthTolPos : item.widthTolPos }}
  108 + </view>
  109 + <view v-if="item.widthTolNeg" class="value-spec_box_2">{{ item.widthTolNeg > 0 ? '+' +
  110 + item.widthTolNeg : item.widthTolNeg }}
  111 + </view>
  112 + </view>
  113 + <view v-if="item.length" class="value-spec_val p12">*</view>
  114 + <view v-if="item.length" class="value-spec_val">{{ item.length }}</view>
  115 + <view v-if="item.length" class="value-spec_box">
  116 + <view v-if="item.lengthTolPos" class="value-spec_box_1">{{ item.lengthTolPos > 0 ? '+' +
  117 + item.lengthTolPos : item.lengthTolPos }}
  118 + </view>
  119 + <view v-if="item.lengthTolNeg" class="value-spec_box_2">{{ item.lengthTolNeg > 0 ? '+' +
  120 + item.lengthTolNeg : item.lengthTolNeg }}
  121 + </view>
  122 + </view>
  123 + </view>
  124 + </view>
  125 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  126 + <view class="row"><text class="label">发货日期</text><text class="value">{{ item.shipmentDate }}</text></view>
  127 + <view class="row"><text class="label">数量(kg)</text><text class="value">{{ item.quantity }}</text></view>
  128 + <view class="row"><text class="label">产量批次号</text><text class="value">{{ item.yieldBatchNo }}</text></view>
  129 + </view>
  130 + </view>
  131 +
  132 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value" @confirm="onProductConfirm" />
  133 + </view>
  134 +</template>
  135 +<script>
  136 +import { uuid } from '@/utils/uuid.js'
  137 +import SingleSelectSheet from '@/components/single-select/index.vue'
  138 +export default {
  139 + name: 'Product',
  140 + props: {
  141 + title: { type: String, default: '' },
  142 + mode: { type: String, default: 'add' },
  143 + list: { type: Array, default: () => [] },
  144 + max: { type: Number, default: 8 },
  145 + provideSamplesOptions: { type: Array, default: () => [] },
  146 + clearParametersOptions: { type: Array, default: () => [] },
  147 + },
  148 + components: { SingleSelectSheet },
  149 + data() {
  150 + return {
  151 + items: [],
  152 + collapsedView: false,
  153 + roleCodes: [],
  154 + sheet: { visible: false, title: '请选择产品', options: [], value: '', idx: -1, mode: '' }
  155 + }
  156 + },
  157 + computed: {
  158 + minDeliveryDate() {
  159 + const s = this.orderDate
  160 + if (!s) return ''
  161 + const parts = String(s).split('-')
  162 + const y = Number(parts[0])
  163 + const m = Number(parts[1])
  164 + const d = Number(parts[2])
  165 + if (!y || !m || !d) return ''
  166 + const dt = new Date(y, m - 1, d)
  167 + dt.setDate(dt.getDate() + 1)
  168 + const yy = dt.getFullYear()
  169 + const mm = String(dt.getMonth() + 1).padStart(2, '0')
  170 + const dd = String(dt.getDate()).padStart(2, '0')
  171 + return `${yy}/${mm}/${dd}`
  172 + },
  173 + // roleCodes() {
  174 + // const g = this.$store && this.$store.getters
  175 + // return (g && g.roleCodes) || [];
  176 + // },
  177 + },
  178 + watch: {
  179 + items: {
  180 + handler() { this.emitChange() },
  181 + deep: true
  182 + },
  183 + list: {
  184 + handler(v) {
  185 + const arr = Array.isArray(v) ? v : []
  186 + this.items = arr.map(x => {
  187 + const it = { ...this.defaultItem(), ...x, collapsed: true }
  188 + return it
  189 + })
  190 + },
  191 + deep: true
  192 + },
  193 + },
  194 + created() {
  195 + const init = Array.isArray(this.list) && this.list.length > 0 ? this.list.map(v => ({ ...this.defaultItem(), ...v, collapsed: false })) : [{ ...this.defaultItem(), collapsed: false }]
  196 + this.items = init;
  197 + },
  198 + methods: {
  199 + defaultItem() {
  200 + return {
  201 + purchaseOrderId: uuid(),
  202 + collapsed: false,
  203 + id: '',
  204 + // 厚度公差
  205 + thicknessTolPos: '',
  206 + thicknessTolNeg: '',
  207 + // 宽度公差
  208 + widthTolPos: '',
  209 + widthTolNeg: '',
  210 + // 长度公差
  211 + lengthTolPos: '',
  212 + lengthTolNeg: '',
  213 + // 其他字段
  214 + industry: '',
  215 + quality: '',
  216 + brand: '',
  217 + thickness: '',
  218 + width: '',
  219 + length: '',
  220 + status: '',
  221 + quantity: '',
  222 + shippedQuantity: '',
  223 + supplementaryQuantity: '',
  224 + confirmedDeliveryDate: '',
  225 + remarks: '',
  226 + }
  227 + },
  228 +
  229 + onAdd() {
  230 + const obj = this.defaultItem()
  231 + obj.collapsed = true
  232 + this.items.push(obj)
  233 + this.emitChange()
  234 + },
  235 + onRemove(id) {
  236 + if (!id) return
  237 + uni.showModal({
  238 + title: '系统提示',
  239 + content: '是否确定删除选中的产品?',
  240 + confirmText: '确定',
  241 + cancelText: '取消',
  242 + success: (res) => {
  243 + if (res && res.confirm) {
  244 + const i = this.items.findIndex(it => String(it.purchaseOrderId) === String(id))
  245 + if (i >= 0) {
  246 + this.items.splice(i, 1)
  247 + this.emitChange()
  248 + }
  249 + }
  250 + }
  251 + })
  252 + },
  253 + toggleItem(idx) {
  254 + const it = this.items[idx]
  255 + if (!it) return
  256 + it.collapsed = !it.collapsed
  257 + this.$set(this.items, idx, it)
  258 + },
  259 + emitChange() {
  260 + const out = this.items.map(it => ({ ...it }))
  261 + this.$emit('input', out)
  262 + this.$emit('update:value', out)
  263 + this.$emit('change', out)
  264 + },
  265 + onNonNegativeNumberInput(val, item, idx, field) {
  266 + let v = String(val != null ? val : (item && item[field]) || '')
  267 + v = v.replace(/[^0-9.]/g, '')
  268 + v = v.replace(/(\..*)\./g, '$1')
  269 + if (v.startsWith('.')) v = '0' + v
  270 + if (v === '') { item[field] = ''; if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  271 + const num = Number(v)
  272 + if (isNaN(num) || num < 0) {
  273 + item[field] = '0'
  274 + } else {
  275 + item[field] = v
  276 + }
  277 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  278 + },
  279 + onNonNegativeNumberBlur(item, idx, field) {
  280 + const v = String((item && item[field]) || '')
  281 + const num = Number(v)
  282 + if (isNaN(num) || num < 0) item[field] = '0'
  283 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  284 + },
  285 + onRealNumberInput(val, item, idx, field) {
  286 + let s = String(val != null ? val : (item && item[field]) || '')
  287 + const neg = s.trim().startsWith('-')
  288 + s = s.replace(/[^0-9.\-]/g, '')
  289 + s = s.replace(/(?!^)-/g, '')
  290 + s = s.replace(/(\..*)\./g, '$1')
  291 + if (s.startsWith('.')) s = '0' + s
  292 + if (s.startsWith('-.')) s = '-0.' + s.slice(2)
  293 + if (neg && !s.startsWith('-')) s = '-' + s.replace(/-/g, '')
  294 + item[field] = s
  295 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  296 + },
  297 + onRealNumberBlur(item, idx, field) {
  298 + const s = String((item && item[field]) || '')
  299 + if (s === '') { if (typeof idx === 'number') this.$set(this.items, idx, { ...item }); return }
  300 + const n = Number(s)
  301 + if (isNaN(n)) item[field] = ''
  302 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  303 + },
  304 + // 限制输入为2位小数
  305 + onTwoDecimalInput(val, item, idx, field) {
  306 + let v = String(val != null ? val : (item && item[field]) || '')
  307 + v = v.replace(/[^0-9.]/g, '')
  308 + v = v.replace(/(\..*)\./g, '$1')
  309 +
  310 + // Restrict to 2 decimal places
  311 + const decimalIndex = v.indexOf('.')
  312 + if (decimalIndex !== -1 && v.length > decimalIndex + 3) {
  313 + v = v.substring(0, decimalIndex + 3)
  314 + }
  315 +
  316 + if (v.startsWith('.')) v = '0' + v
  317 +
  318 + // If the value was modified (truncated or cleaned)
  319 + if (String(val) !== v) {
  320 + // Hack: Temporarily set the dirty value to trigger Vue update mechanism
  321 + // This ensures that when we set the clean value back, Vue detects a change
  322 + item[field] = val
  323 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  324 +
  325 + // Then revert to the clean value asynchronously
  326 + setTimeout(() => {
  327 + item[field] = v
  328 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  329 + }, 0)
  330 + } else {
  331 + item[field] = v
  332 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  333 + }
  334 + },
  335 + onTwoDecimalBlur(item, idx, field) {
  336 + let v = String((item && item[field]) || '')
  337 + const num = Number(v)
  338 + if (isNaN(num) || num < 0) {
  339 + item[field] = '0'
  340 + } else {
  341 + if (v.endsWith('.')) {
  342 + item[field] = v.slice(0, -1)
  343 + }
  344 + }
  345 + if (typeof idx === 'number') this.$set(this.items, idx, { ...item })
  346 + },
  347 + toggleViewCollapse() {
  348 + this.collapsedView = !this.collapsedView
  349 + },
  350 + onDeliveryChange(e, item, idx) {
  351 + const getStr = (x) => {
  352 + if (x && x.detail && x.detail.value !== undefined) return x.detail.value
  353 + if (typeof x === 'string') return x
  354 + return item && item.deliveryDate ? item.deliveryDate : ''
  355 + }
  356 + const val = getStr(e)
  357 + if (!val || !this.orderDate) return
  358 + const parse = (s) => {
  359 + const p = String(s).replace(/\//g, '-').split('-')
  360 + const y = Number(p[0])
  361 + const m = Number(p[1])
  362 + const d = Number(p[2])
  363 + return new Date(y, m - 1, d)
  364 + }
  365 + const sel = parse(val)
  366 + const ord = parse(this.orderDate)
  367 + if (!(sel > ord)) {
  368 + item.deliveryDate = ''
  369 + this.$set(this.items, idx, { ...item })
  370 + uni.showToast({ title: '发货日期必须大于订货日期', icon: 'none' })
  371 + }
  372 + },
  373 + openProductSheet(idx, mode = 'provideSamples') {
  374 + let opts = []
  375 + let title = ''
  376 + let value = ''
  377 + const item = this.items[idx]
  378 +
  379 + if (mode === 'provideSamples') {
  380 + opts = this.provideSamplesOptions
  381 + value = item.provideSamples
  382 + title = '选择是否提供样品'
  383 + } else if (mode === 'clearParameters') {
  384 + opts = this.clearParametersOptions;
  385 + value = item.clearParameters
  386 + title = '是否提供明确参数'
  387 + }
  388 + console.log('____', { ...this.sheet, visible: true, title, options: opts, idx, value, mode })
  389 + this.sheet = { ...this.sheet, visible: true, title, options: opts, idx, value, mode }
  390 + },
  391 + onProductConfirm({ value, label }) {
  392 + const idx = this.sheet.idx
  393 + const _mode = this.sheet.mode;
  394 + const it = this.items[idx]
  395 + if (!it) { this.sheet.visible = false; return }
  396 + it[_mode] = value
  397 + it[_mode + 'Name'] = label || ''
  398 + this.$set(this.items, idx, it)
  399 + this.sheet.visible = false
  400 + this.emitChange()
  401 + },
  402 + }
  403 +}
  404 +</script>
  405 +<style lang="scss" scoped>
  406 +.header {
  407 + background-color: #fff;
  408 + display: flex;
  409 + align-items: center;
  410 + padding: 24rpx 32rpx;
  411 +
  412 + &.bp {
  413 + border-bottom: 1px solid #f0f0f0;
  414 + }
  415 +}
  416 +
  417 +.dot {
  418 + width: 16rpx;
  419 + height: 16rpx;
  420 + background: #3D48A3;
  421 + border-radius: 50%;
  422 + margin-right: 12rpx;
  423 +}
  424 +
  425 +.title {
  426 + font-size: 32rpx;
  427 + color: rgba(0, 0, 0, 0.9);
  428 + font-weight: 600;
  429 +}
  430 +
  431 +.ops {
  432 + margin-left: auto;
  433 +}
  434 +
  435 +.op {
  436 + color: $theme-primary;
  437 + font-size: 28rpx;
  438 + margin-left: 8rpx;
  439 +}
  440 +
  441 +.op1 {
  442 + display: flex;
  443 + align-items: center;
  444 +}
  445 +
  446 +.opAdd {
  447 + color: rgba(0, 0, 0, 0.6);
  448 + width: 40rpx;
  449 + height: 40rpx;
  450 +}
  451 +
  452 +.opCollapse {
  453 + color: rgba(0, 0, 0, 0.6);
  454 + width: 32rpx;
  455 + height: 28rpx;
  456 + margin-right: 16rpx;
  457 +}
  458 +
  459 +::v-deep .uni-list {
  460 + background: transparent;
  461 +
  462 + .uni-list--border-top {
  463 + background-color: transparent !important;
  464 + }
  465 +
  466 + &-item {
  467 + &__extra-text {
  468 + font-size: 32rpx;
  469 + }
  470 +
  471 + &__content-title {
  472 + font-size: 32rpx;
  473 + color: rgba(0, 0, 0, 0.9);
  474 + }
  475 +
  476 + &__container {
  477 + padding: 32rpx;
  478 +
  479 + .uni-easyinput {
  480 +
  481 + .is-disabled {
  482 + background-color: transparent !important;
  483 + }
  484 +
  485 + &__placeholder-class {
  486 + font-size: 32rpx;
  487 + color: rgba(0, 0, 0, 0.4);
  488 + }
  489 +
  490 + &__content {
  491 + border: none;
  492 +
  493 + &-input {
  494 + padding-left: 0 !important;
  495 + height: 48rpx;
  496 + line-height: 48rpx;
  497 + font-size: 32rpx;
  498 + }
  499 +
  500 + .content-clear-icon {
  501 + font-size: 44rpx !important;
  502 + }
  503 + }
  504 + }
  505 +
  506 + .amount-row {
  507 + flex: 1;
  508 + display: flex;
  509 + align-items: center;
  510 +
  511 + .uni-easyinput {
  512 + flex: 1;
  513 + }
  514 +
  515 + .unit {
  516 + margin-left: 16rpx;
  517 + color: rgba(0, 0, 0, 0.9);
  518 + }
  519 + }
  520 +
  521 + .item-title,
  522 + .uni-list-item__content {
  523 + flex: none;
  524 + min-height: 48rpx;
  525 + line-height: 48rpx;
  526 + font-size: 32rpx;
  527 + position: relative;
  528 + width: 210rpx;
  529 + margin-right: 32rpx;
  530 + color: rgba(0, 0, 0, 0.9);
  531 + padding-right: 0;
  532 +
  533 +
  534 + .required {
  535 + color: red;
  536 + position: absolute;
  537 + top: 50%;
  538 + transform: translateY(-50%);
  539 + left: -16rpx;
  540 + }
  541 + }
  542 +
  543 + }
  544 +
  545 + &.select-item {
  546 + &.is-empty {
  547 + .uni-list-item__extra-text {
  548 + color: rgba(0, 0, 0, 0.4) !important;
  549 + }
  550 + }
  551 +
  552 + &.is-filled {
  553 + .uni-list-item__extra-text {
  554 + color: rgba(0, 0, 0, 0.9) !important;
  555 + }
  556 + }
  557 +
  558 + .serial-number-row {
  559 + display: flex;
  560 + align-items: center;
  561 + }
  562 +
  563 + }
  564 +
  565 + &.mgb10 {
  566 + margin-bottom: 20rpx;
  567 + }
  568 +
  569 + }
  570 +
  571 + .title-header {
  572 + background-color: #fff;
  573 + display: flex;
  574 + align-items: center;
  575 + padding: 32rpx 32rpx 22rpx;
  576 +
  577 + &_icon {
  578 + width: 32rpx;
  579 + height: 28rpx;
  580 + margin-right: 16rpx;
  581 + }
  582 +
  583 + span {
  584 + color: rgba(0, 0, 0, 0.9);
  585 + font-size: 32rpx;
  586 + line-height: 44rpx;
  587 + font-weight: 600;
  588 + }
  589 + }
  590 +}
  591 +
  592 +/* 只读 easyinput 根据内容自适应高度 */
  593 +::v-deep .uni-list-item__container {
  594 + align-items: flex-start;
  595 +}
  596 +
  597 +.block-ops {
  598 + display: flex;
  599 + padding: 20rpx 32rpx 20rpx;
  600 + justify-content: space-around;
  601 +}
  602 +
  603 +.del {
  604 + color: #D54941;
  605 + font-size: 28rpx;
  606 + display: flex;
  607 + align-items: center;
  608 +
  609 + image {
  610 + width: 40rpx;
  611 + height: 40rpx;
  612 + }
  613 +}
  614 +
  615 +.toggle {
  616 + color: $theme-primary;
  617 + font-size: 28rpx;
  618 + display: flex;
  619 + align-items: center;
  620 +
  621 + image {
  622 + width: 40rpx;
  623 + height: 40rpx;
  624 + }
  625 +}
  626 +
  627 +.section {
  628 + background: #f1f1f1;
  629 + margin-bottom: 20rpx;
  630 +
  631 + .block {
  632 + background: #ffffff;
  633 + // padding: 32rpx 0;
  634 + margin-bottom: 20rpx;
  635 +
  636 + &:last-child {
  637 + margin-bottom: 0;
  638 + }
  639 + }
  640 +
  641 + .row {
  642 + display: flex;
  643 + // margin-bottom: 24rpx;
  644 + line-height: 32rpx;
  645 + padding: 32rpx;
  646 + border-bottom: 1rpx solid #f2f2f2 !important;
  647 +
  648 +
  649 + &.noneStyle {
  650 + border-bottom: 0;
  651 + border-bottom: none;
  652 + }
  653 +
  654 + &.row-spec {
  655 + align-items: center;
  656 + }
  657 + }
  658 +
  659 + .row:last-child {
  660 + margin-bottom: 0;
  661 + }
  662 +
  663 + .label {
  664 + width: 210rpx;
  665 + margin-right: 32rpx;
  666 + color: rgba(0, 0, 0, 0.9);
  667 + font-size: 32rpx;
  668 + line-height: 48rpx;
  669 + }
  670 +
  671 + .value {
  672 + flex: 1;
  673 + color: rgba(0, 0, 0, 0.9);
  674 + font-size: 32rpx;
  675 + white-space: pre-wrap;
  676 + word-break: break-all;
  677 + line-height: 48rpx;
  678 + }
  679 +
  680 + .value-spec {
  681 + height: 48rpx;
  682 + display: flex;
  683 + align-items: center;
  684 + color: #000000;
  685 +
  686 + &_box {
  687 + position: relative;
  688 + width: 60rpx;
  689 + height: 48rpx;
  690 +
  691 + &_1 {
  692 + font-size: 16rpx;
  693 + position: absolute;
  694 + top: -10rpx;
  695 + left: 0;
  696 + }
  697 +
  698 + &_2 {
  699 + font-size: 16rpx;
  700 + position: absolute;
  701 + bottom: -10rpx;
  702 + left: 0;
  703 + }
  704 + }
  705 +
  706 + &_val {
  707 + font-size: 28rpx;
  708 +
  709 + &.p12 {
  710 + padding-right: 12rpx;
  711 + }
  712 + }
  713 + }
  714 +
  715 + .view-total {
  716 + padding-top: 20rpx;
  717 +
  718 + .head {
  719 + font-size: 32rpx;
  720 + font-weight: 600;
  721 + line-height: 50rpx;
  722 + color: rgba(0, 0, 0, 0.9);
  723 + padding-bottom: 16rpx;
  724 + margin-bottom: 24rpx;
  725 + border-bottom: 1px dashed #E7E7E7;
  726 + }
  727 +
  728 + .row {
  729 + display: flex;
  730 + margin-bottom: 24rpx;
  731 + line-height: 32rpx;
  732 +
  733 + .label {
  734 + width: 180rpx;
  735 + margin-right: 14rpx;
  736 + color: rgba(0, 0, 0, 0.6);
  737 + font-size: 28rpx;
  738 + }
  739 +
  740 + .value {
  741 + flex: 1;
  742 + color: rgba(0, 0, 0, 0.9);
  743 + font-size: 28rpx;
  744 + white-space: pre-wrap;
  745 + word-break: break-all;
  746 + }
  747 + }
  748 + }
  749 +}
  750 +
  751 +
  752 +.view-list {
  753 + padding: 26rpx 32rpx;
  754 + background: #ffffff;
  755 +
  756 + .card {
  757 + background: #f3f3f3;
  758 + border-radius: 16rpx;
  759 + padding: 32rpx 44rpx;
  760 + margin-bottom: 20rpx;
  761 +
  762 + &:last-child {
  763 + margin-bottom: 0;
  764 + }
  765 + }
  766 +
  767 + .row {
  768 + display: flex;
  769 + margin-bottom: 24rpx;
  770 + line-height: 32rpx;
  771 +
  772 + &.row-spec {
  773 + height: 60rpx;
  774 + align-items: center;
  775 + }
  776 + }
  777 +
  778 + .row:last-child {
  779 + margin-bottom: 0;
  780 + }
  781 +
  782 + .label {
  783 + width: 200rpx;
  784 + margin-right: 14rpx;
  785 + color: rgba(0, 0, 0, 0.6);
  786 + font-size: 28rpx;
  787 + }
  788 +
  789 + .value {
  790 + flex: 1;
  791 + color: rgba(0, 0, 0, 0.9);
  792 + font-size: 28rpx;
  793 + white-space: pre-wrap;
  794 + word-break: break-all;
  795 + }
  796 +
  797 + .value-spec {
  798 + height: 60rpx;
  799 + display: flex;
  800 + align-items: center;
  801 + color: #000000;
  802 +
  803 + &_box {
  804 + position: relative;
  805 + width: 60rpx;
  806 + height: 60rpx;
  807 +
  808 + &_1 {
  809 + font-size: 16rpx;
  810 + position: absolute;
  811 + top: 0;
  812 + left: 0;
  813 + }
  814 +
  815 + &_2 {
  816 + font-size: 16rpx;
  817 + position: absolute;
  818 + bottom: 0;
  819 + left: 0;
  820 + }
  821 + }
  822 +
  823 + &_val {
  824 + font-size: 28rpx;
  825 +
  826 + &.p12 {
  827 + padding-right: 12rpx;
  828 + }
  829 + }
  830 + }
  831 +
  832 + .view-total {
  833 + padding-top: 20rpx;
  834 +
  835 + .head {
  836 + font-size: 32rpx;
  837 + font-weight: 600;
  838 + line-height: 50rpx;
  839 + color: rgba(0, 0, 0, 0.9);
  840 + padding-bottom: 16rpx;
  841 + margin-bottom: 24rpx;
  842 + border-bottom: 1px dashed #E7E7E7;
  843 + }
  844 +
  845 + .row {
  846 + display: flex;
  847 + margin-bottom: 24rpx;
  848 + line-height: 32rpx;
  849 +
  850 + .label {
  851 + width: 180rpx;
  852 + margin-right: 14rpx;
  853 + color: rgba(0, 0, 0, 0.6);
  854 + font-size: 28rpx;
  855 + }
  856 +
  857 + .value {
  858 + flex: 1;
  859 + color: rgba(0, 0, 0, 0.9);
  860 + font-size: 28rpx;
  861 + white-space: pre-wrap;
  862 + word-break: break-all;
  863 + }
  864 + }
  865 + }
  866 +}
  867 +</style>
... ...