Commit 55c682d5d3bbaa69b4214653d7603e83cc3fe485

Authored by gesilong
1 parent dca65249

commit: 合同新增/查看/编辑提交

... ... @@ -31,4 +31,55 @@ export function queryContractApi(params) {
31 31 method: 'get',
32 32 params
33 33 })
34   -}
\ No newline at end of file
  34 +}
  35 +
  36 +// 品种列表
  37 +export function productVarietyQuery(params) {
  38 + return request({
  39 + url: `/baseData/product/variety/query`,
  40 + method: 'get',
  41 + params
  42 + })
  43 +}
  44 +
  45 +// 客户查询编号
  46 +export function getCodeApi(params) {
  47 + return request({
  48 + url: `${baseUrl}/contractFramework/code`,
  49 + method: 'get',
  50 + params
  51 + })
  52 +}
  53 +
  54 +// 新增合同框架
  55 +export function createApi(data) {
  56 + return request({
  57 + url: `${baseUrl}/contractFramework`,
  58 + method: 'post',
  59 + data
  60 + })
  61 +}
  62 +
  63 +export function getDetailApi(id) {
  64 + return request({
  65 + url: `${baseUrl}/contractFramework`,
  66 + method: 'get',
  67 + params: { id }
  68 + })
  69 +}
  70 +
  71 +export function updateApi(data) {
  72 + return request({
  73 + url: `${baseUrl}/contractFramework`,
  74 + method: 'put',
  75 + data
  76 + })
  77 +}
  78 +
  79 +//获取经销标准合同编号
  80 +export function getRetailCodeApi() {
  81 + return request({
  82 + url: `${baseUrl}/contractDistributorStandard/code`,
  83 + method: 'get',
  84 + })
  85 +}
