if (typeof Promise !== "undefined" && !Promise.prototype.finally) { Promise.prototype.finally = function(callback) { const promise = this.constructor; return this.then( (value) => promise.resolve(callback()).then(() => value), (reason) => promise.resolve(callback()).then(() => { throw reason; }) ); }; } ; if (typeof uni !== "undefined" && uni && uni.requireGlobal) { const global = uni.requireGlobal(); ArrayBuffer = global.ArrayBuffer; Int8Array = global.Int8Array; Uint8Array = global.Uint8Array; Uint8ClampedArray = global.Uint8ClampedArray; Int16Array = global.Int16Array; Uint16Array = global.Uint16Array; Int32Array = global.Int32Array; Uint32Array = global.Uint32Array; Float32Array = global.Float32Array; Float64Array = global.Float64Array; BigInt64Array = global.BigInt64Array; BigUint64Array = global.BigUint64Array; } ; if (uni.restoreGlobal) { uni.restoreGlobal(Vue, weex, plus, setTimeout, clearTimeout, setInterval, clearInterval); } (function(vue) { "use strict"; function formatAppLog(type, filename, ...args) { if (uni.__log__) { uni.__log__(type, filename, ...args); } else { console[type].apply(console, [...args, filename]); } } var define_process_env_default = {}; const envBaseUrl = typeof process !== "undefined" && define_process_env_default && (define_process_env_default.VITE_APP_API_BASE_URL || define_process_env_default.API_BASE_URL) || ""; const storageBaseUrl = typeof uni !== "undefined" ? uni.getStorageSync("API_BASE_URL") || "" : ""; const fallbackBaseUrl = "http://192.168.31.193:8080"; const API_BASE_URL = (envBaseUrl || storageBaseUrl || fallbackBaseUrl).replace(/\/$/, ""); const candidateBases = [envBaseUrl, storageBaseUrl, fallbackBaseUrl, "http://127.0.0.1:8080", "http://localhost:8080"]; const API_BASE_URL_CANDIDATES = Array.from(new Set(candidateBases.filter(Boolean))).map((u) => String(u).replace(/\/$/, "")); const envShopId = typeof process !== "undefined" && define_process_env_default && (define_process_env_default.VITE_APP_SHOP_ID || define_process_env_default.SHOP_ID) || ""; const storageShopId = typeof uni !== "undefined" ? uni.getStorageSync("SHOP_ID") || "" : ""; const SHOP_ID = Number(envShopId || storageShopId || 1); const envEnableDefaultUser = typeof process !== "undefined" && define_process_env_default && (define_process_env_default.VITE_APP_ENABLE_DEFAULT_USER || define_process_env_default.ENABLE_DEFAULT_USER) || ""; const storageEnableDefaultUser = typeof uni !== "undefined" ? uni.getStorageSync("ENABLE_DEFAULT_USER") || "" : ""; const ENABLE_DEFAULT_USER = String(envEnableDefaultUser || storageEnableDefaultUser || "true").toLowerCase() === "true"; const envDefaultUserId = typeof process !== "undefined" && define_process_env_default && (define_process_env_default.VITE_APP_DEFAULT_USER_ID || define_process_env_default.DEFAULT_USER_ID) || ""; const storageDefaultUserId = typeof uni !== "undefined" ? uni.getStorageSync("DEFAULT_USER_ID") || "" : ""; const DEFAULT_USER_ID = Number(envDefaultUserId || storageDefaultUserId || 2); function buildUrl(path) { if (!path) return API_BASE_URL; if (path.startsWith("http")) return path; return API_BASE_URL + (path.startsWith("/") ? path : "/" + path); } function requestWithFallback(options, candidates, idx, resolve, reject) { const base = candidates[idx] || API_BASE_URL; const url = options.url.replace(/^https?:\/\/[^/]+/, base); uni.request({ ...options, url, success: (res) => { const { statusCode, data } = res; if (statusCode >= 200 && statusCode < 300) return resolve(data); const msg = data && (data.message || data.error || data.msg) || "HTTP " + statusCode; uni.showToast({ title: msg, icon: "none" }); if (idx + 1 < candidates.length) return requestWithFallback(options, candidates, idx + 1, resolve, reject); reject(new Error(msg)); }, fail: (err) => { if (idx + 1 < candidates.length) return requestWithFallback(options, candidates, idx + 1, resolve, reject); reject(err); } }); } function get(path, params = {}) { return new Promise((resolve, reject) => { const headers = { "X-Shop-Id": SHOP_ID }; if (ENABLE_DEFAULT_USER && DEFAULT_USER_ID) headers["X-User-Id"] = DEFAULT_USER_ID; const options = { url: buildUrl(path), method: "GET", data: params, header: headers }; requestWithFallback(options, API_BASE_URL_CANDIDATES, 0, resolve, reject); }); } function post(path, body = {}) { return new Promise((resolve, reject) => { const headers = { "Content-Type": "application/json", "X-Shop-Id": SHOP_ID }; if (ENABLE_DEFAULT_USER && DEFAULT_USER_ID) headers["X-User-Id"] = DEFAULT_USER_ID; const options = { url: buildUrl(path), method: "POST", data: body, header: headers }; requestWithFallback(options, API_BASE_URL_CANDIDATES, 0, resolve, reject); }); } function put(path, body = {}) { return new Promise((resolve, reject) => { const headers = { "Content-Type": "application/json", "X-Shop-Id": SHOP_ID }; if (ENABLE_DEFAULT_USER && DEFAULT_USER_ID) headers["X-User-Id"] = DEFAULT_USER_ID; const options = { url: buildUrl(path), method: "PUT", data: body, header: headers }; requestWithFallback(options, API_BASE_URL_CANDIDATES, 0, resolve, reject); }); } function del(path, body = {}) { return new Promise((resolve, reject) => { const headers = { "Content-Type": "application/json", "X-Shop-Id": SHOP_ID }; if (ENABLE_DEFAULT_USER && DEFAULT_USER_ID) headers["X-User-Id"] = DEFAULT_USER_ID; const options = { url: buildUrl(path), method: "DELETE", data: body, header: headers }; requestWithFallback(options, API_BASE_URL_CANDIDATES, 0, resolve, reject); }); } function uploadWithFallback(options, candidates, idx, resolve, reject) { const base = candidates[idx] || API_BASE_URL; const url = options.url.replace(/^https?:\/\/[^/]+/, base); const uploadOptions = { ...options, url }; uni.uploadFile({ ...uploadOptions, success: (res) => { const statusCode = res.statusCode || 0; if (statusCode >= 200 && statusCode < 300) { try { const data = typeof res.data === "string" ? JSON.parse(res.data) : res.data; return resolve(data); } catch (e) { return resolve(res.data); } } if (idx + 1 < candidates.length) return uploadWithFallback(options, candidates, idx + 1, resolve, reject); reject(new Error("HTTP " + statusCode)); }, fail: (err) => { if (idx + 1 < candidates.length) return uploadWithFallback(options, candidates, idx + 1, resolve, reject); reject(err); } }); } function upload(path, filePath, formData = {}, name = "file") { return new Promise((resolve, reject) => { const header = { "X-Shop-Id": SHOP_ID }; if (ENABLE_DEFAULT_USER && DEFAULT_USER_ID) header["X-User-Id"] = DEFAULT_USER_ID; const options = { url: buildUrl(path), filePath, name, formData, header }; uploadWithFallback(options, API_BASE_URL_CANDIDATES, 0, resolve, reject); }); } const INCOME_CATEGORIES = [ { key: "sale_income", label: "销售收入" }, { key: "operation_income", label: "经营所得" }, { key: "interest_income", label: "利息收入" }, { key: "investment_income", label: "投资收入" }, { key: "other_income", label: "其它收入" } ]; const EXPENSE_CATEGORIES = [ { key: "operation_expense", label: "经营支出" }, { key: "office_supplies", label: "办公用品" }, { key: "rent", label: "房租" }, { key: "interest_expense", label: "利息支出" }, { key: "other_expense", label: "其它支出" } ]; const ROUTES = { home: "/pages/index/index", productList: "/pages/product/list", productForm: "/pages/product/form", productSelect: "/pages/product/select", productSettings: "/pages/product/settings", orderCreate: "/pages/order/create", detail: "/pages/detail/index", my: "/pages/my/index", myAbout: "/pages/my/about", report: "/pages/report/index", customerSelect: "/pages/customer/select", supplierSelect: "/pages/supplier/select", accountSelect: "/pages/account/select" }; const _imports_0$1 = "/static/metal-bg.jpg"; const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _sfc_main$l = { data() { return { kpi: { todaySales: "0.00", monthSales: "0.00", monthProfit: "0.00", stockCount: "0" }, activeTab: "home", notices: [], loadingNotices: false, noticeError: "", features: [ { key: "product", title: "货品", img: "/static/icons/product.png", emoji: "📦" }, { key: "customer", title: "客户", img: "/static/icons/customer.png", emoji: "👥" }, { key: "sale", title: "销售", img: "/static/icons/sale.png", emoji: "💰" }, { key: "account", title: "账户", img: "/static/icons/account.png", emoji: "💳" }, { key: "supplier", title: "供应商", img: "/static/icons/supplier.png", emoji: "🚚" }, { key: "purchase", title: "进货", img: "/static/icons/purchase.png", emoji: "🛒" }, { key: "otherPay", title: "其他支出", img: "/static/icons/other-pay.png", emoji: "💸" }, { key: "vip", title: "VIP会员", img: "/static/icons/vip.png", emoji: "👑" }, { key: "report", title: "报表", img: "/static/icons/report.png", emoji: "📊" }, { key: "more", title: "更多", img: "/static/icons/more.png", emoji: "⋯" } ] }; }, onLoad() { this.fetchMetrics(); this.fetchNotices(); }, methods: { async fetchMetrics() { try { const d = await get("/api/dashboard/overview"); const toNum = (v) => typeof v === "number" ? v : Number(v || 0); this.kpi = { ...this.kpi, todaySales: toNum(d && d.todaySalesAmount).toFixed(2), monthSales: toNum(d && d.monthSalesAmount).toFixed(2), monthProfit: toNum(d && d.monthGrossProfit).toFixed(2), stockCount: String((d && d.stockTotalQuantity) != null ? d.stockTotalQuantity : 0) }; } catch (e) { } }, async fetchNotices() { this.loadingNotices = true; this.noticeError = ""; try { const list = await get("/api/notices"); this.notices = Array.isArray(list) ? list.map((n) => ({ text: n.content || n.title || "", tag: n.tag || "" })) : []; } catch (e) { this.noticeError = e && e.message || "公告加载失败"; } finally { this.loadingNotices = false; } }, onFeatureTap(item) { if (item.key === "product") { uni.switchTab({ url: "/pages/product/list" }); return; } if (item.key === "sale") { try { uni.setStorageSync("ORDER_DEFAULT_PARAMS", { biz: "sale", type: "out" }); } catch (e) { } uni.switchTab({ url: "/pages/order/create" }); return; } if (item.key === "customer") { uni.navigateTo({ url: "/pages/customer/select" }); return; } if (item.key === "account") { uni.navigateTo({ url: "/pages/account/select" }); return; } if (item.key === "supplier") { uni.navigateTo({ url: "/pages/supplier/select" }); return; } if (item.key === "purchase") { try { uni.setStorageSync("ORDER_DEFAULT_PARAMS", { biz: "purchase", type: "in" }); } catch (e) { } uni.switchTab({ url: "/pages/order/create" }); return; } if (item.key === "report") { uni.navigateTo({ url: ROUTES.report }); return; } if (item.key === "otherPay") { try { uni.setStorageSync("ORDER_DEFAULT_PARAMS", { biz: "expense" }); } catch (e) { } uni.switchTab({ url: "/pages/order/create" }); return; } uni.showToast({ title: item.title + "(开发中)", icon: "none" }); }, goProduct() { uni.switchTab({ url: "/pages/product/list" }); }, onCreateOrder() { uni.switchTab({ url: "/pages/order/create" }); }, goDetail() { try { formatAppLog("log", "at pages/index/index.vue:177", "[index] goDetail → /pages/detail/index"); } catch (e) { } uni.switchTab({ url: "/pages/detail/index" }); }, goMe() { uni.switchTab({ url: "/pages/my/index" }); }, onNoticeTap(n) { uni.showModal({ title: "广告", content: n && (n.text || n.title || n.content) || "", showCancel: false }); }, onIconError(item) { item.img = ""; } } }; function _sfc_render$k(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "home" }, [ vue.createElementVNode("image", { class: "home-bg", src: _imports_0$1, mode: "aspectFill" }), vue.createCommentVNode(" 顶部统计卡片 "), vue.createElementVNode("view", { class: "hero" }, [ vue.createElementVNode("view", { class: "hero-top" }, [ vue.createElementVNode("text", { class: "brand" }, "五金配件管家"), vue.createElementVNode("view", { class: "cta" }, [ vue.createElementVNode("text", { class: "cta-text" }, "咨询") ]) ]), vue.createElementVNode("view", { class: "kpi" }, [ vue.createElementVNode("view", { class: "kpi-item" }, [ vue.createElementVNode("text", { class: "kpi-label" }, "今日销售额"), vue.createElementVNode( "text", { class: "kpi-value" }, vue.toDisplayString($data.kpi.todaySales), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "kpi-item" }, [ vue.createElementVNode("text", { class: "kpi-label" }, "本月销售额"), vue.createElementVNode( "text", { class: "kpi-value" }, vue.toDisplayString($data.kpi.monthSales), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "kpi-item" }, [ vue.createElementVNode("text", { class: "kpi-label" }, "本月利润"), vue.createElementVNode( "text", { class: "kpi-value" }, vue.toDisplayString($data.kpi.monthProfit), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "kpi-item" }, [ vue.createElementVNode("text", { class: "kpi-label" }, "库存商品数量"), vue.createElementVNode( "text", { class: "kpi-value" }, vue.toDisplayString($data.kpi.stockCount), 1 /* TEXT */ ) ]) ]) ]), vue.createCommentVNode(" 广告栏:自动轮播,可点击查看详情 "), vue.createElementVNode("view", { class: "notice" }, [ vue.createElementVNode("view", { class: "notice-left" }, "广告"), $data.loadingNotices ? (vue.openBlock(), vue.createElementBlock("view", { key: 0, class: "notice-swiper", style: { "display": "flex", "align-items": "center", "color": "#6b5a2a" } }, "加载中...")) : $data.noticeError ? (vue.openBlock(), vue.createElementBlock( "view", { key: 1, class: "notice-swiper", style: { "display": "flex", "align-items": "center", "color": "#dd524d" } }, vue.toDisplayString($data.noticeError), 1 /* TEXT */ )) : !$data.notices.length ? (vue.openBlock(), vue.createElementBlock("view", { key: 2, class: "notice-swiper", style: { "display": "flex", "align-items": "center", "color": "#6b5a2a" } }, "暂无公告")) : (vue.openBlock(), vue.createElementBlock("swiper", { key: 3, class: "notice-swiper", circular: "", autoplay: "", interval: "4000", duration: "400", vertical: "" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.notices, (n, idx) => { return vue.openBlock(), vue.createElementBlock("swiper-item", { key: idx }, [ vue.createElementVNode("view", { class: "notice-item", onClick: ($event) => $options.onNoticeTap(n) }, [ vue.createElementVNode( "text", { class: "notice-text" }, vue.toDisplayString(n.text), 1 /* TEXT */ ), n.tag ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "notice-tag" }, vue.toDisplayString(n.tag), 1 /* TEXT */ )) : vue.createCommentVNode("v-if", true) ], 8, ["onClick"]) ]); }), 128 /* KEYED_FRAGMENT */ )) ])) ]), vue.createCommentVNode(" 分割标题:产品与功能 "), vue.createElementVNode("view", { class: "section-title" }, [ vue.createElementVNode("text", { class: "section-text" }, "常用功能") ]), vue.createCommentVNode(" 功能九宫格(玻璃容器 + 圆角方形图标) "), vue.createElementVNode("view", { class: "grid-wrap" }, [ vue.createElementVNode("view", { class: "grid" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.features, (item) => { return vue.openBlock(), vue.createElementBlock("view", { class: "grid-item", key: item.key, onClick: ($event) => $options.onFeatureTap(item) }, [ vue.createElementVNode("view", { class: "icon icon-squircle" }, [ item.img ? (vue.openBlock(), vue.createElementBlock("image", { key: 0, src: item.img, class: "icon-img", mode: "aspectFit", onError: ($event) => $options.onIconError(item) }, null, 40, ["src", "onError"])) : item.emoji ? (vue.openBlock(), vue.createElementBlock( "text", { key: 1, class: "icon-emoji" }, vue.toDisplayString(item.emoji), 1 /* TEXT */ )) : (vue.openBlock(), vue.createElementBlock("view", { key: 2, class: "icon-placeholder" })) ]), vue.createElementVNode( "text", { class: "grid-chip" }, vue.toDisplayString(item.title), 1 /* TEXT */ ) ], 8, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) ]) ]), vue.createCommentVNode(" 底部操作条改为原生 tabBar,移除自定义栏 ") ]); } const PagesIndexIndex = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["render", _sfc_render$k], ["__file", "D:/wx/PartsInquiry/frontend/pages/index/index.vue"]]); const _imports_0 = "/static/logo.png"; function todayString() { const d = /* @__PURE__ */ new Date(); const m = (d.getMonth() + 1).toString().padStart(2, "0"); const day = d.getDate().toString().padStart(2, "0"); return `${d.getFullYear()}-${m}-${day}`; } const _sfc_main$k = { data() { return { biz: "sale", saleType: "out", purchaseType: "in", order: { orderTime: todayString(), customerId: null, supplierId: null, remark: "" }, customerName: "", customerPriceLevel: "零售价", _lastCustomerId: null, _priceCache: {}, supplierName: "", items: [], activeCategory: "sale_income", counterpartyType: "customer", trxAmount: 0, selectedAccountId: null, selectedAccountName: "", // 收款/付款输入 payments: { cash: 0, bank: 0, wechat: 0 }, showMore: false }; }, 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 this._incomeCategories || INCOME_CATEGORIES; }, expenseCategories() { return this._expenseCategories || EXPENSE_CATEGORIES; }, accountLabel() { return this.selectedAccountName || "现金"; }, counterpartyLabel() { return this.counterpartyType === "customer" ? this.customerName || "—" : this.supplierName || "—"; }, // 收款/付款合计 payTotal() { const p = this.payments || { cash: 0, bank: 0, wechat: 0 }; return Number(p.cash || 0) + Number(p.bank || 0) + Number(p.wechat || 0); } }, onLoad(query) { try { const preset = uni.getStorageSync("ORDER_DEFAULT_PARAMS") || {}; const biz = query && query.biz || preset.biz; const type = query && query.type || preset.type; if (biz === "sale" || biz === "purchase" || biz === "income" || biz === "expense") { this.biz = biz; } if (this.biz === "sale" && (type === "out" || type === "return" || type === "collect")) { this.saleType = type; } if (this.biz === "purchase" && (type === "in" || type === "return" || type === "pay")) { this.purchaseType = type; } try { uni.removeStorageSync("ORDER_DEFAULT_PARAMS"); } catch (_) { } } catch (e) { } this.fetchCategories(); }, onShow() { if (this.biz === "sale") { if (this.order.customerId && this.order.customerId !== this._lastCustomerId) { this.loadCustomerLevel(this.order.customerId).then(() => { this._lastCustomerId = this.order.customerId; for (const it of this.items) { if (it && (it._autoPrice || !it.unitPrice)) this.autoPriceItem(it); } }); } for (const it of this.items) { if (it && !it.unitPrice) this.autoPriceItem(it); } } }, methods: { async fetchCategories() { try { const res = await get("/api/finance/categories"); if (res && Array.isArray(res.incomeCategories)) this._incomeCategories = res.incomeCategories; if (res && Array.isArray(res.expenseCategories)) this._expenseCategories = res.expenseCategories; this.ensureActiveCategory(); } catch (_) { this.ensureActiveCategory(); } }, ensureActiveCategory() { const list = this.biz === "income" ? this.incomeCategories || [] : this.expenseCategories || []; if (!list.length) return; const exists = list.some((it) => it && it.key === this.activeCategory); if (!exists) this.activeCategory = list[0].key; }, async loadCustomerLevel(customerId) { try { const d = await get(`/api/customers/${customerId}`); this.customerPriceLevel = d && d.priceLevel ? d.priceLevel : "零售价"; } catch (e) { this.customerPriceLevel = "零售价"; } }, priceFieldForLevel() { const lvl = this.customerPriceLevel || "零售价"; if (lvl === "批发价") return "wholesalePrice"; if (lvl === "大单报价") return "bigClientPrice"; return "retailPrice"; }, async autoPriceItem(it) { if (this.biz !== "sale") return; if (!it || !it.productId) return; const pid = it.productId; let detail = this._priceCache[pid]; if (!detail) { try { detail = await get(`/api/products/${pid}`); this._priceCache[pid] = detail; } catch (e) { return; } } const field = this.priceFieldForLevel(); let price = Number(detail && detail[field] != null ? detail[field] : 0); if (!price && field !== "retailPrice") { price = Number(detail && detail.retailPrice != null ? detail.retailPrice : 0); } it.unitPrice = price; it._autoPrice = true; this.recalc(); }, onPriceInput(it) { if (it) { it._autoPrice = false; this.recalc(); } }, switchBiz(type) { this.biz = type; this.ensureActiveCategory(); }, 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?mode=pick" }); }, chooseCounterparty() { if (!(this.biz === "income" || this.biz === "expense")) return; if (this.counterpartyType === "customer") { uni.navigateTo({ url: "/pages/customer/select" }); } else { uni.navigateTo({ url: "/pages/supplier/select" }); } }, setCounterparty(t) { this.counterpartyType = t; this.ensureActiveCategory(); }, recalc() { this.$forceUpdate(); }, recalcPay() { this.$forceUpdate(); }, async submit() { const isSaleOrPurchase = this.biz === "sale" || this.biz === "purchase"; const isCollectOrPay = this.biz === "sale" && this.saleType === "collect" || this.biz === "purchase" && this.purchaseType === "pay"; const saleTypeValue = this.biz === "sale" ? "sale." + this.saleType : "purchase." + this.purchaseType; if (isSaleOrPurchase && !isCollectOrPay) { if (!this.items.length) { uni.showToast({ title: "请先选择商品", icon: "none" }); return; } const invalid = this.items.find((it) => !it.productId || Number(it.quantity || 0) <= 0); if (invalid) { uni.showToast({ title: "数量需大于0", icon: "none" }); return; } } const payload = isSaleOrPurchase ? isCollectOrPay ? [ { method: "cash", amount: Number(this.payments.cash || 0) }, { method: "bank", amount: Number(this.payments.bank || 0) }, { method: "wechat", amount: Number(this.payments.wechat || 0) } ].filter((p) => p.amount > 0) : { type: saleTypeValue, 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, counterpartyType: this.counterpartyType, counterpartyId: this.counterpartyType === "customer" ? this.order.customerId || null : this.order.supplierId || null, accountId: this.selectedAccountId || null, amount: Number(this.trxAmount || 0), txTime: this.order.orderTime, remark: this.order.remark }; try { const url = isSaleOrPurchase ? isCollectOrPay ? `/api/payments/${this.biz}` : "/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 = ""; this.payments = { cash: 0, bank: 0, wechat: 0 }; } } }; function _sfc_render$j(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "order" }, [ vue.createCommentVNode(" 顶部 Tab "), vue.createElementVNode("view", { class: "tabs" }, [ vue.createElementVNode( "text", { class: vue.normalizeClass({ active: $data.biz === "sale" }), onClick: _cache[0] || (_cache[0] = ($event) => $options.switchBiz("sale")) }, "销售", 2 /* CLASS */ ), vue.createElementVNode( "text", { class: vue.normalizeClass({ active: $data.biz === "purchase" }), onClick: _cache[1] || (_cache[1] = ($event) => $options.switchBiz("purchase")) }, "进货", 2 /* CLASS */ ), vue.createElementVNode( "text", { class: vue.normalizeClass({ active: $data.biz === "income" }), onClick: _cache[2] || (_cache[2] = ($event) => $options.switchBiz("income")) }, "其他收入", 2 /* CLASS */ ), vue.createElementVNode( "text", { class: vue.normalizeClass({ active: $data.biz === "expense" }), onClick: _cache[3] || (_cache[3] = ($event) => $options.switchBiz("expense")) }, "其他支出", 2 /* CLASS */ ) ]), vue.createCommentVNode(" 子类目按钮 "), $data.biz === "sale" ? (vue.openBlock(), vue.createElementBlock("view", { key: 0, class: "subtabs" }, [ vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.saleType === "out" }]), onClick: _cache[4] || (_cache[4] = ($event) => $data.saleType = "out") }, "出货", 2 /* CLASS */ ), vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.saleType === "return" }]), onClick: _cache[5] || (_cache[5] = ($event) => $data.saleType = "return") }, "退货", 2 /* CLASS */ ), vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.saleType === "collect" }]), onClick: _cache[6] || (_cache[6] = ($event) => $data.saleType = "collect") }, "收款", 2 /* CLASS */ ) ])) : $data.biz === "purchase" ? (vue.openBlock(), vue.createElementBlock("view", { key: 1, class: "subtabs" }, [ vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.purchaseType === "in" }]), onClick: _cache[7] || (_cache[7] = ($event) => $data.purchaseType = "in") }, "进货", 2 /* CLASS */ ), vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.purchaseType === "return" }]), onClick: _cache[8] || (_cache[8] = ($event) => $data.purchaseType = "return") }, "退货", 2 /* CLASS */ ), vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.purchaseType === "pay" }]), onClick: _cache[9] || (_cache[9] = ($event) => $data.purchaseType = "pay") }, "付款", 2 /* CLASS */ ) ])) : vue.createCommentVNode("v-if", true), vue.createCommentVNode(" 日期与客户 "), vue.createElementVNode("picker", { mode: "date", value: $data.order.orderTime, onChange: _cache[10] || (_cache[10] = (...args) => $options.onDateChange && $options.onDateChange(...args)) }, [ vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "时间"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($data.order.orderTime), 1 /* TEXT */ ) ]) ], 40, ["value"]), $data.biz === "sale" ? (vue.openBlock(), vue.createElementBlock("view", { key: 2, class: "field", onClick: _cache[11] || (_cache[11] = (...args) => $options.chooseCustomer && $options.chooseCustomer(...args)) }, [ vue.createElementVNode("text", { class: "label" }, "客户"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.customerLabel), 1 /* TEXT */ ) ])) : $data.biz === "purchase" ? (vue.openBlock(), vue.createElementBlock("view", { key: 3, class: "field", onClick: _cache[12] || (_cache[12] = (...args) => $options.chooseSupplier && $options.chooseSupplier(...args)) }, [ vue.createElementVNode("text", { class: "label" }, "供应商"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.supplierLabel), 1 /* TEXT */ ) ])) : vue.createCommentVNode("v-if", true), vue.createCommentVNode(" 销售/进货:收款/付款 专用页面 "), $data.biz === "sale" && $data.saleType === "collect" || $data.biz === "purchase" && $data.purchaseType === "pay" ? (vue.openBlock(), vue.createElementBlock("view", { key: 4 }, [ vue.createCommentVNode(" 客户 / 供应商 "), $data.biz === "sale" ? (vue.openBlock(), vue.createElementBlock("view", { key: 0, class: "field", onClick: _cache[13] || (_cache[13] = (...args) => $options.chooseCustomer && $options.chooseCustomer(...args)) }, [ vue.createElementVNode("text", { class: "label" }, "客户"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.customerLabel), 1 /* TEXT */ ) ])) : (vue.openBlock(), vue.createElementBlock("view", { key: 1, class: "field", onClick: _cache[14] || (_cache[14] = (...args) => $options.chooseSupplier && $options.chooseSupplier(...args)) }, [ vue.createElementVNode("text", { class: "label" }, "供应商"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.supplierLabel), 1 /* TEXT */ ) ])), vue.createCommentVNode(" 三种收付款方式 "), vue.createElementVNode("view", { class: "field pay-row" }, [ vue.createElementVNode("text", { class: "label" }, "现金"), vue.withDirectives(vue.createElementVNode( "input", { class: "pay-input", type: "digit", "onUpdate:modelValue": _cache[15] || (_cache[15] = ($event) => $data.payments.cash = $event), placeholder: "0.00", onInput: _cache[16] || (_cache[16] = ($event) => $options.recalcPay()) }, null, 544 /* NEED_HYDRATION, NEED_PATCH */ ), [ [ vue.vModelText, $data.payments.cash, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "field pay-row" }, [ vue.createElementVNode("text", { class: "label" }, "银行存款"), vue.withDirectives(vue.createElementVNode( "input", { class: "pay-input", type: "digit", "onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => $data.payments.bank = $event), placeholder: "0.00", onInput: _cache[18] || (_cache[18] = ($event) => $options.recalcPay()) }, null, 544 /* NEED_HYDRATION, NEED_PATCH */ ), [ [ vue.vModelText, $data.payments.bank, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "field pay-row" }, [ vue.createElementVNode("text", { class: "label" }, "微信"), vue.withDirectives(vue.createElementVNode( "input", { class: "pay-input", type: "digit", "onUpdate:modelValue": _cache[19] || (_cache[19] = ($event) => $data.payments.wechat = $event), placeholder: "0.00", onInput: _cache[20] || (_cache[20] = ($event) => $options.recalcPay()) }, null, 544 /* NEED_HYDRATION, NEED_PATCH */ ), [ [ vue.vModelText, $data.payments.wechat, void 0, { number: true } ] ]) ]), vue.createElementVNode( "view", { class: "collapse-trigger", onClick: _cache[21] || (_cache[21] = ($event) => $data.showMore = !$data.showMore) }, vue.toDisplayString($data.showMore ? "收起" : ""), 1 /* TEXT */ ), vue.createCommentVNode(" 备注与日期 "), vue.createElementVNode("view", { class: "textarea" }, [ vue.createElementVNode( "view", { class: "amount-badge" }, "总金额:" + vue.toDisplayString($options.payTotal.toFixed(2)), 1 /* TEXT */ ), vue.withDirectives(vue.createElementVNode( "textarea", { "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => $data.order.remark = $event), maxlength: "200", placeholder: "备注(最多输入200个字)" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.order.remark] ]), vue.createElementVNode("view", { class: "date-mini" }, [ vue.createElementVNode("picker", { mode: "date", value: $data.order.orderTime, onChange: _cache[23] || (_cache[23] = (...args) => $options.onDateChange && $options.onDateChange(...args)) }, [ vue.createElementVNode( "text", null, vue.toDisplayString($data.order.orderTime), 1 /* TEXT */ ) ], 40, ["value"]) ]) ]) ])) : $data.biz === "sale" || $data.biz === "purchase" ? (vue.openBlock(), vue.createElementBlock( vue.Fragment, { key: 5 }, [ vue.createCommentVNode(" 已选商品与合计(销售/进货 出入库) "), vue.createElementVNode("view", null, [ vue.createElementVNode("view", { class: "summary" }, [ vue.createElementVNode( "text", null, "选中货品(" + vue.toDisplayString($options.totalQuantity) + ")", 1 /* TEXT */ ), vue.createElementVNode( "text", null, "合计金额:¥ " + vue.toDisplayString($options.totalAmount.toFixed(2)), 1 /* TEXT */ ) ]), vue.createCommentVNode(" 加号添加商品 "), vue.createElementVNode("view", { class: "add", onClick: _cache[24] || (_cache[24] = (...args) => $options.chooseProduct && $options.chooseProduct(...args)) }, "+") ]) ], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */ )) : (vue.openBlock(), vue.createElementBlock( vue.Fragment, { key: 6 }, [ vue.createCommentVNode(" 其它收入/支出 表单 "), vue.createElementVNode("view", null, [ vue.createCommentVNode(" 往来单位类型切换 "), vue.createElementVNode("view", { class: "subtabs" }, [ vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.counterpartyType === "customer" }]), onClick: _cache[25] || (_cache[25] = ($event) => $options.setCounterparty("customer")) }, "客户", 2 /* CLASS */ ), vue.createElementVNode( "button", { class: vue.normalizeClass(["subbtn", { active: $data.counterpartyType === "supplier" }]), onClick: _cache[26] || (_cache[26] = ($event) => $options.setCounterparty("supplier")) }, "供应商", 2 /* CLASS */ ) ]), vue.createElementVNode("view", { class: "chips" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.biz === "income" ? $options.incomeCategories : $options.expenseCategories, (c) => { return vue.openBlock(), vue.createElementBlock("view", { key: c.key, class: vue.normalizeClass(["chip", { active: $data.activeCategory === c.key }]), onClick: ($event) => $data.activeCategory = c.key }, vue.toDisplayString(c.label), 11, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) ]), vue.createElementVNode("view", { class: "field", onClick: _cache[27] || (_cache[27] = (...args) => $options.chooseCounterparty && $options.chooseCounterparty(...args)) }, [ vue.createElementVNode("text", { class: "label" }, "往来单位"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.counterpartyLabel), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "field", onClick: _cache[28] || (_cache[28] = (...args) => $options.chooseAccount && $options.chooseAccount(...args)) }, [ vue.createElementVNode("text", { class: "label" }, "结算账户"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.accountLabel), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "金额"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", type: "digit", "onUpdate:modelValue": _cache[29] || (_cache[29] = ($event) => $data.trxAmount = $event), placeholder: "0.00" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.trxAmount, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "textarea" }, [ vue.withDirectives(vue.createElementVNode( "textarea", { "onUpdate:modelValue": _cache[30] || (_cache[30] = ($event) => $data.order.remark = $event), maxlength: "200", placeholder: "备注(最多输入200个字)" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.order.remark] ]) ]) ]) ], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */ )), vue.createCommentVNode(" 购物车空态 "), !$data.items.length ? (vue.openBlock(), vue.createElementBlock("view", { key: 7, class: "empty" }, [ vue.createElementVNode("image", { src: _imports_0, mode: "widthFix", class: "empty-img" }), vue.createElementVNode("text", { class: "empty-text" }, "购物车里空空如也"), vue.createElementVNode("text", { class: "empty-sub" }, "扫描或点击 “+” 选择商品吧") ])) : (vue.openBlock(), vue.createElementBlock( vue.Fragment, { key: 8 }, [ vue.createCommentVNode(" 商品列表 "), vue.createElementVNode("view", { class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.items, (it, idx) => { return vue.openBlock(), vue.createElementBlock("view", { class: "row", key: idx }, [ vue.createElementVNode( "view", { class: "col name" }, vue.toDisplayString(it.productName), 1 /* TEXT */ ), vue.createElementVNode("view", { class: "col qty" }, [ vue.withDirectives(vue.createElementVNode("input", { type: "number", "onUpdate:modelValue": ($event) => it.quantity = $event, onInput: _cache[31] || (_cache[31] = ($event) => $options.recalc()) }, null, 40, ["onUpdate:modelValue"]), [ [ vue.vModelText, it.quantity, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "col price" }, [ vue.withDirectives(vue.createElementVNode("input", { type: "number", "onUpdate:modelValue": ($event) => it.unitPrice = $event, onInput: ($event) => $options.onPriceInput(it) }, null, 40, ["onUpdate:modelValue", "onInput"]), [ [ vue.vModelText, it.unitPrice, void 0, { number: true } ] ]) ]), vue.createElementVNode( "view", { class: "col amount" }, "¥ " + vue.toDisplayString((Number(it.quantity) * Number(it.unitPrice)).toFixed(2)), 1 /* TEXT */ ) ]); }), 128 /* KEYED_FRAGMENT */ )) ]) ], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */ )), vue.createCommentVNode(" 底部提交栏 "), vue.createElementVNode("view", { class: "bottom" }, [ vue.createElementVNode("button", { class: "ghost", onClick: _cache[32] || (_cache[32] = (...args) => $options.saveAndReset && $options.saveAndReset(...args)) }, "再记一笔"), vue.createElementVNode("button", { class: "primary", onClick: _cache[33] || (_cache[33] = (...args) => $options.submit && $options.submit(...args)) }, "保存") ]) ]); } const PagesOrderCreate = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["render", _sfc_render$j], ["__file", "D:/wx/PartsInquiry/frontend/pages/order/create.vue"]]); const _sfc_main$j = { 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 == null ? void 0 : 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) { const initPrice = Number(p.retailPrice != null ? p.retailPrice : p.price || 0); opener.$vm.items.push({ productId: p.id, productName: p.name, quantity: 1, unitPrice: initPrice, _autoPrice: true }); } uni.navigateBack(); } } }; function _sfc_render$i(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "search" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.kw = $event), placeholder: "搜索商品名称/编码", onConfirm: _cache[1] || (_cache[1] = (...args) => $options.search && $options.search(...args)) }, null, 544 /* NEED_HYDRATION, NEED_PATCH */ ), [ [vue.vModelText, $data.kw] ]), vue.createElementVNode("button", { size: "mini", onClick: _cache[2] || (_cache[2] = (...args) => $options.search && $options.search(...args)) }, "搜索") ]), vue.createElementVNode("scroll-view", { "scroll-y": "", class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.products, (p) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: p.id, onClick: ($event) => $options.select(p) }, [ vue.createElementVNode( "view", { class: "name" }, vue.toDisplayString(p.name), 1 /* TEXT */ ), vue.createElementVNode( "view", { class: "meta" }, vue.toDisplayString((p.brand || "") + " " + (p.model || "") + " " + (p.spec || "")) + " · 库存:" + vue.toDisplayString(p.stock ?? 0), 1 /* TEXT */ ) ], 8, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) ]) ]); } const PagesProductSelect = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["render", _sfc_render$i], ["__file", "D:/wx/PartsInquiry/frontend/pages/product/select.vue"]]); const _sfc_main$i = { data() { return { items: [], query: { kw: "", page: 1, size: 20, categoryId: "" }, finished: false, loading: false, tab: "all", categories: [] }; }, onLoad() { this.fetchCategories(); this.reload(); }, onShow() { this.reload(); }, computed: { categoryNames() { return this.categories.map((c) => c.name); }, categoryLabel() { const c = this.categories.find((x) => String(x.id) === String(this.query.categoryId)); return c ? "类别:" + c.name : "选择类别"; } }, methods: { switchTab(t) { this.tab = t; this.query.categoryId = ""; this.reload(); }, onPickCategory(e) { const idx = Number(e.detail.value); const c = this.categories[idx]; this.query.categoryId = c ? c.id : ""; this.reload(); }, async fetchCategories() { try { const res = await get("/api/product-categories", {}); this.categories = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; } catch (_) { } }, reload() { this.items = []; this.query.page = 1; this.finished = false; this.loadMore(); }, async loadMore() { if (this.loading || this.finished) return; this.loading = true; try { const params = { kw: this.query.kw, page: this.query.page, size: this.query.size }; if (this.tab === "category" && this.query.categoryId) params.categoryId = this.query.categoryId; const res = await get("/api/products", params); const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; this.items = this.items.concat(list); if (list.length < this.query.size) this.finished = true; this.query.page += 1; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } finally { this.loading = false; } }, openForm(id) { const url = "/pages/product/form" + (id ? "?id=" + id : ""); uni.navigateTo({ url }); } } }; function _sfc_render$h(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "tabs" }, [ vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.tab === "all" }]), onClick: _cache[0] || (_cache[0] = ($event) => $options.switchTab("all")) }, "全部", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.tab === "category" }]), onClick: _cache[1] || (_cache[1] = ($event) => $options.switchTab("category")) }, "按类别", 2 /* CLASS */ ) ]), vue.createElementVNode("view", { class: "search" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => $data.query.kw = $event), placeholder: "输入名称/条码/规格查询", onConfirm: _cache[3] || (_cache[3] = (...args) => $options.reload && $options.reload(...args)) }, null, 544 /* NEED_HYDRATION, NEED_PATCH */ ), [ [ vue.vModelText, $data.query.kw, void 0, { trim: true } ] ]), $data.tab === "category" ? (vue.openBlock(), vue.createElementBlock("picker", { key: 0, mode: "selector", range: $options.categoryNames, onChange: _cache[4] || (_cache[4] = (...args) => $options.onPickCategory && $options.onPickCategory(...args)) }, [ vue.createElementVNode( "view", { class: "picker" }, vue.toDisplayString($options.categoryLabel), 1 /* TEXT */ ) ], 40, ["range"])) : vue.createCommentVNode("v-if", true), vue.createElementVNode("button", { size: "mini", onClick: _cache[5] || (_cache[5] = (...args) => $options.reload && $options.reload(...args)) }, "查询") ]), vue.createElementVNode( "scroll-view", { "scroll-y": "", class: "list", onScrolltolower: _cache[6] || (_cache[6] = (...args) => $options.loadMore && $options.loadMore(...args)) }, [ $data.items.length ? (vue.openBlock(true), vue.createElementBlock( vue.Fragment, { key: 0 }, vue.renderList($data.items, (it) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: it.id, onClick: ($event) => $options.openForm(it.id) }, [ it.cover ? (vue.openBlock(), vue.createElementBlock("image", { key: 0, src: it.cover, class: "thumb", mode: "aspectFill" }, null, 8, ["src"])) : vue.createCommentVNode("v-if", true), vue.createElementVNode("view", { class: "content" }, [ vue.createElementVNode( "view", { class: "name" }, vue.toDisplayString(it.name), 1 /* TEXT */ ), vue.createElementVNode( "view", { class: "meta" }, vue.toDisplayString(it.brand || "-") + " " + vue.toDisplayString(it.model || "") + " " + vue.toDisplayString(it.spec || ""), 1 /* TEXT */ ), vue.createElementVNode("view", { class: "meta" }, [ vue.createTextVNode( "库存:" + vue.toDisplayString(it.stock ?? 0) + " ", 1 /* TEXT */ ), vue.createElementVNode( "text", { class: "price" }, "零售价:¥" + vue.toDisplayString((it.retailPrice ?? it.price ?? 0).toFixed(2)), 1 /* TEXT */ ) ]) ]) ], 8, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) : (vue.openBlock(), vue.createElementBlock("view", { key: 1, class: "empty" }, [ vue.createElementVNode("text", null, "暂无数据,点击右上角“+”新增") ])) ], 32 /* NEED_HYDRATION */ ), vue.createElementVNode("view", { class: "fab", onClick: _cache[7] || (_cache[7] = ($event) => $options.openForm()) }, "+") ]); } const PagesProductList = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["render", _sfc_render$h], ["__file", "D:/wx/PartsInquiry/frontend/pages/product/list.vue"]]); const ITEM_SIZE = 210; const GAP = 18; const COLS = 3; function px(rpx) { return rpx; } const _sfc_main$h = { name: "ImageUploader", props: { modelValue: { type: Array, default: () => [] }, max: { type: Number, default: 9 }, uploadPath: { type: String, default: "/api/attachments" }, uploadFieldName: { type: String, default: "file" }, formData: { type: Object, default: () => ({ ownerType: "product" }) } }, data() { return { innerList: [] }; }, computed: { areaHeight() { const rows = Math.ceil((this.innerList.length + 1) / COLS) || 1; return rows * ITEM_SIZE + (rows - 1) * GAP; } }, watch: { modelValue: { immediate: true, handler(list) { const mapped = (list || []).map((u, i) => ({ uid: String(i) + "_" + (u.id || u.url || Math.random().toString(36).slice(2)), url: typeof u === "string" ? u : u.url || "", x: this.posOf(i).x, y: this.posOf(i).y })); this.innerList = mapped; } } }, methods: { posOf(index) { const row = Math.floor(index / COLS); const col = index % COLS; return { x: px(col * (ITEM_SIZE + GAP)), y: px(row * (ITEM_SIZE + GAP)) }; }, cellStyle(index) { return { width: ITEM_SIZE + "rpx", height: ITEM_SIZE + "rpx" }; }, preview(index) { uni.previewImage({ urls: this.innerList.map((i) => i.url), current: index }); }, remove(index) { this.innerList.splice(index, 1); this.reflow(); this.emit(); }, choose() { const remain = this.max - this.innerList.length; if (remain <= 0) return; uni.chooseImage({ count: remain, success: async (res) => { for (const path of res.tempFilePaths) { await this.doUpload(path); } } }); }, async doUpload(filePath) { var _a; try { const resp = await upload(this.uploadPath, filePath, this.formData, this.uploadFieldName); const url = (resp == null ? void 0 : resp.url) || ((_a = resp == null ? void 0 : resp.data) == null ? void 0 : _a.url) || (resp == null ? void 0 : resp.path) || ""; if (!url) throw new Error("上传响应无 url"); this.innerList.push({ uid: Math.random().toString(36).slice(2), url, ...this.posOf(this.innerList.length) }); this.reflow(); this.emit(); } catch (e) { uni.showToast({ title: "上传失败", icon: "none" }); } }, onMoving(index, e) { const { x, y } = e.detail; this.innerList[index].x = x; this.innerList[index].y = y; }, onMoveEnd(index) { const mv = this.innerList[index]; const col = Math.round(mv.x / (ITEM_SIZE + GAP)); const row = Math.round(mv.y / (ITEM_SIZE + GAP)); let newIndex = row * COLS + col; newIndex = Math.max(0, Math.min(newIndex, this.innerList.length - 1)); if (newIndex !== index) { const moved = this.innerList.splice(index, 1)[0]; this.innerList.splice(newIndex, 0, moved); } this.reflow(); this.emit(); }, reflow() { this.innerList.forEach((it, i) => { const p = this.posOf(i); it.x = p.x; it.y = p.y; }); }, emit() { this.$emit("update:modelValue", this.innerList.map((i) => i.url)); this.$emit("change", this.innerList.map((i) => i.url)); } } }; function _sfc_render$g(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "uploader" }, [ vue.createElementVNode( "view", { class: "grid", style: vue.normalizeStyle({ height: $options.areaHeight + "rpx" }) }, [ vue.createElementVNode( "movable-area", { class: "area", style: vue.normalizeStyle({ height: $options.areaHeight + "rpx" }) }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.innerList, (img, index) => { return vue.openBlock(), vue.createElementBlock("movable-view", { key: img.uid, class: "cell", style: vue.normalizeStyle($options.cellStyle(index)), direction: "all", damping: 40, friction: 2, x: img.x, y: img.y, onChange: ($event) => $options.onMoving(index, $event), onTouchend: ($event) => $options.onMoveEnd(index) }, [ vue.createElementVNode("image", { src: img.url, mode: "aspectFill", class: "thumb", onClick: ($event) => $options.preview(index) }, null, 8, ["src", "onClick"]), vue.createElementVNode("view", { class: "remove", onClick: vue.withModifiers(($event) => $options.remove(index), ["stop"]) }, "×", 8, ["onClick"]) ], 44, ["x", "y", "onChange", "onTouchend"]); }), 128 /* KEYED_FRAGMENT */ )), $data.innerList.length < $props.max ? (vue.openBlock(), vue.createElementBlock("view", { key: 0, class: "adder", onClick: _cache[0] || (_cache[0] = (...args) => $options.choose && $options.choose(...args)) }, [ vue.createElementVNode("text", null, "+") ])) : vue.createCommentVNode("v-if", true) ], 4 /* STYLE */ ) ], 4 /* STYLE */ ) ]); } const ImageUploader = /* @__PURE__ */ _export_sfc(_sfc_main$h, [["render", _sfc_render$g], ["__scopeId", "data-v-7bd1ddd2"], ["__file", "D:/wx/PartsInquiry/frontend/components/ImageUploader.vue"]]); const _sfc_main$g = { components: { ImageUploader }, data() { return { id: "", form: { name: "", barcode: "", brand: "", model: "", spec: "", origin: "", categoryId: "", unitId: "", stock: null, safeMin: null, safeMax: null, purchasePrice: null, retailPrice: null, wholesalePrice: null, bigClientPrice: null, images: [], remark: "" }, units: [], categories: [] }; }, onLoad(query) { this.id = (query == null ? void 0 : query.id) || ""; this.bootstrap(); }, computed: { unitNames() { return this.units.map((u) => u.name); }, categoryNames() { return this.categories.map((c) => c.name); }, unitLabel() { const u = this.units.find((x) => String(x.id) === String(this.form.unitId)); return u ? u.name : "选择单位"; }, categoryLabel() { const c = this.categories.find((x) => String(x.id) === String(this.form.categoryId)); return c ? c.name : "选择类别"; } }, methods: { async bootstrap() { await Promise.all([this.fetchUnits(), this.fetchCategories()]); if (this.id) this.loadDetail(); }, async fetchUnits() { try { const res = await get("/api/product-units"); this.units = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; } catch (_) { } }, async fetchCategories() { try { const res = await get("/api/product-categories"); this.categories = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; } catch (_) { } }, onPickUnit(e) { const idx = Number(e.detail.value); const u = this.units[idx]; this.form.unitId = u ? u.id : ""; }, onPickCategory(e) { const idx = Number(e.detail.value); const c = this.categories[idx]; this.form.categoryId = c ? c.id : ""; }, scan() { uni.scanCode({ onlyFromCamera: false, success: (res) => { this.form.barcode = res.result; } }); }, async loadDetail() { try { const data = await get("/api/products/" + this.id); Object.assign(this.form, { name: data.name, barcode: data.barcode, brand: data.brand, model: data.model, spec: data.spec, origin: data.origin, categoryId: data.categoryId, unitId: data.unitId, stock: data.stock, safeMin: data.safeMin, safeMax: data.safeMax, purchasePrice: data.purchasePrice, retailPrice: data.retailPrice, wholesalePrice: data.wholesalePrice, bigClientPrice: data.bigClientPrice, images: (data.images || []).map((i) => i.url || i) }); } catch (_) { } }, validate() { if (!this.form.name) { uni.showToast({ title: "请填写名称", icon: "none" }); return false; } if (this.form.safeMin != null && this.form.safeMax != null && Number(this.form.safeMin) > Number(this.form.safeMax)) { uni.showToast({ title: "安全库存区间不合法", icon: "none" }); return false; } return true; }, buildPayload() { const f = this.form; return { name: f.name, barcode: f.barcode, brand: f.brand, model: f.model, spec: f.spec, origin: f.origin, categoryId: f.categoryId || null, unitId: f.unitId, safeMin: f.safeMin, safeMax: f.safeMax, prices: { purchasePrice: f.purchasePrice, retailPrice: f.retailPrice, wholesalePrice: f.wholesalePrice, bigClientPrice: f.bigClientPrice }, stock: f.stock, images: f.images, remark: f.remark }; }, async save(goOn) { if (!this.validate()) return; const payload = this.buildPayload(); try { if (this.id) await put("/api/products/" + this.id, payload); else await post("/api/products", payload); uni.showToast({ title: "保存成功", icon: "success" }); if (goOn && !this.id) { this.form = { name: "", barcode: "", brand: "", model: "", spec: "", origin: "", categoryId: "", unitId: "", stock: null, safeMin: null, safeMax: null, purchasePrice: null, retailPrice: null, wholesalePrice: null, bigClientPrice: null, images: [], remark: "" }; } else { setTimeout(() => uni.navigateBack(), 400); } } catch (e) { uni.showToast({ title: "保存失败", icon: "none" }); } } } }; function _sfc_render$f(_ctx, _cache, $props, $setup, $data, $options) { const _component_ImageUploader = vue.resolveComponent("ImageUploader"); return vue.openBlock(), vue.createElementBlock("scroll-view", { "scroll-y": "", class: "page" }, [ vue.createElementVNode("view", { class: "card" }, [ vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "商品名称"), vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.form.name = $event), placeholder: "必填" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.name, void 0, { trim: true } ] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "条形码"), vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => $data.form.barcode = $event), placeholder: "可扫码或输入" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.barcode, void 0, { trim: true } ] ]), vue.createElementVNode("button", { size: "mini", onClick: _cache[2] || (_cache[2] = (...args) => $options.scan && $options.scan(...args)) }, "扫码") ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "品牌/型号/规格/产地") ]), vue.createElementVNode("view", { class: "row" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.form.brand = $event), placeholder: "品牌" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.brand, void 0, { trim: true } ] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => $data.form.model = $event), placeholder: "型号" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.model, void 0, { trim: true } ] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => $data.form.spec = $event), placeholder: "规格" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.spec, void 0, { trim: true } ] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => $data.form.origin = $event), placeholder: "产地" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.origin, void 0, { trim: true } ] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("picker", { mode: "selector", range: $options.unitNames, onChange: _cache[7] || (_cache[7] = (...args) => $options.onPickUnit && $options.onPickUnit(...args)) }, [ vue.createElementVNode( "view", { class: "picker" }, "主单位:" + vue.toDisplayString($options.unitLabel), 1 /* TEXT */ ) ], 40, ["range"]), vue.createElementVNode("picker", { mode: "selector", range: $options.categoryNames, onChange: _cache[8] || (_cache[8] = (...args) => $options.onPickCategory && $options.onPickCategory(...args)) }, [ vue.createElementVNode( "view", { class: "picker" }, "类别:" + vue.toDisplayString($options.categoryLabel), 1 /* TEXT */ ) ], 40, ["range"]) ]) ]), vue.createElementVNode("view", { class: "card" }, [ vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "库存与安全库存") ]), vue.createElementVNode("view", { class: "row" }, [ vue.withDirectives(vue.createElementVNode( "input", { type: "number", "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => $data.form.stock = $event), placeholder: "当前库存" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.stock, void 0, { number: true } ] ]), vue.withDirectives(vue.createElementVNode( "input", { type: "number", "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => $data.form.safeMin = $event), placeholder: "安全库存下限" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.safeMin, void 0, { number: true } ] ]), vue.withDirectives(vue.createElementVNode( "input", { type: "number", "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => $data.form.safeMax = $event), placeholder: "安全库存上限" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.safeMax, void 0, { number: true } ] ]) ]) ]), vue.createElementVNode("view", { class: "card" }, [ vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "价格(进价/零售/批发/大单)") ]), vue.createElementVNode("view", { class: "row prices" }, [ vue.withDirectives(vue.createElementVNode( "input", { type: "number", "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => $data.form.purchasePrice = $event), placeholder: "进货价" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.purchasePrice, void 0, { number: true } ] ]), vue.withDirectives(vue.createElementVNode( "input", { type: "number", "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => $data.form.retailPrice = $event), placeholder: "零售价" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.retailPrice, void 0, { number: true } ] ]), vue.withDirectives(vue.createElementVNode( "input", { type: "number", "onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => $data.form.wholesalePrice = $event), placeholder: "批发价" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.wholesalePrice, void 0, { number: true } ] ]), vue.withDirectives(vue.createElementVNode( "input", { type: "number", "onUpdate:modelValue": _cache[15] || (_cache[15] = ($event) => $data.form.bigClientPrice = $event), placeholder: "大单价" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.bigClientPrice, void 0, { number: true } ] ]) ]) ]), vue.createElementVNode("view", { class: "card" }, [ vue.createElementVNode("text", { class: "label" }, "图片"), vue.createVNode(_component_ImageUploader, { modelValue: $data.form.images, "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => $data.form.images = $event), formData: { ownerType: "product" } }, null, 8, ["modelValue"]) ]), vue.createElementVNode("view", { class: "card" }, [ vue.createElementVNode("text", { class: "label" }, "备注"), vue.withDirectives(vue.createElementVNode( "textarea", { "onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => $data.form.remark = $event), placeholder: "可选", "auto-height": "" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.remark, void 0, { trim: true } ] ]) ]), vue.createElementVNode("view", { class: "fixed" }, [ vue.createElementVNode("button", { type: "default", onClick: _cache[18] || (_cache[18] = ($event) => $options.save(false)) }, "保存"), vue.createElementVNode("button", { type: "primary", onClick: _cache[19] || (_cache[19] = ($event) => $options.save(true)) }, "保存并继续") ]) ]); } const PagesProductForm = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["render", _sfc_render$f], ["__file", "D:/wx/PartsInquiry/frontend/pages/product/form.vue"]]); const _sfc_main$f = { data() { return { name: "", list: [] }; }, onLoad() { this.reload(); }, methods: { async reload() { try { const res = await get("/api/product-categories"); this.list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; } catch (_) { } }, async create() { if (!this.name) return; await post("/api/product-categories", { name: this.name }); this.name = ""; this.reload(); }, async update(c) { await put("/api/product-categories/" + c.id, { name: c.name }); uni.showToast({ title: "已保存", icon: "success" }); }, async remove(c) { uni.showModal({ content: "确定删除该类别?", success: async (r) => { if (!r.confirm) return; await del("/api/product-categories/" + c.id); this.reload(); } }); } } }; function _sfc_render$e(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "toolbar" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.name = $event), placeholder: "新类别名称" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.name, void 0, { trim: true } ] ]), vue.createElementVNode("button", { size: "mini", onClick: _cache[1] || (_cache[1] = (...args) => $options.create && $options.create(...args)) }, "新增") ]), vue.createElementVNode("scroll-view", { "scroll-y": "", class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.list, (c) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: c.id }, [ vue.withDirectives(vue.createElementVNode("input", { "onUpdate:modelValue": ($event) => c.name = $event }, null, 8, ["onUpdate:modelValue"]), [ [ vue.vModelText, c.name, void 0, { trim: true } ] ]), vue.createElementVNode("view", { class: "ops" }, [ vue.createElementVNode("button", { size: "mini", onClick: ($event) => $options.update(c) }, "保存", 8, ["onClick"]), vue.createElementVNode("button", { size: "mini", type: "warn", onClick: ($event) => $options.remove(c) }, "删除", 8, ["onClick"]) ]) ]); }), 128 /* KEYED_FRAGMENT */ )) ]) ]); } const PagesProductCategories = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["render", _sfc_render$e], ["__file", "D:/wx/PartsInquiry/frontend/pages/product/categories.vue"]]); const _sfc_main$e = { data() { return { name: "", list: [] }; }, onLoad() { this.reload(); }, methods: { async reload() { try { const res = await get("/api/product-units"); this.list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; } catch (_) { } }, async create() { if (!this.name) return; await post("/api/product-units", { name: this.name }); this.name = ""; this.reload(); }, async update(u) { await put("/api/product-units/" + u.id, { name: u.name }); uni.showToast({ title: "已保存", icon: "success" }); }, async remove(u) { uni.showModal({ content: "确定删除该单位?", success: async (r) => { if (!r.confirm) return; await del("/api/product-units/" + u.id); this.reload(); } }); } } }; function _sfc_render$d(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "toolbar" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.name = $event), placeholder: "新单位名称" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.name, void 0, { trim: true } ] ]), vue.createElementVNode("button", { size: "mini", onClick: _cache[1] || (_cache[1] = (...args) => $options.create && $options.create(...args)) }, "新增") ]), vue.createElementVNode("scroll-view", { "scroll-y": "", class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.list, (u) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: u.id }, [ vue.withDirectives(vue.createElementVNode("input", { "onUpdate:modelValue": ($event) => u.name = $event }, null, 8, ["onUpdate:modelValue"]), [ [ vue.vModelText, u.name, void 0, { trim: true } ] ]), vue.createElementVNode("view", { class: "ops" }, [ vue.createElementVNode("button", { size: "mini", onClick: ($event) => $options.update(u) }, "保存", 8, ["onClick"]), vue.createElementVNode("button", { size: "mini", type: "warn", onClick: ($event) => $options.remove(u) }, "删除", 8, ["onClick"]) ]) ]); }), 128 /* KEYED_FRAGMENT */ )) ]) ]); } const PagesProductUnits = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$d], ["__file", "D:/wx/PartsInquiry/frontend/pages/product/units.vue"]]); const _sfc_main$d = { data() { return { settings: { hideZeroStock: false, hidePurchasePrice: false } }; }, onLoad() { this.load(); }, methods: { async load() { try { const res = await get("/api/product-settings"); this.settings = { hideZeroStock: !!(res == null ? void 0 : res.hideZeroStock), hidePurchasePrice: !!(res == null ? void 0 : res.hidePurchasePrice) }; } catch (_) { } }, async update(key, val) { const next = { ...this.settings, [key]: val }; this.settings = next; try { await put("/api/product-settings", next); } catch (_) { } } } }; function _sfc_render$c(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "item" }, [ vue.createElementVNode("text", null, "隐藏零库存商品"), vue.createElementVNode("switch", { checked: $data.settings.hideZeroStock, onChange: _cache[0] || (_cache[0] = (e) => $options.update("hideZeroStock", e.detail.value)) }, null, 40, ["checked"]) ]), vue.createElementVNode("view", { class: "item" }, [ vue.createElementVNode("text", null, "隐藏进货价"), vue.createElementVNode("switch", { checked: $data.settings.hidePurchasePrice, onChange: _cache[1] || (_cache[1] = (e) => $options.update("hidePurchasePrice", e.detail.value)) }, null, 40, ["checked"]) ]) ]); } const PagesProductSettings = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["render", _sfc_render$c], ["__file", "D:/wx/PartsInquiry/frontend/pages/product/settings.vue"]]); const _sfc_main$c = { data() { return { kw: "", debtOnly: false, customers: [] }; }, onLoad() { this.search(); }, onShow() { this.search(); }, methods: { toggleDebtOnly() { this.debtOnly = !this.debtOnly; this.search(); }, async search() { try { const res = await get("/api/customers", { kw: this.kw, debtOnly: this.debtOnly, page: 1, size: 50 }); this.customers = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, createCustomer() { uni.navigateTo({ url: "/pages/customer/form" }); }, select(c) { const pages = getCurrentPages(); const prev = pages.length >= 2 ? pages[pages.length - 2] : null; const vm = prev && prev.$vm ? prev.$vm : null; if (vm && vm.order) { vm.order.customerId = c.id; vm.customerName = c.name; } uni.navigateBack(); }, openDetail(c) { uni.navigateTo({ url: "/pages/customer/detail?id=" + c.id }); } } }; function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "search" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.kw = $event), placeholder: "搜索客户名称/电话", onConfirm: _cache[1] || (_cache[1] = (...args) => $options.search && $options.search(...args)) }, null, 544 /* NEED_HYDRATION, NEED_PATCH */ ), [ [vue.vModelText, $data.kw] ]), vue.createElementVNode("button", { size: "mini", onClick: _cache[2] || (_cache[2] = (...args) => $options.search && $options.search(...args)) }, "搜索"), vue.createElementVNode("button", { size: "mini", type: $data.debtOnly ? "primary" : "default", onClick: _cache[3] || (_cache[3] = (...args) => $options.toggleDebtOnly && $options.toggleDebtOnly(...args)) }, "只看欠款", 8, ["type"]) ]), vue.createElementVNode("scroll-view", { "scroll-y": "", class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.customers, (c) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: c.id, onClick: ($event) => $options.openDetail(c) }, [ vue.createElementVNode( "view", { class: "name" }, vue.toDisplayString(c.name), 1 /* TEXT */ ), vue.createElementVNode("view", { class: "meta" }, [ vue.createTextVNode( vue.toDisplayString(c.mobile || "—") + " ", 1 /* TEXT */ ), typeof c.receivable === "number" ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0 }, "|应收:¥ " + vue.toDisplayString(Number(c.receivable).toFixed(2)), 1 /* TEXT */ )) : vue.createCommentVNode("v-if", true) ]) ], 8, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) ]), vue.createElementVNode("view", { class: "bottom" }, [ vue.createElementVNode("button", { class: "primary", onClick: _cache[4] || (_cache[4] = (...args) => $options.createCustomer && $options.createCustomer(...args)) }, "新增客户") ]) ]); } const PagesCustomerSelect = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["render", _sfc_render$b], ["__file", "D:/wx/PartsInquiry/frontend/pages/customer/select.vue"]]); const _sfc_main$b = { data() { return { id: null, form: { name: "", level: "", priceLevel: "retail", contactName: "", mobile: "", phone: "", address: "", arOpening: 0, remark: "" }, priceLevels: ["零售价", "批发价", "大单报价"], priceLabels: ["零售价", "批发价", "大单报价"], priceIdx: 0 }; }, onLoad(query) { if (query && query.id) { this.id = Number(query.id); } }, methods: { onPriceChange(e) { this.priceIdx = Number(e.detail.value); this.form.priceLevel = this.priceLevels[this.priceIdx]; }, async save() { if (!this.form.name) return uni.showToast({ title: "请填写客户名称", icon: "none" }); try { if (this.id) await put(`/api/customers/${this.id}`, this.form); else await post("/api/customers", this.form); uni.showToast({ title: "保存成功", icon: "success" }); setTimeout(() => uni.navigateBack(), 500); } catch (e) { uni.showToast({ title: (e == null ? void 0 : e.message) || "保存失败", icon: "none" }); } } } }; function _sfc_render$a(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "客户名称"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.form.name = $event), placeholder: "必填" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.name] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "客户等级"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => $data.form.level = $event), placeholder: "可选,如 VIP/A/B" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.level] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "售价档位"), vue.createElementVNode("picker", { range: $data.priceLabels, value: $data.priceIdx, onChange: _cache[2] || (_cache[2] = (...args) => $options.onPriceChange && $options.onPriceChange(...args)) }, [ vue.createElementVNode( "view", { class: "value" }, vue.toDisplayString($data.priceLabels[$data.priceIdx]), 1 /* TEXT */ ) ], 40, ["range", "value"]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "联系人"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.form.contactName = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.contactName] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "手机"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => $data.form.mobile = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.mobile] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "电话"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => $data.form.phone = $event), placeholder: "可选(座机)" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.phone] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "送货地址"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => $data.form.address = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.address] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "初始应收"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", type: "digit", "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => $data.form.arOpening = $event), placeholder: "默认 0.00" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.arOpening, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "textarea" }, [ vue.withDirectives(vue.createElementVNode( "textarea", { "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => $data.form.remark = $event), maxlength: "200", placeholder: "备注(最多200字)" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.remark] ]) ]), vue.createElementVNode("view", { class: "bottom" }, [ vue.createElementVNode("button", { class: "primary", onClick: _cache[9] || (_cache[9] = (...args) => $options.save && $options.save(...args)) }, "保存") ]) ]); } const PagesCustomerForm = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["render", _sfc_render$a], ["__file", "D:/wx/PartsInquiry/frontend/pages/customer/form.vue"]]); const _sfc_main$a = { data() { return { id: null, d: {}, editing: false, form: { name: "", contactName: "", mobile: "", phone: "", address: "", level: "", priceLevel: "零售价", arOpening: 0, remark: "" }, priceLevels: ["零售价", "批发价", "大单报价"], priceLabels: ["零售价", "批发价", "大单报价"], priceIdx: 0 }; }, onLoad(q) { if (q && q.id) { this.id = Number(q.id); this.fetch(); } }, methods: { async fetch() { try { this.d = await get(`/api/customers/${this.id}`); this.form = { name: this.d.name || "", contactName: this.d.contactName || "", mobile: this.d.mobile || "", phone: this.d.phone || "", address: this.d.address || "", level: this.d.level || "", priceLevel: this.d.priceLevel || "retail", arOpening: Number(this.d.arOpening || 0), remark: this.d.remark || "" }; const idx = this.priceLevels.indexOf(this.form.priceLevel); this.priceIdx = idx >= 0 ? idx : 0; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, toggleEdit() { this.editing = !this.editing; }, onPriceChange(e) { this.priceIdx = Number(e.detail.value); this.form.priceLevel = this.priceLevels[this.priceIdx]; }, choose() { const pages = getCurrentPages(); let targetIdx = -1; for (let i = pages.length - 2; i >= 0; i--) { const vm = pages[i] && pages[i].$vm ? pages[i].$vm : null; if (vm && vm.order) { vm.order.customerId = this.d.id; vm.customerName = this.d.name; targetIdx = i; break; } } if (targetIdx >= 0) { const delta = pages.length - 1 - targetIdx; uni.navigateBack({ delta }); } else { uni.navigateBack(); } }, async save() { if (!this.form.name) return uni.showToast({ title: "请填写客户名称", icon: "none" }); try { await put(`/api/customers/${this.id}`, this.form); uni.showToast({ title: "已保存", icon: "success" }); this.editing = false; await this.fetch(); } catch (e) { uni.showToast({ title: (e == null ? void 0 : e.message) || "保存失败", icon: "none" }); } } } }; function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "card" }, [ vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "名称"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.name), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.form.name = $event), placeholder: "必填" }, null, 512 /* NEED_PATCH */ )), [ [vue.vModelText, $data.form.name] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "联系人"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.contactName || "—"), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => $data.form.contactName = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ )), [ [vue.vModelText, $data.form.contactName] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "手机"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.mobile || "—"), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => $data.form.mobile = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ )), [ [vue.vModelText, $data.form.mobile] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "电话"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.phone || "—"), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.form.phone = $event), placeholder: "可选(座机)" }, null, 512 /* NEED_PATCH */ )), [ [vue.vModelText, $data.form.phone] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "地址"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.address || "—"), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => $data.form.address = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ )), [ [vue.vModelText, $data.form.address] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "等级"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.level || "—"), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => $data.form.level = $event), placeholder: "可选,如 VIP/A/B" }, null, 512 /* NEED_PATCH */ )), [ [vue.vModelText, $data.form.level] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "售价档位"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.priceLevel), 1 /* TEXT */ )) : (vue.openBlock(), vue.createElementBlock("picker", { key: 1, range: $data.priceLabels, value: $data.priceIdx, onChange: _cache[6] || (_cache[6] = (...args) => $options.onPriceChange && $options.onPriceChange(...args)) }, [ vue.createElementVNode( "view", { class: "value" }, vue.toDisplayString($data.priceLabels[$data.priceIdx]), 1 /* TEXT */ ) ], 40, ["range", "value"])) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "初始应收"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, "¥ " + vue.toDisplayString(Number($data.d.arOpening || 0).toFixed(2)), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", type: "digit", "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => $data.form.arOpening = $event), placeholder: "0.00" }, null, 512 /* NEED_PATCH */ )), [ [ vue.vModelText, $data.form.arOpening, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "当前应收"), vue.createElementVNode( "text", { class: "value emp" }, "¥ " + vue.toDisplayString(Number($data.d.receivable || 0).toFixed(2)), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "备注"), !$data.editing ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0, class: "value" }, vue.toDisplayString($data.d.remark || "—"), 1 /* TEXT */ )) : vue.withDirectives((vue.openBlock(), vue.createElementBlock( "input", { key: 1, class: "value-input", "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => $data.form.remark = $event), placeholder: "—" }, null, 512 /* NEED_PATCH */ )), [ [vue.vModelText, $data.form.remark] ]) ]) ]), vue.createElementVNode("view", { class: "bottom" }, [ vue.createElementVNode( "button", { class: "ghost", onClick: _cache[9] || (_cache[9] = (...args) => $options.toggleEdit && $options.toggleEdit(...args)) }, vue.toDisplayString($data.editing ? "取消" : "编辑"), 1 /* TEXT */ ), $data.editing ? (vue.openBlock(), vue.createElementBlock("button", { key: 0, class: "primary", onClick: _cache[10] || (_cache[10] = (...args) => $options.save && $options.save(...args)) }, "保存")) : (vue.openBlock(), vue.createElementBlock("button", { key: 1, class: "primary", onClick: _cache[11] || (_cache[11] = (...args) => $options.choose && $options.choose(...args)) }, "选择此客户")) ]) ]); } const PagesCustomerDetail = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["render", _sfc_render$9], ["__file", "D:/wx/PartsInquiry/frontend/pages/customer/detail.vue"]]); const _sfc_main$9 = { data() { return { kw: "", debtOnly: false, suppliers: [] }; }, onLoad() { this.search(); }, methods: { toggleDebtOnly() { this.debtOnly = !this.debtOnly; this.search(); }, async search() { try { const res = await get("/api/suppliers", { kw: this.kw, debtOnly: this.debtOnly, page: 1, size: 50 }); this.suppliers = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, createSupplier() { uni.navigateTo({ url: "/pages/supplier/form" }); }, 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(); } } }; function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "search" }, [ vue.withDirectives(vue.createElementVNode( "input", { "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.kw = $event), placeholder: "搜索供应商名称/电话", onConfirm: _cache[1] || (_cache[1] = (...args) => $options.search && $options.search(...args)) }, null, 544 /* NEED_HYDRATION, NEED_PATCH */ ), [ [vue.vModelText, $data.kw] ]), vue.createElementVNode("button", { size: "mini", onClick: _cache[2] || (_cache[2] = (...args) => $options.search && $options.search(...args)) }, "搜索"), vue.createElementVNode("button", { size: "mini", type: $data.debtOnly ? "primary" : "default", onClick: _cache[3] || (_cache[3] = (...args) => $options.toggleDebtOnly && $options.toggleDebtOnly(...args)) }, "只看欠款", 8, ["type"]) ]), vue.createElementVNode("scroll-view", { "scroll-y": "", class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.suppliers, (s) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: s.id, onClick: ($event) => $options.select(s) }, [ vue.createElementVNode( "view", { class: "name" }, vue.toDisplayString(s.name), 1 /* TEXT */ ), vue.createElementVNode("view", { class: "meta" }, [ vue.createTextVNode( vue.toDisplayString(s.mobile || "—") + " ", 1 /* TEXT */ ), typeof s.apPayable === "number" ? (vue.openBlock(), vue.createElementBlock( "text", { key: 0 }, "|应付:¥ " + vue.toDisplayString(Number(s.apPayable).toFixed(2)), 1 /* TEXT */ )) : vue.createCommentVNode("v-if", true) ]) ], 8, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) ]), vue.createElementVNode("view", { class: "bottom" }, [ vue.createElementVNode("button", { class: "primary", onClick: _cache[4] || (_cache[4] = (...args) => $options.createSupplier && $options.createSupplier(...args)) }, "新增供应商") ]) ]); } const PagesSupplierSelect = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$8], ["__file", "D:/wx/PartsInquiry/frontend/pages/supplier/select.vue"]]); const _sfc_main$8 = { data() { return { id: null, form: { name: "", contactName: "", mobile: "", phone: "", address: "", apOpening: 0, apPayable: 0, remark: "" } }; }, onLoad(query) { if (query && query.id) { this.id = Number(query.id); } }, methods: { async save() { if (!this.form.name) return uni.showToast({ title: "请填写供应商名称", icon: "none" }); try { if (this.id) await put(`/api/suppliers/${this.id}`, this.form); else await post("/api/suppliers", this.form); uni.showToast({ title: "保存成功", icon: "success" }); setTimeout(() => uni.navigateBack(), 500); } catch (e) { uni.showToast({ title: (e == null ? void 0 : e.message) || "保存失败", icon: "none" }); } } } }; function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "供应商名称"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.form.name = $event), placeholder: "必填" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.name] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "联系人"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => $data.form.contactName = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.contactName] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "手机"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => $data.form.mobile = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.mobile] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "电话"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.form.phone = $event), placeholder: "可选(座机)" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.phone] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "经营地址"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => $data.form.address = $event), placeholder: "可选" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.address] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "初始应付款"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", type: "digit", "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => $data.form.apOpening = $event), placeholder: "默认 0.00" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.apOpening, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "应付款"), vue.withDirectives(vue.createElementVNode( "input", { class: "value", type: "digit", "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => $data.form.apPayable = $event), placeholder: "默认 0.00" }, null, 512 /* NEED_PATCH */ ), [ [ vue.vModelText, $data.form.apPayable, void 0, { number: true } ] ]) ]), vue.createElementVNode("view", { class: "textarea" }, [ vue.withDirectives(vue.createElementVNode( "textarea", { "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => $data.form.remark = $event), maxlength: "200", placeholder: "备注(最多200字)" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.remark] ]) ]), vue.createElementVNode("view", { class: "bottom" }, [ vue.createElementVNode("button", { class: "primary", onClick: _cache[8] || (_cache[8] = (...args) => $options.save && $options.save(...args)) }, "保存") ]) ]); } const PagesSupplierForm = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$7], ["__file", "D:/wx/PartsInquiry/frontend/pages/supplier/form.vue"]]); const TYPE_MAP = { cash: "现金", bank: "银行", alipay: "支付宝", wechat: "微信", other: "其他" }; const _sfc_main$7 = { data() { return { accounts: [], mode: "view" }; }, async onLoad(q) { this.mode = q && q.mode || "view"; try { const res = await get("/api/accounts"); this.accounts = Array.isArray(res) ? res : (res == null ? void 0 : res.list) || []; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, methods: { select(a) { if (this.mode === "pick") { const opener = getCurrentPages()[getCurrentPages().length - 2]; if (opener && opener.$vm) { opener.$vm.selectedAccountId = a.id; opener.$vm.selectedAccountName = a.name; } uni.navigateBack(); } else { uni.navigateTo({ url: `/pages/account/ledger?id=${a.id}` }); } }, create() { uni.navigateTo({ url: "/pages/account/form" }); }, typeLabel(t) { return TYPE_MAP[t] || t; } } }; function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("scroll-view", { "scroll-y": "", class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.accounts, (a) => { var _a; return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: a.id, onClick: ($event) => $options.select(a) }, [ vue.createElementVNode( "view", { class: "name" }, vue.toDisplayString(a.name), 1 /* TEXT */ ), vue.createElementVNode( "view", { class: "meta" }, vue.toDisplayString($options.typeLabel(a.type)) + " · 余额:" + vue.toDisplayString(((_a = a.balance) == null ? void 0 : _a.toFixed) ? a.balance.toFixed(2) : a.balance), 1 /* TEXT */ ) ], 8, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) ]), vue.createElementVNode("view", { class: "fab", onClick: _cache[0] || (_cache[0] = (...args) => $options.create && $options.create(...args)) }, "+") ]); } const PagesAccountSelect = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$6], ["__file", "D:/wx/PartsInquiry/frontend/pages/account/select.vue"]]); const _sfc_main$6 = { data() { return { accountId: null, startDate: "", endDate: "", list: [], opening: 0, income: 0, expense: 0, ending: 0 }; }, onLoad(query) { this.accountId = Number(query && query.id); this.quickInit(); this.load(); }, methods: { quickInit() { const now = /* @__PURE__ */ new Date(); const y = now.getFullYear(), m = now.getMonth() + 1; this.startDate = `${y}-${String(m).padStart(2, "0")}-01`; const lastDay = new Date(y, m, 0).getDate(); this.endDate = `${y}-${String(m).padStart(2, "0")}-${String(lastDay).padStart(2, "0")}`; }, async load(page = 1, size = 50) { try { const res = await get(`/api/accounts/${this.accountId}/ledger`, { startDate: this.startDate, endDate: this.endDate, page, size }); this.list = res && res.list || []; this.opening = Number(res && res.opening || 0); this.income = Number(res && res.income || 0); this.expense = Number(res && res.expense || 0); this.ending = Number(res && res.ending || 0); } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, fmt(v) { return (typeof v === "number" ? v : Number(v || 0)).toFixed(2); }, formatDate(s) { if (!s) return "-"; try { const d = new Date(s); const pad = (n) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; } catch (e) { return s; } } } }; function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "filters" }, [ vue.createElementVNode("picker", { mode: "date", value: $data.startDate, onChange: _cache[0] || (_cache[0] = (e) => { $data.startDate = e.detail.value; $options.load(); }) }, [ vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "开始"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($data.startDate || "—"), 1 /* TEXT */ ) ]) ], 40, ["value"]), vue.createElementVNode("picker", { mode: "date", value: $data.endDate, onChange: _cache[1] || (_cache[1] = (e) => { $data.endDate = e.detail.value; $options.load(); }) }, [ vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "结束"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($data.endDate || "—"), 1 /* TEXT */ ) ]) ], 40, ["value"]) ]), vue.createElementVNode("view", { class: "summary" }, [ vue.createElementVNode("view", { class: "sum-item" }, [ vue.createElementVNode("text", { class: "k" }, "收入"), vue.createElementVNode( "text", { class: "v" }, vue.toDisplayString($options.fmt($data.income)), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "sum-item" }, [ vue.createElementVNode("text", { class: "k" }, "支出"), vue.createElementVNode( "text", { class: "v" }, vue.toDisplayString($options.fmt($data.expense)), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "sum-item" }, [ vue.createElementVNode("text", { class: "k" }, "期初"), vue.createElementVNode( "text", { class: "v" }, vue.toDisplayString($options.fmt($data.opening)), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "sum-item" }, [ vue.createElementVNode("text", { class: "k" }, "期末"), vue.createElementVNode( "text", { class: "v" }, vue.toDisplayString($options.fmt($data.ending)), 1 /* TEXT */ ) ]) ]), vue.createElementVNode("scroll-view", { "scroll-y": "", class: "list" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.list, (it) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: it.id }, [ vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode( "text", { class: "title" }, vue.toDisplayString(it.src === "other" ? it.category || "其他" : it.remark || "收付款"), 1 /* TEXT */ ), vue.createElementVNode( "text", { class: vue.normalizeClass(["amount", { in: it.direction === "in", out: it.direction === "out" }]) }, vue.toDisplayString(it.direction === "in" ? "+" : "-") + vue.toDisplayString($options.fmt(it.amount)), 3 /* TEXT, CLASS */ ) ]), vue.createElementVNode( "view", { class: "meta" }, vue.toDisplayString($options.formatDate(it.tx_time || it.txTime)) + " · " + vue.toDisplayString(it.remark || "-"), 1 /* TEXT */ ) ]); }), 128 /* KEYED_FRAGMENT */ )) ]) ]); } const PagesAccountLedger = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$5], ["__file", "D:/wx/PartsInquiry/frontend/pages/account/ledger.vue"]]); const _sfc_main$5 = { data() { return { id: null, form: { name: "", type: "cash", bankName: "", bankAccount: "", openingBalance: "" }, showType: false, types: [ { key: "cash", name: "现金" }, { key: "bank", name: "银行存款" }, { key: "wechat", name: "微信" }, { key: "alipay", name: "支付宝" }, { key: "other", name: "其他" } ] }; }, onLoad(q) { this.id = q && q.id ? Number(q.id) : null; if (this.id) this.load(); }, methods: { typeLabel(t) { const m = { cash: "现金", bank: "银行存款", wechat: "微信", alipay: "支付宝", other: "其他" }; return m[t] || t; }, async load() { try { const list = await get("/api/accounts"); const a = (Array.isArray(list) ? list : (list == null ? void 0 : list.list) || []).find((x) => x.id == this.id); if (a) { this.form = { name: a.name, type: a.type, bankName: a.bank_name || a.bankName || "", bankAccount: a.bank_account || a.bankAccount || "", openingBalance: "" }; } } catch (e) { } }, async save() { if (!this.form.name) { uni.showToast({ title: "请输入名称", icon: "none" }); return; } try { const body = { ...this.form, openingBalance: Number(this.form.openingBalance || 0) }; if (this.id) await put(`/api/accounts/${this.id}`, body); else await post("/api/accounts", { ...body, status: 1 }); uni.showToast({ title: "已保存", icon: "success" }); setTimeout(() => uni.navigateBack(), 300); } catch (e) { uni.showToast({ title: "保存失败", icon: "none" }); } } } }; function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) { const _component_uni_popup = vue.resolveComponent("uni-popup"); return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createElementVNode("view", { class: "form" }, [ vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "账户名称"), vue.withDirectives(vue.createElementVNode( "input", { class: "input", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.form.name = $event), placeholder: "必填" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.name] ]) ]), vue.createElementVNode("view", { class: "field", onClick: _cache[1] || (_cache[1] = ($event) => $data.showType = true) }, [ vue.createElementVNode("text", { class: "label" }, "账户类型"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.typeLabel($data.form.type)), 1 /* TEXT */ ) ]), $data.form.type === "bank" ? (vue.openBlock(), vue.createElementBlock("view", { key: 0, class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "银行名称"), vue.withDirectives(vue.createElementVNode( "input", { class: "input", "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => $data.form.bankName = $event), placeholder: "选填" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.bankName] ]) ])) : vue.createCommentVNode("v-if", true), $data.form.type === "bank" ? (vue.openBlock(), vue.createElementBlock("view", { key: 1, class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "银行账号"), vue.withDirectives(vue.createElementVNode( "input", { class: "input", "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => $data.form.bankAccount = $event), placeholder: "选填" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.bankAccount] ]) ])) : vue.createCommentVNode("v-if", true), vue.createElementVNode("view", { class: "field" }, [ vue.createElementVNode("text", { class: "label" }, "当前余额"), vue.withDirectives(vue.createElementVNode( "input", { class: "input", type: "number", "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => $data.form.openingBalance = $event), placeholder: "0.00" }, null, 512 /* NEED_PATCH */ ), [ [vue.vModelText, $data.form.openingBalance] ]) ]) ]), vue.createElementVNode("view", { class: "actions" }, [ vue.createElementVNode("button", { class: "primary", onClick: _cache[5] || (_cache[5] = (...args) => $options.save && $options.save(...args)) }, "保存") ]), vue.createVNode(_component_uni_popup, { ref: "popup", type: "bottom", modelValue: $data.showType, "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => $data.showType = $event) }, { default: vue.withCtx(() => [ vue.createElementVNode("view", { class: "sheet" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.types, (t) => { return vue.openBlock(), vue.createElementBlock("view", { class: "sheet-item", key: t.key, onClick: ($event) => { $data.form.type = t.key; $data.showType = false; } }, vue.toDisplayString(t.name), 9, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )), vue.createElementVNode("view", { class: "sheet-cancel", onClick: _cache[6] || (_cache[6] = ($event) => $data.showType = false) }, "取消") ]) ]), _: 1 /* STABLE */ }, 8, ["modelValue"]) ]); } const PagesAccountForm = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["render", _sfc_render$4], ["__file", "D:/wx/PartsInquiry/frontend/pages/account/form.vue"]]); const API_OF = { sale: "/api/orders", purchase: "/api/purchase-orders", collect: "/api/payments", fund: "/api/other-transactions", stock: "/api/inventories/logs" }; const _sfc_main$4 = { data() { return { biz: "sale", bizList: [ { key: "sale", name: "出货" }, { key: "purchase", name: "进货" }, { key: "collect", name: "收款" }, { key: "fund", name: "资金" }, { key: "stock", name: "盘点" } ], range: "month", query: { kw: "" }, items: [], page: 1, size: 20, finished: false, loading: false, startDate: "", endDate: "" }; }, computed: { placeholder() { return "单据号/客户名称/品名规格/备注"; }, periodLabel() { return this.startDate && this.endDate ? `${this.startDate}~${this.endDate}` : ""; }, totalAmount() { return this.items.reduce((s, it) => s + Number(it.amount || 0), 0); } }, onLoad() { try { formatAppLog("log", "at pages/detail/index.vue:92", "[detail] onLoad route = pages/detail/index"); } catch (e) { } this.computeRange(); this.reload(); }, methods: { switchBiz(k) { if (this.biz === k) return; this.biz = k; this.reload(); }, switchRange(r) { this.range = r; this.computeRange(); this.reload(); }, computeRange() { const now = /* @__PURE__ */ new Date(); const pad = (n) => String(n).padStart(2, "0"); const fmt = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; let start = now, end = now; if (this.range === "today") { start = end = now; } else if (this.range === "week") { const day = now.getDay() || 7; start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - day + 1); end = now; } else if (this.range === "month") { start = new Date(now.getFullYear(), now.getMonth(), 1); end = new Date(now.getFullYear(), now.getMonth() + 1, 0); } else if (this.range === "year") { start = new Date(now.getFullYear(), 0, 1); end = new Date(now.getFullYear(), 11, 31); } else { start = new Date(now.getFullYear(), now.getMonth(), 1); end = new Date(now.getFullYear(), now.getMonth() + 1, 0); } this.startDate = fmt(start); this.endDate = fmt(end); }, reload() { this.items = []; this.page = 1; this.finished = false; this.loadMore(); }, async loadMore() { if (this.loading || this.finished) return; this.loading = true; try { const path = API_OF[this.biz] || "/api/orders"; const params = { kw: this.query.kw, page: this.page, size: this.size, startDate: this.startDate, endDate: this.endDate, biz: this.biz }; if (this.biz === "sale") params.type = "out"; const res = await get(path, params); const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; this.items = this.items.concat(list); if (list.length < this.size) this.finished = true; this.page += 1; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } finally { this.loading = false; } }, formatDate(s) { if (!s) return ""; try { const d = new Date(s); const pad = (n) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; } catch (_) { return String(s).slice(0, 10); } }, onCreate() { if (this.biz === "sale") { uni.switchTab({ url: "/pages/order/create" }); return; } uni.showToast({ title: "该类型创建页待实现", icon: "none" }); }, openDetail(it) { uni.showToast({ title: "详情开发中", icon: "none" }); } } }; function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "page" }, [ vue.createCommentVNode(" 顶部时间维度筛选 "), vue.createElementVNode("view", { class: "seg" }, [ vue.createElementVNode( "view", { class: vue.normalizeClass(["seg-item", $data.range === "custom" && "active"]), onClick: _cache[0] || (_cache[0] = ($event) => $options.switchRange("custom")) }, "自定义", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["seg-item", $data.range === "week" && "active"]), onClick: _cache[1] || (_cache[1] = ($event) => $options.switchRange("week")) }, "本周", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["seg-item", $data.range === "today" && "active"]), onClick: _cache[2] || (_cache[2] = ($event) => $options.switchRange("today")) }, "今日", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["seg-item", $data.range === "month" && "active"]), onClick: _cache[3] || (_cache[3] = ($event) => $options.switchRange("month")) }, "本月", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["seg-item", $data.range === "year" && "active"]), onClick: _cache[4] || (_cache[4] = ($event) => $options.switchRange("year")) }, "本年", 2 /* CLASS */ ) ]), vue.createCommentVNode(" 业务类型侧边切换:销售/进货/收款/资金/盘点 "), vue.createElementVNode("view", { class: "content" }, [ vue.createElementVNode("view", { class: "biz-tabs" }, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.bizList, (b) => { return vue.openBlock(), vue.createElementBlock("view", { key: b.key, class: vue.normalizeClass(["biz", $data.biz === b.key && "active"]), onClick: ($event) => $options.switchBiz(b.key) }, vue.toDisplayString(b.name), 11, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) ]), vue.createElementVNode("view", { class: "panel" }, [ vue.createCommentVNode(" 搜索框与期间显示、总额 "), vue.createElementVNode("view", { class: "toolbar" }, [ vue.createElementVNode("view", { class: "search" }, [ vue.withDirectives(vue.createElementVNode("input", { class: "search-input", "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => $data.query.kw = $event), placeholder: $options.placeholder, onConfirm: _cache[6] || (_cache[6] = (...args) => $options.reload && $options.reload(...args)) }, null, 40, ["placeholder"]), [ [ vue.vModelText, $data.query.kw, void 0, { trim: true } ] ]) ]), vue.createElementVNode( "view", { class: "period" }, vue.toDisplayString($options.periodLabel), 1 /* TEXT */ ), vue.createElementVNode("button", { size: "mini", onClick: _cache[7] || (_cache[7] = (...args) => $options.reload && $options.reload(...args)) }, "查询") ]), vue.createElementVNode( "view", { class: "total" }, "合计:¥" + vue.toDisplayString($options.totalAmount.toFixed(2)), 1 /* TEXT */ ), vue.createCommentVNode(" 列表 "), vue.createElementVNode( "scroll-view", { "scroll-y": "", class: "list", onScrolltolower: _cache[8] || (_cache[8] = (...args) => $options.loadMore && $options.loadMore(...args)) }, [ $data.items.length ? (vue.openBlock(true), vue.createElementBlock( vue.Fragment, { key: 0 }, vue.renderList($data.items, (it) => { return vue.openBlock(), vue.createElementBlock("view", { class: "item", key: it.id, onClick: ($event) => $options.openDetail(it) }, [ vue.createElementVNode("view", { class: "item-left" }, [ vue.createElementVNode( "view", { class: "date" }, vue.toDisplayString($options.formatDate(it.orderTime || it.txTime || it.createdAt)), 1 /* TEXT */ ), vue.createElementVNode( "view", { class: "name" }, vue.toDisplayString(it.customerName || it.supplierName || it.accountName || it.remark || "-"), 1 /* TEXT */ ), vue.createElementVNode( "view", { class: "no" }, vue.toDisplayString(it.orderNo || it.code || it.id), 1 /* TEXT */ ) ]), vue.createElementVNode( "view", { class: "amount" }, "¥ " + vue.toDisplayString((it.amount || 0).toFixed(2)), 1 /* TEXT */ ), vue.createElementVNode("view", { class: "arrow" }, "›") ], 8, ["onClick"]); }), 128 /* KEYED_FRAGMENT */ )) : (vue.openBlock(), vue.createElementBlock("view", { key: 1, class: "empty" }, "暂无数据")) ], 32 /* NEED_HYDRATION */ ), vue.createCommentVNode(" 右下角新增按钮:根据业务类型跳转对应开单页或创建页 "), vue.createElementVNode("view", { class: "fab", onClick: _cache[9] || (_cache[9] = (...args) => $options.onCreate && $options.onCreate(...args)) }, "+") ]) ]) ]); } const PagesDetailIndex = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$3], ["__file", "D:/wx/PartsInquiry/frontend/pages/detail/index.vue"]]); const _sfc_main$3 = { data() { return { avatarUrl: "/static/logo.png", shopName: "我的店铺", mobile: "" }; }, onLoad() { this.fetchProfile(); }, computed: { mobileDisplay() { const m = String(this.mobile || ""); return m.length === 11 ? m.slice(0, 3) + "****" + m.slice(7) : m || "未绑定手机号"; } }, methods: { async fetchProfile() { try { await get("/api/dashboard/overview"); } catch (e) { } try { const storeName = uni.getStorageSync("SHOP_NAME") || ""; const avatar = uni.getStorageSync("USER_AVATAR") || ""; const phone = uni.getStorageSync("USER_MOBILE") || ""; if (storeName) this.shopName = storeName; if (avatar) this.avatarUrl = avatar; this.mobile = phone; } catch (e) { } }, onAvatarError() { this.avatarUrl = "/static/logo.png"; }, goVip() { uni.showToast({ title: "VIP会员(开发中)", icon: "none" }); }, goMyOrders() { uni.switchTab({ url: "/pages/detail/index" }); }, goSupplier() { uni.navigateTo({ url: "/pages/supplier/select" }); }, goCustomer() { uni.navigateTo({ url: "/pages/customer/select" }); }, goCustomerQuote() { uni.showToast({ title: "客户报价(开发中)", icon: "none" }); }, goShop() { uni.showToast({ title: "店铺管理(开发中)", icon: "none" }); }, editProfile() { uni.showToast({ title: "账号与安全(开发中)", icon: "none" }); }, goProductSettings() { uni.navigateTo({ url: "/pages/product/settings" }); }, goSystemParams() { uni.showToast({ title: "系统参数(开发中)", icon: "none" }); }, goAbout() { uni.navigateTo({ url: "/pages/my/about" }); }, logout() { try { uni.removeStorageSync("TOKEN"); uni.removeStorageSync("USER_AVATAR"); uni.removeStorageSync("USER_NAME"); uni.removeStorageSync("USER_MOBILE"); uni.removeStorageSync("SHOP_NAME"); uni.showToast({ title: "已退出", icon: "none" }); setTimeout(() => { uni.reLaunch({ url: "/pages/index/index" }); }, 300); } catch (e) { uni.reLaunch({ url: "/pages/index/index" }); } } } }; function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "me" }, [ vue.createElementVNode("view", { class: "card user" }, [ vue.createElementVNode("image", { class: "avatar", src: $data.avatarUrl, mode: "aspectFill", onError: _cache[0] || (_cache[0] = (...args) => $options.onAvatarError && $options.onAvatarError(...args)) }, null, 40, ["src"]), vue.createElementVNode("view", { class: "meta" }, [ vue.createElementVNode( "text", { class: "name" }, vue.toDisplayString($data.shopName), 1 /* TEXT */ ), vue.createElementVNode( "text", { class: "phone" }, vue.toDisplayString($options.mobileDisplay), 1 /* TEXT */ ), vue.createElementVNode("text", { class: "role" }, "老板") ]) ]), vue.createElementVNode("view", { class: "group" }, [ vue.createElementVNode("view", { class: "group-title" }, "会员与订单"), vue.createElementVNode("view", { class: "cell", onClick: _cache[1] || (_cache[1] = (...args) => $options.goVip && $options.goVip(...args)) }, [ vue.createElementVNode("text", null, "VIP会员"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell", onClick: _cache[2] || (_cache[2] = (...args) => $options.goMyOrders && $options.goMyOrders(...args)) }, [ vue.createElementVNode("text", null, "我的订单"), vue.createElementVNode("text", { class: "arrow" }, "›") ]) ]), vue.createElementVNode("view", { class: "group" }, [ vue.createElementVNode("view", { class: "group-title" }, "基础管理"), vue.createElementVNode("view", { class: "cell", onClick: _cache[3] || (_cache[3] = (...args) => $options.goSupplier && $options.goSupplier(...args)) }, [ vue.createElementVNode("text", null, "供应商管理"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell", onClick: _cache[4] || (_cache[4] = (...args) => $options.goCustomer && $options.goCustomer(...args)) }, [ vue.createElementVNode("text", null, "客户管理"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell", onClick: _cache[5] || (_cache[5] = (...args) => $options.goCustomerQuote && $options.goCustomerQuote(...args)) }, [ vue.createElementVNode("text", null, "客户报价"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell", onClick: _cache[6] || (_cache[6] = (...args) => $options.goShop && $options.goShop(...args)) }, [ vue.createElementVNode("text", null, "店铺管理"), vue.createElementVNode("text", { class: "arrow" }, "›") ]) ]), vue.createElementVNode("view", { class: "group" }, [ vue.createElementVNode("view", { class: "group-title" }, "设置中心"), vue.createElementVNode("view", { class: "cell", onClick: _cache[7] || (_cache[7] = (...args) => $options.editProfile && $options.editProfile(...args)) }, [ vue.createElementVNode("text", null, "账号与安全"), vue.createElementVNode("text", { class: "desc" }, "修改头像、姓名、密码"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell", onClick: _cache[8] || (_cache[8] = (...args) => $options.goProductSettings && $options.goProductSettings(...args)) }, [ vue.createElementVNode("text", null, "商品设置"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell", onClick: _cache[9] || (_cache[9] = (...args) => $options.goSystemParams && $options.goSystemParams(...args)) }, [ vue.createElementVNode("text", null, "系统参数"), vue.createElementVNode("text", { class: "desc" }, "低价提示、默认收款、单行折扣等"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell", onClick: _cache[10] || (_cache[10] = (...args) => $options.goAbout && $options.goAbout(...args)) }, [ vue.createElementVNode("text", null, "关于与协议"), vue.createElementVNode("text", { class: "arrow" }, "›") ]), vue.createElementVNode("view", { class: "cell danger", onClick: _cache[11] || (_cache[11] = (...args) => $options.logout && $options.logout(...args)) }, [ vue.createElementVNode("text", null, "退出登录") ]) ]) ]); } const PagesMyIndex = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$2], ["__file", "D:/wx/PartsInquiry/frontend/pages/my/index.vue"]]); const _sfc_main$2 = { methods: { openPolicy() { uni.showModal({ title: "隐私协议", content: "隐私协议(静态占位)", showCancel: false }); }, openTerms() { uni.showModal({ title: "用户协议", content: "用户协议(静态占位)", showCancel: false }); }, openComplaint() { uni.showToast({ title: "暂未开通", icon: "none" }); } } }; function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "about" }, [ vue.createElementVNode("view", { class: "hero" }, [ vue.createElementVNode("image", { class: "logo", src: _imports_0, mode: "aspectFit" }), vue.createElementVNode("text", { class: "title" }, "五金配件管家"), vue.createElementVNode("text", { class: "subtitle" }, "专注小微门店的极简进销存") ]), vue.createElementVNode("view", { class: "card" }, [ vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "版本"), vue.createElementVNode("text", { class: "value" }, "1.0.0") ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "隐私协议"), vue.createElementVNode("text", { class: "link", onClick: _cache[0] || (_cache[0] = (...args) => $options.openPolicy && $options.openPolicy(...args)) }, "查看") ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "用户协议"), vue.createElementVNode("text", { class: "link", onClick: _cache[1] || (_cache[1] = (...args) => $options.openTerms && $options.openTerms(...args)) }, "查看") ]), vue.createElementVNode("view", { class: "row" }, [ vue.createElementVNode("text", { class: "label" }, "个人信息安全投诉"), vue.createElementVNode("text", { class: "link", onClick: _cache[2] || (_cache[2] = (...args) => $options.openComplaint && $options.openComplaint(...args)) }, "提交") ]) ]) ]); } const PagesMyAbout = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$1], ["__file", "D:/wx/PartsInquiry/frontend/pages/my/about.vue"]]); function formatDate(d) { const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, "0"); const day = String(d.getDate()).padStart(2, "0"); return `${y}-${m}-${day}`; } const _sfc_main$1 = { data() { const now = /* @__PURE__ */ new Date(); const start = new Date(now.getFullYear(), now.getMonth(), 1); return { startDate: formatDate(start), endDate: formatDate(now), mode: "sale", dim: "customer", rows: [], total: { sales: 0, cost: 0, profit: 0 } }; }, onLoad(query) { try { const m = query && query.mode; const d = query && query.dim; if (m) this.mode = m; if (d) this.dim = d; } catch (e) { } this.refresh(); }, computed: { profitRate() { const { sales, profit } = this.total; if (!sales) return "0.00%"; return (profit / sales * 100).toFixed(2) + "%"; } }, methods: { fmt(n) { return Number(n || 0).toFixed(2); }, setMode(m) { this.mode = m; this.dim = m === "sale" ? "customer" : m === "purchase" ? "supplier" : m === "inventory" ? "qty" : "ar"; this.refresh(); }, onStartChange(e) { this.startDate = e.detail.value; this.refresh(); }, onEndChange(e) { this.endDate = e.detail.value; this.refresh(); }, async refresh() { if (this.mode === "sale") { if (this.dim === "customer") return this.loadByCustomer(); if (this.dim === "product") return this.loadByProduct(); } if (this.mode === "purchase") { if (this.dim === "supplier") return this.loadPurchaseBySupplier(); if (this.dim === "product") return this.loadPurchaseByProduct(); } if (this.mode === "inventory") { if (this.dim === "qty") return this.loadInventoryByQty(); if (this.dim === "amount") return this.loadInventoryByAmount(); } if (this.mode === "arap") { if (this.dim === "ar") return this.loadAR(); if (this.dim === "ap") return this.loadAP(); } }, async loadByCustomer() { try { const listResp = await get("/api/orders", { biz: "sale", type: "out", startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); const list = listResp && (listResp.list || listResp) || []; const map = /* @__PURE__ */ new Map(); let totalSales = 0; for (const it of list) { const name = it.customerName || "未知客户"; const amount = Number(it.amount || 0); totalSales += amount; if (!map.has(name)) map.set(name, { name, sales: 0, cost: 0, profit: 0 }); const row = map.get(name); row.sales += amount; } const rows = Array.from(map.values()).map((r) => ({ ...r, profit: r.sales - r.cost })); const total = { sales: totalSales, cost: 0, profit: totalSales }; this.rows = rows; this.total = total; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, async loadByProduct() { try { const listResp = await get("/api/orders", { biz: "sale", type: "out", startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); const list = listResp && (listResp.list || listResp) || []; const agg = /* @__PURE__ */ new Map(); for (const it of list) { try { const d = await get(`/api/orders/${it.id}`); const items = d && d.items || []; for (const m of items) { const key = String(m.productId || m.name); if (!agg.has(key)) agg.set(key, { name: m.name || "#" + key, sales: 0, cost: 0, profit: 0 }); const row = agg.get(key); const sales = Number(m.amount || 0); row.sales += sales; } } catch (_) { } } const rows = Array.from(agg.values()).map((r) => ({ ...r, profit: r.sales - r.cost })); const totalSales = rows.reduce((s, r) => s + r.sales, 0); this.rows = rows; this.total = { sales: totalSales, cost: 0, profit: totalSales }; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, async loadPurchaseBySupplier() { try { const listResp = await get("/api/purchase-orders", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); const list = listResp && (listResp.list || listResp) || []; const map = /* @__PURE__ */ new Map(); let total = 0; for (const it of list) { const name = it.supplierName || "未知供应商"; const amount = Number(it.amount || 0); total += amount; if (!map.has(name)) map.set(name, { name, sales: 0, cost: 0, profit: 0 }); const row = map.get(name); row.sales += amount; } this.rows = Array.from(map.values()); this.total = { sales: total, cost: 0, profit: 0 }; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, async loadPurchaseByProduct() { try { const listResp = await get("/api/purchase-orders", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); const list = listResp && (listResp.list || listResp) || []; const agg = /* @__PURE__ */ new Map(); for (const it of list) { try { const d = await get(`/api/purchase-orders/${it.id}`); for (const m of (d == null ? void 0 : d.items) || []) { const key = String(m.productId || m.name); if (!agg.has(key)) agg.set(key, { name: m.name || "#" + key, sales: 0, cost: 0, profit: 0 }); const row = agg.get(key); row.sales += Number(m.amount || 0); } } catch (_) { } } const rows = Array.from(agg.values()); const total = rows.reduce((s, r) => s + r.sales, 0); this.rows = rows; this.total = { sales: total, cost: 0, profit: 0 }; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, async loadInventoryByQty() { try { const resp = await get("/api/inventories/logs", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); const list = resp && (resp.list || resp) || []; const map = /* @__PURE__ */ new Map(); let totalQty = 0; for (const it of list) { const key = it.productId || "未知"; if (!map.has(key)) map.set(key, { name: String(key), sales: 0, cost: 0, profit: 0 }); const row = map.get(key); const q = Number(it.qtyDelta || 0); row.sales += q; totalQty += q; } this.rows = Array.from(map.values()); this.total = { sales: totalQty, cost: 0, profit: 0 }; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, async loadInventoryByAmount() { try { const resp = await get("/api/inventories/logs", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); const list = resp && (resp.list || resp) || []; const map = /* @__PURE__ */ new Map(); let totalAmt = 0; for (const it of list) { const key = it.productId || "未知"; if (!map.has(key)) map.set(key, { name: String(key), sales: 0, cost: 0, profit: 0 }); const row = map.get(key); const a = Number(it.amount || it.amountDelta || 0); row.sales += a; totalAmt += a; } this.rows = Array.from(map.values()); this.total = { sales: totalAmt, cost: 0, profit: 0 }; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, async loadAR() { try { const res = await get("/api/customers", { page: 1, size: 100, debtOnly: false }); const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; const rows = list.map((c) => ({ name: c.name, sales: Number(c.receivable || 0), cost: 0, profit: 0 })); const total = rows.reduce((s, r) => s + r.sales, 0); this.rows = rows; this.total = { sales: total, cost: 0, profit: 0 }; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } }, async loadAP() { try { const res = await get("/api/suppliers", { page: 1, size: 100 }); const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; const rows = list.map((s) => ({ name: s.name, sales: Number(s.apPayable || 0), cost: 0, profit: 0 })); const total = rows.reduce((s, r) => s + r.sales, 0); this.rows = rows; this.total = { sales: total, cost: 0, profit: 0 }; } catch (e) { uni.showToast({ title: "加载失败", icon: "none" }); } } } }; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "report" }, [ vue.createElementVNode("view", { class: "modes" }, [ vue.createElementVNode( "view", { class: vue.normalizeClass(["mode-tab", { active: $data.mode === "sale" }]), onClick: _cache[0] || (_cache[0] = ($event) => $options.setMode("sale")) }, "销售统计", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["mode-tab", { active: $data.mode === "purchase" }]), onClick: _cache[1] || (_cache[1] = ($event) => $options.setMode("purchase")) }, "进货统计", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["mode-tab", { active: $data.mode === "inventory" }]), onClick: _cache[2] || (_cache[2] = ($event) => $options.setMode("inventory")) }, "库存统计", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["mode-tab", { active: $data.mode === "arap" }]), onClick: _cache[3] || (_cache[3] = ($event) => $options.setMode("arap")) }, "应收/应付对账", 2 /* CLASS */ ) ]), vue.createElementVNode("view", { class: "toolbar" }, [ vue.createElementVNode("picker", { mode: "date", value: $data.startDate, onChange: _cache[4] || (_cache[4] = (...args) => $options.onStartChange && $options.onStartChange(...args)) }, [ vue.createElementVNode( "view", { class: "date" }, vue.toDisplayString($data.startDate), 1 /* TEXT */ ) ], 40, ["value"]), vue.createElementVNode("text", { style: { "margin": "0 8rpx" } }, "—"), vue.createElementVNode("picker", { mode: "date", value: $data.endDate, onChange: _cache[5] || (_cache[5] = (...args) => $options.onEndChange && $options.onEndChange(...args)) }, [ vue.createElementVNode( "view", { class: "date" }, vue.toDisplayString($data.endDate), 1 /* TEXT */ ) ], 40, ["value"]) ]), $data.mode === "sale" ? (vue.openBlock(), vue.createElementBlock("view", { key: 0, class: "tabs" }, [ vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "customer" }]), onClick: _cache[6] || (_cache[6] = ($event) => { $data.dim = "customer"; $options.refresh(); }) }, "按客户", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "product" }]), onClick: _cache[7] || (_cache[7] = ($event) => { $data.dim = "product"; $options.refresh(); }) }, "按货品", 2 /* CLASS */ ) ])) : $data.mode === "purchase" ? (vue.openBlock(), vue.createElementBlock("view", { key: 1, class: "tabs" }, [ vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "supplier" }]), onClick: _cache[8] || (_cache[8] = ($event) => { $data.dim = "supplier"; $options.refresh(); }) }, "按供应商", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "product" }]), onClick: _cache[9] || (_cache[9] = ($event) => { $data.dim = "product"; $options.refresh(); }) }, "按货品", 2 /* CLASS */ ) ])) : $data.mode === "inventory" ? (vue.openBlock(), vue.createElementBlock("view", { key: 2, class: "tabs" }, [ vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "qty" }]), onClick: _cache[10] || (_cache[10] = ($event) => { $data.dim = "qty"; $options.refresh(); }) }, "按数量", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "amount" }]), onClick: _cache[11] || (_cache[11] = ($event) => { $data.dim = "amount"; $options.refresh(); }) }, "按金额", 2 /* CLASS */ ) ])) : $data.mode === "arap" ? (vue.openBlock(), vue.createElementBlock("view", { key: 3, class: "tabs" }, [ vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "ar" }]), onClick: _cache[12] || (_cache[12] = ($event) => { $data.dim = "ar"; $options.refresh(); }) }, "应收对账", 2 /* CLASS */ ), vue.createElementVNode( "view", { class: vue.normalizeClass(["tab", { active: $data.dim === "ap" }]), onClick: _cache[13] || (_cache[13] = ($event) => { $data.dim = "ap"; $options.refresh(); }) }, "应付对账", 2 /* CLASS */ ) ])) : vue.createCommentVNode("v-if", true), vue.createElementVNode("view", { class: "summary" }, [ vue.createElementVNode("view", { class: "item" }, [ vue.createElementVNode("text", { class: "label" }, "销售额"), vue.createElementVNode( "text", { class: "value" }, "¥ " + vue.toDisplayString($options.fmt($data.total.sales)), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "item" }, [ vue.createElementVNode("text", { class: "label" }, "成本"), vue.createElementVNode( "text", { class: "value" }, "¥ " + vue.toDisplayString($options.fmt($data.total.cost)), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "item" }, [ vue.createElementVNode("text", { class: "label" }, "利润"), vue.createElementVNode( "text", { class: "value" }, "¥ " + vue.toDisplayString($options.fmt($data.total.profit)), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "item" }, [ vue.createElementVNode("text", { class: "label" }, "利润率"), vue.createElementVNode( "text", { class: "value" }, vue.toDisplayString($options.profitRate), 1 /* TEXT */ ) ]) ]), (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList($data.rows, (row, idx) => { return vue.openBlock(), vue.createElementBlock("view", { key: idx, class: "card" }, [ vue.createElementVNode("view", { class: "row-head" }, [ row.avatar ? (vue.openBlock(), vue.createElementBlock("image", { key: 0, class: "thumb", src: row.avatar }, null, 8, ["src"])) : vue.createCommentVNode("v-if", true), vue.createElementVNode( "view", { class: "title" }, vue.toDisplayString(row.name), 1 /* TEXT */ ) ]), vue.createElementVNode("view", { class: "row-body" }, [ vue.createElementVNode( "text", null, "销售额:¥ " + vue.toDisplayString($options.fmt(row.sales)), 1 /* TEXT */ ), vue.createElementVNode( "text", { style: { "margin-left": "18rpx" } }, "成本:¥ " + vue.toDisplayString($options.fmt(row.cost)), 1 /* TEXT */ ), vue.createElementVNode( "text", { style: { "margin-left": "18rpx" } }, "利润:¥ " + vue.toDisplayString($options.fmt(row.profit)), 1 /* TEXT */ ) ]) ]); }), 128 /* KEYED_FRAGMENT */ )) ]); } const PagesReportIndex = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render], ["__file", "D:/wx/PartsInquiry/frontend/pages/report/index.vue"]]); __definePage("pages/index/index", PagesIndexIndex); __definePage("pages/order/create", PagesOrderCreate); __definePage("pages/product/select", PagesProductSelect); __definePage("pages/product/list", PagesProductList); __definePage("pages/product/form", PagesProductForm); __definePage("pages/product/categories", PagesProductCategories); __definePage("pages/product/units", PagesProductUnits); __definePage("pages/product/settings", PagesProductSettings); __definePage("pages/customer/select", PagesCustomerSelect); __definePage("pages/customer/form", PagesCustomerForm); __definePage("pages/customer/detail", PagesCustomerDetail); __definePage("pages/supplier/select", PagesSupplierSelect); __definePage("pages/supplier/form", PagesSupplierForm); __definePage("pages/account/select", PagesAccountSelect); __definePage("pages/account/ledger", PagesAccountLedger); __definePage("pages/account/form", PagesAccountForm); __definePage("pages/detail/index", PagesDetailIndex); __definePage("pages/my/index", PagesMyIndex); __definePage("pages/my/about", PagesMyAbout); __definePage("pages/report/index", PagesReportIndex); const _sfc_main = { onLaunch: function() { formatAppLog("log", "at App.vue:4", "App Launch"); }, onShow: function() { formatAppLog("log", "at App.vue:7", "App Show"); }, onHide: function() { formatAppLog("log", "at App.vue:10", "App Hide"); } }; const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "D:/wx/PartsInquiry/frontend/App.vue"]]); function createApp() { const app = vue.createVueApp(App); return { app }; } const { app: __app__, Vuex: __Vuex__, Pinia: __Pinia__ } = createApp(); uni.Vuex = __Vuex__; uni.Pinia = __Pinia__; __app__.provide("__globalStyles", __uniConfig.styles); __app__._component.mpType = "app"; __app__._component.render = () => { }; __app__.mount("#app"); })(Vue);