diff --git a/packageUser/self-report/create.vue b/packageUser/self-report/create.vue index 69663bb..73b3041 100644 --- a/packageUser/self-report/create.vue +++ b/packageUser/self-report/create.vue @@ -74,46 +74,33 @@ 销量填写 已添加{{ totalSalesItemCount }}项 - - - - 新增商品 + + + + + + + + {{ totalSalesItemCount > 0 ? '已填写销量商品' : '去填写销量' }} + + + {{ totalSalesItemCount > 0 ? `共 ${totalSalesItemCount} 项,点击可继续修改` : '支持搜索、分类筛选与批量填写' }} + + + + + {{ totalSalesItemCount }} + - 请点击“新增商品”逐个添加销量商品 - - - - - {{ item.name }} - {{ item.groupTitle }} - - 删除 - - - - 厂家 - {{ item.makerAbb }} - - - 编码 - {{ item.goodsCode || '-' }} - - - - - - - {{ item.spec || '规格' }} - - - - - - - {{ item.unit || '盒' }} - - + 请点击上方进入「销量填写」添加商品 + + + {{ item.name }} + {{ formatSalesQty(item.qty) }}{{ item.unit || '盒' }} + + + 等共 {{ totalSalesItemCount }} 项 @@ -192,7 +179,7 @@ 保存草稿 - {{ submitLoading ? '提交中...' : (isResubmit ? '重新提交' : '提交销量') }} + {{ submitLoading ? '提交中...' : (isResubmit ? '重新提交' : '提交填报') }} @@ -253,60 +240,6 @@ - - - - 取消 - 选择商品 - 完成 - - - - - - - - - - - {{ group.title }} - - - - 暂无可选商品 - 该分类暂无可选商品 - - - - - {{ item.name }} - {{ item.makerAbb || '-' }} / {{ item.spec || '规格' }} - - - {{ isProductSelected(item) ? '已添加' : '添加' }} - - - - - - - { - const items = Array.isArray(group.items) ? group.items : [] - const nextItems = items.filter(item => { - const name = String(item.name || '').toLowerCase() - const maker = String(item.makerAbb || '').toLowerCase() - const spec = String(item.spec || '').toLowerCase() - return name.includes(keyword) || maker.includes(keyword) || spec.includes(keyword) - }) - return Object.assign({}, group, {items: nextItems}) - }) - .filter(group => Array.isArray(group.items) && group.items.length) - }, - currentProductGroupKey() { - const groups = Array.isArray(this.filteredProductGroups) ? this.filteredProductGroups : [] - if (!groups.length) return '' - const hasActive = groups.some(group => group.key === this.activeProductGroupKey) - return hasActive ? this.activeProductGroupKey : groups[0].key - }, - displayedProductOptions() { - const groups = Array.isArray(this.filteredProductGroups) ? this.filteredProductGroups : [] - const current = groups.find(group => group.key === this.currentProductGroupKey) - return current && Array.isArray(current.items) ? current.items : [] - }, totalSalesItemCount() { return Array.isArray(this.salesItems) ? this.salesItems.length : 0 }, + // 填报页只做摘要展示,明细与编辑都在「销量填写」页 + salesSummaryLimit() { + return 3 + }, + salesSummaryRows() { + const items = Array.isArray(this.salesItems) ? this.salesItems : [] + return items.slice(0, this.salesSummaryLimit) + }, totalRewardAmount() { return (Array.isArray(this.salesItems) ? this.salesItems : []).reduce((sum, item) => { return sum + (this.parseSalesQty(item && item.qty) * this.getTaskIncomeNumber(item)) @@ -476,9 +388,43 @@ export default { } else { await this.checkDraftOnEntry() } + return } + // 从「销量填写」页返回时接收交接数据(仅在用户主动保存/提交后才有 action) + this.consumeSalesHandoff() }, methods: { + // 销量页只回传数据,整单的提交动作仍由本页的「提交填报」统一完成。 + // action='submit' 为销量页点了它自己的「提交销量」,'merge' 为返回时同步明细, + // 两者都只做合并,不代表本页已提交。 + consumeSalesHandoff() { + const handoff = getSalesHandoff() + if (!handoff || !handoff.action) return + const items = Array.isArray(handoff.items) ? handoff.items : [] + this.salesItems = cloneSalesItems(items) + clearSalesHandoff() + if (handoff.action === 'submit' && !items.length) { + uni.showToast({title: '销量商品不能为空', icon: 'none'}) + } + }, + openSalesEntry() { + if (!this.form.chainId || !this.form.merchantId) { + uni.showToast({title: '请先选择连锁和门店', icon: 'none'}) + return + } + // 销量页需要连锁名去拉商品库,进页前先把当前明细交出去 + setSalesHandoff({ + action: '', + chainName: this.form.chainName || '', + items: cloneSalesItems(this.salesItems) + }) + uni.navigateTo({ + url: '/packageUser/self-report/sales', + fail: () => { + uni.showToast({title: '页面打开失败', icon: 'none'}) + } + }) + }, buildForm() { return { chainId: '', @@ -503,19 +449,14 @@ export default { ] this.boothPhotos = [] this.receiptPhotos = [] - this.productGroups = [] this.salesItems = [] - this.salesKeyword = '' - this.showProductPicker = false this.showChainPicker = false - this.activeProductGroupKey = '' this.currentAddress = '' this.lat = null this.lng = null this.currentProvince = '' this.currentCity = '' await this.getMerchantList() - await this.getProductGroups() }, getDraftStorageKey() { const user = getUserInfo() || {} @@ -644,10 +585,6 @@ export default { if (!this.currentAddress || !this.lat || !this.lng) { await this.fetchCurrentLocation() } - // 销量商品按连锁重新拉取,保证规格选项与当前连锁一致 - if (this.form.chainName) { - await this.getProductGroups() - } } catch (error) { await this.toast(error && error.message ? error.message : '填报记录加载失败') } finally { @@ -809,13 +746,8 @@ export default { this.lng = draft.lng this.currentProvince = draft.currentProvince || '' this.currentCity = draft.currentCity || '' - this.salesKeyword = '' - this.showProductPicker = false this.showChainPicker = false this.showMerchantPicker = false - if (this.form.chainName) { - await this.getProductGroups() - } }, async fetchCurrentLocation() { const location = await getLocationOnly().catch(() => null) @@ -1033,14 +965,12 @@ export default { this.form.lng = '' this.merchantStoreSearchKeyword = '' this.merchantPickerValue = [0] + // 商品库按连锁过滤,换连锁后原销量明细已不适用。 + // 草稿不清:按规则只有「提交成功」与「恢复询问时放弃」才丢弃草稿。 this.salesItems = [] - this.productGroups = [] - this.productLoadedChainName = '' - this.activeProductGroupKey = '' - this.salesKeyword = '' + clearSalesHandoff() } this.closeChainPicker() - if (changed) await this.getProductGroups() }, openMerchantPicker() { if (!this.form.chainId) { @@ -1091,285 +1021,14 @@ export default { const prevChainName = String(this.form.chainName || '').trim() this.applyMerchant(chain, selected) const nextChainName = String(this.form.chainName || '').trim() - this.salesKeyword = '' - this.productGroups = [] - this.productLoadedChainName = '' - this.activeProductGroupKey = '' this.closeMerchantPicker() if (nextChainName && nextChainName !== prevChainName) { - await this.getProductGroups() + // 换连锁后商品库与销量明细不再适用。 + // 草稿不清:按规则只有「提交成功」与「恢复询问时放弃」才丢弃草稿。 + this.salesItems = [] + clearSalesHandoff() } }, - isProductNode(node) { - if (!node || typeof node !== 'object') return false - const product = node.product && typeof node.product === 'object' ? node.product : {} - const hasChildrenOnly = Array.isArray(node.children) - && !this.pickFirstText(node, ['goodsName', 'goods_name', 'goodsCode', 'code', 'productCode', 'batchCode']) - && !node.product - if (hasChildrenOnly) return false - return !!( - this.pickFirstText(node, ['goodsName', 'goods_name', 'goodsCode', 'code', 'productCode', 'batchCode']) || - this.pickFirstText(product, ['goodsName', 'goods_name', 'goodsCode', 'code', 'productCode', 'batchCode']) - ) - }, - collectProductNodes(node, depth = 0) { - if (!node || depth > 4) return [] - if (Array.isArray(node)) { - return node.reduce((acc, item) => acc.concat(this.collectProductNodes(item, depth + 1)), []) - } - if (typeof node !== 'object') return [] - if (this.isProductNode(node)) return [node] - const keys = ['productList', 'products', 'list', 'records', 'rows', 'items', 'children', 'data'] - return keys.reduce((acc, key) => { - const value = node[key] - if (Array.isArray(value) || (value && typeof value === 'object')) { - return acc.concat(this.collectProductNodes(value, depth + 1)) - } - return acc - }, []) - }, - buildCategoryTabs(rawData) { - const rootList = this.unwrapList(rawData) - const tabs = [] - rootList.forEach((categoryNode, categoryIndex) => { - if (!categoryNode || typeof categoryNode !== 'object') return - const label = categoryNode.cate - const products = Array.isArray(categoryNode.children) ? categoryNode.children : [] - if (!label || !products.length) return - tabs.push({ - key: `cate_children_${categoryIndex}`, - label, - rawProducts: products - }) - }) - if (tabs.length) return tabs - const allProducts = this.collectProductNodes(rootList) - if (allProducts.length) { - tabs.push({ - key: 'all', - label: '全部', - rawProducts: allProducts - }) - } - return tabs - }, - normalizeSpecOptions(item) { - const raw = item.specOptions || item.specList || item.specs || [] - if (Array.isArray(raw)) { - return raw.map(value => `${value}`.trim()).filter(Boolean) - } - if (typeof raw === 'string') { - return raw.split(/[、,,]/).map(value => value.trim()).filter(Boolean) - } - const spec = item.spec || item.specification || item.standard || '' - return spec ? [spec] : [] - }, - normalizeProduct(item) { - const product = item && item.product ? item.product : {} - const code = item.goodsCode || item.code || item.productCode || item.batchCode || product.code || product.goodsCode || '' - const productId = item.productId || item.id || item.goodsId || item.skuId || product.productId || product.id || '' - const name = item.goodsName || item.goods_name || item.title || item.name || product.title || product.goodsName || product.name || '' - const maker = item.makerAbb || item.maker || item.manufacturer || product.makerAbb || product.maker || product.manufacturer || '' - const spec = product.spec || item.spec || item.specification || '' - const cover = item.cover || product.cover || '' - const chainId = item.chainId || item.chain_id || product.chainId || product.chain_id || '' - const chainName = item.chainName || item.chain_name || item.chain || product.chainName || product.chain_name || product.chain || '' - const merchantId = item.merchantId || item.merchant_id || product.merchantId || product.merchant_id || '' - const merchantName = item.merchantName || item.merchant_name || item.shopName || item.shop_name || product.merchantName || product.merchant_name || '' - return { - productId, - goodsCode: code, - name, - cover, - makerAbb: maker, - spec, - chainId, - chainName, - merchantId, - merchantName, - unit: item.unit || product.unit || '盒', - taskIncome: this.resolveTaskIncome(item), - specOptions: this.normalizeSpecOptions(Object.assign({}, product, item)), - qty: '' - } - }, - hasDisplayValue(value) { - return value !== undefined && value !== null && String(value).trim() !== '' - }, - resolveTaskIncome(item) { - if (!item || typeof item !== 'object') return '' - const product = item.product && typeof item.product === 'object' ? item.product : {} - const candidates = [ - item.taskIncome - ] - for (let i = 0; i < candidates.length; i += 1) { - const value = candidates[i] - if (this.hasDisplayValue(value)) return value - } - return '' - }, - hasTaskIncome(item) { - return this.hasDisplayValue(this.resolveTaskIncome(item)) - }, - formatTaskIncome(item) { - const value = this.resolveTaskIncome(item) - if (!this.hasDisplayValue(value)) return '' - const num = Number(value) - if (!Number.isFinite(num)) return String(value) - return Number.isInteger(num) ? String(num) : num.toFixed(2) - }, - parseSalesQty(value) { - const num = Number(value) - return Number.isFinite(num) ? num : 0 - }, - getTaskIncomeNumber(item) { - const num = Number(this.resolveTaskIncome(item)) - return Number.isFinite(num) ? num : 0 - }, - formatMoney(value) { - const num = Number(value) - if (!Number.isFinite(num)) return '0.00' - return num.toFixed(2) - }, - filterProductGroupsByChain(groups = [], rawChainId = '') { - const chainId = this.normalizeChainIdForApi(rawChainId) - if (!chainId) return Array.isArray(groups) ? groups : [] - return (Array.isArray(groups) ? groups : []) - .map(group => Object.assign({}, group, { - items: (Array.isArray(group.items) ? group.items : []).filter(item => { - const productChainId = String(item.chainId || '').trim() - return !productChainId || productChainId === chainId - }) - })) - .filter(group => Array.isArray(group.items) && group.items.length) - }, - buildSalesGroupsFromProductData(rawData) { - const tabs = this.buildCategoryTabs(rawData) - let rowSeed = 0 - const groups = tabs.map((tab, tabIndex) => { - const items = (Array.isArray(tab.rawProducts) ? tab.rawProducts : []) - .map((rawItem, itemIndex) => { - const product = this.normalizeProduct(rawItem) - if (!product.name) return null - const specOptions = Array.isArray(product.specOptions) && product.specOptions.length - ? product.specOptions - : [product.spec || '规格'] - return { - ...product, - groupTitle: tab.label || `分类${tabIndex + 1}`, - spec: product.spec || specOptions[0] || '规格', - specOptions, - _key: `sales_${tabIndex}_${itemIndex}_${rowSeed++}` - } - }) - .filter(Boolean) - return { - key: tab.key || `group_${tabIndex}`, - title: tab.label || `分类${tabIndex + 1}`, - items - } - }).filter(group => group.items.length) - return groups - }, - async getProductGroups() { - const chainName = String(this.form.chainName || '').trim() - if (!chainName) { - this.productGroups = [] - this.productLoadedChainName = '' - this.activeProductGroupKey = '' - return - } - this.productLoading = true - try { - const {data} = await productGroupByCateReq({chain: chainName, type: 0}) - this.productGroups = this.buildSalesGroupsFromProductData(data) - this.productLoadedChainName = chainName - } catch (error) { - this.productGroups = [] - this.productLoadedChainName = '' - uni.showToast({ - title: '商品数据获取失败', - icon: 'none' - }) - } finally { - this.activeProductGroupKey = this.productGroups[0] ? this.productGroups[0].key : '' - this.productLoading = false - } - }, - async openProductPicker() { - if (!this.form.chainName || !this.form.merchantId) { - uni.showToast({ - title: '请先选择连锁和门店', - icon: 'none' - }) - return - } - const currentChainName = String(this.form.chainName || '').trim() - if (!currentChainName) { - uni.showToast({ - title: '当前连锁无效', - icon: 'none' - }) - return - } - if (this.productLoadedChainName !== currentChainName || !this.productGroups.length) { - await this.getProductGroups() - } - if (!this.filteredProductGroups.length) { - uni.showToast({ - title: '当前连锁暂无可选商品', - icon: 'none' - }) - return - } - if (!this.activeProductGroupKey) { - this.activeProductGroupKey = this.filteredProductGroups[0] ? this.filteredProductGroups[0].key : '' - } - this.showProductPicker = true - }, - closeProductPicker() { - this.showProductPicker = false - }, - selectProductGroup(key) { - this.activeProductGroupKey = key - }, - isProductSelected(product) { - return (Array.isArray(this.salesItems) ? this.salesItems : []).some(item => { - if (product.productId && item.productId) { - return String(item.productId) === String(product.productId) - } - return item.name === product.name - }) - }, - selectProduct(product) { - if (this.isProductSelected(product)) { - uni.showToast({ - title: '该商品已添加', - icon: 'none' - }) - return - } - const specOptions = Array.isArray(product.specOptions) && product.specOptions.length - ? [...product.specOptions] - : [product.spec || '规格'] - this.salesItems.push({ - ...product, - groupTitle: product.groupTitle || '', - specOptions, - spec: product.spec || specOptions[0] || '规格', - qty: '' - }) - this.showProductPicker = false - this.salesKeyword = '' - }, - removeSalesItem(index) { - this.salesItems.splice(index, 1) - }, - onSpecChange(event, item) { - const value = Number(event.detail.value || 0) - const nextSpec = item.specOptions[value] || item.spec - item.spec = nextSpec - }, async ensureLogin() { if (this.isLoggedIn) return true this.$refs.Login.open() @@ -1476,6 +1135,32 @@ export default { if (emptyQty) item.qty = 0 }) }, + hasDisplayValue(value) { + return value !== undefined && value !== null && String(value).trim() !== '' + }, + resolveTaskIncome(item) { + if (!item || typeof item !== 'object') return '' + return this.hasDisplayValue(item.taskIncome) ? item.taskIncome : '' + }, + parseSalesQty(value) { + const num = Number(value) + return Number.isFinite(num) ? num : 0 + }, + getTaskIncomeNumber(item) { + const num = Number(this.resolveTaskIncome(item)) + return Number.isFinite(num) ? num : 0 + }, + formatMoney(value) { + const num = Number(value) + if (!Number.isFinite(num)) return '0.00' + return num.toFixed(2) + }, + formatSalesQty(value) { + const empty = value === '' || value === null || value === undefined + if (empty) return '0' + const num = Number(value) + return Number.isFinite(num) ? String(num) : '0' + }, buildSubmitSalesGroups() { const groupsMap = {} ;(Array.isArray(this.salesItems) ? this.salesItems : []).forEach(item => { @@ -1596,10 +1281,13 @@ export default { delete payload.status payload.id = this.resubmitId await selfReportResubmitReq(payload) + clearSalesHandoff() await this.toast('重新提交成功,请等待审核') } else { await selfReportAddReq(this.buildPayload()) this.clearDraft() + // 整页已提交,交接数据不该留到下次 + clearSalesHandoff() await this.toast('提交成功,请等待审核') } uni.navigateBack({ @@ -1882,153 +1570,114 @@ export default { justify-content: center; } -.sales-search { - margin-bottom: 18rpx; -} - -.sales-actions { - margin-bottom: 18rpx; -} - -.sales-add-btn { - width: 240rpx; - min-height: 76rpx; - border-radius: 999rpx; - background: linear-gradient(135deg, #ff8a4c, #ff6b4a); - box-shadow: 0 12rpx 24rpx rgba(255, 107, 74, 0.2); - display: inline-flex; +.sales-entry { + display: flex; align-items: center; - justify-content: center; - gap: 10rpx; - color: #ffffff; - font-size: 26rpx; - font-weight: 700; - letter-spacing: 1rpx; -} - -.selected-sales-list { - display: flex; - flex-direction: column; - gap: 18rpx; -} - -.selected-sales-item { - padding: 22rpx; - border-radius: 22rpx; - background: linear-gradient(180deg, #fffaf5, #ffffff); - border: 1rpx solid #fde7d8; -} - -.selected-sales-head { - display: flex; - align-items: flex-start; justify-content: space-between; gap: 20rpx; + padding: 26rpx 24rpx; + border-radius: 20rpx; + background: linear-gradient(135deg, #fff6ef, #fffaf6); + border: 2rpx solid #ffd9c2; } -.selected-sales-name { - font-size: 30rpx; - font-weight: 700; - color: #0f172a; -} - -.selected-sales-group { - margin-top: 8rpx; - font-size: 22rpx; - color: #c2410c; -} - -.selected-sales-remove { - color: #ef4444; - font-size: 24rpx; -} - -.selected-sales-meta { - margin-top: 16rpx; +.sales-entry-left { + flex: 1; + min-width: 0; display: flex; - flex-wrap: wrap; - gap: 14rpx; -} - -.selected-sales-meta-item { - min-width: 220rpx; - padding: 12rpx 16rpx; - border-radius: 16rpx; - background: #fff7ed; -} - -.meta-label { - color: #9a3412; - font-size: 22rpx; -} - -.meta-value { - display: block; - margin-top: 4rpx; - color: #7c2d12; - font-size: 24rpx; -} - -.sales-controls { - margin-top: 16rpx; - display: flex; - align-items: flex-start; - justify-content: space-between; + align-items: center; gap: 18rpx; } -.spec-wrap { +.sales-entry-icon { + flex-shrink: 0; + width: 76rpx; + height: 76rpx; + border-radius: 20rpx; + background: #ffffff; + border: 1rpx solid #ffd9c2; + display: flex; + align-items: center; + justify-content: center; +} + +.sales-entry-text { flex: 1; min-width: 0; } -.spec-picker { - display: block; -} - -.spec-pill { - min-height: 72rpx; - border-radius: 999rpx; - background: #fff7ed; - border: 1rpx solid #fdba74; - color: #c2410c; - display: flex; - align-items: center; - justify-content: center; - padding: 0 22rpx; - font-size: 24rpx; -} - -.sales-income { - margin-top: 10rpx; - padding-left: 8rpx; - color: #dc2626; - font-size: 24rpx; - line-height: 1.4; -} - -.qty-box { - width: 240rpx; - display: flex; - align-items: center; - justify-content: space-between; - gap: 12rpx; - padding: 0 20rpx; - min-height: 72rpx; - border-radius: 18rpx; - background: #f8fafc; - border: 1rpx solid #dbe3ef; -} - -.qty-input { - flex: 1; - font-size: 30rpx; +.sales-entry-title { + font-size: 29rpx; + font-weight: 700; color: #0f172a; } -.qty-unit { - color: #7a8495; - font-size: 24rpx; +.sales-entry-sub { + margin-top: 6rpx; + font-size: 23rpx; + color: #9aa3b2; +} + +.sales-entry-right { + flex-shrink: 0; + display: flex; + align-items: center; + gap: 10rpx; +} + +.sales-entry-count { + min-width: 40rpx; + height: 40rpx; + padding: 0 12rpx; + border-radius: 999rpx; + background: linear-gradient(135deg, #ff8a4c, #ff6b4a); + color: #ffffff; + font-size: 22rpx; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; +} + +.sales-summary-list { + margin-top: 18rpx; + display: flex; + flex-direction: column; + gap: 12rpx; +} + +.sales-summary-item { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16rpx; + padding: 16rpx 20rpx; + border-radius: 14rpx; + background: #f8fafc; +} + +.sales-summary-name { + flex: 1; + min-width: 0; + font-size: 26rpx; + color: #374151; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.sales-summary-qty { + flex-shrink: 0; + font-size: 26rpx; + font-weight: 700; + color: #ff7a35; +} + +.sales-summary-more { + padding-top: 4rpx; + text-align: center; + font-size: 23rpx; + color: #9aa3b2; } .summary-input { @@ -2158,104 +1807,6 @@ export default { color: #1f2937; } -.product-picker { - background: #ffffff; - padding-bottom: calc(env(safe-area-inset-bottom) + 12rpx); -} - -.product-panel { - display: flex; - height: 62vh; - border-top: 1rpx solid #eef2f7; -} - -.category-sidebar { - width: 220rpx; - background: linear-gradient(180deg, #f8fafc, #fff7ed); - border-right: 1rpx solid #eef2f7; -} - -.category-item { - min-height: 88rpx; - padding: 18rpx 16rpx; - box-sizing: border-box; - display: flex; - align-items: center; - justify-content: center; - text-align: center; - color: #64748b; - font-size: 24rpx; - border-bottom: 1rpx solid rgba(226, 232, 240, 0.8); -} - -.category-item-active { - background: #ffffff; - color: #ea580c; - font-weight: 700; -} - -.product-panel-main { - flex: 1; - padding: 20rpx 24rpx 24rpx; - box-sizing: border-box; -} - -.product-picker-item { - display: flex; - align-items: center; - justify-content: space-between; - gap: 18rpx; - padding: 18rpx 20rpx; - border-radius: 18rpx; - background: #f8fafc; - border: 1rpx solid #e2e8f0; -} - -.product-picker-item + .product-picker-item { - margin-top: 12rpx; -} - -.product-picker-main { - flex: 1; - min-width: 0; -} - -.product-picker-cover { - flex-shrink: 0; - width: 96rpx; - height: 96rpx; - border-radius: 16rpx; - background: #ffffff; -} - -.product-picker-name { - color: #0f172a; - font-size: 28rpx; - font-weight: 600; -} - -.product-picker-sub { - margin-top: 6rpx; - color: #64748b; - font-size: 22rpx; -} - -.product-picker-income { - margin-top: 6rpx; - color: #dc2626; - font-size: 22rpx; -} - -.product-picker-tag { - flex-shrink: 0; - padding: 8rpx 18rpx; - border-radius: 999rpx; - background: #dcfce7; - color: #15803d; - font-size: 22rpx; - font-weight: 700; -} - .audit-empty-tip { padding: 30rpx 0; text-align: center; diff --git a/packageUser/self-report/sales.vue b/packageUser/self-report/sales.vue new file mode 100644 index 0000000..bd0a574 --- /dev/null +++ b/packageUser/self-report/sales.vue @@ -0,0 +1,1258 @@ + + + + + diff --git a/pages.json b/pages.json index dd0c9c3..765af2c 100644 --- a/pages.json +++ b/pages.json @@ -170,6 +170,13 @@ "navigationStyle": "custom" } }, + { + "path": "self-report/sales", + "style": { + "navigationBarTitleText": "销量填写", + "navigationStyle": "custom" + } + }, { "path": "self-report/records", "style": { diff --git a/util/sales-handoff.js b/util/sales-handoff.js new file mode 100644 index 0000000..81d2e68 --- /dev/null +++ b/util/sales-handoff.js @@ -0,0 +1,44 @@ +import {getUserInfo} from "@/util/user"; + +// 「自主填报」(create.vue) 与「销量填写」(sales.vue) 两个页面之间的数据交接。 +// 本工程没有全局状态管理,页面间只能靠 storage 传递。 +// +// 这里只负责一次性的交接,不是草稿: +// - 进销量页前,create 页写入连锁名与当前明细作为上下文; +// - 销量页返回时写回明细(action='submit' 表示用户点了销量页自己的 +// 「提交销量」,'merge' 表示按返回键离开时同步明细); +// - create 页消费后即清。两者都不代表整单已提交,整单提交是 +// create 页「提交填报」按钮的职责。 +// +// 持久化草稿统一由 create 页的整单草稿负责(含 salesItems/打卡/小票/小结), +// 销量页不再单独存草稿,避免两份状态互相覆盖。 +const normalizeUid = () => { + const user = getUserInfo() || {} + const uid = user.uid || user.id || user.userId || 'guest' + return String(uid) +} + +const readObject = key => { + const value = uni.getStorageSync(key) + return value && typeof value === 'object' ? value : null +} + +export const cloneSalesItems = (items = []) => { + try { + return JSON.parse(JSON.stringify(Array.isArray(items) ? items : [])) + } catch (error) { + return [] + } +} + +export const getSalesHandoffKey = () => `yxe_self_report_sales_handoff_${normalizeUid()}` + +export const setSalesHandoff = (payload = {}) => { + uni.setStorageSync(getSalesHandoffKey(), Object.assign({savedAt: Date.now()}, payload)) +} + +export const getSalesHandoff = () => readObject(getSalesHandoffKey()) + +export const clearSalesHandoff = () => { + uni.removeStorageSync(getSalesHandoffKey()) +}