... ...
... ... @@ -114,13 +114,55 @@
114 114 "navigationBarTextStyle": "black"
115 115 }
116 116 }, {
117   - "path": "pages/contract_retail/index",
  117 + "path": "pages/contract_framework/add",
118 118 "style": {
119   - "navigationBarTitleText": "经销标准合同",
  119 + "navigationBarTitleText": "新增框架合同",
120 120 "navigationBarBackgroundColor": "#ffffff",
121 121 "navigationBarTextStyle": "black"
122 122 }
  123 + }, {
  124 + "path": "pages/contract_framework/detail",
  125 + "style": {
  126 + "navigationBarTitleText": "框架合同详情",
  127 + "navigationBarBackgroundColor": "#ffffff",
  128 + "navigationBarTextStyle": "black"
  129 + }
  130 + }, {
  131 + "path": "pages/contract_framework/modify",
  132 + "style": {
  133 + "navigationBarTitleText": "编辑框架合同",
  134 + "navigationBarBackgroundColor": "#ffffff",
  135 + "navigationBarTextStyle": "black"
  136 + }
  137 + },{
  138 + "path": "pages/contract_retail/index",
  139 + "style": {
  140 + "navigationBarTitleText": "经销标准合同",
  141 + "navigationBarBackgroundColor": "#ffffff",
  142 + "navigationBarTextStyle": "black"
  143 + }
123 144 }, {
  145 + "path": "pages/contract_retail/add",
  146 + "style": {
  147 + "navigationBarTitleText": "新增经销标准合同",
  148 + "navigationBarBackgroundColor": "#ffffff",
  149 + "navigationBarTextStyle": "black"
  150 + }
  151 + },{
  152 + "path": "pages/contract_retail/detail",
  153 + "style": {
  154 + "navigationBarTitleText": "经销标准合同详情",
  155 + "navigationBarBackgroundColor": "#ffffff",
  156 + "navigationBarTextStyle": "black"
  157 + }
  158 + },{
  159 + "path": "pages/contract_retail/modify",
  160 + "style": {
  161 + "navigationBarTitleText": "编辑经销标准合同",
  162 + "navigationBarBackgroundColor": "#ffffff",
  163 + "navigationBarTextStyle": "black"
  164 + }
  165 + },{
124 166 "path": "pages/contract_stock/index",
125 167 "style": {
126 168 "navigationBarTitleText": "经销库存合同",
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item title="框架合同编号">
  6 + <template v-slot:footer>
  7 + <uni-easyinput disabled v-model="form.code" :inputBorder="false" />
  8 + </template>
  9 + </uni-list-item>
  10 +
  11 + <uni-list-item class="select-item" :class="form.customerId ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openRelate('customerId')" :rightText="form.customerIdName || '请选择客户名称'" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text class="required">*</text><text>客户名称</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item class="select-item" :class="form.company ? 'is-filled' : 'is-empty'" clickable
  19 + @click="openSheet('company')" :rightText="displayLabel('companyName')" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text class="required">*</text><text>所属单位</text></view>
  22 + </template>
  23 + </uni-list-item>
  24 +
  25 + <uni-list-item class="select-item" :class="form.materialTypeId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openSheet('materialTypeId')" :rightText="displayLabel('materialTypeIdName')" showArrow>
  27 + <template v-slot:body>
  28 + <view class="item-title"><text class="required">*</text><text>品种</text></view>
  29 + </template>
  30 + </uni-list-item>
  31 +
  32 + <uni-list-item class="select-item" :class="form.hasFrameworkAgreementName ? 'is-filled' : 'is-empty'" clickable
  33 + @click="openSheet('hasFrameworkAgreement')" :rightText="displayLabel('hasFrameworkAgreementName')" showArrow>
  34 + <template v-slot:body>
  35 + <view class="item-title"><text class="required">*</text><text>是否签订框架合同</text></view>
  36 + </template>
  37 + </uni-list-item>
  38 +
  39 + <uni-list-item title="授信截止日期">
  40 + <template v-slot:footer>
  41 + <uni-datetime-picker type="date" v-model="form.validityTime" />
  42 + </template>
  43 + </uni-list-item>
  44 + </uni-list>
  45 + </scroll-view>
  46 +
  47 + <view class="footer">
  48 + <button class="btn submit" type="primary" @click="onSubmit">提交</button>
  49 + </view>
  50 +
  51 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  52 + @confirm="onSheetConfirm" />
  53 +
  54 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  55 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  56 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  57 + </view>
  58 +</template>
  59 +<script>
  60 +import SingleSelectSheet from '@/components/single-select/index.vue'
  61 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  62 +import { productVarietyQuery, getCodeApi, createApi } from '@/api/contract'
  63 +import { getDicByCodes } from '@/utils/dic'
  64 +
  65 +export default {
  66 + components: { SingleSelectSheet, RelateSelectSheet },
  67 + data() {
  68 + return {
  69 + form: {
  70 + code: '',
  71 + customerId: '',
  72 + customerIdName: '',
  73 + company: '',
  74 + companyName: '',
  75 + materialTypeId: '',
  76 + materialTypeIdName: '',
  77 + hasFrameworkAgreement: '',
  78 + hasFrameworkAgreementName: '',
  79 + validityTime: ''
  80 + },
  81 + productVarietyList: [],
  82 + companyList: [],
  83 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  84 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' }
  85 + }
  86 + },
  87 + created() {
  88 + this.loadCompanyList()
  89 + this.loadProductVariety()
  90 + },
  91 + watch: {
  92 + 'form.company'(val) {
  93 + if (!val) return
  94 + getCodeApi({ company: val }).then(res => {
  95 + console.log(res)
  96 + const code = (res && res.data) ? res.data : ''
  97 + this.form.code = code
  98 + })
  99 + }
  100 + },
  101 + methods: {
  102 + displayLabel(field) {
  103 + const m = this.form
  104 + const map = {
  105 + companyName: '请选择所属单位',
  106 + materialTypeIdName: '请选择品种',
  107 + hasFrameworkAgreementName: '请选择是否签订'
  108 + }
  109 + const val = m[field]
  110 + return val ? String(val) : map[field]
  111 + },
  112 + async loadCompanyList() {
  113 + try {
  114 + const results = await getDicByCodes(['SUPPLIER'])
  115 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  116 + this.companyList = items.map(it => ({ label: it.name, value: it.code }))
  117 + } catch (e) {
  118 + this.companyList = []
  119 + }
  120 + },
  121 + async loadProductVariety() {
  122 + try {
  123 + const res = await productVarietyQuery({ pageIndex: 1, pageSize: 9999 })
  124 + const list = (res.data && res.data.datas) ? res.data.datas : []
  125 + this.productVarietyList = list.map(it => ({ label: it.name, value: it.id }))
  126 + } catch (e) {
  127 + this.productVarietyList = []
  128 + }
  129 + },
  130 + openSheet(field) {
  131 + const setSheet = (title, options) => {
  132 + const current = this.form[field]
  133 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  134 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  135 + }
  136 + if (field === 'company') {
  137 + setSheet('所属单位', this.companyList)
  138 + } else if (field === 'materialTypeId') {
  139 + setSheet('品种', this.productVarietyList)
  140 + } else if (field === 'hasFrameworkAgreement') {
  141 + setSheet('是否签订框架合同', [{ label: '是', value: true }, { label: '否', value: false }])
  142 + }
  143 + },
  144 + onSheetConfirm({ value, label }) {
  145 + const field = this.sheet.field
  146 + if (!field) return
  147 + const v = (value === undefined || value === null) ? '' : value
  148 + this.form[field] = v
  149 + this.form[field + 'Name'] = label || ''
  150 + if (field === 'company' && value !== undefined && value !== null) {
  151 + getCodeApi({ company: value }).then(res => { const code = (res && res.data) ? res.data : ''; this.form.code = code })
  152 + }
  153 + },
  154 + openRelate(fieldKey) {
  155 + let config = {}
  156 + if (fieldKey === 'customerId') {
  157 + config = {
  158 + title: '客户名称',
  159 + source: 'customer',
  160 + rowKey: 'id',
  161 + multiple: false,
  162 + display: [
  163 + { label: '姓名', field: 'name' },
  164 + { label: '编号', field: 'code' },
  165 + { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }
  166 + ]
  167 + }
  168 + }
  169 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  170 + this.sheet.visible = false
  171 + this.relate.title = config.title
  172 + this.relate.source = config.source
  173 + this.relate.display = config.display
  174 + this.relate.multiple = config.multiple
  175 + this.relate.rowKey = config.rowKey
  176 + this.relate.selectedKeys = selectedKeys
  177 + this.relate.fieldKey = fieldKey
  178 + this.$nextTick(() => { this.relate.visible = true })
  179 + },
  180 + onRelateConfirm({ items }) {
  181 + const _fieldKey = this.relate.fieldKey
  182 + const first = (items && items.length > 0) ? items[0] : null
  183 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  184 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  185 + },
  186 + onSubmit() {
  187 + if (!this.validateRequired()) return
  188 + const hv = this.form.hasFrameworkAgreement
  189 + const hasBool = typeof hv === 'string' ? (hv === 'Y') : !!hv
  190 + const payload = {
  191 + code: this.form.code,
  192 + customerId: this.form.customerId,
  193 + company: this.form.company,
  194 + materialTypeId: this.form.materialTypeId,
  195 + hasFrameworkAgreement: hasBool,
  196 + validityTime: this.form.validityTime
  197 + }
  198 + createApi(payload)
  199 + .then(() => {
  200 + uni.showToast({ title: '已提交', icon: 'none' })
  201 + setTimeout(() => { uni.redirectTo({ url: '/pages/contract_framework/index' }) }, 800)
  202 + })
  203 + .catch(() => {
  204 + uni.showToast({ title: '提交失败', icon: 'none' })
  205 + })
  206 + },
  207 + validateRequired() {
  208 + const checks = [
  209 + { key: 'code', label: '框架合同编号' },
  210 + { key: 'customerId', label: '客户名称' },
  211 + { key: 'company', label: '所属单位' },
  212 + { key: 'materialTypeId', label: '品种' },
  213 + { key: 'hasFrameworkAgreement', label: '是否签订框架合同' },
  214 + { key: 'validityTime', label: '授信截止日期' }
  215 + ]
  216 + for (const it of checks) {
  217 + const val = this.form[it.key]
  218 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  219 + if (empty) {
  220 + uni.showToast({ title: `请先选择${it.label}`, icon: 'none' })
  221 + return false
  222 + }
  223 + }
  224 + return true
  225 + }
  226 + }
  227 +}
  228 +</script>
  229 +<style lang="scss" scoped>
  230 +.page {
  231 + display: flex;
  232 + flex-direction: column;
  233 + height: 100%;
  234 +}
  235 +
  236 +.scroll {
  237 + flex: 1;
  238 + padding: 12rpx 0 160rpx;
  239 +}
  240 +
  241 +.footer {
  242 + position: fixed;
  243 + left: 0;
  244 + right: 0;
  245 + bottom: 0;
  246 + padding: 32rpx;
  247 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  248 + background: #fff;
  249 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  250 +
  251 + .btn {
  252 + height: 80rpx;
  253 + line-height: 80rpx;
  254 + border-radius: 12rpx;
  255 + font-size: 32rpx;
  256 + }
  257 +
  258 + .submit {
  259 + background: $theme-primary;
  260 + color: #fff;
  261 + }
  262 +}
  263 +
  264 +::v-deep .uni-list {
  265 + .uni-easyinput {
  266 + display: flex;
  267 +
  268 + .uni-input-input {
  269 + color: rgba(0, 0, 0, 0.9);
  270 + }
  271 + }
  272 +
  273 + background: transparent;
  274 +
  275 + &-item {
  276 + &__extra-text {
  277 + font-size: 32rpx;
  278 + }
  279 +
  280 + &__content-title {
  281 + font-size: 32rpx;
  282 + color: rgba(0, 0, 0, 0.9);
  283 + }
  284 +
  285 + &__container {
  286 + padding: 32rpx;
  287 +
  288 + .uni-easyinput {
  289 + &__placeholder-class {
  290 + font-size: 32rpx;
  291 + color: rgba(0, 0, 0, 0.4);
  292 + }
  293 +
  294 + &__content {
  295 + border: none;
  296 +
  297 + &-input {
  298 + padding-left: 0 !important;
  299 + height: 48rpx;
  300 + line-height: 48rpx;
  301 + font-size: 32rpx;
  302 + }
  303 +
  304 + .content-clear-icon {
  305 + font-size: 44rpx !important;
  306 + }
  307 + }
  308 + }
  309 +
  310 + .item-title,
  311 + .uni-list-item__content {
  312 + flex: none;
  313 + min-height: 48rpx;
  314 + line-height: 48rpx;
  315 + font-size: 32rpx;
  316 + position: relative;
  317 + width: 162rpx;
  318 + margin-right: 32rpx;
  319 + color: rgba(0, 0, 0, 0.9);
  320 +
  321 + .required {
  322 + color: red;
  323 + position: absolute;
  324 + top: 50%;
  325 + transform: translateY(-50%);
  326 + left: -16rpx;
  327 + }
  328 + }
  329 + }
  330 +
  331 + &.select-item {
  332 + &.is-empty {
  333 + .uni-list-item__extra-text {
  334 + color: rgba(0, 0, 0, 0.4) !important;
  335 + }
  336 + }
  337 +
  338 + &.is-filled {
  339 + .uni-list-item__extra-text {
  340 + color: rgba(0, 0, 0, 0.9) !important;
  341 + }
  342 + }
  343 + }
  344 +
  345 + &.mgb10 {
  346 + margin-bottom: 20rpx;
  347 + }
  348 + }
  349 +}
  350 +</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 customer">{{ form.code }}</text>
  7 + <view class="row"><text class="label">客户名称</text><text class="value">{{ form.customerName }}</text></view>
  8 + <view class="row"><text class="label">所属单位</text><text class="value">{{ form.companyName }}</text></view>
  9 + <view class="row"><text class="label">品种</text><text class="value">{{ form.materialTypeName }}</text></view>
  10 + <view class="row"><text class="label">是否签订</text><text class="value">{{ form.hasFrameworkAgreementName
  11 + }}</text></view>
  12 + <view class="row"><text class="label">授信截止日期</text><text class="value">{{ form.validityTime }}</text></view>
  13 + </view>
  14 + </view>
  15 + </scroll-view>
  16 + <detail-buttons :buttons="displayButtons" @click="handleButtonClick" />
  17 + </view>
  18 +</template>
  19 +
  20 +<script>
  21 +import DetailButtons from '@/components/detail-buttons/index.vue'
  22 +import { getDetailApi } from '@/api/contract.js'
  23 +
  24 +export default {
  25 + components: { DetailButtons },
  26 + data() {
  27 + return {
  28 + id: '',
  29 + form: {
  30 + id: '', code: '', customerName: '', companyName: '', materialTypeName: '', hasFrameworkAgreementName: '', validityTime: ''
  31 + }
  32 + }
  33 + },
  34 + computed: {
  35 + displayButtons() {
  36 + return [
  37 + // { text: '删除', variant: 'danger' },
  38 + { text: '编辑', variant: 'outline' }
  39 + ]
  40 + }
  41 + },
  42 + onLoad(query) {
  43 + this.id = (query && query.id) ? query.id : ''
  44 + },
  45 + created() {
  46 + this.loadDetail()
  47 + },
  48 + methods: {
  49 + loadDetail() {
  50 + if (!this.id) return
  51 + getDetailApi(this.id).then(res => {
  52 + const d = res.data || {}
  53 + const m = d || {}
  54 + const yesNo = m.hasFrameworkAgreement === 'Y' || m.hasFrameworkAgreement === true
  55 + this.form = {
  56 + id: m.id || '',
  57 + code: m.code || '',
  58 + customerName: m.customerName || (m.customer && m.customer.name) || '',
  59 + companyName: m.companyName || (m.company && m.company.name) || '',
  60 + materialTypeName: m.materialTypeName || (m.materialType && m.materialType.name) || '',
  61 + hasFrameworkAgreementName: yesNo ? '是' : '否',
  62 + validityTime: m.validityTime || ''
  63 + }
  64 + })
  65 + },
  66 + handleButtonClick(btn) {
  67 + if (btn && btn.text === '编辑') {
  68 + return uni.navigateTo({ url: `/pages/contract_framework/modify?id=${this.id}` })
  69 + }
  70 + // if (btn && btn.text === '删除') {
  71 + // uni.showToast({ title: '暂未接入删除接口', icon: 'none' })
  72 + // }
  73 + }
  74 + }
  75 +}
  76 +</script>
  77 +
  78 +<style lang="scss" scoped>
  79 +.page {
  80 + display: flex;
  81 + flex-direction: column;
  82 + height: 100%;
  83 +}
  84 +
  85 +.scroll {
  86 + flex: 1;
  87 + padding: 8rpx 0 144rpx 0;
  88 +}
  89 +
  90 +.detail-page {
  91 + background: #f3f3f3;
  92 +}
  93 +
  94 +.section {
  95 + padding: 32rpx;
  96 + background: #fff;
  97 + margin-bottom: 20rpx;
  98 +}
  99 +
  100 +.row {
  101 + display: flex;
  102 + margin-bottom: 28rpx;
  103 +
  104 + &.customer {
  105 + font-size: 36rpx;
  106 + font-weight: 600;
  107 + color: rgba(0, 0, 0, 0.9);
  108 + margin-bottom: 12rpx;
  109 + }
  110 +
  111 + .label {
  112 + width: 120rpx;
  113 + line-height: 32rpx;
  114 + font-size: 28rpx;
  115 + color: rgba(0, 0, 0, 0.6);
  116 + }
  117 +
  118 + .value {
  119 + flex: 1;
  120 + line-height: 32rpx;
  121 + font-size: 28rpx;
  122 + color: rgba(0, 0, 0, 0.9);
  123 + text-align: right;
  124 + }
  125 +}
  126 +</style>
\ No newline at end of file
... ...
1 1 <template>
2 2 <view class="page">
3 3 <view class="framework-list-fixed">
4   - <view class="search-row">
5   - <uni-search-bar
6   - v-model="searchKeyword"
7   - radius="6"
8   - placeholder="请输入客户名称或编号"
9   - clearButton="auto"
10   - cancelButton="none"
11   - bgColor="#F3F3F3"
12   - textColor="rgba(0,0,0,0.4)"
13   - @confirm="search"
14   - @input="onSearchInput"
15   - />
16   - <view class="tool-icons">
17   - <image class="tool-icon" src="/static/images/dev_manage/add_icon.png" @click="onAdd" />
18   - <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
19   - </view>
  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" @input="onSearchInput" />
  7 + <view class="tool-icons">
  8 + <image class="tool-icon" src="/static/images/dev_manage/add_icon.png" @click="onAdd" />
  9 + <image class="tool-icon" src="/static/images/dev_manage/filter_icon.png" @click="openFilter" />
20 10 </view>
  11 + </view>
21 12
22   - </view>
  13 + </view>
23 14 <!-- 列表卡片组件 -->
24 15 <view :class="['list-box', { 'pad-batch': batchMode }]">
25   - <card-list
26   - ref="cardRef"
27   - :fetch-fn="fetchList"
28   - :query="query"
29   - :extra="extraParams"
30   - :selectable="batchMode"
31   - row-key="id"
32   - :enable-refresh="true"
33   - :enable-load-more="true"
34   - @error="onCardError"
35   - >
  16 + <card-list ref="cardRef" :fetch-fn="fetchList" :query="query" :extra="extraParams" :selectable="batchMode"
  17 + row-key="id" :enable-refresh="true" :enable-load-more="true" @error="onCardError">
36 18 <template v-slot="{ item, selected }">
37   - <view class="card">
  19 + <view class="card" @click="goDetail(item)">
38 20 <view class="card-header">
39 21 <text class="title omit2">{{ item.customerName }}</text>
40 22 </view>
41   - <view class="info-row">
  23 + <view class="info-row">
42 24 <text>框架合同编号</text><text>{{ item.code }}</text>
43 25 </view>
44   - <view class="info-row">
  26 + <view class="info-row">
45 27 <text>是否签订</text><text>{{ item.hasFrameworkAgreement }}</text>
46 28 </view>
47   - <view class="info-row">
  29 + <view class="info-row">
48 30 <text>品种</text><text>{{ item.materialTypeName }}</text>
49 31 </view>
50   - <view class="info-row">
  32 + <view class="info-row">
51 33 <text>授信截至时间</text><text>{{ item.validityTime }}</text>
52 34 </view>
53 35 </view>
... ... @@ -55,26 +37,14 @@
55 37 </card-list>
56 38 </view>
57 39 <!-- 筛选弹框 -->
58   - <filter-modal
59   - :visible.sync="filterVisible"
60   - :value.sync="filterForm"
61   - title="筛选"
62   - @reset="onFilterReset"
63   - @confirm="onFilterConfirm"
64   - >
  40 + <filter-modal :visible.sync="filterVisible" :value.sync="filterForm" title="筛选" @reset="onFilterReset"
  41 + @confirm="onFilterConfirm">
65 42 <template v-slot="{ model }">
66 43 <view class="filter-form">
67 44 <view class="form-item">
68 45 <view class="label">品种</view>
69   - <uni-data-checkbox
70   - mode="tag"
71   - :multiple="false"
72   - :value-field="'value'"
73   - :text-field="'text'"
74   - v-model="model.materialTypeId"
75   - @change="onMaterialTypeChange"
76   - :localdata="materialTypeOptions"
77   - />
  46 + <uni-data-checkbox mode="tag" :multiple="false" :value-field="'value'" :text-field="'text'"
  47 + v-model="model.materialTypeId" @change="onMaterialTypeChange" :localdata="materialTypeOptions" />
78 48 </view>
79 49 <view class="form-item">
80 50 <view class="label">授权截止时间</view>
... ... @@ -89,7 +59,7 @@
89 59 <script>
90 60 import CardList from '@/components/card/index.vue'
91 61 import FilterModal from '@/components/filter/index.vue'
92   -import {getDicByCodes, getDicName} from '@/utils/dic';
  62 +import { getDicByCodes, getDicName } from '@/utils/dic';
93 63 import { queryApi } from '@/api/contract.js'
94 64 import { productVarietyQueryApi } from '@/api/devManage.js'
95 65 export default {
... ... @@ -99,10 +69,10 @@ export default {
99 69 searchKeyword: '',
100 70 searchKeywordDebounced: '',
101 71 // 批量选择
102   - batchMode: false,
  72 + batchMode: false,
103 73 // 给到 card 的筛选值
104   - query: { materialTypeId: '', dateRange: [] },
105   - extraParams: {},
  74 + query: { materialTypeId: '', dateRange: [] },
  75 + extraParams: {},
106 76
107 77 // 筛选弹框
108 78 filterVisible: false,
... ... @@ -183,12 +153,12 @@ export default {
183 153 this.filterVisible = true
184 154 },
185 155 onFilterReset(payload) {
186   - // 保持弹框不关闭,仅同步表单
187   - this.filterForm = payload
  156 + // 保持弹框不关闭,仅同步表单
  157 + this.filterForm = payload
188 158 },
189 159 onFilterConfirm(payload) {
190   - // 合并筛选值
191   - this.query = { ...this.query, ...payload }
  160 + // 合并筛选值
  161 + this.query = { ...this.query, ...payload }
192 162 },
193 163 onMaterialTypeChange(e) {
194 164 const raw = e && e.detail && e.detail.value !== undefined
... ... @@ -199,23 +169,30 @@ export default {
199 169 },
200 170
201 171 onAdd() {
202   - // uni.navigateTo({ url: '/pages/contract_framework/add' })
  172 + uni.navigateTo({ url: '/pages/contract_framework/add' })
  173 + },
  174 +
  175 + goDetail(item) {
  176 + const id = item && item.id ? item.id : ''
  177 + if (!id) return
  178 + uni.navigateTo({ url: `/pages/contract_framework/detail?id=${id}` })
203 179 },
204 180
205 181
206 182
207 183 getProductVariety() {
208   - productVarietyQueryApi({
  184 + productVarietyQueryApi({
209 185 pageIndex: 1,
210 186 pageSize: 9999,
211   - available: true}).then(res => {
212   - const _data = res.data || {};
213   - const records = _data.datas || [];
214   - this.materialTypeOptions = records.map(item => ({
215   - value: item.id,
216   - text: item.name
217   - }))
218   - })
  187 + available: true
  188 + }).then(res => {
  189 + const _data = res.data || {};
  190 + const records = _data.datas || [];
  191 + this.materialTypeOptions = records.map(item => ({
  192 + value: item.id,
  193 + text: item.name
  194 + }))
  195 + })
219 196 },
220 197 }
221 198 }
... ... @@ -227,157 +204,197 @@ export default {
227 204 flex-direction: column;
228 205 height: 100vh;
229 206 }
  207 +
230 208 .framework-list-fixed {
231   - position: fixed;
232   - top: 96rpx;
233   - left: 0;
234   - right: 0;
235   - z-index: 2;
236   - background: #fff;
237   -
238   - .search-row {
239   - display: flex;
240   - align-items: center;
241   - padding: 16rpx 32rpx;
242   - .uni-searchbar {
243   - padding: 0;
244   - flex: 1;
245   - }
246   - .tool-icons {
247   - display: flex;
248   - .tool-icon {
249   - width: 48rpx; height: 48rpx; display: block;
250   - margin-left: 32rpx;
251   - }
252   - }
  209 + position: fixed;
  210 + top: 96rpx;
  211 + left: 0;
  212 + right: 0;
  213 + z-index: 2;
  214 + background: #fff;
  215 +
  216 + .search-row {
  217 + display: flex;
  218 + align-items: center;
  219 + padding: 16rpx 32rpx;
  220 +
  221 + .uni-searchbar {
  222 + padding: 0;
  223 + flex: 1;
253 224 }
254   -
255   -
  225 +
  226 + .tool-icons {
  227 + display: flex;
  228 +
  229 + .tool-icon {
  230 + width: 48rpx;
  231 + height: 48rpx;
  232 + display: block;
  233 + margin-left: 32rpx;
  234 + }
  235 + }
  236 + }
  237 +
  238 +
256 239 }
  240 +
257 241 /* 仅当前页覆盖 uni-search-bar 盒子高度 */
258   -::v-deep .uni-searchbar__box {
259   - height: 80rpx !important;
260   - justify-content: start;
261   - .uni-searchbar__box-search-input {
262   - font-size: 32rpx !important;
263   - }
  242 +::v-deep .uni-searchbar__box {
  243 + height: 80rpx !important;
  244 + justify-content: start;
  245 +
  246 + .uni-searchbar__box-search-input {
  247 + font-size: 32rpx !important;
  248 + }
264 249 }
265 250
266 251 .list-box {
267 252 flex: 1;
268 253 padding-top: 112rpx;
269   - &.pad-batch { padding-bottom: 144rpx; }
270   - .card { position: relative; }
271   - .card-header {
272   - margin-bottom: 28rpx;
273   - position: relative;
274   -
275   - .title {
276   - font-size: 36rpx;
277   - font-weight: 600;
278   - line-height: 50rpx;
279   - color: rgba(0,0,0,0.9);
280   - width: 578rpx;
281   - }
282   -
283   - .status {
284   - font-size: 30rpx;
285   - font-weight: 600;
286   - position: absolute;
287   - top: -36rpx;
288   - right: -32rpx;
289   - height: 48rpx;
290   - line-height: 48rpx;
291   - color: #fff;
292   - font-size: 24rpx;
293   - padding: 0 14rpx;
294   - border-radius: 6rpx;
295   - &.status_1 {
296   - background: #3D48A3;
297   - }
298   - &.status_2 {
299   - background: #2BA471;
300   - }
301   - &.status_3 {
302   - background: #D54941;
303   - }
304   - &.status_4 {
305   - background: #E7E7E7;
306   - color: rgba(0,0,0,0.9);
307   - }
308   - }
  254 +
  255 + &.pad-batch {
  256 + padding-bottom: 144rpx;
  257 + }
  258 +
  259 + .card {
  260 + position: relative;
  261 + }
  262 +
  263 + .card-header {
  264 + margin-bottom: 28rpx;
  265 + position: relative;
  266 +
  267 + .title {
  268 + font-size: 36rpx;
  269 + font-weight: 600;
  270 + line-height: 50rpx;
  271 + color: rgba(0, 0, 0, 0.9);
  272 + width: 578rpx;
309 273 }
310   - .info-row {
311   - display: flex;
312   - align-items: center;
313   - color: rgba(0,0,0,0.6);
314   - font-size: 28rpx;
315   - margin-bottom: 24rpx;
316   - height: 32rpx;
317   - &:last-child {
318   - margin-bottom: 0;
319   - }
320   - text {
321   - width: 60%;
322   - &:last-child {
323   - color: rgba(0,0,0,0.9);
324   - width: 40%;
325   - }
326   - }
  274 +
  275 + .status {
  276 + font-size: 30rpx;
  277 + font-weight: 600;
  278 + position: absolute;
  279 + top: -36rpx;
  280 + right: -32rpx;
  281 + height: 48rpx;
  282 + line-height: 48rpx;
  283 + color: #fff;
  284 + font-size: 24rpx;
  285 + padding: 0 14rpx;
  286 + border-radius: 6rpx;
  287 +
  288 + &.status_1 {
  289 + background: #3D48A3;
  290 + }
  291 +
  292 + &.status_2 {
  293 + background: #2BA471;
  294 + }
  295 +
  296 + &.status_3 {
  297 + background: #D54941;
  298 + }
  299 +
  300 + &.status_4 {
  301 + background: #E7E7E7;
  302 + color: rgba(0, 0, 0, 0.9);
  303 + }
327 304 }
  305 + }
  306 +
  307 + .info-row {
  308 + display: flex;
  309 + align-items: center;
  310 + color: rgba(0, 0, 0, 0.6);
  311 + font-size: 28rpx;
  312 + margin-bottom: 24rpx;
  313 + height: 32rpx;
  314 +
  315 + &:last-child {
  316 + margin-bottom: 0;
  317 + }
  318 +
  319 + text {
  320 + width: 60%;
  321 +
  322 + &:last-child {
  323 + color: rgba(0, 0, 0, 0.9);
  324 + width: 40%;
  325 + }
  326 + }
  327 + }
328 328 }
329 329
330   -.filter-form {
331   - .form-item { margin-bottom: 24rpx; }
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   - .fake-select {
340   - height: 80rpx; line-height: 80rpx; padding: 0 20rpx; background: #f3f3f3; border-radius: 12rpx;
341   - .placeholder { color: #999; }
342   - .value { color: #333; }
  330 +.filter-form {
  331 + .form-item {
  332 + margin-bottom: 24rpx;
  333 + }
  334 +
  335 + .label {
  336 + margin-bottom: 20rpx;
  337 + color: rgba(0, 0, 0, 0.9);
  338 + height: 44rpx;
  339 + line-height: 44rpx;
  340 + font-size: 30rpx;
  341 + }
  342 +
  343 + .fake-select {
  344 + height: 80rpx;
  345 + line-height: 80rpx;
  346 + padding: 0 20rpx;
  347 + background: #f3f3f3;
  348 + border-radius: 12rpx;
  349 +
  350 + .placeholder {
  351 + color: #999;
343 352 }
  353 +
  354 + .value {
  355 + color: #333;
  356 + }
  357 + }
344 358 }
345 359
346 360 /* 深度覆盖 uni-data-checkbox(mode=tag)内部的 tag 展示与间距 */
347 361 ::v-deep .filter-form .uni-data-checklist .checklist-group {
348 362 .checklist-box {
349 363 &.is--tag {
350   - width: 212rpx;
351   - margin-top: 0;
352   - margin-bottom: 24rpx;
353   - margin-right: 24rpx;
354   - height: 80rpx;
355   - padding: 0;
356   - border-radius: 12rpx;
357   - background-color: #f3f3f3;
358   - border-color: #f3f3f3;
359   - &:nth-child(3n) {
360   - margin-right: 0;
361   - }
362   - .checklist-content {
363   - display: flex;
364   - justify-content: center;
365   - }
366   - .checklist-text {
367   - color: rgba(0,0,0,0.9);
368   - font-size: 28rpx;
369   - }
  364 + width: 212rpx;
  365 + margin-top: 0;
  366 + margin-bottom: 24rpx;
  367 + margin-right: 24rpx;
  368 + height: 80rpx;
  369 + padding: 0;
  370 + border-radius: 12rpx;
  371 + background-color: #f3f3f3;
  372 + border-color: #f3f3f3;
  373 +
  374 + &:nth-child(3n) {
  375 + margin-right: 0;
  376 + }
  377 +
  378 + .checklist-content {
  379 + display: flex;
  380 + justify-content: center;
  381 + }
  382 +
  383 + .checklist-text {
  384 + color: rgba(0, 0, 0, 0.9);
  385 + font-size: 28rpx;
  386 + }
370 387 }
  388 +
371 389 &.is-checked {
372   - background-color: $theme-primary-plain-bg !important;
373   - border-color: $theme-primary-plain-bg !important;
374   - .checklist-text {
375   - color: $theme-primary !important;
376   - }
  390 + background-color: $theme-primary-plain-bg !important;
  391 + border-color: $theme-primary-plain-bg !important;
  392 +
  393 + .checklist-text {
  394 + color: $theme-primary !important;
  395 + }
377 396 }
378 397 }
379   -
380   -}
381   -
382 398
  399 +}
383 400 </style>
\ No newline at end of file
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item title="框架合同编号">
  6 + <template v-slot:footer>
  7 + <uni-easyinput v-model="form.code" :inputBorder="false" disabled />
  8 + </template>
  9 + </uni-list-item>
  10 +
  11 + <uni-list-item class="select-item" :class="form.customerId ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openRelate('customerId')" :rightText="form.customerIdName || '请选择客户名称'" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text class="required">*</text><text>客户名称</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item class="select-item" :class="form.company ? 'is-filled' : 'is-empty'" clickable
  19 + @click="openSheet('company')" :rightText="displayLabel('companyName')" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text class="required">*</text><text>所属单位</text></view>
  22 + </template>
  23 + </uni-list-item>
  24 +
  25 + <uni-list-item class="select-item" :class="form.materialTypeId ? 'is-filled' : 'is-empty'" clickable
  26 + @click="openSheet('materialTypeId')" :rightText="displayLabel('materialTypeIdName')" showArrow>
  27 + <template v-slot:body>
  28 + <view class="item-title"><text class="required">*</text><text>品种</text></view>
  29 + </template>
  30 + </uni-list-item>
  31 +
  32 + <uni-list-item class="select-item" :class="form.hasFrameworkAgreementName ? 'is-filled' : 'is-empty'" clickable
  33 + @click="openSheet('hasFrameworkAgreement')" :rightText="displayLabel('hasFrameworkAgreementName')" showArrow>
  34 + <template v-slot:body>
  35 + <view class="item-title"><text class="required">*</text><text>是否签订框架合同</text></view>
  36 + </template>
  37 + </uni-list-item>
  38 +
  39 + <uni-list-item title="授信截止日期">
  40 + <template v-slot:footer>
  41 + <uni-datetime-picker type="date" v-model="form.validityTime" />
  42 + </template>
  43 + </uni-list-item>
  44 + </uni-list>
  45 + </scroll-view>
  46 +
  47 + <view class="footer">
  48 + <button class="btn submit" type="primary" @click="onSubmit">保存</button>
  49 + </view>
  50 +
  51 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options" v-model="sheet.value"
  52 + @confirm="onSheetConfirm" />
  53 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  54 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  55 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  56 + </view>
  57 +</template>
  58 +
  59 +<script>
  60 +import SingleSelectSheet from '@/components/single-select/index.vue'
  61 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  62 +import { productVarietyQuery, getCodeApi, getDetailApi, updateApi } from '@/api/contract'
  63 +import { getDicByCodes } from '@/utils/dic'
  64 +
  65 +export default {
  66 + components: { SingleSelectSheet, RelateSelectSheet },
  67 + data() {
  68 + return {
  69 + id: '',
  70 + form: { id: '', code: '', customerId: '', customerIdName: '', company: '', companyName: '', materialTypeId: '', materialTypeIdName: '', hasFrameworkAgreement: '', hasFrameworkAgreementName: '', validityTime: '' },
  71 + companyList: [],
  72 + productVarietyList: [],
  73 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  74 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' }
  75 + }
  76 + },
  77 + onLoad(query) { this.id = (query && query.id) ? query.id : '' },
  78 + created() { this.loadCompanyList(); this.loadProductVariety(); this.loadDetail() },
  79 + methods: {
  80 + displayLabel(field) {
  81 + const m = this.form
  82 + const map = { companyName: '请选择所属单位', materialTypeIdName: '请选择品种', hasFrameworkAgreementName: '请选择是否签订' }
  83 + const val = m[field]
  84 + return val ? String(val) : map[field]
  85 + },
  86 + async loadCompanyList() {
  87 + try {
  88 + const results = await getDicByCodes(['SUPPLIER'])
  89 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  90 + this.companyList = items.map(it => ({ label: it.name, value: it.code }))
  91 + } catch (e) { this.companyList = [] }
  92 + },
  93 + async loadProductVariety() {
  94 + try {
  95 + const res = await productVarietyQuery({ pageIndex: 1, pageSize: 9999 })
  96 + const list = (res.data && res.data.datas) ? res.data.datas : []
  97 + this.productVarietyList = list.map(it => ({ label: it.name, value: it.id }))
  98 + } catch (e) { this.productVarietyList = [] }
  99 + },
  100 + loadDetail() {
  101 + if (!this.id) return
  102 + getDetailApi(this.id).then(res => {
  103 + const m = res.data || {}
  104 + const yesNo = m.hasFrameworkAgreement === 'Y' || m.hasFrameworkAgreement === true
  105 + this.form = {
  106 + id: m.id || '',
  107 + code: m.code || '',
  108 + customerId: m.customerId || (m.customer && m.customer.id) || '',
  109 + customerIdName: m.customerName || (m.customer && m.customer.name) || '',
  110 + company: m.company || '',
  111 + companyName: m.companyName || (m.company && m.company.name) || '',
  112 + materialTypeId: m.materialTypeId || (m.materialType && m.materialType.id) || '',
  113 + materialTypeIdName: m.materialTypeName || (m.materialType && m.materialType.name) || '',
  114 + hasFrameworkAgreement: yesNo ? true : false,
  115 + hasFrameworkAgreementName: yesNo ? '是' : '否',
  116 + validityTime: m.validityTime || ''
  117 + }
  118 + })
  119 + },
  120 + openSheet(field) {
  121 + const setSheet = (title, options) => {
  122 + const current = this.form[field]
  123 + const match = (options || []).find(o => String(o.value) === String(current))
  124 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  125 + }
  126 + if (field === 'company') setSheet('所属单位', this.companyList)
  127 + else if (field === 'materialTypeId') setSheet('品种', this.productVarietyList)
  128 + else if (field === 'hasFrameworkAgreement') setSheet('是否签订框架合同', [{ label: '是', value: true }, { label: '否', value: false }])
  129 + },
  130 + onSheetConfirm({ value, label }) {
  131 + const field = this.sheet.field
  132 + if (!field) return
  133 + const v = (value === undefined || value === null) ? '' : value
  134 + this.form[field] = v
  135 + this.form[field + 'Name'] = label || ''
  136 + if (field === 'company' && value !== undefined && value !== null) {
  137 + getCodeApi({ company: value }).then(res => { const code = (res && res.data) ? res.data : ''; this.form.code = code })
  138 + }
  139 + },
  140 + openRelate(fieldKey) {
  141 + let config = {}
  142 + if (fieldKey === 'customerId') {
  143 + config = { title: '客户名称', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '姓名', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  144 + }
  145 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  146 + this.sheet.visible = false
  147 + this.relate = { ...this.relate, title: config.title, source: config.source, display: config.display, multiple: config.multiple, rowKey: config.rowKey, selectedKeys, fieldKey }
  148 + this.$nextTick(() => { this.relate.visible = true })
  149 + },
  150 + onRelateConfirm({ items }) {
  151 + const _fieldKey = this.relate.fieldKey
  152 + const first = (items && items.length > 0) ? items[0] : null
  153 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  154 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  155 + },
  156 + validateRequired() {
  157 + const checks = [
  158 + { key: 'code', label: '框架合同编号' },
  159 + { key: 'customerId', label: '客户名称' },
  160 + { key: 'company', label: '所属单位' },
  161 + { key: 'materialTypeId', label: '品种' },
  162 + { key: 'hasFrameworkAgreement', label: '是否签订框架合同' },
  163 + { key: 'validityTime', label: '授信截止日期' }
  164 + ]
  165 + for (const it of checks) {
  166 + const val = this.form[it.key]
  167 + const empty = (val === undefined || val === null || (typeof val === 'string' && val.trim() === '') || (typeof val === 'number' && isNaN(val)))
  168 + if (empty) { uni.showToast({ title: `请先选择${it.label}`, icon: 'none' }); return false }
  169 + }
  170 + return true
  171 + },
  172 + onSubmit() {
  173 + if (!this.validateRequired()) return
  174 + const payload = { id: this.form.id, code: this.form.code, customerId: this.form.customerId, company: this.form.company, materialTypeId: this.form.materialTypeId, hasFrameworkAgreement: !!this.form.hasFrameworkAgreement, validityTime: this.form.validityTime }
  175 + updateApi(payload).then(() => { uni.showToast({ title: '已保存', icon: 'none' }); setTimeout(() => { uni.redirectTo({ url: '/pages/contract_framework/index' }) }, 800) }).catch(() => { uni.showToast({ title: '保存失败', icon: 'none' }) })
  176 + }
  177 + }
  178 +}
  179 +</script>
  180 +
  181 +<style lang="scss" scoped>
  182 +.page {
  183 + display: flex;
  184 + flex-direction: column;
  185 + height: 100%;
  186 +}
  187 +
  188 +.scroll {
  189 + flex: 1;
  190 + padding: 12rpx 0 160rpx;
  191 +}
  192 +
  193 +.footer {
  194 + position: fixed;
  195 + left: 0;
  196 + right: 0;
  197 + bottom: 0;
  198 + padding: 32rpx;
  199 + padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
  200 + background: #fff;
  201 + box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
  202 +
  203 + .btn {
  204 + height: 80rpx;
  205 + line-height: 80rpx;
  206 + border-radius: 12rpx;
  207 + font-size: 32rpx;
  208 + }
  209 +
  210 + .submit {
  211 + background: $theme-primary;
  212 + color: #fff;
  213 + }
  214 +}
  215 +
  216 +::v-deep .uni-list {
  217 + .uni-easyinput {
  218 + display: flex;
  219 +
  220 + .uni-input-input {
  221 + color: rgba(0, 0, 0, 0.9);
  222 + }
  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 +
  249 + &-input {
  250 + padding-left: 0 !important;
  251 + height: 48rpx;
  252 + line-height: 48rpx;
  253 + font-size: 32rpx;
  254 + }
  255 +
  256 + .content-clear-icon {
  257 + font-size: 44rpx !important;
  258 + }
  259 + }
  260 + }
  261 +
  262 + .item-title,
  263 + .uni-list-item__content {
  264 + flex: none;
  265 + min-height: 48rpx;
  266 + line-height: 48rpx;
  267 + font-size: 32rpx;
  268 + position: relative;
  269 + width: 162rpx;
  270 + margin-right: 32rpx;
  271 + color: rgba(0, 0, 0, 0.9);
  272 +
  273 + .required {
  274 + color: red;
  275 + position: absolute;
  276 + top: 50%;
  277 + transform: translateY(-50%);
  278 + left: -16rpx;
  279 + }
  280 + }
  281 + }
  282 +
  283 + &.select-item {
  284 + &.is-empty {
  285 + .uni-list-item__extra-text {
  286 + color: rgba(0, 0, 0, 0.4) !important;
  287 + }
  288 + }
  289 +
  290 + &.is-filled {
  291 + .uni-list-item__extra-text {
  292 + color: rgba(0, 0, 0, 0.9) !important;
  293 + }
  294 + }
  295 + }
  296 +
  297 + &.mgb10 {
  298 + margin-bottom: 20rpx;
  299 + }
  300 + }
  301 +}
  302 +</style>
\ No newline at end of file
... ...
  1 +<template>
  2 + <view class="page">
  3 + <scroll-view class="scroll" scroll-y>
  4 + <uni-list>
  5 + <uni-list-item title="编号">
  6 + <template v-slot:footer>
  7 + <uni-easyinput v-model="form.code" :inputBorder="false" disabled />
  8 + </template>
  9 + </uni-list-item>
  10 +
  11 + <uni-list-item class="select-item" :class="form.supplier ? 'is-filled' : 'is-empty'" clickable
  12 + @click="openSheet('supplier')" :rightText="displayLabel('supplierName')" showArrow>
  13 + <template v-slot:body>
  14 + <view class="item-title"><text class="required">*</text><text>供方</text></view>
  15 + </template>
  16 + </uni-list-item>
  17 +
  18 + <uni-list-item class="select-item" :class="form.buyer ? 'is-filled' : 'is-empty'" clickable
  19 + @click="openRelate('buyer')" :rightText="form.buyerName || '请选择需方'" showArrow>
  20 + <template v-slot:body>
  21 + <view class="item-title"><text class="required">*</text><text>需方</text></view>
  22 + </template>
  23 + </uni-list-item>
  24 +
  25 + <uni-list-item title="订货日期">
  26 + <template v-slot:footer>
  27 + <uni-datetime-picker type="date" v-model="form.orderDate" />
  28 + </template>
  29 + </uni-list-item>
  30 +
  31 + <uni-list-item title="单位">
  32 + <template v-slot:footer>
  33 + <uni-easyinput v-model="form.unit" :inputBorder="false" disabled />
  34 + </template>
  35 + </uni-list-item>
  36 + <ProductRel type="add" v-model="form.productRel" />
  37 + </uni-list>
  38 + </scroll-view>
  39 +
  40 + <SingleSelectSheet :visible.sync="sheet.visible" :title="sheet.title" :options="sheet.options"
  41 + v-model="sheet.value" @confirm="onSheetConfirm" />
  42 + <RelateSelectSheet :visible.sync="relate.visible" :title="relate.title" :source="relate.source"
  43 + :display-fields="relate.display" :multiple="relate.multiple" :row-key="relate.rowKey"
  44 + :selectedKeys.sync="relate.selectedKeys" @confirm="onRelateConfirm" />
  45 + </view>
  46 +
  47 +</template>
  48 +<script>
  49 +import SingleSelectSheet from '@/components/single-select/index.vue'
  50 +import RelateSelectSheet from '@/components/relate-select/index.vue'
  51 +import ProductRel from './productRel.vue'
  52 +import { getRetailCodeApi } from '@/api/contract'
  53 +import { getDicByCodes } from '@/utils/dic'
  54 +
  55 +export default {
  56 + name: 'AddContractRetail',
  57 + components: { SingleSelectSheet, RelateSelectSheet, ProductRel },
  58 + data() {
  59 + return {
  60 + form: {
  61 + code: '',
  62 + supplier: '',
  63 + supplierName: '',
  64 + buyer: '',
  65 + buyerName: '',
  66 + orderDate: '',
  67 + unit: '元、公斤、元/公斤'
  68 + },
  69 + supplierList: [],
  70 + sheet: { visible: false, title: '请选择', field: '', options: [], value: '' },
  71 + relate: { visible: false, title: '选择', source: '', display: [], multiple: false, rowKey: 'id', selectedKeys: [], fieldKey: '' }
  72 + }
  73 + },
  74 + created() {
  75 + this.loadSuppliers()
  76 + this.initCode()
  77 + this.form.orderDate = this.formatDate(new Date())
  78 + },
  79 + methods: {
  80 + formatDate(d) {
  81 + const y = d.getFullYear()
  82 + const m = String(d.getMonth() + 1).padStart(2, '0')
  83 + const day = String(d.getDate()).padStart(2, '0')
  84 + return `${y}-${m}-${day}`
  85 + },
  86 + async initCode() {
  87 + try {
  88 + const res = await getRetailCodeApi()
  89 + const code = (res && res.data) ? res.data : ''
  90 + this.form.code = code
  91 + } catch (e) { this.form.code = '' }
  92 + },
  93 + async loadSuppliers() {
  94 + try {
  95 + const results = await getDicByCodes(['SUPPLIER'])
  96 + const items = results && results.SUPPLIER && results.SUPPLIER.data ? results.SUPPLIER.data : []
  97 + this.supplierList = items.map(it => ({ label: it.name, value: it.code }))
  98 + } catch (e) { this.supplierList = [] }
  99 + },
  100 + displayLabel(field) {
  101 + const m = this.form
  102 + const map = { supplierName: '请选择供方' }
  103 + const val = m[field]
  104 + return val ? String(val) : map[field]
  105 + },
  106 + openSheet(field) {
  107 + const setSheet = (title, options) => {
  108 + const current = this.form[field]
  109 + const match = (options || []).find(o => String(o.label) === String(current) || String(o.value) === String(current))
  110 + this.sheet = { ...this.sheet, visible: true, title, options, field, value: match ? match.value : '' }
  111 + }
  112 + if (field === 'supplier') setSheet('供方', this.supplierList)
  113 + },
  114 + onSheetConfirm({ value, label }) {
  115 + const field = this.sheet.field
  116 + if (!field) return
  117 + const v = (value === undefined || value === null) ? '' : value
  118 + this.form[field] = v
  119 + this.form[field + 'Name'] = label || ''
  120 + },
  121 + openRelate(fieldKey) {
  122 + let config = {}
  123 + if (fieldKey === 'buyer') {
  124 + config = { title: '需方', source: 'customer', rowKey: 'id', multiple: false, display: [{ label: '姓名', field: 'name' }, { label: '编号', field: 'code' }, { label: '状态', field: 'available', format: v => (v ? '启用' : '停用') }] }
  125 + }
  126 + const selectedKeys = this.form[fieldKey] ? [this.form[fieldKey]] : []
  127 + this.sheet.visible = false
  128 + this.relate = { ...this.relate, title: config.title, source: config.source, display: config.display, multiple: config.multiple, rowKey: config.rowKey, selectedKeys, fieldKey }
  129 + this.$nextTick(() => { this.relate.visible = true })
  130 + },
  131 + onRelateConfirm({ items }) {
  132 + const _fieldKey = this.relate.fieldKey
  133 + const first = (items && items.length > 0) ? items[0] : null
  134 + this.form[_fieldKey] = (first && first.id) ? first.id : ''
  135 + this.form[_fieldKey + 'Name'] = (first && first.name) ? first.name : ''
  136 + }
  137 + }
  138 +}
  139 +
  140 +</script>
  141 +<style lang="scss" scoped>
  142 +.page {
  143 + display: flex;
  144 + flex-direction: column;
  145 + height: 100%;
  146 +}
  147 +
  148 +.scroll {
  149 + flex: 1;
  150 + padding: 12rpx 0 160rpx;
  151 +}
  152 +
  153 +::v-deep .uni-list {
  154 + .uni-easyinput {
  155 + display: flex;
  156 +
  157 + .uni-input-input {
  158 + color: rgba(0, 0, 0, 0.9);
  159 + }
  160 + }
  161 +
  162 + .uni-input-input {
  163 + background-color: #ffffff;
  164 + }
  165 +
  166 + background: transparent;
  167 +
  168 + &-item {
  169 + &__extra-text {
  170 + font-size: 32rpx;
  171 + }
  172 +
  173 + &__content-title {
  174 + font-size: 32rpx;
  175 + color: rgba(0, 0, 0, 0.9);
  176 + }
  177 +
  178 + &__container {
  179 + padding: 32rpx;
  180 +
  181 + .uni-easyinput {
  182 + &__placeholder-class {
  183 + font-size: 32rpx;
  184 + color: rgba(0, 0, 0, 0.4);
  185 + }
  186 +
  187 + &__content {
  188 + border: none;
  189 +
  190 + &-input {
  191 + padding-left: 0 !important;
  192 + height: 48rpx;
  193 + line-height: 48rpx;
  194 + font-size: 32rpx;
  195 + }
  196 +
  197 + .content-clear-icon {
  198 + font-size: 44rpx !important;
  199 + }
  200 + }
  201 + }
  202 +
  203 + .item-title,
  204 + .uni-list-item__content {
  205 + flex: none;
  206 + min-height: 48rpx;
  207 + line-height: 48rpx;
  208 + font-size: 32rpx;
  209 + position: relative;
  210 + width: 162rpx;
  211 + margin-right: 32rpx;
  212 + color: rgba(0, 0, 0, 0.9);
  213 +
  214 + .required {
  215 + color: red;
  216 + position: absolute;
  217 + top: 50%;
  218 + transform: translateY(-50%);
  219 + left: -16rpx;
  220 + }
  221 + }
  222 + }
  223 +
  224 + &.select-item {
  225 + &.is-empty {
  226 + .uni-list-item__extra-text {
  227 + color: rgba(0, 0, 0, 0.4) !important;
  228 + }
  229 + }
  230 +
  231 + &.is-filled {
  232 + .uni-list-item__extra-text {
  233 + color: rgba(0, 0, 0, 0.9) !important;
  234 + }
  235 + }
  236 + }
  237 +
  238 + &.mgb10 {
  239 + margin-bottom: 20rpx;
  240 + }
  241 + }
  242 +}
  243 +</style>
\ No newline at end of file
... ...
... ... @@ -201,7 +201,7 @@ export default {
201 201 if (!this.batchMode) this.selectedKeys = []
202 202 },
203 203 onAdd() {
204   - uni.showToast({ title: '点击新增', icon: 'none' })
  204 + uni.navigateTo({ url: '/pages/contract_retail/add' })
205 205 },
206 206 fetchList({ pageIndex, pageSize, query, extra }) {
207 207 console.log('fetchList', pageIndex, pageSize, query, extra)
... ...
  1 +<template>
  2 + <view class="product-rel">
  3 + <view class="header">
  4 + <image class="opCollapse" src="/static/images/title.png" />
  5 + <text class="title">产品</text>
  6 + <view class="ops">
  7 + <image v-if="mode === 'add'" class="opAdd" @click="onAdd" src="/static/images/plus.png" />
  8 + <view v-if="mode === 'view'" class="op1" @click="toggleViewCollapse">
  9 + <image class="opAdd" :src="collapsedView ? '/static/images/down.png' : '/static/images/up.png'" />
  10 + <text class="op">{{ collapsedView ? '展开' : '收起'}} </text>
  11 + </view>
  12 +
  13 + </view>
  14 + </view>
  15 +
  16 + <view v-if="mode === 'add'" class="add-list">
  17 + <view v-for="(item, idx) in items" :key="idx" class="block">
  18 + <uni-list v-show="item.collapsed">
  19 + <uni-list-item title="产品名称">
  20 + <template v-slot:footer>
  21 + <uni-easyinput v-model="item.name" :inputBorder="false" placeholder="请输入产品名称" />
  22 + </template>
  23 + </uni-list-item>
  24 + <uni-list-item title="行业">
  25 + <template v-slot:footer>
  26 + <uni-easyinput v-model="item.industry" :inputBorder="false" placeholder="请输入行业名称" />
  27 + </template>
  28 + </uni-list-item>
  29 + <uni-list-item title="牌号">
  30 + <template v-slot:footer>
  31 + <uni-easyinput v-model="item.brand" :inputBorder="false" placeholder="请输入牌号" />
  32 + </template>
  33 + </uni-list-item>
  34 + </uni-list>
  35 + <uni-list v-show="!item.collapsed">
  36 + <uni-list-item title="产品名称">
  37 + <template v-slot:footer>
  38 + <uni-easyinput v-model="item.name" :inputBorder="false" placeholder="请输入产品名称" />
  39 + </template>
  40 + </uni-list-item>
  41 + <uni-list-item title="行业">
  42 + <template v-slot:footer>
  43 + <uni-easyinput v-model="item.industry" :inputBorder="false" placeholder="请输入行业名称" />
  44 + </template>
  45 + </uni-list-item>
  46 + <uni-list-item title="牌号">
  47 + <template v-slot:footer>
  48 + <uni-easyinput v-model="item.brand" :inputBorder="false" placeholder="请输入牌号" />
  49 + </template>
  50 + </uni-list-item>
  51 + <uni-list-item title="品质">
  52 + <template v-slot:footer>
  53 + <uni-easyinput v-model="item.quality" :inputBorder="false" placeholder="请输入品质" />
  54 + </template>
  55 + </uni-list-item>
  56 + <uni-list-item title="厚度">
  57 + <template v-slot:footer>
  58 + <uni-easyinput v-model="item.thickness" :inputBorder="false" placeholder="请输入厚度" />
  59 + </template>
  60 + </uni-list-item>
  61 + <uni-list-item title="厚度公差(单项+)">
  62 + <template v-slot:footer>
  63 + <uni-easyinput v-model="item.thicknessTolPos" :inputBorder="false"
  64 + placeholder="请输入厚度公差(单项+)" />
  65 + </template>
  66 + </uni-list-item>
  67 + <uni-list-item title="厚度公差(单项-)">
  68 + <template v-slot:footer>
  69 + <uni-easyinput v-model="item.thicknessTolNeg" :inputBorder="false"
  70 + placeholder="请输入厚度公差(单项-)" />
  71 + </template>
  72 + </uni-list-item>
  73 + <uni-list-item title="宽度">
  74 + <template v-slot:footer>
  75 + <uni-easyinput v-model="item.width" :inputBorder="false" placeholder="请输入宽度" />
  76 + </template>
  77 + </uni-list-item>
  78 + <uni-list-item title="宽度公差(单项+)">
  79 + <template v-slot:footer>
  80 + <uni-easyinput v-model="item.widthTolPos" :inputBorder="false" placeholder="请输入宽度公差(单项+)" />
  81 + </template>
  82 + </uni-list-item>
  83 + <uni-list-item title="宽度公差(单项-)">
  84 + <template v-slot:footer>
  85 + <uni-easyinput v-model="item.widthTolNeg" :inputBorder="false" placeholder="请输入宽度公差(单项-)" />
  86 + </template>
  87 + </uni-list-item>
  88 + <uni-list-item title="长度">
  89 + <template v-slot:footer>
  90 + <uni-easyinput v-model="item.length" :inputBorder="false" placeholder="请输入长度" />
  91 + </template>
  92 + </uni-list-item>
  93 + <uni-list-item title="长度公差(单项+)">
  94 + <template v-slot:footer>
  95 + <uni-easyinput v-model="item.lengthTolPos" :inputBorder="false"
  96 + placeholder="请输入长度公差(单项+)" />
  97 + </template>
  98 + </uni-list-item>
  99 + <uni-list-item title="长度公差(单项-)">
  100 + <template v-slot:footer>
  101 + <uni-easyinput v-model="item.lengthTolNeg" :inputBorder="false"
  102 + placeholder="请输入长度公差(单项-)" />
  103 + </template>
  104 + </uni-list-item>
  105 + <uni-list-item title="状态">
  106 + <template v-slot:footer>
  107 + <uni-easyinput v-model="item.status" :inputBorder="false" placeholder="请输入状态" />
  108 + </template>
  109 + </uni-list-item>
  110 + <uni-list-item title="数量">
  111 + <template v-slot:footer>
  112 + <uni-easyinput v-model="item.quantity" :inputBorder="false" placeholder="请输入数量" />
  113 + </template>
  114 + </uni-list-item>
  115 + <uni-list-item title="单价">
  116 + <template v-slot:footer>
  117 + <uni-easyinput v-model="item.unitPrice" :inputBorder="false" placeholder="请输入单价" />
  118 + </template>
  119 + </uni-list-item>
  120 + <uni-list-item title="不含税金额">
  121 + <template v-slot:footer>
  122 + <uni-easyinput v-model="item.amountExcludingTax" :inputBorder="false"
  123 + placeholder="请输入不含税金额" />
  124 + </template>
  125 + </uni-list-item>
  126 + <uni-list-item title="总金额">
  127 + <template v-slot:footer>
  128 + <uni-easyinput v-model="item.totalAmount" :inputBorder="false" placeholder="请输入总金额" />
  129 + </template>
  130 + </uni-list-item>
  131 + <uni-list-item title="发货日期">
  132 + <template v-slot:footer>
  133 + <uni-datetime-picker type="date" v-model="item.orderDate" />
  134 + </template>
  135 + </uni-list-item>
  136 + </uni-list>
  137 + <view class="block-ops">
  138 + <div class="del" @click="onRemove(idx)">
  139 + <image src="/static/images/delete.png" class="icon" />
  140 + 删除
  141 + </div>
  142 + <div class="toggle" @click="toggleItem(idx)">
  143 + <image :src="item.collapsed ? '/static/images/up.png' : '/static/images/down.png'" class="icon" />
  144 + {{ item.collapsed ? '展开' : '收起' }}</div>
  145 + </view>
  146 + </view>
  147 + </view>
  148 +
  149 + <view v-else class="view-list" v-show="!collapsedView">
  150 + <view v-for="(item, idx) in items" :key="'v-' + idx" class="card">
  151 + <view class="row"><text class="label">产品名称</text><text class="value">{{ item.name }}</text></view>
  152 + <view class="row"><text class="label">行业</text><text class="value">{{ item.industry }}</text></view>
  153 + <view class="row"><text class="label">牌号</text><text class="value">{{ item.brand }}</text></view>
  154 + <view class="row"><text class="label">品质</text><text class="value">{{ item.quality }}</text></view>
  155 + <view class="row"><text class="label">规格</text><text class="value">{{ item.specDisplay }}</text></view>
  156 + <view class="row"><text class="label">状态</text><text class="value">{{ item.status }}</text></view>
  157 + <view class="row"><text class="label">数量</text><text class="value">{{ item.quantity }}</text></view>
  158 + <view class="row"><text class="label">单价</text><text class="value">{{ formatCurrency(item.unitPrice)
  159 + }}</text>
  160 + </view>
  161 + <view class="row"><text class="label">不含税金额</text><text class="value">{{
  162 + formatCurrency(item.amountExcludingTax)
  163 + }}</text></view>
  164 + <view class="row"><text class="label">总金额</text><text class="value">{{ formatCurrency(item.totalAmount)
  165 + }}</text></view>
  166 + <view class="row"><text class="label">发货日期</text><text class="value">{{ item.orderDate }}</text></view>
  167 + </view>
  168 + </view>
  169 + </view>
  170 +</template>
  171 +<script>
  172 +export default {
  173 + name: 'ProductRel',
  174 + props: {
  175 + mode: { type: String, default: 'add' },
  176 + value: { type: Array, default: () => [] },
  177 + max: { type: Number, default: 8 }
  178 + },
  179 + data() {
  180 + return {
  181 + items: [],
  182 + collapsedView: false
  183 + }
  184 + },
  185 + watch: {
  186 + items: {
  187 + handler() { this.emitChange() },
  188 + deep: true
  189 + },
  190 + value: {
  191 + handler(v) {
  192 + const arr = Array.isArray(v) ? v : []
  193 + this.items = arr.map(x => ({ ...this.defaultItem(), ...x, collapsed: true }))
  194 + },
  195 + deep: true
  196 + }
  197 + },
  198 + created() {
  199 + const init = Array.isArray(this.value) && this.value.length > 0 ? this.value.map(v => ({ ...this.defaultItem(), ...v, collapsed: true })) : [{ ...this.defaultItem(), collapsed: false }]
  200 + this.items = init
  201 + },
  202 + methods: {
  203 + defaultItem() {
  204 + return { name: '', industry: '', brand: '', quality: '', thickness: '', thicknessTolPos: '', thicknessTolNeg: '', width: '', widthTolPos: '', widthTolNeg: '', length: '', lengthTolPos: '', lengthTolNeg: '', status: '', quantity: '', unitPrice: '', amountExcludingTax: '', totalAmount: '', orderDate: '' }
  205 + },
  206 + formatCurrency(val) {
  207 + if (val == null || val === '') return ''
  208 + const num = Number(val)
  209 + const pre = isNaN(num) ? '' : '¥'
  210 + const fixed = isNaN(num) ? String(val) : num.toFixed(2)
  211 + return `${pre}${fixed}`
  212 + },
  213 + specOf(item) {
  214 + const t = [item.thickness, item.thicknessTolPos, item.thicknessTolNeg].filter(Boolean).join('/')
  215 + const w = [item.width, item.widthTolPos, item.widthTolNeg].filter(Boolean).join('/')
  216 + const l = [item.length, item.lengthTolPos, item.lengthTolNeg].filter(Boolean).join('/')
  217 + return [t, w, l].filter(Boolean).join(' × ')
  218 + },
  219 + onAdd() {
  220 + if (this.items.length >= this.max) return uni.showToast({ title: `最多添加${this.max}个`, icon: 'none' })
  221 + const obj = this.defaultItem()
  222 + obj.collapsed = true
  223 + this.items.push(obj)
  224 + this.emitChange()
  225 + },
  226 + onRemove(idx) {
  227 + this.items.splice(idx, 1)
  228 + this.emitChange()
  229 + },
  230 + toggleItem(idx) {
  231 + const it = this.items[idx]
  232 + if (!it) return
  233 + it.collapsed = !it.collapsed
  234 + this.$set(this.items, idx, it)
  235 + },
  236 + emitChange() {
  237 + const out = this.items.map(it => ({ ...it, specDisplay: this.specOf(it) }))
  238 + this.$emit('input', out)
  239 + this.$emit('update:value', out)
  240 + this.$emit('change', out)
  241 + },
  242 + toggleViewCollapse() {
  243 + this.collapsedView = !this.collapsedView
  244 + }
  245 + }
  246 +}
  247 +</script>
  248 +<style lang="scss" scoped>
  249 +.product-rel {
  250 + margin-top: 10px;
  251 +}
  252 +
  253 +.header {
  254 + background-color: #fff;
  255 + display: flex;
  256 + align-items: center;
  257 + padding: 24rpx 32rpx;
  258 + border-bottom: 1rpx solid #f0f0f0;
  259 +}
  260 +
  261 +.dot {
  262 + width: 16rpx;
  263 + height: 16rpx;
  264 + background: #3D48A3;
  265 + border-radius: 50%;
  266 + margin-right: 12rpx;
  267 +}
  268 +
  269 +.title {
  270 + font-size: 32rpx;
  271 + color: rgba(0, 0, 0, 0.9);
  272 +}
  273 +
  274 +.ops {
  275 + margin-left: auto;
  276 +}
  277 +.op {
  278 + color: $theme-primary;
  279 + font-size: 28rpx;
  280 + margin-left: 8rpx;
  281 +}
  282 +.op1 {
  283 + display: flex;
  284 + align-items: center;
  285 +}
  286 +
  287 +.opAdd {
  288 + color: rgba(0, 0, 0, 0.6);
  289 + width: 40rpx;
  290 + height: 40rpx;
  291 +}
  292 +
  293 +.opCollapse {
  294 + color: rgba(0, 0, 0, 0.6);
  295 + width: 24rpx;
  296 + height: 24rpx;
  297 + margin-right: 16rpx;
  298 + margin-top: 16rpx;
  299 +}
  300 +
  301 +
  302 +.block {
  303 + background: #fff;
  304 + margin-bottom: 20rpx;
  305 +}
  306 +::v-deep .uni-list-item__content {
  307 + display: flex;
  308 + justify-content: center;
  309 +}
  310 +::v-deep .uni-list {
  311 + background: transparent;
  312 +
  313 + &-item {
  314 + &__container {
  315 + padding: 32rpx;
  316 + }
  317 +
  318 + &__content-title {
  319 + font-size: 28rpx;
  320 + color: rgba(0, 0, 0, 0.9);
  321 + }
  322 +
  323 + &__extra-text {
  324 + font-size: 32rpx;
  325 + }
  326 +
  327 + .uni-easyinput {
  328 + width: 100%;
  329 +
  330 + &__placeholder-class {
  331 + font-size: 32rpx;
  332 + color: rgba(0, 0, 0, 0.4);
  333 + }
  334 +
  335 + &__content {
  336 + border: none;
  337 + display: flex;
  338 + &-input {
  339 + padding-left: 0 !important;
  340 + height: 48rpx;
  341 + line-height: 48rpx;
  342 + font-size: 32rpx;
  343 + }
  344 + }
  345 +
  346 + .uni-input-placeholder {
  347 + z-index: 2;
  348 + }
  349 + }
  350 + }
  351 +}
  352 +
  353 +.block-ops {
  354 + display: flex;
  355 + padding: 20rpx 32rpx 20rpx;
  356 + justify-content: space-around;
  357 +}
  358 +
  359 +.del {
  360 + color: #D54941;
  361 + font-size: 28rpx;
  362 + display: flex;
  363 + align-items: center;
  364 + image {
  365 + width: 40rpx;
  366 + height: 40rpx;
  367 + }
  368 +}
  369 +
  370 +.toggle {
  371 + color: $theme-primary;
  372 + font-size: 28rpx;
  373 + display: flex;
  374 + align-items: center;
  375 + image {
  376 + width: 40rpx;
  377 + height: 40rpx;
  378 + }
  379 +}
  380 +
  381 +.view-list {
  382 + padding: 24rpx 32rpx;
  383 + background: #ffffff;
  384 +}
  385 +
  386 +.card {
  387 + background: #f3f3f3;
  388 + border-radius: 16rpx;
  389 + padding: 24rpx;
  390 + margin-bottom: 20rpx;
  391 +}
  392 +
  393 +.row {
  394 + display: flex;
  395 + margin-bottom: 20rpx;
  396 +}
  397 +
  398 +.row:last-child {
  399 + margin-bottom: 0;
  400 +}
  401 +
  402 +.label {
  403 + width: 120rpx;
  404 + color: rgba(0, 0, 0, 0.6);
  405 + font-size: 28rpx;
  406 +}
  407 +
  408 +.value {
  409 + flex: 1;
  410 + text-align: right;
  411 + color: rgba(0, 0, 0, 0.9);
  412 + font-size: 28rpx;
  413 +}
  414 +</style>
... ...