9.16/1
This commit is contained in:
45
frontend/pages/account/select.vue
Normal file
45
frontend/pages/account/select.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<scroll-view scroll-y class="list">
|
||||
<view class="item" v-for="a in accounts" :key="a.id" @click="select(a)">
|
||||
<view class="name">{{ a.name }}</view>
|
||||
<view class="meta">{{ typeLabel(a.type) }} · 余额:{{ a.balance?.toFixed ? a.balance.toFixed(2) : a.balance }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get } from '../../common/http.js'
|
||||
const TYPE_MAP = { cash: '现金', bank: '银行', alipay: '支付宝', wechat: '微信', other: '其他' }
|
||||
export default {
|
||||
data() { return { accounts: [] } },
|
||||
async onLoad() {
|
||||
try {
|
||||
const res = await get('/api/accounts')
|
||||
this.accounts = Array.isArray(res) ? res : (res?.list || [])
|
||||
} catch(e) { uni.showToast({ title: '加载失败', icon: 'none' }) }
|
||||
},
|
||||
methods: {
|
||||
select(a) {
|
||||
const opener = getCurrentPages()[getCurrentPages().length-2]
|
||||
if (opener && opener.$vm) {
|
||||
opener.$vm.selectedAccountId = a.id
|
||||
opener.$vm.selectedAccountName = a.name
|
||||
}
|
||||
uni.navigateBack()
|
||||
},
|
||||
typeLabel(t) { return TYPE_MAP[t] || t }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page { display:flex; flex-direction: column; height: 100vh; }
|
||||
.list { flex:1; }
|
||||
.item { padding: 20rpx 24rpx; background:#fff; border-bottom: 1rpx solid #f1f1f1; }
|
||||
.name { color:#333; margin-bottom: 6rpx; }
|
||||
.meta { color:#888; font-size: 24rpx; }
|
||||
</style>
|
||||
|
||||
|
||||
50
frontend/pages/customer/select.vue
Normal file
50
frontend/pages/customer/select.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="search">
|
||||
<input v-model="kw" placeholder="搜索客户名称/电话" @confirm="search" />
|
||||
<button size="mini" @click="search">搜索</button>
|
||||
</view>
|
||||
<scroll-view scroll-y class="list">
|
||||
<view class="item" v-for="c in customers" :key="c.id" @click="select(c)">
|
||||
<view class="name">{{ c.name }}</view>
|
||||
<view class="meta">{{ c.mobile || '—' }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get } from '../../common/http.js'
|
||||
export default {
|
||||
data() { return { kw: '', customers: [] } },
|
||||
onLoad() { this.search() },
|
||||
methods: {
|
||||
async search() {
|
||||
try {
|
||||
const res = await get('/api/customers', { kw: this.kw, page: 1, size: 50 })
|
||||
this.customers = Array.isArray(res?.list) ? res.list : (Array.isArray(res) ? res : [])
|
||||
} catch(e) { uni.showToast({ title: '加载失败', icon: 'none' }) }
|
||||
},
|
||||
select(c) {
|
||||
const opener = getCurrentPages()[getCurrentPages().length-2]
|
||||
if (opener && opener.$vm) {
|
||||
opener.$vm.order.customerId = c.id
|
||||
opener.$vm.customerName = c.name
|
||||
}
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page { display:flex; flex-direction: column; height: 100vh; }
|
||||
.search { display:flex; gap: 12rpx; padding: 16rpx; background:#fff; }
|
||||
.search input { flex:1; background:#f6f6f6; border-radius: 12rpx; padding: 12rpx; }
|
||||
.list { flex:1; }
|
||||
.item { padding: 20rpx 24rpx; background:#fff; border-bottom: 1rpx solid #f1f1f1; }
|
||||
.name { color:#333; margin-bottom: 6rpx; }
|
||||
.meta { color:#888; font-size: 24rpx; }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -12,22 +12,26 @@
|
||||
<view class="kpi">
|
||||
<view class="kpi-item">
|
||||
<text class="kpi-label">今日销售额</text>
|
||||
<text class="kpi-value">{{ todayAmount }}</text>
|
||||
<text class="kpi-value">{{ kpi.todaySales }}</text>
|
||||
</view>
|
||||
<view class="kpi-item">
|
||||
<text class="kpi-label">本月销售额</text>
|
||||
<text class="kpi-value">{{ kpi.monthSales }}</text>
|
||||
</view>
|
||||
<view class="kpi-item">
|
||||
<text class="kpi-label">本月利润</text>
|
||||
<text class="kpi-value">{{ monthProfit }}</text>
|
||||
<text class="kpi-value">{{ kpi.monthProfit }}</text>
|
||||
</view>
|
||||
<view class="kpi-item">
|
||||
<text class="kpi-label">库存数量</text>
|
||||
<text class="kpi-value">{{ stockQty }}</text>
|
||||
<text class="kpi-label">库存商品数量</text>
|
||||
<text class="kpi-value">{{ kpi.stockCount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 公告栏:自动轮播,可点击查看详情 -->
|
||||
<!-- 广告栏:自动轮播,可点击查看详情 -->
|
||||
<view class="notice">
|
||||
<view class="notice-left">公告</view>
|
||||
<view class="notice-left">广告</view>
|
||||
<view v-if="loadingNotices" class="notice-swiper" style="display:flex;align-items:center;color:#6b5a2a;">加载中...</view>
|
||||
<view v-else-if="noticeError" class="notice-swiper" style="display:flex;align-items:center;color:#dd524d;">{{ noticeError }}</view>
|
||||
<view v-else-if="!notices.length" class="notice-swiper" style="display:flex;align-items:center;color:#6b5a2a;">暂无公告</view>
|
||||
@@ -39,7 +43,6 @@
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="notice-right" @click="onNoticeList">更多</view>
|
||||
</view>
|
||||
|
||||
<!-- 分割标题:产品与功能 -->
|
||||
@@ -66,12 +69,18 @@
|
||||
<view class="tab" :class="{ active: activeTab==='home' }" @click="activeTab='home'">
|
||||
<text>首页</text>
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeTab==='product' }" @click="activeTab='product'">
|
||||
<text>货品</text>
|
||||
</view>
|
||||
<view class="tab primary" @click="onCreateOrder">
|
||||
<text>开单</text>
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeTab==='detail' }" @click="activeTab='detail'">
|
||||
<text>明细</text>
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeTab==='report' }" @click="activeTab='report'">
|
||||
<text>报表</text>
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeTab==='me' }" @click="activeTab='me'">
|
||||
<text>我的</text>
|
||||
</view>
|
||||
@@ -84,9 +93,7 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
todayAmount: '0.00',
|
||||
monthProfit: '0.00',
|
||||
stockQty: '0.00',
|
||||
kpi: { todaySales: '0.00', monthSales: '0.00', monthProfit: '0.00', stockCount: '0' },
|
||||
activeTab: 'home',
|
||||
notices: [],
|
||||
loadingNotices: false,
|
||||
@@ -105,9 +112,23 @@
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.fetchMetrics()
|
||||
this.fetchNotices()
|
||||
},
|
||||
methods: {
|
||||
async fetchMetrics() {
|
||||
try {
|
||||
const d = await get('/api/metrics/overview')
|
||||
this.kpi = {
|
||||
todaySales: (d && d.todaySales) || '0.00',
|
||||
monthSales: (d && d.monthSales) || '0.00',
|
||||
monthProfit: (d && d.monthProfit) || '0.00',
|
||||
stockCount: (d && d.stockCount) || '0'
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略错误,保留默认值
|
||||
}
|
||||
},
|
||||
async fetchNotices() {
|
||||
this.loadingNotices = true
|
||||
this.noticeError = ''
|
||||
@@ -127,18 +148,16 @@
|
||||
uni.showToast({ title: item.title + '(开发中)', icon: 'none' })
|
||||
},
|
||||
onCreateOrder() {
|
||||
uni.showToast({ title: '开单(开发中)', icon: 'none' })
|
||||
uni.navigateTo({ url: '/pages/order/create' })
|
||||
},
|
||||
onNoticeTap(n) {
|
||||
uni.showModal({
|
||||
title: '公告',
|
||||
title: '广告',
|
||||
content: n && (n.text || n.title || n.content) || '',
|
||||
showCancel: false
|
||||
})
|
||||
},
|
||||
onNoticeList() {
|
||||
uni.showToast({ title: '公告列表(开发中)', icon: 'none' })
|
||||
},
|
||||
|
||||
onIconError(item) {
|
||||
item.img = ''
|
||||
}
|
||||
@@ -192,7 +211,7 @@
|
||||
.notice-item { display: flex; align-items: center; gap: 12rpx; min-height: 72rpx; }
|
||||
.notice-text { color: #4b3e19; font-size: 28rpx; line-height: 36rpx; font-weight: 600; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.notice-tag { color: #B4880F; font-size: 22rpx; padding: 4rpx 10rpx; border-radius: 999rpx; background: rgba(215,167,46,0.18); }
|
||||
.notice-right { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; min-width: 72rpx; height: 44rpx; color: #B4880F; font-size: 26rpx; padding-left: 8rpx; }
|
||||
|
||||
|
||||
/* 分割标题 */
|
||||
.section-title { display: flex; align-items: center; gap: 16rpx; padding: 10rpx 28rpx 0; }
|
||||
|
||||
224
frontend/pages/order/create.vue
Normal file
224
frontend/pages/order/create.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<view class="order">
|
||||
<!-- 顶部 Tab -->
|
||||
<view class="tabs">
|
||||
<text :class="{ active: biz==='sale' }" @click="switchBiz('sale')">销售</text>
|
||||
<text :class="{ active: biz==='purchase' }" @click="switchBiz('purchase')">进货</text>
|
||||
<text :class="{ active: biz==='income' }" @click="switchBiz('income')">其他收入</text>
|
||||
<text :class="{ active: biz==='expense' }" @click="switchBiz('expense')">其他支出</text>
|
||||
</view>
|
||||
|
||||
<!-- 子类目按钮 -->
|
||||
<view class="subtabs" v-if="biz==='sale'">
|
||||
<button class="subbtn" :class="{ active: saleType==='out' }" @click="saleType='out'">出货</button>
|
||||
<button class="subbtn" :class="{ active: saleType==='return' }" @click="saleType='return'">退货</button>
|
||||
<button class="subbtn" :class="{ active: saleType==='collect' }" @click="saleType='collect'">收款</button>
|
||||
</view>
|
||||
<view class="subtabs" v-else-if="biz==='purchase'">
|
||||
<button class="subbtn" :class="{ active: purchaseType==='in' }" @click="purchaseType='in'">进货</button>
|
||||
<button class="subbtn" :class="{ active: purchaseType==='return' }" @click="purchaseType='return'">退货</button>
|
||||
<button class="subbtn" :class="{ active: purchaseType==='pay' }" @click="purchaseType='pay'">付款</button>
|
||||
</view>
|
||||
|
||||
<!-- 日期与客户 -->
|
||||
<picker mode="date" :value="order.orderTime" @change="onDateChange">
|
||||
<view class="field">
|
||||
<text class="label">时间</text>
|
||||
<text class="value">{{ order.orderTime }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="field" v-if="biz==='sale'" @click="chooseCustomer">
|
||||
<text class="label">客户</text>
|
||||
<text class="value">{{ customerLabel }}</text>
|
||||
</view>
|
||||
<view class="field" v-else-if="biz==='purchase'" @click="chooseSupplier">
|
||||
<text class="label">供应商</text>
|
||||
<text class="value">{{ supplierLabel }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 已选商品与合计(销售/进货) -->
|
||||
<view v-if="biz==='sale' || biz==='purchase'">
|
||||
<view class="summary">
|
||||
<text>选中货品({{ totalQuantity }})</text>
|
||||
<text>合计金额:¥ {{ totalAmount.toFixed(2) }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 加号添加商品 -->
|
||||
<view class="add" @click="chooseProduct">+</view>
|
||||
</view>
|
||||
|
||||
<!-- 其它收入/支出 表单 -->
|
||||
<view v-else>
|
||||
<view class="chips">
|
||||
<view v-for="c in (biz==='income' ? incomeCategories : expenseCategories)" :key="c.key" class="chip" :class="{ active: activeCategory===c.key }" @click="activeCategory=c.key">{{ c.label }}</view>
|
||||
</view>
|
||||
<view class="field" @click="chooseCounterparty">
|
||||
<text class="label">往来单位</text>
|
||||
<text class="value">{{ counterpartyLabel }}</text>
|
||||
</view>
|
||||
<view class="field" @click="chooseAccount">
|
||||
<text class="label">结算账户</text>
|
||||
<text class="value">{{ accountLabel }}</text>
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">金额</text>
|
||||
<input class="value" type="digit" v-model.number="trxAmount" placeholder="0.00" />
|
||||
</view>
|
||||
<view class="textarea">
|
||||
<textarea v-model="order.remark" maxlength="200" placeholder="备注(最多输入200个字)"></textarea>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 购物车空态 -->
|
||||
<view class="empty" v-if="!items.length">
|
||||
<image src="/static/logo.png" mode="widthFix" class="empty-img"></image>
|
||||
<text class="empty-text">购物车里空空如也</text>
|
||||
<text class="empty-sub">扫描或点击 “+” 选择商品吧</text>
|
||||
</view>
|
||||
|
||||
<!-- 商品列表 -->
|
||||
<view v-else class="list">
|
||||
<view class="row" v-for="(it, idx) in items" :key="idx">
|
||||
<view class="col name">{{ it.productName }}</view>
|
||||
<view class="col qty">
|
||||
<input type="number" v-model.number="it.quantity" @input="recalc()" />
|
||||
</view>
|
||||
<view class="col price">
|
||||
<input type="number" v-model.number="it.unitPrice" @input="recalc()" />
|
||||
</view>
|
||||
<view class="col amount">¥ {{ (Number(it.quantity)*Number(it.unitPrice)).toFixed(2) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部提交栏 -->
|
||||
<view class="bottom">
|
||||
<button class="ghost" @click="saveAndReset">再记一笔</button>
|
||||
<button class="primary" @click="submit">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { post } from '../../common/http.js'
|
||||
import { INCOME_CATEGORIES, EXPENSE_CATEGORIES } from '../../common/constants.js'
|
||||
|
||||
function todayString() {
|
||||
const d = new Date()
|
||||
const m = (d.getMonth()+1).toString().padStart(2,'0')
|
||||
const day = d.getDate().toString().padStart(2,'0')
|
||||
return `${d.getFullYear()}-${m}-${day}`
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
biz: 'sale',
|
||||
saleType: 'out',
|
||||
purchaseType: 'in',
|
||||
order: {
|
||||
orderTime: todayString(),
|
||||
customerId: null,
|
||||
supplierId: null,
|
||||
remark: ''
|
||||
},
|
||||
customerName: '',
|
||||
supplierName: '',
|
||||
items: [],
|
||||
activeCategory: 'sale_income',
|
||||
trxAmount: 0,
|
||||
selectedAccountId: null,
|
||||
selectedAccountName: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalQuantity() {
|
||||
return this.items.reduce((s, it) => s + Number(it.quantity || 0), 0)
|
||||
},
|
||||
totalAmount() {
|
||||
return this.items.reduce((s, it) => s + Number(it.quantity || 0) * Number(it.unitPrice || 0), 0)
|
||||
},
|
||||
customerLabel() { return this.customerName || '零售客户' },
|
||||
supplierLabel() { return this.supplierName || '零散供应商' },
|
||||
incomeCategories() { return INCOME_CATEGORIES },
|
||||
expenseCategories() { return EXPENSE_CATEGORIES },
|
||||
accountLabel() { return this.selectedAccountName || '现金' },
|
||||
counterpartyLabel() { return this.customerName || this.supplierName || '—' }
|
||||
},
|
||||
methods: {
|
||||
switchBiz(type) { this.biz = type },
|
||||
onDateChange(e) { this.order.orderTime = e.detail.value },
|
||||
chooseCustomer() {
|
||||
uni.navigateTo({ url: '/pages/customer/select' })
|
||||
},
|
||||
chooseSupplier() { uni.navigateTo({ url: '/pages/supplier/select' }) },
|
||||
chooseProduct() {
|
||||
uni.navigateTo({ url: '/pages/product/select' })
|
||||
},
|
||||
chooseAccount() { uni.navigateTo({ url: '/pages/account/select' }) },
|
||||
chooseCounterparty() {
|
||||
if (this.biz==='income' || this.biz==='expense') {
|
||||
uni.navigateTo({ url: '/pages/customer/select' })
|
||||
}
|
||||
},
|
||||
recalc() { this.$forceUpdate() },
|
||||
async submit() {
|
||||
const isSaleOrPurchase = (this.biz==='sale' || this.biz==='purchase')
|
||||
const payload = isSaleOrPurchase ? {
|
||||
type: this.biz === 'sale' ? (this.saleType) : ('purchase.' + this.purchaseType),
|
||||
orderTime: this.order.orderTime,
|
||||
customerId: this.order.customerId,
|
||||
supplierId: this.order.supplierId,
|
||||
items: this.items.map(it => ({ productId: it.productId, quantity: Number(it.quantity||0), unitPrice: Number(it.unitPrice||0) })),
|
||||
amount: this.totalAmount
|
||||
} : {
|
||||
type: this.biz,
|
||||
category: this.activeCategory,
|
||||
counterpartyId: this.order.customerId || null,
|
||||
accountId: this.selectedAccountId || null,
|
||||
amount: Number(this.trxAmount||0),
|
||||
txTime: this.order.orderTime,
|
||||
remark: this.order.remark
|
||||
}
|
||||
try {
|
||||
const url = isSaleOrPurchase ? '/api/orders' : '/api/other-transactions'
|
||||
await post(url, payload)
|
||||
uni.showToast({ title: '已保存', icon: 'success' })
|
||||
setTimeout(() => { uni.navigateBack() }, 600)
|
||||
} catch (e) {
|
||||
uni.showToast({ title: e && e.message || '保存失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
saveAndReset() {
|
||||
this.items = []
|
||||
this.trxAmount = 0
|
||||
this.order.remark = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.order { padding-bottom: 140rpx; }
|
||||
.tabs { display: flex; justify-content: space-around; padding: 16rpx 24rpx; }
|
||||
.tabs text { color: #666; }
|
||||
.tabs text.active { color: #333; font-weight: 700; }
|
||||
.subtabs { display: flex; gap: 16rpx; padding: 0 24rpx 16rpx; }
|
||||
.subbtn { padding: 10rpx 20rpx; border-radius: 999rpx; background: #f4f4f4; color: #666; }
|
||||
.subbtn.active { background: #ffe69a; color: #3f320f; }
|
||||
.field { display:flex; justify-content: space-between; padding: 22rpx 24rpx; background: #fff; border-bottom: 1rpx solid #eee; }
|
||||
.label { color:#666; }
|
||||
.value { color:#333; }
|
||||
.summary { display:flex; justify-content: space-between; padding: 22rpx 24rpx; color:#333; }
|
||||
.add { margin: 24rpx auto; width: 120rpx; height: 120rpx; border-radius: 20rpx; background: #c7eef7; color:#16a1c4; font-size: 72rpx; display:flex; align-items:center; justify-content:center; }
|
||||
.empty { display:flex; flex-direction: column; align-items:center; padding: 60rpx 0; color:#888; }
|
||||
.empty-img { width: 220rpx; margin-bottom: 20rpx; }
|
||||
.empty-text { margin-bottom: 8rpx; }
|
||||
.list { background:#fff; }
|
||||
.row { display:grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 12rpx; padding: 16rpx 12rpx; align-items:center; border-bottom: 1rpx solid #f3f3f3; }
|
||||
.col.name { padding-left: 12rpx; }
|
||||
.col.amount { text-align:right; padding-right: 12rpx; color:#333; }
|
||||
.bottom { position: fixed; left:0; right:0; bottom:0; background:#fff; padding: 16rpx 24rpx calc(env(safe-area-inset-bottom) + 16rpx); box-shadow: 0 -4rpx 12rpx rgba(0,0,0,0.06); }
|
||||
.primary { width: 100%; background: linear-gradient(135deg, #FFE69A 0%, #F4CF62 45%, #D7A72E 100%); color:#493c1b; border-radius: 999rpx; padding: 20rpx 0; font-weight:800; }
|
||||
</style>
|
||||
|
||||
|
||||
49
frontend/pages/product/select.vue
Normal file
49
frontend/pages/product/select.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="search">
|
||||
<input v-model="kw" placeholder="搜索商品名称/编码" @confirm="search" />
|
||||
<button size="mini" @click="search">搜索</button>
|
||||
</view>
|
||||
<scroll-view scroll-y class="list">
|
||||
<view class="item" v-for="p in products" :key="p.id" @click="select(p)">
|
||||
<view class="name">{{ p.name }}</view>
|
||||
<view class="meta">{{ p.code }} · 库存:{{ p.stock || 0 }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get } from '../../common/http.js'
|
||||
export default {
|
||||
data() { return { kw: '', products: [] } },
|
||||
onLoad() { this.search() },
|
||||
methods: {
|
||||
async search() {
|
||||
try {
|
||||
const res = await get('/api/products', { kw: this.kw, page: 1, size: 50 })
|
||||
this.products = Array.isArray(res?.list) ? res.list : (Array.isArray(res) ? res : [])
|
||||
} catch(e) { uni.showToast({ title: '加载失败', icon: 'none' }) }
|
||||
},
|
||||
select(p) {
|
||||
const opener = getCurrentPages()[getCurrentPages().length-2]
|
||||
if (opener && opener.$vm && opener.$vm.items) {
|
||||
opener.$vm.items.push({ productId: p.id, productName: p.name, quantity: 1, unitPrice: Number(p.price || 0) })
|
||||
}
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page { display:flex; flex-direction: column; height: 100vh; }
|
||||
.search { display:flex; gap: 12rpx; padding: 16rpx; background:#fff; }
|
||||
.search input { flex:1; background:#f6f6f6; border-radius: 12rpx; padding: 12rpx; }
|
||||
.list { flex:1; }
|
||||
.item { padding: 20rpx 24rpx; background:#fff; border-bottom: 1rpx solid #f1f1f1; }
|
||||
.name { color:#333; margin-bottom: 6rpx; }
|
||||
.meta { color:#888; font-size: 24rpx; }
|
||||
</style>
|
||||
|
||||
|
||||
50
frontend/pages/supplier/select.vue
Normal file
50
frontend/pages/supplier/select.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="search">
|
||||
<input v-model="kw" placeholder="搜索供应商名称/电话" @confirm="search" />
|
||||
<button size="mini" @click="search">搜索</button>
|
||||
</view>
|
||||
<scroll-view scroll-y class="list">
|
||||
<view class="item" v-for="s in suppliers" :key="s.id" @click="select(s)">
|
||||
<view class="name">{{ s.name }}</view>
|
||||
<view class="meta">{{ s.mobile || '—' }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get } from '../../common/http.js'
|
||||
export default {
|
||||
data() { return { kw: '', suppliers: [] } },
|
||||
onLoad() { this.search() },
|
||||
methods: {
|
||||
async search() {
|
||||
try {
|
||||
const res = await get('/api/suppliers', { kw: this.kw, page: 1, size: 50 })
|
||||
this.suppliers = Array.isArray(res?.list) ? res.list : (Array.isArray(res) ? res : [])
|
||||
} catch(e) { uni.showToast({ title: '加载失败', icon: 'none' }) }
|
||||
},
|
||||
select(s) {
|
||||
const opener = getCurrentPages()[getCurrentPages().length-2]
|
||||
if (opener && opener.$vm) {
|
||||
opener.$vm.order.supplierId = s.id
|
||||
opener.$vm.supplierName = s.name
|
||||
}
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page { display:flex; flex-direction: column; height: 100vh; }
|
||||
.search { display:flex; gap: 12rpx; padding: 16rpx; background:#fff; }
|
||||
.search input { flex:1; background:#f6f6f6; border-radius: 12rpx; padding: 12rpx; }
|
||||
.list { flex:1; }
|
||||
.item { padding: 20rpx 24rpx; background:#fff; border-bottom: 1rpx solid #f1f1f1; }
|
||||
.name { color:#333; margin-bottom: 6rpx; }
|
||||
.meta { color:#888; font-size: 24rpx; }
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user