2
4
frontend/unpackage/dist/dev/mp-weixin/app.js
vendored
@@ -6,6 +6,8 @@ if (!Math) {
|
||||
"./pages/order/create.js";
|
||||
"./pages/product/select.js";
|
||||
"./pages/product/list.js";
|
||||
"./pages/product/submit.js";
|
||||
"./pages/product/submissions.js";
|
||||
"./pages/product/form.js";
|
||||
"./pages/product/categories.js";
|
||||
"./pages/product/units.js";
|
||||
@@ -23,7 +25,9 @@ if (!Math) {
|
||||
"./pages/auth/register.js";
|
||||
"./pages/my/index.js";
|
||||
"./pages/my/about.js";
|
||||
"./pages/my/security.js";
|
||||
"./pages/my/vip.js";
|
||||
"./pages/my/orders.js";
|
||||
"./pages/report/index.js";
|
||||
}
|
||||
const _sfc_main = {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
"pages/order/create",
|
||||
"pages/product/select",
|
||||
"pages/product/list",
|
||||
"pages/product/submit",
|
||||
"pages/product/submissions",
|
||||
"pages/product/form",
|
||||
"pages/product/categories",
|
||||
"pages/product/units",
|
||||
@@ -21,7 +23,9 @@
|
||||
"pages/auth/register",
|
||||
"pages/my/index",
|
||||
"pages/my/about",
|
||||
"pages/my/security",
|
||||
"pages/my/vip",
|
||||
"pages/my/orders",
|
||||
"pages/report/index"
|
||||
],
|
||||
"window": {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
"use strict";
|
||||
const _imports_0$1 = "/static/icons/icons8-shopping-cart-100.png";
|
||||
const _imports_0 = "/static/logo.png";
|
||||
exports._imports_0 = _imports_0$1;
|
||||
exports._imports_0$1 = _imports_0;
|
||||
const _imports_0$4 = "/static/icons/icons8-shopping-cart-100.png";
|
||||
const _imports_0$3 = "/static/icons/icons8-login-50.png";
|
||||
const _imports_0$2 = "/static/logo.png";
|
||||
const _imports_0$1 = "/static/icons/icons8-vip-48 (1).png";
|
||||
const _imports_0 = "/static/icons/icons8-close-48.png";
|
||||
exports._imports_0 = _imports_0$4;
|
||||
exports._imports_0$1 = _imports_0$3;
|
||||
exports._imports_0$2 = _imports_0$2;
|
||||
exports._imports_0$3 = _imports_0$1;
|
||||
exports._imports_0$4 = _imports_0;
|
||||
//# sourceMappingURL=../../.sourcemap/mp-weixin/common/assets.js.map
|
||||
|
||||
@@ -6,26 +6,29 @@ const fallbackBaseUrl = "http://127.0.0.1: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(/\/$/, ""));
|
||||
typeof process !== "undefined" && process.env && (process.env.VITE_APP_SHOP_ID || process.env.SHOP_ID) || "";
|
||||
typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("SHOP_ID") || "" : "";
|
||||
const envShopId = typeof process !== "undefined" && process.env && (process.env.VITE_APP_SHOP_ID || process.env.SHOP_ID) || "";
|
||||
const storageShopId = typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("SHOP_ID") || "" : "";
|
||||
const SHOP_ID = Number(envShopId || storageShopId || 1);
|
||||
const envEnableDefaultUser = typeof process !== "undefined" && process.env && (process.env.VITE_APP_ENABLE_DEFAULT_USER || process.env.ENABLE_DEFAULT_USER) || "";
|
||||
const storageEnableDefaultUser = typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("ENABLE_DEFAULT_USER") || "" : "";
|
||||
String(envEnableDefaultUser || storageEnableDefaultUser || "false").toLowerCase() === "true";
|
||||
typeof process !== "undefined" && process.env && (process.env.VITE_APP_DEFAULT_USER_ID || process.env.DEFAULT_USER_ID) || "";
|
||||
typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("DEFAULT_USER_ID") || "" : "";
|
||||
const envVipPrice = typeof process !== "undefined" && process.env && (process.env.VITE_APP_VIP_PRICE || process.env.VIP_PRICE) || "";
|
||||
const storageVipPrice = typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("VIP_PRICE") || "" : "";
|
||||
const VIP_PRICE_PER_MONTH = Number(envVipPrice || storageVipPrice || 15);
|
||||
const ENABLE_DEFAULT_USER = String(envEnableDefaultUser || storageEnableDefaultUser || "false").toLowerCase() === "true";
|
||||
const envDefaultUserId = typeof process !== "undefined" && process.env && (process.env.VITE_APP_DEFAULT_USER_ID || process.env.DEFAULT_USER_ID) || "";
|
||||
const storageDefaultUserId = typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("DEFAULT_USER_ID") || "" : "";
|
||||
const DEFAULT_USER_ID = Number(envDefaultUserId || storageDefaultUserId || 0);
|
||||
typeof process !== "undefined" && process.env && (process.env.VITE_APP_VIP_PRICE || process.env.VIP_PRICE) || "";
|
||||
typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("VIP_PRICE") || "" : "";
|
||||
typeof process !== "undefined" && process.env && (process.env.VITE_APP_HOME_BANNER_IMG || process.env.HOME_BANNER_IMG) || "";
|
||||
typeof common_vendor.index !== "undefined" ? common_vendor.index.getStorageSync("HOME_BANNER_IMG") || "" : "";
|
||||
const KPI_ICONS = {
|
||||
todaySales: "/static/icons/sale.png",
|
||||
monthSales: "/static/icons/report.png",
|
||||
monthProfit: "/static/icons/report.png",
|
||||
todaySales: "/static/icons/webwxgetmsgimg.jpg",
|
||||
monthSales: "/static/icons/webwxgetmsgimg.jpg",
|
||||
monthProfit: "/static/icons/icons8-profit-50.png",
|
||||
stockCount: "/static/icons/product.png"
|
||||
};
|
||||
exports.API_BASE_URL = API_BASE_URL;
|
||||
exports.API_BASE_URL_CANDIDATES = API_BASE_URL_CANDIDATES;
|
||||
exports.DEFAULT_USER_ID = DEFAULT_USER_ID;
|
||||
exports.ENABLE_DEFAULT_USER = ENABLE_DEFAULT_USER;
|
||||
exports.KPI_ICONS = KPI_ICONS;
|
||||
exports.VIP_PRICE_PER_MONTH = VIP_PRICE_PER_MONTH;
|
||||
exports.SHOP_ID = SHOP_ID;
|
||||
//# sourceMappingURL=../../.sourcemap/mp-weixin/common/config.js.map
|
||||
|
||||
@@ -30,8 +30,19 @@ function buildAuthHeaders(base = {}) {
|
||||
headers["X-Shop-Id"] = claims.shopId;
|
||||
if (claims && claims.userId)
|
||||
headers["X-User-Id"] = claims.userId;
|
||||
} else if (common_config.ENABLE_DEFAULT_USER && common_config.DEFAULT_USER_ID) {
|
||||
if (headers["Authorization"])
|
||||
delete headers["Authorization"];
|
||||
headers["X-User-Id"] = headers["X-User-Id"] || common_config.DEFAULT_USER_ID;
|
||||
if (common_config.SHOP_ID)
|
||||
headers["X-Shop-Id"] = headers["X-Shop-Id"] || common_config.SHOP_ID;
|
||||
}
|
||||
} catch (_) {
|
||||
if (common_config.ENABLE_DEFAULT_USER && common_config.DEFAULT_USER_ID) {
|
||||
headers["X-User-Id"] = headers["X-User-Id"] || common_config.DEFAULT_USER_ID;
|
||||
if (common_config.SHOP_ID)
|
||||
headers["X-Shop-Id"] = headers["X-Shop-Id"] || common_config.SHOP_ID;
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
@@ -71,7 +82,7 @@ function post(path, body = {}) {
|
||||
const headers = buildAuthHeaders({ "Content-Type": "application/json" });
|
||||
const options = { url: buildUrl(path), method: "POST", data: body, header: headers };
|
||||
const p = String(path || "");
|
||||
if (p.includes("/api/auth/wxmp/login") || p.includes("/api/auth/sms/login") || p.includes("/api/auth/sms/send") || p.includes("/api/auth/password/login") || p.includes("/api/auth/register"))
|
||||
if (p.includes("/api/auth/wxmp/login") || p.includes("/api/auth/sms/login") || p.includes("/api/auth/sms/send") || p.includes("/api/auth/email/login") || p.includes("/api/auth/email/send") || p.includes("/api/auth/password/login") || p.includes("/api/auth/register"))
|
||||
options.__noRetry = true;
|
||||
requestWithFallback(options, common_config.API_BASE_URL_CANDIDATES, 0, resolve, reject);
|
||||
});
|
||||
@@ -106,9 +117,22 @@ function uploadWithFallback(options, candidates, idx, resolve, reject) {
|
||||
return resolve(res.data);
|
||||
}
|
||||
}
|
||||
if (statusCode >= 400 && statusCode < 500) {
|
||||
try {
|
||||
const data = typeof res.data === "string" ? JSON.parse(res.data) : res.data;
|
||||
return resolve(data);
|
||||
} catch (e) {
|
||||
return resolve({ success: false, message: "HTTP " + statusCode });
|
||||
}
|
||||
}
|
||||
if (idx + 1 < candidates.length)
|
||||
return uploadWithFallback(options, candidates, idx + 1, resolve, reject);
|
||||
reject(new Error("HTTP " + statusCode));
|
||||
try {
|
||||
const data = typeof res.data === "string" ? JSON.parse(res.data) : res.data;
|
||||
return resolve(data);
|
||||
} catch (e) {
|
||||
return resolve({ success: false, message: "HTTP " + statusCode });
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
if (idx + 1 < candidates.length)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../common/vendor.js");
|
||||
const common_http = require("../common/http.js");
|
||||
const common_config = require("../common/config.js");
|
||||
const common_assets = require("../common/assets.js");
|
||||
const ITEM_SIZE = 210;
|
||||
const GAP = 18;
|
||||
const COLS = 3;
|
||||
@@ -25,6 +27,14 @@ const _sfc_main = {
|
||||
areaHeight() {
|
||||
const rows = Math.ceil((this.innerList.length + 1) / COLS) || 1;
|
||||
return rows * ITEM_SIZE + (rows - 1) * GAP;
|
||||
},
|
||||
adderStyle() {
|
||||
const index = this.innerList.length;
|
||||
const row = Math.floor(index / COLS);
|
||||
const col = index % COLS;
|
||||
const x = px(col * (ITEM_SIZE + GAP));
|
||||
const y = px(row * (ITEM_SIZE + GAP));
|
||||
return { left: x + "rpx", top: y + "rpx" };
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -33,7 +43,7 @@ const _sfc_main = {
|
||||
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 || "",
|
||||
url: this.ensureAbsoluteUrl(typeof u === "string" ? u : u.url || ""),
|
||||
x: this.posOf(i).x,
|
||||
y: this.posOf(i).y
|
||||
}));
|
||||
@@ -42,6 +52,14 @@ const _sfc_main = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ensureAbsoluteUrl(u) {
|
||||
if (!u)
|
||||
return "";
|
||||
const s = String(u);
|
||||
if (s.startsWith("http://") || s.startsWith("https://"))
|
||||
return s;
|
||||
return common_config.API_BASE_URL + (s.startsWith("/") ? s : "/" + s);
|
||||
},
|
||||
posOf(index) {
|
||||
const row = Math.floor(index / COLS);
|
||||
const col = index % COLS;
|
||||
@@ -75,7 +93,7 @@ const _sfc_main = {
|
||||
var _a;
|
||||
try {
|
||||
const resp = await common_http.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) || "";
|
||||
const url = this.ensureAbsoluteUrl((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) });
|
||||
@@ -131,12 +149,14 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
i: common_vendor.o(($event) => $options.onMoveEnd(index), img.uid)
|
||||
};
|
||||
}),
|
||||
b: $data.innerList.length < $props.max
|
||||
b: common_assets._imports_0$4,
|
||||
c: $data.innerList.length < $props.max
|
||||
}, $data.innerList.length < $props.max ? {
|
||||
c: common_vendor.o((...args) => $options.choose && $options.choose(...args))
|
||||
d: common_vendor.s($options.adderStyle),
|
||||
e: common_vendor.o((...args) => $options.choose && $options.choose(...args))
|
||||
} : {}, {
|
||||
d: $options.areaHeight + "rpx",
|
||||
e: $options.areaHeight + "rpx"
|
||||
f: $options.areaHeight + "rpx",
|
||||
g: $options.areaHeight + "rpx"
|
||||
});
|
||||
}
|
||||
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="uploader"><view class="grid" style="{{'height:' + e}}"><movable-area class="area" style="{{'height:' + d}}"><movable-view wx:for="{{a}}" wx:for-item="img" wx:key="d" class="cell" style="{{img.e}}" direction="{{'all'}}" damping="{{40}}" friction="{{2}}" x="{{img.f}}" y="{{img.g}}" bindchange="{{img.h}}" bindtouchend="{{img.i}}"><image src="{{img.a}}" mode="aspectFill" class="thumb" bindtap="{{img.b}}"/><view class="remove" catchtap="{{img.c}}">×</view></movable-view><view wx:if="{{b}}" class="adder" bindtap="{{c}}"><text>+</text></view></movable-area></view></view>
|
||||
<view class="uploader"><view class="grid" style="{{'height:' + g}}"><movable-area class="area" style="{{'height:' + f}}"><movable-view wx:for="{{a}}" wx:for-item="img" wx:key="d" class="cell" style="{{img.e}}" direction="{{'all'}}" damping="{{40}}" friction="{{2}}" x="{{img.f}}" y="{{img.g}}" bindchange="{{img.h}}" bindtouchend="{{img.i}}"><image src="{{img.a}}" mode="aspectFill" class="thumb" bindtap="{{img.b}}"/><image class="remove" src="{{b}}" mode="aspectFit" catchtap="{{img.c}}"/></movable-view><view wx:if="{{c}}" class="adder" style="{{d}}" bindtap="{{e}}"><text>+</text></view></movable-area></view></view>
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
.thumb { width: 100%; height: 100%;
|
||||
}
|
||||
.remove { position: absolute; right: 6rpx; top: 6rpx; background: rgba(0,0,0,0.45); color: #fff; width: 40rpx; height: 40rpx; text-align: center; line-height: 40rpx; border-radius: 20rpx; font-size: 28rpx;
|
||||
.remove { position: absolute; right: 6rpx; top: 6rpx; width: 42rpx; height: 42rpx;
|
||||
}
|
||||
.adder { width: 210rpx; height: 210rpx; border: 2rpx dashed #ccc; border-radius: 12rpx; display: flex; align-items: center; justify-content: center; color: #999; position: absolute; left: 0; top: 0;
|
||||
}
|
||||
|
||||
@@ -4,92 +4,215 @@ const common_http = require("../../common/http.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return {
|
||||
form: { phone: "", password: "" },
|
||||
phoneFocused: false,
|
||||
passwordFocused: false
|
||||
loading: false,
|
||||
tab: "login",
|
||||
loginForm: { email: "", password: "" },
|
||||
regForm: { name: "", email: "", code: "", password: "", password2: "" },
|
||||
resetForm: { email: "", code: "", password: "", password2: "" },
|
||||
regCountdown: 0,
|
||||
resetCountdown: 0,
|
||||
_timers: []
|
||||
};
|
||||
},
|
||||
beforeUnmount() {
|
||||
this._timers.forEach((t) => clearInterval(t));
|
||||
},
|
||||
methods: {
|
||||
validate() {
|
||||
const p = String(this.form.phone || "").trim();
|
||||
const okPhone = /^1[3-9]\d{9}$/.test(p);
|
||||
if (!okPhone) {
|
||||
common_vendor.index.showToast({ title: "请输入正确的手机号", icon: "none" });
|
||||
return false;
|
||||
toast(msg) {
|
||||
try {
|
||||
common_vendor.index.showToast({ title: String(msg || "操作失败"), icon: "none" });
|
||||
} catch (_) {
|
||||
}
|
||||
return true;
|
||||
},
|
||||
validateEmail(v) {
|
||||
return /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(String(v || "").trim());
|
||||
},
|
||||
startCountdown(key) {
|
||||
if (this[key] > 0)
|
||||
return;
|
||||
this[key] = 60;
|
||||
const timer = setInterval(() => {
|
||||
this[key] = Math.max(0, this[key] - 1);
|
||||
if (this[key] === 0)
|
||||
clearInterval(timer);
|
||||
}, 1e3);
|
||||
this._timers.push(timer);
|
||||
},
|
||||
async onLogin() {
|
||||
if (!this.validate())
|
||||
return;
|
||||
const { email, password } = this.loginForm;
|
||||
if (!this.validateEmail(email))
|
||||
return this.toast("请输入正确邮箱");
|
||||
if (!password || password.length < 6)
|
||||
return this.toast("请输入至少6位密码");
|
||||
this.loading = true;
|
||||
try {
|
||||
const phone = String(this.form.phone || "").trim();
|
||||
const password = String(this.form.password || "");
|
||||
const res = await common_http.post("/api/auth/password/login", { phone, password });
|
||||
if (res && res.token) {
|
||||
common_vendor.index.setStorageSync("TOKEN", res.token);
|
||||
if (res.user && res.user.phone)
|
||||
common_vendor.index.setStorageSync("USER_MOBILE", res.user.phone);
|
||||
common_vendor.index.showToast({ title: "登录成功", icon: "none" });
|
||||
setTimeout(() => {
|
||||
common_vendor.index.reLaunch({ url: "/pages/index/index" });
|
||||
}, 200);
|
||||
}
|
||||
const data = await common_http.post("/api/auth/password/login", { email, password });
|
||||
this.afterLogin(data);
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: e && e.message || "登录失败", icon: "none" });
|
||||
this.toast(e.message);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
onGoRegister() {
|
||||
common_vendor.index.navigateTo({
|
||||
url: "/pages/auth/register"
|
||||
});
|
||||
afterLogin(data) {
|
||||
try {
|
||||
if (data && data.token) {
|
||||
common_vendor.index.setStorageSync("TOKEN", data.token);
|
||||
if (data.user && data.user.shopId)
|
||||
common_vendor.index.setStorageSync("SHOP_ID", data.user.shopId);
|
||||
common_vendor.index.setStorageSync("ENABLE_DEFAULT_USER", "false");
|
||||
common_vendor.index.removeStorageSync("DEFAULT_USER_ID");
|
||||
this.toast("登录成功");
|
||||
setTimeout(() => {
|
||||
common_vendor.index.reLaunch({ url: "/pages/index/index" });
|
||||
}, 300);
|
||||
} else {
|
||||
this.toast("登录失败");
|
||||
}
|
||||
} catch (_) {
|
||||
this.toast("登录失败");
|
||||
}
|
||||
},
|
||||
async sendRegCode() {
|
||||
if (!this.validateEmail(this.regForm.email))
|
||||
return this.toast("请输入正确邮箱");
|
||||
this.loading = true;
|
||||
try {
|
||||
const r = await common_http.post("/api/auth/email/send", { email: this.regForm.email, scene: "register" });
|
||||
if (r && r.ok)
|
||||
this.startCountdown("regCountdown");
|
||||
this.toast(r && r.ok ? "验证码已发送" : "发送过于频繁");
|
||||
} catch (e) {
|
||||
this.toast(e.message);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async onRegister() {
|
||||
const f = this.regForm;
|
||||
if (!f.name || f.name.trim().length < 1)
|
||||
return this.toast("请输入用户名");
|
||||
if (!this.validateEmail(f.email))
|
||||
return this.toast("请输入正确邮箱");
|
||||
if (!f.code)
|
||||
return this.toast("请输入验证码");
|
||||
if (!f.password || f.password.length < 6)
|
||||
return this.toast("密码至少6位");
|
||||
if (f.password !== f.password2)
|
||||
return this.toast("两次密码不一致");
|
||||
this.loading = true;
|
||||
try {
|
||||
const data = await common_http.post("/api/auth/email/register", { name: f.name.trim(), email: f.email.trim(), code: f.code.trim(), password: f.password });
|
||||
this.afterLogin(data);
|
||||
} catch (e) {
|
||||
this.toast(e.message);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async sendResetCode() {
|
||||
if (!this.validateEmail(this.resetForm.email))
|
||||
return this.toast("请输入正确邮箱");
|
||||
this.loading = true;
|
||||
try {
|
||||
const r = await common_http.post("/api/auth/email/send", { email: this.resetForm.email, scene: "reset" });
|
||||
if (r && r.ok)
|
||||
this.startCountdown("resetCountdown");
|
||||
this.toast(r && r.ok ? "验证码已发送" : "发送过于频繁");
|
||||
} catch (e) {
|
||||
this.toast(e.message);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async onReset() {
|
||||
const f = this.resetForm;
|
||||
if (!this.validateEmail(f.email))
|
||||
return this.toast("请输入正确邮箱");
|
||||
if (!f.code)
|
||||
return this.toast("请输入验证码");
|
||||
if (!f.password || f.password.length < 6)
|
||||
return this.toast("新密码至少6位");
|
||||
if (f.password !== f.password2)
|
||||
return this.toast("两次密码不一致");
|
||||
this.loading = true;
|
||||
try {
|
||||
const r = await common_http.post("/api/auth/email/reset-password", { email: f.email.trim(), code: f.code.trim(), newPassword: f.password, confirmPassword: f.password2 });
|
||||
if (r && r.ok) {
|
||||
this.toast("已重置,请使用新密码登录");
|
||||
this.tab = "login";
|
||||
this.loginForm.email = f.email;
|
||||
} else
|
||||
this.toast("重置失败");
|
||||
} catch (e) {
|
||||
this.toast(e.message);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!Array) {
|
||||
const _component_path = common_vendor.resolveComponent("path");
|
||||
const _component_svg = common_vendor.resolveComponent("svg");
|
||||
(_component_path + _component_svg)();
|
||||
}
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return {
|
||||
a: common_vendor.p({
|
||||
d: "M12 2C13.1 2 14 2.9 14 4C14 5.1 13.1 6 12 6C10.9 6 10 5.1 10 4C10 2.9 10.9 2 12 2ZM21 9V7L15 4V6C15 7.66 13.66 9 12 9S9 7.66 9 6V4L3 7V9C3 10.1 3.9 11 5 11V17C5 18.1 5.9 19 7 19H9C9 20.1 9.9 21 11 21H13C14.1 21 15 20.1 15 19H17C18.1 19 19 18.1 19 17V11C20.1 11 21 10.1 21 9Z"
|
||||
}),
|
||||
b: common_vendor.p({
|
||||
viewBox: "0 0 24 24"
|
||||
}),
|
||||
c: common_vendor.p({
|
||||
d: "M6.62,10.79C8.06,13.62 10.38,15.94 13.21,17.38L15.41,15.18C15.69,14.9 16.08,14.82 16.43,14.93C17.55,15.3 18.75,15.5 20,15.5A1,1 0 0,1 21,16.5V20A1,1 0 0,1 20,21A17,17 0 0,1 3,4A1,1 0 0,1 4,3H7.5A1,1 0 0,1 8.5,4C8.5,5.25 8.7,6.45 9.07,7.57C9.18,7.92 9.1,8.31 8.82,8.59L6.62,10.79Z"
|
||||
}),
|
||||
d: common_vendor.p({
|
||||
viewBox: "0 0 24 24"
|
||||
}),
|
||||
e: common_vendor.o(($event) => $data.phoneFocused = true),
|
||||
f: common_vendor.o(($event) => $data.phoneFocused = false),
|
||||
g: $data.form.phone,
|
||||
h: common_vendor.o(common_vendor.m(($event) => $data.form.phone = $event.detail.value, {
|
||||
return common_vendor.e({
|
||||
a: common_vendor.n($data.tab === "login" ? "active" : ""),
|
||||
b: common_vendor.o(($event) => $data.tab = "login"),
|
||||
c: common_vendor.n($data.tab === "register" ? "active" : ""),
|
||||
d: common_vendor.o(($event) => $data.tab = "register"),
|
||||
e: common_vendor.n($data.tab === "reset" ? "active" : ""),
|
||||
f: common_vendor.o(($event) => $data.tab = "reset"),
|
||||
g: $data.tab === "login"
|
||||
}, $data.tab === "login" ? {
|
||||
h: $data.loginForm.email,
|
||||
i: common_vendor.o(common_vendor.m(($event) => $data.loginForm.email = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
i: $data.phoneFocused ? 1 : "",
|
||||
j: $data.form.phone ? 1 : "",
|
||||
k: common_vendor.p({
|
||||
d: "M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z"
|
||||
}),
|
||||
l: common_vendor.p({
|
||||
viewBox: "0 0 24 24"
|
||||
}),
|
||||
m: common_vendor.o(($event) => $data.passwordFocused = true),
|
||||
n: common_vendor.o(($event) => $data.passwordFocused = false),
|
||||
o: $data.form.password,
|
||||
p: common_vendor.o(common_vendor.m(($event) => $data.form.password = $event.detail.value, {
|
||||
j: $data.loginForm.password,
|
||||
k: common_vendor.o(($event) => $data.loginForm.password = $event.detail.value),
|
||||
l: $data.loading,
|
||||
m: common_vendor.o((...args) => $options.onLogin && $options.onLogin(...args))
|
||||
} : $data.tab === "register" ? {
|
||||
o: $data.regForm.name,
|
||||
p: common_vendor.o(common_vendor.m(($event) => $data.regForm.name = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
q: $data.passwordFocused ? 1 : "",
|
||||
r: $data.form.password ? 1 : "",
|
||||
s: common_vendor.o((...args) => $options.onLogin && $options.onLogin(...args)),
|
||||
t: common_vendor.o((...args) => $options.onGoRegister && $options.onGoRegister(...args))
|
||||
};
|
||||
q: $data.regForm.email,
|
||||
r: common_vendor.o(common_vendor.m(($event) => $data.regForm.email = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
s: $data.regForm.code,
|
||||
t: common_vendor.o(common_vendor.m(($event) => $data.regForm.code = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
v: common_vendor.t($data.regCountdown > 0 ? $data.regCountdown + "s" : "获取验证码"),
|
||||
w: $data.regCountdown > 0 || $data.loading,
|
||||
x: common_vendor.o((...args) => $options.sendRegCode && $options.sendRegCode(...args)),
|
||||
y: $data.regForm.password,
|
||||
z: common_vendor.o(($event) => $data.regForm.password = $event.detail.value),
|
||||
A: $data.regForm.password2,
|
||||
B: common_vendor.o(($event) => $data.regForm.password2 = $event.detail.value),
|
||||
C: $data.loading,
|
||||
D: common_vendor.o((...args) => $options.onRegister && $options.onRegister(...args))
|
||||
} : {
|
||||
E: $data.resetForm.email,
|
||||
F: common_vendor.o(common_vendor.m(($event) => $data.resetForm.email = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
G: $data.resetForm.code,
|
||||
H: common_vendor.o(common_vendor.m(($event) => $data.resetForm.code = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
I: common_vendor.t($data.resetCountdown > 0 ? $data.resetCountdown + "s" : "获取验证码"),
|
||||
J: $data.resetCountdown > 0 || $data.loading,
|
||||
K: common_vendor.o((...args) => $options.sendResetCode && $options.sendResetCode(...args)),
|
||||
L: $data.resetForm.password,
|
||||
M: common_vendor.o(($event) => $data.resetForm.password = $event.detail.value),
|
||||
N: $data.resetForm.password2,
|
||||
O: common_vendor.o(($event) => $data.resetForm.password2 = $event.detail.value),
|
||||
P: $data.loading,
|
||||
Q: common_vendor.o((...args) => $options.onReset && $options.onReset(...args))
|
||||
}, {
|
||||
n: $data.tab === "register"
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="login-container"><view class="background-decoration"><view class="circle circle-1"></view><view class="circle circle-2"></view><view class="circle circle-3"></view></view><view class="login-card"><view class="header-section"><view class="logo-container"><view class="logo-icon"><svg wx:if="{{b}}" u-s="{{['d']}}" class="icon" u-i="5ce84e30-0" bind:__l="__l" u-p="{{b}}"><path wx:if="{{a}}" u-i="5ce84e30-1,5ce84e30-0" bind:__l="__l" u-p="{{a}}"/></svg></view><text class="app-name">配件询价</text></view><text class="welcome-text">欢迎回来</text><text class="subtitle">请登录您的账户</text></view><view class="form-section"><view class="input-group"><view class="{{['input-container', i && 'focused', j && 'filled']}}"><view class="input-icon"><svg wx:if="{{d}}" u-s="{{['d']}}" class="icon" u-i="5ce84e30-2" bind:__l="__l" u-p="{{d}}"><path wx:if="{{c}}" u-i="5ce84e30-3,5ce84e30-2" bind:__l="__l" u-p="{{c}}"/></svg></view><input class="input-field" type="number" placeholder="请输入手机号" maxlength="11" bindfocus="{{e}}" bindblur="{{f}}" value="{{g}}" bindinput="{{h}}"/></view></view><view class="input-group"><view class="{{['input-container', q && 'focused', r && 'filled']}}"><view class="input-icon"><svg wx:if="{{l}}" u-s="{{['d']}}" class="icon" u-i="5ce84e30-4" bind:__l="__l" u-p="{{l}}"><path wx:if="{{k}}" u-i="5ce84e30-5,5ce84e30-4" bind:__l="__l" u-p="{{k}}"/></svg></view><input class="input-field" password placeholder="请输入密码" bindfocus="{{m}}" bindblur="{{n}}" value="{{o}}" bindinput="{{p}}"/></view></view></view><view class="actions-section"><button class="login-button" bindtap="{{s}}"><text class="button-text">登录</text></button><button class="register-button" bindtap="{{t}}"><text class="button-text">注册新账户</text></button></view><view class="footer-section"></view></view></view>
|
||||
<view class="auth-page"><view class="tabs"><view class="{{['tab', a]}}" bindtap="{{b}}">登录</view><view class="{{['tab', c]}}" bindtap="{{d}}">注册</view><view class="{{['tab', e]}}" bindtap="{{f}}">忘记密码</view></view><view wx:if="{{g}}" class="panel"><input class="input" type="text" placeholder="输入邮箱" value="{{h}}" bindinput="{{i}}"/><input class="input" type="password" placeholder="输入密码" value="{{j}}" bindinput="{{k}}"/><button class="btn primary" disabled="{{l}}" bindtap="{{m}}">登录</button></view><view wx:elif="{{n}}" class="panel"><input class="input" type="text" placeholder="输入用户名" value="{{o}}" bindinput="{{p}}"/><input class="input" type="text" placeholder="输入邮箱" value="{{q}}" bindinput="{{r}}"/><view class="row"><input class="input flex1" type="text" placeholder="邮箱验证码" value="{{s}}" bindinput="{{t}}"/><button class="btn ghost" disabled="{{w}}" bindtap="{{x}}">{{v}}</button></view><input class="input" type="password" placeholder="输入密码(≥6位)" value="{{y}}" bindinput="{{z}}"/><input class="input" type="password" placeholder="再次输入密码" value="{{A}}" bindinput="{{B}}"/><button class="btn primary" disabled="{{C}}" bindtap="{{D}}">注册新用户</button></view><view wx:else class="panel"><input class="input" type="text" placeholder="输入邮箱" value="{{E}}" bindinput="{{F}}"/><view class="row"><input class="input flex1" type="text" placeholder="邮箱验证码" value="{{G}}" bindinput="{{H}}"/><button class="btn ghost" disabled="{{J}}" bindtap="{{K}}">{{I}}</button></view><input class="input" type="password" placeholder="新密码(≥6位)" value="{{L}}" bindinput="{{M}}"/><input class="input" type="password" placeholder="再次输入新密码" value="{{N}}" bindinput="{{O}}"/><button class="btn primary" disabled="{{P}}" bindtap="{{Q}}">重置密码</button></view></view>
|
||||
@@ -24,257 +24,62 @@
|
||||
/* 垂直间距 */
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
.login-container {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
.auth-page {
|
||||
padding: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 40rpx 20rpx;
|
||||
overflow: hidden;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.background-decoration {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
.background-decoration .circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.background-decoration .circle.circle-1 {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
.background-decoration .circle.circle-2 {
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
top: 60%;
|
||||
right: 15%;
|
||||
animation: float 8s ease-in-out infinite reverse;
|
||||
}
|
||||
.background-decoration .circle.circle-3 {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
bottom: 20%;
|
||||
left: 20%;
|
||||
animation: float 5s ease-in-out infinite;
|
||||
}
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
.login-card {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 90%;
|
||||
max-width: 680rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
-webkit-backdrop-filter: blur(20rpx);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 32rpx;
|
||||
padding: 60rpx 40rpx 50rpx;
|
||||
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.1);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
.header-section {
|
||||
text-align: center;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
.header-section .logo-container {
|
||||
.tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.tab {
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f2f4f8;
|
||||
color: #5b6b80;
|
||||
font-weight: 700;
|
||||
}
|
||||
.tab.active {
|
||||
background: #2d6be6;
|
||||
color: #fff;
|
||||
}
|
||||
.panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.header-section .logo-container .logo-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
background: #fff;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx solid #eef2f9;
|
||||
}
|
||||
.header-section .logo-container .logo-icon .icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
fill: white;
|
||||
}
|
||||
.header-section .logo-container .app-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
.header-section .welcome-text {
|
||||
display: block;
|
||||
font-size: 48rpx;
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
margin-bottom: 8rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
.header-section .subtitle {
|
||||
display: block;
|
||||
.input {
|
||||
background: #f7f9ff;
|
||||
border: 2rpx solid rgba(45, 107, 230, 0.12);
|
||||
border-radius: 12rpx;
|
||||
padding: 22rpx 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #718096;
|
||||
font-weight: 400;
|
||||
}
|
||||
.form-section {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
.form-section .input-group {
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
.form-section .input-group .input-container {
|
||||
position: relative;
|
||||
background: #f7fafc;
|
||||
border: 2rpx solid #e2e8f0;
|
||||
border-radius: 16rpx;
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
align-items: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.form-section .input-group .input-container.focused {
|
||||
border-color: #667eea;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 0 0 6rpx rgba(102, 126, 234, 0.1);
|
||||
transform: translateY(-2rpx);
|
||||
}
|
||||
.form-section .input-group .input-container.filled {
|
||||
background: #ffffff;
|
||||
border-color: #cbd5e0;
|
||||
}
|
||||
.form-section .input-group .input-container .input-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50rpx;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
.form-section .input-group .input-container .input-icon .icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
fill: #a0aec0;
|
||||
transition: fill 0.3s ease;
|
||||
}
|
||||
.form-section .input-group .input-container.focused .input-icon .icon {
|
||||
fill: #667eea;
|
||||
}
|
||||
.form-section .input-group .input-container .input-field {
|
||||
.flex1 {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 24rpx 20rpx 24rpx 12rpx;
|
||||
font-size: 32rpx;
|
||||
color: #2d3748;
|
||||
}
|
||||
.form-section .input-group .input-container .input-field::-webkit-input-placeholder {
|
||||
color: #a0aec0;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.form-section .input-group .input-container .input-field::placeholder {
|
||||
color: #a0aec0;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.actions-section {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.actions-section .login-button {
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.actions-section .login-button:active {
|
||||
transform: translateY(2rpx);
|
||||
box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
.actions-section .login-button::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, transparent 50%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.actions-section .login-button:active::before {
|
||||
opacity: 1;
|
||||
}
|
||||
.actions-section .login-button .button-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
.actions-section .register-button {
|
||||
width: 100%;
|
||||
height: 86rpx;
|
||||
background: transparent;
|
||||
border: 2rpx solid #e2e8f0;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.actions-section .register-button:active {
|
||||
background: #f7fafc;
|
||||
border-color: #cbd5e0;
|
||||
transform: translateY(1rpx);
|
||||
}
|
||||
.actions-section .register-button .button-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #718096;
|
||||
}
|
||||
.footer-section {
|
||||
.btn {
|
||||
padding: 22rpx 20rpx;
|
||||
border-radius: 12rpx;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
}
|
||||
.footer-section .hint-text {
|
||||
font-size: 24rpx;
|
||||
color: #a0aec0;
|
||||
line-height: 1.5;
|
||||
background: rgba(160, 174, 192, 0.1);
|
||||
padding: 16rpx 20rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 1rpx solid rgba(160, 174, 192, 0.2);
|
||||
}
|
||||
@media (max-width: 750rpx) {
|
||||
.login-card {
|
||||
margin: 20rpx;
|
||||
padding: 50rpx 30rpx 40rpx;
|
||||
}
|
||||
.header-section .welcome-text {
|
||||
font-size: 42rpx;
|
||||
.btn.primary {
|
||||
background: linear-gradient(135deg, #4788ff 0%, #2d6be6 100%);
|
||||
color: #fff;
|
||||
}
|
||||
.btn.ghost {
|
||||
background: #eef3ff;
|
||||
color: #2d6be6;
|
||||
}
|
||||
@@ -7,55 +7,97 @@ const _sfc_main = {
|
||||
form: {
|
||||
shopName: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
password: "",
|
||||
confirmPassword: ""
|
||||
email: "",
|
||||
code: "",
|
||||
password: ""
|
||||
},
|
||||
shopNameFocused: false,
|
||||
nameFocused: false,
|
||||
phoneFocused: false,
|
||||
passwordFocused: false,
|
||||
confirmPasswordFocused: false
|
||||
emailFocused: false,
|
||||
codeFocused: false,
|
||||
pwdFocused: false,
|
||||
countdown: 0,
|
||||
timer: null,
|
||||
sending: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
btnText() {
|
||||
if (this.countdown > 0)
|
||||
return `${this.countdown}s`;
|
||||
if (this.sending)
|
||||
return "发送中...";
|
||||
return "获取验证码";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validate() {
|
||||
const phone = String(this.form.phone || "").trim();
|
||||
const ok = /^1[3-9]\d{9}$/.test(phone);
|
||||
const email = String(this.form.email || "").trim();
|
||||
const ok = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(email);
|
||||
if (!ok) {
|
||||
common_vendor.index.showToast({ title: "请输入正确的手机号", icon: "none" });
|
||||
common_vendor.index.showToast({ title: "请输入正确的邮箱地址", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
if (!this.form.password) {
|
||||
common_vendor.index.showToast({ title: "请输入密码", icon: "none" });
|
||||
if (!/^\d{6}$/.test(String(this.form.code || "").trim())) {
|
||||
common_vendor.index.showToast({ title: "验证码格式不正确", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
if (this.form.password.length < 6) {
|
||||
if (String(this.form.password || "").length < 6) {
|
||||
common_vendor.index.showToast({ title: "密码至少6位", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
if (!this.form.confirmPassword) {
|
||||
common_vendor.index.showToast({ title: "请确认密码", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
if (this.form.password !== this.form.confirmPassword) {
|
||||
common_vendor.index.showToast({ title: "两次密码不一致", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
startCountdown(sec) {
|
||||
this.countdown = sec;
|
||||
if (this.timer)
|
||||
clearInterval(this.timer);
|
||||
this.timer = setInterval(() => {
|
||||
if (this.countdown <= 1) {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
this.countdown = 0;
|
||||
return;
|
||||
}
|
||||
this.countdown--;
|
||||
}, 1e3);
|
||||
},
|
||||
async sendCode() {
|
||||
if (this.sending || this.countdown > 0)
|
||||
return;
|
||||
const e = String(this.form.email || "").trim();
|
||||
const ok = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(e);
|
||||
if (!ok)
|
||||
return common_vendor.index.showToast({ title: "请输入正确的邮箱地址", icon: "none" });
|
||||
this.sending = true;
|
||||
try {
|
||||
const res = await common_http.post("/api/auth/email/send", { email: e, scene: "login" });
|
||||
const cd = Number(res && res.cooldownSec || 60);
|
||||
this.startCountdown(cd);
|
||||
common_vendor.index.showToast({ title: "验证码已发送", icon: "none" });
|
||||
} catch (e2) {
|
||||
const msg = e2 && e2.message || "发送失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.sending = false;
|
||||
}
|
||||
},
|
||||
async onRegister() {
|
||||
if (!this.validate())
|
||||
return;
|
||||
const phone = String(this.form.phone || "").trim();
|
||||
const email = String(this.form.email || "").trim();
|
||||
const name = String(this.form.name || "").trim();
|
||||
const password = String(this.form.password || "");
|
||||
try {
|
||||
const data = await common_http.post("/api/auth/register", { phone, name: name || void 0, password });
|
||||
const data = await common_http.post("/api/auth/email/register", { email, code: String(this.form.code || "").trim(), name, password: String(this.form.password || "") });
|
||||
if (data && data.token) {
|
||||
common_vendor.index.setStorageSync("TOKEN", data.token);
|
||||
if (data.user && data.user.phone)
|
||||
common_vendor.index.setStorageSync("USER_MOBILE", data.user.phone);
|
||||
if (data.user && data.user.email)
|
||||
common_vendor.index.setStorageSync("USER_EMAIL", data.user.email);
|
||||
if (name)
|
||||
try {
|
||||
common_vendor.index.setStorageSync("USER_NAME", name);
|
||||
} catch (_) {
|
||||
}
|
||||
common_vendor.index.showToast({ title: "注册成功", icon: "none" });
|
||||
setTimeout(() => {
|
||||
common_vendor.index.reLaunch({ url: "/pages/index/index" });
|
||||
@@ -115,49 +157,52 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
q: $data.nameFocused ? 1 : "",
|
||||
r: $data.form.name ? 1 : "",
|
||||
s: common_vendor.p({
|
||||
d: "M6.62,10.79C8.06,13.62 10.38,15.94 13.21,17.38L15.41,15.18C15.69,14.9 16.08,14.82 16.43,14.93C17.55,15.3 18.75,15.5 20,15.5A1,1 0 0,1 21,16.5V20A1,1 0 0,1 20,21A17,17 0 0,1 3,4A1,1 0 0,1 4,3H7.5A1,1 0 0,1 8.5,4C8.5,5.25 8.7,6.45 9.07,7.57C9.18,7.92 9.1,8.31 8.82,8.59L6.62,10.79Z"
|
||||
d: "M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-1 4l-7 4-7-4V6l7 4 7-4v2z"
|
||||
}),
|
||||
t: common_vendor.p({
|
||||
viewBox: "0 0 24 24"
|
||||
}),
|
||||
v: common_vendor.o(($event) => $data.phoneFocused = true),
|
||||
w: common_vendor.o(($event) => $data.phoneFocused = false),
|
||||
x: $data.form.phone,
|
||||
y: common_vendor.o(common_vendor.m(($event) => $data.form.phone = $event.detail.value, {
|
||||
v: common_vendor.o(($event) => $data.emailFocused = true),
|
||||
w: common_vendor.o(($event) => $data.emailFocused = false),
|
||||
x: $data.form.email,
|
||||
y: common_vendor.o(common_vendor.m(($event) => $data.form.email = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
z: $data.phoneFocused ? 1 : "",
|
||||
A: $data.form.phone ? 1 : "",
|
||||
z: $data.emailFocused ? 1 : "",
|
||||
A: $data.form.email ? 1 : "",
|
||||
B: common_vendor.p({
|
||||
d: "M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z"
|
||||
d: "M3 10h18v2H3v-2zm0 6h12v2H3v-2zM3 6h18v2H3V6z"
|
||||
}),
|
||||
C: common_vendor.p({
|
||||
viewBox: "0 0 24 24"
|
||||
}),
|
||||
D: common_vendor.o(($event) => $data.passwordFocused = true),
|
||||
E: common_vendor.o(($event) => $data.passwordFocused = false),
|
||||
F: $data.form.password,
|
||||
G: common_vendor.o(common_vendor.m(($event) => $data.form.password = $event.detail.value, {
|
||||
D: common_vendor.o(($event) => $data.codeFocused = true),
|
||||
E: common_vendor.o(($event) => $data.codeFocused = false),
|
||||
F: $data.form.code,
|
||||
G: common_vendor.o(common_vendor.m(($event) => $data.form.code = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
H: $data.passwordFocused ? 1 : "",
|
||||
I: $data.form.password ? 1 : "",
|
||||
H: $data.codeFocused ? 1 : "",
|
||||
I: $data.form.code ? 1 : "",
|
||||
J: common_vendor.p({
|
||||
d: "M12,17A2,2 0 0,0 14,15C14,13.89 13.1,13 12,13A2,2 0 0,0 10,15A2,2 0 0,0 12,17M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V10C4,8.89 4.9,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z"
|
||||
}),
|
||||
K: common_vendor.p({
|
||||
viewBox: "0 0 24 24"
|
||||
}),
|
||||
L: common_vendor.o(($event) => $data.confirmPasswordFocused = true),
|
||||
M: common_vendor.o(($event) => $data.confirmPasswordFocused = false),
|
||||
N: $data.form.confirmPassword,
|
||||
O: common_vendor.o(common_vendor.m(($event) => $data.form.confirmPassword = $event.detail.value, {
|
||||
L: common_vendor.o(($event) => $data.pwdFocused = true),
|
||||
M: common_vendor.o(($event) => $data.pwdFocused = false),
|
||||
N: $data.form.password,
|
||||
O: common_vendor.o(common_vendor.m(($event) => $data.form.password = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
P: $data.confirmPasswordFocused ? 1 : "",
|
||||
Q: $data.form.confirmPassword ? 1 : "",
|
||||
R: common_vendor.o((...args) => $options.onRegister && $options.onRegister(...args)),
|
||||
S: common_vendor.o((...args) => $options.onGoLogin && $options.onGoLogin(...args))
|
||||
P: $data.pwdFocused ? 1 : "",
|
||||
Q: $data.form.password ? 1 : "",
|
||||
R: common_vendor.t($options.btnText),
|
||||
S: $data.countdown > 0 || $data.sending,
|
||||
T: common_vendor.o((...args) => $options.sendCode && $options.sendCode(...args)),
|
||||
U: common_vendor.o((...args) => $options.onRegister && $options.onRegister(...args)),
|
||||
V: common_vendor.o((...args) => $options.onGoLogin && $options.onGoLogin(...args))
|
||||
};
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="register-container"><view class="background-decoration"><view class="circle circle-1"></view><view class="circle circle-2"></view><view class="circle circle-3"></view></view><view class="register-card"><view class="header-section"><view class="logo-container"><view class="logo-icon"><svg wx:if="{{b}}" u-s="{{['d']}}" class="icon" u-i="41009218-0" bind:__l="__l" u-p="{{b}}"><path wx:if="{{a}}" u-i="41009218-1,41009218-0" bind:__l="__l" u-p="{{a}}"/></svg></view><text class="app-name">配件询价</text></view><text class="welcome-text">创建账户</text><text class="subtitle">请填写以下信息完成注册</text></view><view class="form-section"><view class="input-group"><view class="{{['input-container', i && 'focused', j && 'filled']}}"><view class="input-icon"><svg wx:if="{{d}}" u-s="{{['d']}}" class="icon" u-i="41009218-2" bind:__l="__l" u-p="{{d}}"><path wx:if="{{c}}" u-i="41009218-3,41009218-2" bind:__l="__l" u-p="{{c}}"/></svg></view><input class="input-field" type="text" placeholder="请输入店铺名称" bindfocus="{{e}}" bindblur="{{f}}" value="{{g}}" bindinput="{{h}}"/></view></view><view class="input-group"><view class="{{['input-container', q && 'focused', r && 'filled']}}"><view class="input-icon"><svg wx:if="{{l}}" u-s="{{['d']}}" class="icon" u-i="41009218-4" bind:__l="__l" u-p="{{l}}"><path wx:if="{{k}}" u-i="41009218-5,41009218-4" bind:__l="__l" u-p="{{k}}"/></svg></view><input class="input-field" type="text" placeholder="请输入您的姓名" bindfocus="{{m}}" bindblur="{{n}}" value="{{o}}" bindinput="{{p}}"/></view></view><view class="input-group"><view class="{{['input-container', z && 'focused', A && 'filled']}}"><view class="input-icon"><svg wx:if="{{t}}" u-s="{{['d']}}" class="icon" u-i="41009218-6" bind:__l="__l" u-p="{{t}}"><path wx:if="{{s}}" u-i="41009218-7,41009218-6" bind:__l="__l" u-p="{{s}}"/></svg></view><input class="input-field" type="number" placeholder="请输入手机号" maxlength="11" bindfocus="{{v}}" bindblur="{{w}}" value="{{x}}" bindinput="{{y}}"/></view></view><view class="input-group"><view class="{{['input-container', H && 'focused', I && 'filled']}}"><view class="input-icon"><svg wx:if="{{C}}" u-s="{{['d']}}" class="icon" u-i="41009218-8" bind:__l="__l" u-p="{{C}}"><path wx:if="{{B}}" u-i="41009218-9,41009218-8" bind:__l="__l" u-p="{{B}}"/></svg></view><input class="input-field" password placeholder="请输入密码(至少6位)" bindfocus="{{D}}" bindblur="{{E}}" value="{{F}}" bindinput="{{G}}"/></view></view><view class="input-group"><view class="{{['input-container', P && 'focused', Q && 'filled']}}"><view class="input-icon"><svg wx:if="{{K}}" u-s="{{['d']}}" class="icon" u-i="41009218-10" bind:__l="__l" u-p="{{K}}"><path wx:if="{{J}}" u-i="41009218-11,41009218-10" bind:__l="__l" u-p="{{J}}"/></svg></view><input class="input-field" password placeholder="请再次输入密码" bindfocus="{{L}}" bindblur="{{M}}" value="{{N}}" bindinput="{{O}}"/></view></view></view><view class="actions-section"><button class="register-button" bindtap="{{R}}"><text class="button-text">立即注册</text></button><button class="login-button" bindtap="{{S}}"><text class="button-text">已有账户?去登录</text></button></view><view class="footer-section"><text class="hint-text">注册即表示您同意我们的服务条款和隐私政策</text></view></view></view>
|
||||
<view class="register-container"><view class="background-decoration"><view class="circle circle-1"></view><view class="circle circle-2"></view><view class="circle circle-3"></view></view><view class="register-card"><view class="header-section"><view class="logo-container"><view class="logo-icon"><svg wx:if="{{b}}" u-s="{{['d']}}" class="icon" u-i="41009218-0" bind:__l="__l" u-p="{{b}}"><path wx:if="{{a}}" u-i="41009218-1,41009218-0" bind:__l="__l" u-p="{{a}}"/></svg></view><text class="app-name">配件询价</text></view><text class="welcome-text">创建账户</text><text class="subtitle">请填写以下信息完成注册</text></view><view class="form-section"><view class="input-group"><view class="{{['input-container', i && 'focused', j && 'filled']}}"><view class="input-icon"><svg wx:if="{{d}}" u-s="{{['d']}}" class="icon" u-i="41009218-2" bind:__l="__l" u-p="{{d}}"><path wx:if="{{c}}" u-i="41009218-3,41009218-2" bind:__l="__l" u-p="{{c}}"/></svg></view><input class="input-field" type="text" placeholder="请输入店铺名称" bindfocus="{{e}}" bindblur="{{f}}" value="{{g}}" bindinput="{{h}}"/></view></view><view class="input-group"><view class="{{['input-container', q && 'focused', r && 'filled']}}"><view class="input-icon"><svg wx:if="{{l}}" u-s="{{['d']}}" class="icon" u-i="41009218-4" bind:__l="__l" u-p="{{l}}"><path wx:if="{{k}}" u-i="41009218-5,41009218-4" bind:__l="__l" u-p="{{k}}"/></svg></view><input class="input-field" type="text" placeholder="请输入您的姓名" bindfocus="{{m}}" bindblur="{{n}}" value="{{o}}" bindinput="{{p}}"/></view></view><view class="input-group"><view class="{{['input-container', z && 'focused', A && 'filled']}}"><view class="input-icon"><svg wx:if="{{t}}" u-s="{{['d']}}" class="icon" u-i="41009218-6" bind:__l="__l" u-p="{{t}}"><path wx:if="{{s}}" u-i="41009218-7,41009218-6" bind:__l="__l" u-p="{{s}}"/></svg></view><input class="input-field" type="text" placeholder="请输入邮箱地址" bindfocus="{{v}}" bindblur="{{w}}" value="{{x}}" bindinput="{{y}}"/></view></view><view class="input-group"><view class="{{['input-container', H && 'focused', I && 'filled']}}"><view class="input-icon"><svg wx:if="{{C}}" u-s="{{['d']}}" class="icon" u-i="41009218-8" bind:__l="__l" u-p="{{C}}"><path wx:if="{{B}}" u-i="41009218-9,41009218-8" bind:__l="__l" u-p="{{B}}"/></svg></view><input class="input-field" type="number" maxlength="6" placeholder="请输入6位验证码" bindfocus="{{D}}" bindblur="{{E}}" value="{{F}}" bindinput="{{G}}"/></view></view><view class="input-group"><view class="{{['input-container', P && 'focused', Q && 'filled']}}"><view class="input-icon"><svg wx:if="{{K}}" u-s="{{['d']}}" class="icon" u-i="41009218-10" bind:__l="__l" u-p="{{K}}"><path wx:if="{{J}}" u-i="41009218-11,41009218-10" bind:__l="__l" u-p="{{J}}"/></svg></view><input class="input-field" password placeholder="请设置登录密码(至少6位)" bindfocus="{{L}}" bindblur="{{M}}" value="{{N}}" bindinput="{{O}}"/></view></view><view class="input-group"><button class="login-button" disabled="{{S}}" bindtap="{{T}}">{{R}}</button></view></view><view class="actions-section"><button class="register-button" bindtap="{{U}}"><text class="button-text">立即注册</text></button><button class="login-button" bindtap="{{V}}"><text class="button-text">已有账户?去登录</text></button></view><view class="footer-section"><text class="hint-text">注册即表示您同意我们的服务条款和隐私政策</text></view></view></view>
|
||||
@@ -3,7 +3,7 @@ const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return { id: null, d: {}, editing: false, form: { name: "", contactName: "", mobile: "", phone: "", address: "", level: "", priceLevel: "零售价", arOpening: 0, remark: "" }, priceLevels: ["零售价", "批发价", "大单报价"], priceLabels: ["零售价", "批发价", "大单报价"], priceIdx: 0 };
|
||||
return { id: null, d: {}, editing: false, form: { name: "", contactName: "", mobile: "", phone: "", address: "", priceLevel: "零售价", arOpening: 0, remark: "" }, priceLevels: ["零售价", "批发价", "大单报价"], priceLabels: ["零售价", "批发价", "大单报价"], priceIdx: 0 };
|
||||
},
|
||||
onLoad(q) {
|
||||
if (q && q.id) {
|
||||
@@ -21,7 +21,6 @@ const _sfc_main = {
|
||||
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 || ""
|
||||
@@ -111,44 +110,37 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
}, {
|
||||
v: !$data.editing
|
||||
}, !$data.editing ? {
|
||||
w: common_vendor.t($data.d.level || "—")
|
||||
w: common_vendor.t($data.d.priceLevel)
|
||||
} : {
|
||||
x: $data.form.level,
|
||||
y: common_vendor.o(($event) => $data.form.level = $event.detail.value)
|
||||
x: common_vendor.t($data.priceLabels[$data.priceIdx]),
|
||||
y: $data.priceLabels,
|
||||
z: $data.priceIdx,
|
||||
A: common_vendor.o((...args) => $options.onPriceChange && $options.onPriceChange(...args))
|
||||
}, {
|
||||
z: !$data.editing
|
||||
B: !$data.editing
|
||||
}, !$data.editing ? {
|
||||
A: common_vendor.t($data.d.priceLevel)
|
||||
C: common_vendor.t(Number($data.d.arOpening || 0).toFixed(2))
|
||||
} : {
|
||||
B: common_vendor.t($data.priceLabels[$data.priceIdx]),
|
||||
C: $data.priceLabels,
|
||||
D: $data.priceIdx,
|
||||
E: common_vendor.o((...args) => $options.onPriceChange && $options.onPriceChange(...args))
|
||||
}, {
|
||||
F: !$data.editing
|
||||
}, !$data.editing ? {
|
||||
G: common_vendor.t(Number($data.d.arOpening || 0).toFixed(2))
|
||||
} : {
|
||||
H: $data.form.arOpening,
|
||||
I: common_vendor.o(common_vendor.m(($event) => $data.form.arOpening = $event.detail.value, {
|
||||
D: $data.form.arOpening,
|
||||
E: common_vendor.o(common_vendor.m(($event) => $data.form.arOpening = $event.detail.value, {
|
||||
number: true
|
||||
}))
|
||||
}, {
|
||||
J: common_vendor.t(Number($data.d.receivable || 0).toFixed(2)),
|
||||
K: !$data.editing
|
||||
F: common_vendor.t(Number($data.d.receivable || 0).toFixed(2)),
|
||||
G: !$data.editing
|
||||
}, !$data.editing ? {
|
||||
L: common_vendor.t($data.d.remark || "—")
|
||||
H: common_vendor.t($data.d.remark || "—")
|
||||
} : {
|
||||
M: $data.form.remark,
|
||||
N: common_vendor.o(($event) => $data.form.remark = $event.detail.value)
|
||||
I: $data.form.remark,
|
||||
J: common_vendor.o(($event) => $data.form.remark = $event.detail.value)
|
||||
}, {
|
||||
O: common_vendor.t($data.editing ? "取消" : "编辑"),
|
||||
P: common_vendor.o((...args) => $options.toggleEdit && $options.toggleEdit(...args)),
|
||||
Q: $data.editing
|
||||
K: common_vendor.t($data.editing ? "取消" : "编辑"),
|
||||
L: common_vendor.o((...args) => $options.toggleEdit && $options.toggleEdit(...args)),
|
||||
M: $data.editing
|
||||
}, $data.editing ? {
|
||||
R: common_vendor.o((...args) => $options.save && $options.save(...args))
|
||||
N: common_vendor.o((...args) => $options.save && $options.save(...args))
|
||||
} : {
|
||||
S: common_vendor.o((...args) => $options.choose && $options.choose(...args))
|
||||
O: common_vendor.o((...args) => $options.choose && $options.choose(...args))
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="page"><view class="card"><view class="row"><text class="label">名称</text><text wx:if="{{a}}" class="value">{{b}}</text><input wx:else class="value-input" placeholder="必填" value="{{c}}" bindinput="{{d}}"/></view><view class="row"><text class="label">联系人</text><text wx:if="{{e}}" class="value">{{f}}</text><input wx:else class="value-input" placeholder="可选" value="{{g}}" bindinput="{{h}}"/></view><view class="row"><text class="label">手机</text><text wx:if="{{i}}" class="value">{{j}}</text><input wx:else class="value-input" placeholder="可选" value="{{k}}" bindinput="{{l}}"/></view><view class="row"><text class="label">电话</text><text wx:if="{{m}}" class="value">{{n}}</text><input wx:else class="value-input" placeholder="可选(座机)" value="{{o}}" bindinput="{{p}}"/></view><view class="row"><text class="label">地址</text><text wx:if="{{q}}" class="value">{{r}}</text><input wx:else class="value-input" placeholder="可选" value="{{s}}" bindinput="{{t}}"/></view><view class="row"><text class="label">等级</text><text wx:if="{{v}}" class="value">{{w}}</text><input wx:else class="value-input" placeholder="可选,如 VIP/A/B" value="{{x}}" bindinput="{{y}}"/></view><view class="row"><text class="label">售价档位</text><text wx:if="{{z}}" class="value">{{A}}</text><picker wx:else range="{{C}}" value="{{D}}" bindchange="{{E}}"><view class="value">{{B}}</view></picker></view><view class="row"><text class="label">初始应收</text><text wx:if="{{F}}" class="value">¥ {{G}}</text><input wx:else class="value-input" type="digit" placeholder="0.00" value="{{H}}" bindinput="{{I}}"/></view><view class="row"><text class="label">当前应收</text><text class="value emp">¥ {{J}}</text></view><view class="row"><text class="label">备注</text><text wx:if="{{K}}" class="value">{{L}}</text><input wx:else class="value-input" placeholder="—" value="{{M}}" bindinput="{{N}}"/></view></view><view class="bottom"><button class="ghost" bindtap="{{P}}">{{O}}</button><button wx:if="{{Q}}" class="primary" bindtap="{{R}}">保存</button><button wx:else class="primary" bindtap="{{S}}">选择此客户</button></view></view>
|
||||
<view class="page"><view class="card"><view class="row"><text class="label">名称</text><text wx:if="{{a}}" class="value">{{b}}</text><input wx:else class="value-input" placeholder="必填" value="{{c}}" bindinput="{{d}}"/></view><view class="row"><text class="label">联系人</text><text wx:if="{{e}}" class="value">{{f}}</text><input wx:else class="value-input" placeholder="可选" value="{{g}}" bindinput="{{h}}"/></view><view class="row"><text class="label">手机</text><text wx:if="{{i}}" class="value">{{j}}</text><input wx:else class="value-input" placeholder="可选" value="{{k}}" bindinput="{{l}}"/></view><view class="row"><text class="label">电话</text><text wx:if="{{m}}" class="value">{{n}}</text><input wx:else class="value-input" placeholder="可选(座机)" value="{{o}}" bindinput="{{p}}"/></view><view class="row"><text class="label">地址</text><text wx:if="{{q}}" class="value">{{r}}</text><input wx:else class="value-input" placeholder="可选" value="{{s}}" bindinput="{{t}}"/></view><view class="row"><text class="label">售价档位</text><text wx:if="{{v}}" class="value">{{w}}</text><picker wx:else range="{{y}}" value="{{z}}" bindchange="{{A}}"><view class="value">{{x}}</view></picker></view><view class="row"><text class="label">初始应收</text><text wx:if="{{B}}" class="value">¥ {{C}}</text><input wx:else class="value-input" type="digit" placeholder="0.00" value="{{D}}" bindinput="{{E}}"/></view><view class="row"><text class="label">当前应收</text><text class="value emp">¥ {{F}}</text></view><view class="row"><text class="label">备注</text><text wx:if="{{G}}" class="value">{{H}}</text><input wx:else class="value-input" placeholder="—" value="{{I}}" bindinput="{{J}}"/></view></view><view class="bottom"><button class="ghost" bindtap="{{L}}">{{K}}</button><button wx:if="{{M}}" class="primary" bindtap="{{N}}">保存</button><button wx:else class="primary" bindtap="{{O}}">选择此客户</button></view></view>
|
||||
@@ -5,7 +5,7 @@ const _sfc_main = {
|
||||
data() {
|
||||
return {
|
||||
id: null,
|
||||
form: { name: "", level: "", priceLevel: "retail", contactName: "", mobile: "", phone: "", address: "", arOpening: 0, remark: "" },
|
||||
form: { name: "", priceLevel: "retail", contactName: "", mobile: "", phone: "", address: "", arOpening: 0, remark: "" },
|
||||
priceLevels: ["零售价", "批发价", "大单报价"],
|
||||
priceLabels: ["零售价", "批发价", "大单报价"],
|
||||
priceIdx: 0
|
||||
@@ -14,6 +14,7 @@ const _sfc_main = {
|
||||
onLoad(query) {
|
||||
if (query && query.id) {
|
||||
this.id = Number(query.id);
|
||||
this.load();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -21,6 +22,27 @@ const _sfc_main = {
|
||||
this.priceIdx = Number(e.detail.value);
|
||||
this.form.priceLevel = this.priceLevels[this.priceIdx];
|
||||
},
|
||||
async load() {
|
||||
if (!this.id)
|
||||
return;
|
||||
try {
|
||||
const d = await common_http.get(`/api/customers/${this.id}`);
|
||||
this.form = {
|
||||
name: (d == null ? void 0 : d.name) || "",
|
||||
priceLevel: (d == null ? void 0 : d.priceLevel) || "零售价",
|
||||
contactName: (d == null ? void 0 : d.contactName) || "",
|
||||
mobile: (d == null ? void 0 : d.mobile) || "",
|
||||
phone: (d == null ? void 0 : d.phone) || "",
|
||||
address: (d == null ? void 0 : d.address) || "",
|
||||
arOpening: Number((d == null ? void 0 : d.arOpening) || 0),
|
||||
remark: (d == null ? void 0 : d.remark) || ""
|
||||
};
|
||||
const idx = this.priceLevels.indexOf(this.form.priceLevel || "零售价");
|
||||
this.priceIdx = idx >= 0 ? idx : 0;
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: (e == null ? void 0 : e.message) || "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
if (!this.form.name)
|
||||
return common_vendor.index.showToast({ title: "请填写客户名称", icon: "none" });
|
||||
@@ -41,27 +63,25 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return {
|
||||
a: $data.form.name,
|
||||
b: common_vendor.o(($event) => $data.form.name = $event.detail.value),
|
||||
c: $data.form.level,
|
||||
d: common_vendor.o(($event) => $data.form.level = $event.detail.value),
|
||||
e: common_vendor.t($data.priceLabels[$data.priceIdx]),
|
||||
f: $data.priceLabels,
|
||||
g: $data.priceIdx,
|
||||
h: common_vendor.o((...args) => $options.onPriceChange && $options.onPriceChange(...args)),
|
||||
i: $data.form.contactName,
|
||||
j: common_vendor.o(($event) => $data.form.contactName = $event.detail.value),
|
||||
k: $data.form.mobile,
|
||||
l: common_vendor.o(($event) => $data.form.mobile = $event.detail.value),
|
||||
m: $data.form.phone,
|
||||
n: common_vendor.o(($event) => $data.form.phone = $event.detail.value),
|
||||
o: $data.form.address,
|
||||
p: common_vendor.o(($event) => $data.form.address = $event.detail.value),
|
||||
q: $data.form.arOpening,
|
||||
r: common_vendor.o(common_vendor.m(($event) => $data.form.arOpening = $event.detail.value, {
|
||||
c: common_vendor.t($data.priceLabels[$data.priceIdx]),
|
||||
d: $data.priceLabels,
|
||||
e: $data.priceIdx,
|
||||
f: common_vendor.o((...args) => $options.onPriceChange && $options.onPriceChange(...args)),
|
||||
g: $data.form.contactName,
|
||||
h: common_vendor.o(($event) => $data.form.contactName = $event.detail.value),
|
||||
i: $data.form.mobile,
|
||||
j: common_vendor.o(($event) => $data.form.mobile = $event.detail.value),
|
||||
k: $data.form.phone,
|
||||
l: common_vendor.o(($event) => $data.form.phone = $event.detail.value),
|
||||
m: $data.form.address,
|
||||
n: common_vendor.o(($event) => $data.form.address = $event.detail.value),
|
||||
o: $data.form.arOpening,
|
||||
p: common_vendor.o(common_vendor.m(($event) => $data.form.arOpening = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
s: $data.form.remark,
|
||||
t: common_vendor.o(($event) => $data.form.remark = $event.detail.value),
|
||||
v: common_vendor.o((...args) => $options.save && $options.save(...args))
|
||||
q: $data.form.remark,
|
||||
r: common_vendor.o(($event) => $data.form.remark = $event.detail.value),
|
||||
s: common_vendor.o((...args) => $options.save && $options.save(...args))
|
||||
};
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="page"><view class="field"><text class="label">客户名称</text><input class="value" placeholder="必填" value="{{a}}" bindinput="{{b}}"/></view><view class="field"><text class="label">客户等级</text><input class="value" placeholder="可选,如 VIP/A/B" value="{{c}}" bindinput="{{d}}"/></view><view class="field"><text class="label">售价档位</text><picker range="{{f}}" value="{{g}}" bindchange="{{h}}"><view class="value">{{e}}</view></picker></view><view class="field"><text class="label">联系人</text><input class="value" placeholder="可选" value="{{i}}" bindinput="{{j}}"/></view><view class="field"><text class="label">手机</text><input class="value" placeholder="可选" value="{{k}}" bindinput="{{l}}"/></view><view class="field"><text class="label">电话</text><input class="value" placeholder="可选(座机)" value="{{m}}" bindinput="{{n}}"/></view><view class="field"><text class="label">送货地址</text><input class="value" placeholder="可选" value="{{o}}" bindinput="{{p}}"/></view><view class="field"><text class="label">初始应收</text><input class="value" type="digit" placeholder="默认 0.00" value="{{q}}" bindinput="{{r}}"/></view><view class="textarea"><block wx:if="{{r0}}"><textarea maxlength="200" placeholder="备注(最多200字)" value="{{s}}" bindinput="{{t}}"></textarea></block></view><view class="bottom"><button class="primary" bindtap="{{v}}">保存</button></view></view>
|
||||
<view class="page"><view class="field"><text class="label">客户名称</text><input class="value" placeholder="必填" value="{{a}}" bindinput="{{b}}"/></view><view class="field"><text class="label">售价档位</text><picker range="{{d}}" value="{{e}}" bindchange="{{f}}"><view class="value">{{c}}</view></picker></view><view class="field"><text class="label">联系人</text><input class="value" placeholder="可选" value="{{g}}" bindinput="{{h}}"/></view><view class="field"><text class="label">手机</text><input class="value" placeholder="可选" value="{{i}}" bindinput="{{j}}"/></view><view class="field"><text class="label">电话</text><input class="value" placeholder="可选(座机)" value="{{k}}" bindinput="{{l}}"/></view><view class="field"><text class="label">送货地址</text><input class="value" placeholder="可选" value="{{m}}" bindinput="{{n}}"/></view><view class="field"><text class="label">初始应收</text><input class="value" type="digit" placeholder="默认 0.00" value="{{o}}" bindinput="{{p}}"/></view><view class="textarea"><block wx:if="{{r0}}"><textarea maxlength="200" placeholder="备注(最多200字)" value="{{q}}" bindinput="{{r}}"></textarea></block></view><view class="bottom"><button class="primary" bindtap="{{s}}">保存</button></view></view>
|
||||
@@ -5,8 +5,7 @@ const API_OF = {
|
||||
sale: "/api/orders",
|
||||
purchase: "/api/purchase-orders",
|
||||
collect: "/api/payments",
|
||||
fund: "/api/other-transactions",
|
||||
stock: "/api/inventories/logs"
|
||||
fund: "/api/other-transactions"
|
||||
};
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
@@ -16,18 +15,19 @@ const _sfc_main = {
|
||||
{ key: "sale", name: "出货" },
|
||||
{ key: "purchase", name: "进货" },
|
||||
{ key: "collect", name: "收款" },
|
||||
{ key: "fund", name: "资金" },
|
||||
{ key: "stock", name: "盘点" }
|
||||
{ key: "fund", name: "资金" }
|
||||
],
|
||||
range: "month",
|
||||
query: { kw: "" },
|
||||
items: [],
|
||||
page: 1,
|
||||
size: 20,
|
||||
size: 15,
|
||||
finished: false,
|
||||
loading: false,
|
||||
startDate: "",
|
||||
endDate: ""
|
||||
endDate: "",
|
||||
nonVipRetentionDays: 0,
|
||||
isVip: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -56,7 +56,7 @@ const _sfc_main = {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
common_vendor.index.__f__("log", "at pages/detail/index.vue:102", "[detail] onLoad route = pages/detail/index");
|
||||
common_vendor.index.__f__("log", "at pages/detail/index.vue:104", "[detail] onLoad route = pages/detail/index");
|
||||
} catch (e) {
|
||||
}
|
||||
this.computeRange();
|
||||
@@ -133,12 +133,43 @@ const _sfc_main = {
|
||||
if (list.length < this.size)
|
||||
this.finished = true;
|
||||
this.page += 1;
|
||||
await this.hintIfNonVipOutOfWindow();
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async hintIfNonVipOutOfWindow() {
|
||||
try {
|
||||
if (this.isVip && this.isVip === true)
|
||||
return;
|
||||
if (!this.nonVipRetentionDays) {
|
||||
const v = await common_http.get("/api/vip/status");
|
||||
this.isVip = !!(v == null ? void 0 : v.isVip);
|
||||
this.nonVipRetentionDays = Number((v == null ? void 0 : v.nonVipRetentionDays) || 60);
|
||||
if (this.isVip)
|
||||
return;
|
||||
}
|
||||
if (!this.startDate)
|
||||
return;
|
||||
const start = new Date(this.startDate).getTime();
|
||||
const threshold = Date.now() - this.nonVipRetentionDays * 24 * 3600 * 1e3;
|
||||
if (start < threshold) {
|
||||
common_vendor.index.showModal({
|
||||
title: "提示",
|
||||
content: `普通用户仅显示近${this.nonVipRetentionDays}天数据,开通VIP可查看全部历史。`,
|
||||
confirmText: "去开通VIP",
|
||||
cancelText: "我知道了",
|
||||
success: (r) => {
|
||||
if (r.confirm)
|
||||
common_vendor.index.navigateTo({ url: "/pages/my/vip" });
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
},
|
||||
formatDate(s) {
|
||||
if (!s)
|
||||
return "";
|
||||
@@ -201,8 +232,14 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
};
|
||||
})
|
||||
} : {}, {
|
||||
p: common_vendor.o((...args) => $options.loadMore && $options.loadMore(...args)),
|
||||
q: common_vendor.o((...args) => $options.onCreate && $options.onCreate(...args))
|
||||
p: $data.items.length && !$data.finished
|
||||
}, $data.items.length && !$data.finished ? {
|
||||
q: $data.loading
|
||||
} : {}, {
|
||||
r: $data.finished && $data.items.length
|
||||
}, $data.finished && $data.items.length ? {} : {}, {
|
||||
s: common_vendor.o((...args) => $options.loadMore && $options.loadMore(...args)),
|
||||
t: common_vendor.o((...args) => $options.onCreate && $options.onCreate(...args))
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="page"><view class="content"><view class="biz-tabs"><view wx:for="{{a}}" wx:for-item="b" wx:key="b" class="{{['biz', b.c]}}" bindtap="{{b.d}}">{{b.a}}</view></view><view class="panel"><view class="toolbar"><view class="period-group"><text class="period-label">期间</text><picker mode="date" value="{{c}}" bindchange="{{d}}"><view class="date-chip">{{b}}</view></picker><text class="sep">~</text><picker mode="date" value="{{f}}" bindchange="{{g}}"><view class="date-chip">{{e}}</view></picker></view><view class="search-row"><view class="search"><input class="search-input" placeholder="{{h}}" bindconfirm="{{i}}" value="{{j}}" bindinput="{{k}}"/></view><button class="btn" size="mini" bindtap="{{l}}">查询</button></view></view><view class="total">合计:¥{{m}}</view><scroll-view scroll-y class="list" bindscrolltolower="{{p}}"><block wx:if="{{n}}"><view wx:for="{{o}}" wx:for-item="it" wx:key="g" class="item" bindtap="{{it.h}}"><view class="item-left"><view class="date">{{it.a}}</view><view class="name">{{it.b}}</view><view class="no">{{it.c}}</view></view><view class="{{['amount', it.e && 'in', it.f && 'out']}}">¥ {{it.d}}</view><view class="arrow">›</view></view></block><view wx:else class="empty">暂无数据</view></scroll-view><view class="fab" bindtap="{{q}}">+</view></view></view></view>
|
||||
<view class="page"><view class="content"><view class="biz-tabs"><view wx:for="{{a}}" wx:for-item="b" wx:key="b" class="{{['biz', b.c]}}" bindtap="{{b.d}}">{{b.a}}</view></view><view class="panel"><view class="toolbar"><view class="period-group"><text class="period-label">期间</text><picker mode="date" value="{{c}}" bindchange="{{d}}"><view class="date-chip">{{b}}</view></picker><text class="sep">~</text><picker mode="date" value="{{f}}" bindchange="{{g}}"><view class="date-chip">{{e}}</view></picker></view><view class="search-row"><view class="search"><input class="search-input" placeholder="{{h}}" bindconfirm="{{i}}" value="{{j}}" bindinput="{{k}}"/></view><button class="btn" size="mini" bindtap="{{l}}">查询</button></view></view><view class="total">合计:¥{{m}}</view><scroll-view scroll-y class="list" bindscrolltolower="{{s}}"><block wx:if="{{n}}"><view wx:for="{{o}}" wx:for-item="it" wx:key="g" class="item" bindtap="{{it.h}}"><view class="item-left"><view class="date">{{it.a}}</view><view class="name">{{it.b}}</view><view class="no">{{it.c}}</view></view><view class="{{['amount', it.e && 'in', it.f && 'out']}}">¥ {{it.d}}</view><view class="arrow">›</view></view></block><view wx:else class="empty">暂无数据</view><view wx:if="{{p}}" class="loading" hidden="{{!q}}">加载中...</view><view wx:if="{{r}}" class="finished">没有更多了</view></scroll-view><view class="fab" bindtap="{{t}}">+</view></view></view></view>
|
||||
@@ -66,7 +66,6 @@
|
||||
margin: 16rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 12rpx;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
@@ -80,7 +79,6 @@
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
background: #f6f8fb;
|
||||
border: 2rpx solid #e6ebf2;
|
||||
border-radius: 10rpx;
|
||||
padding: 8rpx 10rpx;
|
||||
}
|
||||
@@ -100,23 +98,42 @@
|
||||
.search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.search {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
}
|
||||
.search-input {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
line-height: 72rpx;
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 12rpx;
|
||||
color: #111;
|
||||
border: 2rpx solid #e6ebf2;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.btn {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 72rpx;
|
||||
padding: 0 32rpx;
|
||||
margin-left: 4rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
border: none;
|
||||
font-size: 26rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.btn::after {
|
||||
border: none;
|
||||
}
|
||||
.total {
|
||||
color: #4C8DFF;
|
||||
@@ -127,6 +144,16 @@
|
||||
.list {
|
||||
flex: 1;
|
||||
}
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
color: #444;
|
||||
}
|
||||
.finished {
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
color: #444;
|
||||
}
|
||||
.item {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
|
||||
@@ -12,17 +12,19 @@ const _sfc_main = {
|
||||
notices: [],
|
||||
loadingNotices: false,
|
||||
noticeError: "",
|
||||
consultLabel: "咨询",
|
||||
consultDialogVisible: false,
|
||||
consultMessage: "",
|
||||
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: "⋯" }
|
||||
{ key: "customer", title: "客户", img: "/static/icons/webwxgetmsgimg.png", emoji: "👥" },
|
||||
{ key: "sale", title: "销售", img: "/static/icons/webwxgetmsgimg.jpg", emoji: "💰" },
|
||||
{ key: "account", title: "账户", img: "/static/icons/icons8-profile-50.png", emoji: "💳" },
|
||||
{ key: "supplier", title: "供应商", img: "/static/icons/icons8-supplier-50.png", emoji: "🚚" },
|
||||
{ key: "purchase", title: "进货", img: "/static/icons/icons8-dollar-ethereum-exchange-50.png", emoji: "🛒" },
|
||||
{ key: "otherPay", title: "其他支出", img: "/static/icons/icons8-expenditure-64.png", emoji: "💸" },
|
||||
{ key: "vip", title: "VIP会员", img: "/static/icons/icons8-vip-48.png", emoji: "👑" },
|
||||
{ key: "report", title: "报表", img: "/static/icons/icons8-graph-report-50.png", emoji: "📊" }
|
||||
]
|
||||
};
|
||||
},
|
||||
@@ -42,6 +44,7 @@ const _sfc_main = {
|
||||
}
|
||||
this.fetchMetrics();
|
||||
this.fetchNotices();
|
||||
this.fetchLatestConsult();
|
||||
},
|
||||
methods: {
|
||||
async fetchMetrics() {
|
||||
@@ -58,6 +61,59 @@ const _sfc_main = {
|
||||
} catch (e) {
|
||||
}
|
||||
},
|
||||
async fetchLatestConsult() {
|
||||
try {
|
||||
const d = await common_http.get("/api/consults");
|
||||
if (d && d.replied)
|
||||
this.consultLabel = "已回复";
|
||||
else
|
||||
this.consultLabel = "咨询";
|
||||
this._latestConsult = d;
|
||||
} catch (e) {
|
||||
this.consultLabel = "咨询";
|
||||
}
|
||||
},
|
||||
onConsultTap() {
|
||||
if (this.consultLabel === "已回复" && this._latestConsult && this._latestConsult.id) {
|
||||
const msg = this._latestConsult.latestReply ? this._latestConsult.latestReply : this._latestConsult.message || "";
|
||||
common_vendor.index.showModal({ title: "咨询回复", content: msg || "暂无内容", showCancel: false, success: async (res) => {
|
||||
if (!res || res.confirm !== true)
|
||||
return;
|
||||
try {
|
||||
const r = await common_http.put(`/api/consults/${this._latestConsult.id}/ack`, {});
|
||||
this.consultLabel = "咨询";
|
||||
this._latestConsult = null;
|
||||
setTimeout(() => this.fetchLatestConsult(), 200);
|
||||
} catch (e) {
|
||||
try {
|
||||
common_vendor.index.showToast({ title: e && e.message || "已读同步失败", icon: "none" });
|
||||
} catch (_) {
|
||||
}
|
||||
}
|
||||
} });
|
||||
return;
|
||||
}
|
||||
this.consultMessage = "";
|
||||
this.consultDialogVisible = true;
|
||||
},
|
||||
closeConsultDialog() {
|
||||
this.consultDialogVisible = false;
|
||||
},
|
||||
async submitConsult() {
|
||||
const text = String(this.consultMessage || "").trim();
|
||||
if (!text) {
|
||||
common_vendor.index.showToast({ title: "请输入咨询内容", icon: "none" });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await common_http.post("/api/consults", { message: text });
|
||||
this.consultDialogVisible = false;
|
||||
common_vendor.index.showToast({ title: "已提交", icon: "success" });
|
||||
setTimeout(() => this.fetchLatestConsult(), 300);
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: e && e.message || "提交失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async fetchNotices() {
|
||||
this.loadingNotices = true;
|
||||
this.noticeError = "";
|
||||
@@ -128,7 +184,7 @@ const _sfc_main = {
|
||||
},
|
||||
goDetail() {
|
||||
try {
|
||||
common_vendor.index.__f__("log", "at pages/index/index.vue:198", "[index] goDetail → /pages/detail/index");
|
||||
common_vendor.index.__f__("log", "at pages/index/index.vue:253", "[index] goDetail → /pages/detail/index");
|
||||
} catch (e) {
|
||||
}
|
||||
common_vendor.index.switchTab({ url: "/pages/detail/index" });
|
||||
@@ -150,11 +206,32 @@ const _sfc_main = {
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return common_vendor.e({
|
||||
a: $data.loadingNotices
|
||||
a: common_vendor.t($data.consultLabel),
|
||||
b: common_vendor.o((...args) => $options.onConsultTap && $options.onConsultTap(...args)),
|
||||
c: $data.KPI_ICONS.todaySales,
|
||||
d: common_vendor.t($data.kpi.todaySales),
|
||||
e: $data.KPI_ICONS.monthSales,
|
||||
f: common_vendor.t($data.kpi.monthSales),
|
||||
g: $data.KPI_ICONS.monthProfit,
|
||||
h: common_vendor.t($data.kpi.monthProfit),
|
||||
i: $data.KPI_ICONS.stockCount,
|
||||
j: common_vendor.t($data.kpi.stockCount),
|
||||
k: $data.consultDialogVisible
|
||||
}, $data.consultDialogVisible ? {
|
||||
l: $data.consultMessage,
|
||||
m: common_vendor.o(($event) => $data.consultMessage = $event.detail.value),
|
||||
n: common_vendor.o((...args) => $options.closeConsultDialog && $options.closeConsultDialog(...args)),
|
||||
o: common_vendor.o((...args) => $options.submitConsult && $options.submitConsult(...args)),
|
||||
p: common_vendor.o(() => {
|
||||
}),
|
||||
q: common_vendor.o(() => {
|
||||
})
|
||||
} : {}, {
|
||||
r: $data.loadingNotices
|
||||
}, $data.loadingNotices ? {} : $data.noticeError ? {
|
||||
c: common_vendor.t($data.noticeError)
|
||||
t: common_vendor.t($data.noticeError)
|
||||
} : !$data.notices.length ? {} : {
|
||||
e: common_vendor.f($data.notices, (n, idx, i0) => {
|
||||
w: common_vendor.f($data.notices, (n, idx, i0) => {
|
||||
return common_vendor.e({
|
||||
a: common_vendor.t(n.text),
|
||||
b: n.tag
|
||||
@@ -166,17 +243,9 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
});
|
||||
})
|
||||
}, {
|
||||
b: $data.noticeError,
|
||||
d: !$data.notices.length,
|
||||
f: $data.KPI_ICONS.todaySales,
|
||||
g: common_vendor.t($data.kpi.todaySales),
|
||||
h: $data.KPI_ICONS.monthSales,
|
||||
i: common_vendor.t($data.kpi.monthSales),
|
||||
j: $data.KPI_ICONS.monthProfit,
|
||||
k: common_vendor.t($data.kpi.monthProfit),
|
||||
l: $data.KPI_ICONS.stockCount,
|
||||
m: common_vendor.t($data.kpi.stockCount),
|
||||
n: common_vendor.f($data.features, (item, k0, i0) => {
|
||||
s: $data.noticeError,
|
||||
v: !$data.notices.length,
|
||||
x: common_vendor.f($data.features, (item, k0, i0) => {
|
||||
return common_vendor.e({
|
||||
a: item.img
|
||||
}, item.img ? {
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="home"><view class="notice"><view class="notice-left">公告</view><view wx:if="{{a}}" class="notice-swiper" style="display:flex;align-items:center;color:#6b5a2a">加载中...</view><view wx:elif="{{b}}" class="notice-swiper" style="display:flex;align-items:center;color:#dd524d">{{c}}</view><view wx:elif="{{d}}" class="notice-swiper" style="display:flex;align-items:center;color:#6b5a2a">暂无公告</view><swiper wx:else class="notice-swiper" circular autoplay interval="4000" duration="400" vertical><swiper-item wx:for="{{e}}" wx:for-item="n" wx:key="e"><view class="notice-item" bindtap="{{n.d}}"><text class="notice-text">{{n.a}}</text><text wx:if="{{n.b}}" class="notice-tag">{{n.c}}</text></view></swiper-item></swiper></view><view class="hero"><view class="hero-top"><text class="brand">五金配件管家</text><view class="cta"><text class="cta-text">咨询</text></view></view><view class="kpi kpi-grid"><view class="kpi-item kpi-card"><image src="{{f}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">今日销售额</text><text class="kpi-value">{{g}}</text></view></view><view class="kpi-item kpi-card"><image src="{{h}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">本月销售额</text><text class="kpi-value">{{i}}</text></view></view><view class="kpi-item kpi-card"><image src="{{j}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">本月利润</text><text class="kpi-value">{{k}}</text></view></view><view class="kpi-item kpi-card"><image src="{{l}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">库存商品数量</text><text class="kpi-value">{{m}}</text></view></view></view></view><view class="section-title"><text class="section-text">常用功能</text></view><view class="grid-wrap"><view class="feature-grid"><view wx:for="{{n}}" wx:for-item="item" wx:key="g" class="feature-card" bindtap="{{item.h}}"><view class="fc-icon"><image wx:if="{{item.a}}" src="{{item.b}}" class="fc-img" mode="aspectFit" binderror="{{item.c}}"></image><text wx:elif="{{item.d}}" class="fc-emoji">{{item.e}}</text><view wx:else class="fc-placeholder"></view></view><view class="fc-title">{{item.f}}</view></view></view></view></view>
|
||||
<view class="home"><view class="hero"><view class="hero-top"><text class="brand">五金配件管家</text><view class="cta" bindtap="{{b}}" hover-class="cta-active" hover-stay-time="80"><text class="cta-text">{{a}}</text></view></view><view class="kpi kpi-grid"><view class="kpi-item kpi-card"><image src="{{c}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">今日销售额</text><text class="kpi-value">{{d}}</text></view></view><view class="kpi-item kpi-card"><image src="{{e}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">本月销售额</text><text class="kpi-value">{{f}}</text></view></view><view class="kpi-item kpi-card"><image src="{{g}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">本月利润</text><text class="kpi-value">{{h}}</text></view></view><view class="kpi-item kpi-card"><image src="{{i}}" class="kpi-icon" mode="aspectFit"></image><view class="kpi-content"><text class="kpi-label">库存商品数量</text><text class="kpi-value">{{j}}</text></view></view></view></view><view wx:if="{{k}}" class="dialog-mask" catchtouchmove="{{p}}" catchtap="{{q}}"><view class="dialog"><view class="dialog-title">咨询</view><block wx:if="{{r0}}"><textarea class="dialog-textarea" placeholder="请输入咨询内容..." maxlength="500" value="{{l}}" bindinput="{{m}}"></textarea></block><view class="dialog-actions"><view class="btn" bindtap="{{n}}">取消</view><view class="btn primary" bindtap="{{o}}">提交</view></view></view></view><view class="notice"><view class="notice-left">公告</view><view wx:if="{{r}}" class="notice-swiper" style="display:flex;align-items:center;color:#6b5a2a">加载中...</view><view wx:elif="{{s}}" class="notice-swiper" style="display:flex;align-items:center;color:#dd524d">{{t}}</view><view wx:elif="{{v}}" class="notice-swiper" style="display:flex;align-items:center;color:#6b5a2a">暂无公告</view><swiper wx:else class="notice-swiper" circular autoplay interval="4000" duration="400" vertical><swiper-item wx:for="{{w}}" wx:for-item="n" wx:key="e"><view class="notice-item" bindtap="{{n.d}}"><text class="notice-text">{{n.a}}</text><text wx:if="{{n.b}}" class="notice-tag">{{n.c}}</text></view></swiper-item></swiper></view><view class="section-title"><text class="section-text">常用功能</text></view><view class="grid-wrap"><view class="feature-grid"><view wx:for="{{x}}" wx:for-item="item" wx:key="g" class="feature-card" bindtap="{{item.h}}"><view class="fc-icon"><image wx:if="{{item.a}}" src="{{item.b}}" class="fc-img" mode="aspectFit" binderror="{{item.c}}"></image><text wx:elif="{{item.d}}" class="fc-emoji">{{item.e}}</text><view wx:else class="fc-placeholder"></view></view><view class="fc-title">{{item.f}}</view></view></view></view></view>
|
||||
@@ -24,12 +24,21 @@
|
||||
/* 垂直间距 */
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
page {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(180deg, #f8fbff 0%, #ffffff 60%);
|
||||
}
|
||||
.home {
|
||||
padding-bottom: 140rpx;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 32rpx);
|
||||
position: relative;
|
||||
/* 渐变背景:顶部淡蓝过渡到白色 */
|
||||
background: linear-gradient(180deg, #f8fbff 0%, #ffffff 60%);
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 首页横幅(移除) */
|
||||
@@ -92,6 +101,7 @@
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 10rpx 28rpx 0;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.section-title::before {
|
||||
content: "";
|
||||
@@ -111,12 +121,13 @@
|
||||
/* 顶部英雄区:浅色玻璃卡片,带金色描边与柔和阴影 */
|
||||
.hero {
|
||||
margin: 16rpx 20rpx;
|
||||
padding: 18rpx;
|
||||
padding: 18rpx 18rpx 12rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #ffffff;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
box-shadow: none;
|
||||
color: #111;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.hero-top {
|
||||
display: flex;
|
||||
@@ -159,11 +170,65 @@
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* KPI 卡片化布局:2×2 */
|
||||
/* 简易弹层样式 */
|
||||
.dialog-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10000;
|
||||
}
|
||||
.dialog {
|
||||
width: 82vw;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx;
|
||||
border: 2rpx solid #eef2f6;
|
||||
}
|
||||
.dialog-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 800;
|
||||
color: #111;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.dialog-textarea {
|
||||
width: 100%;
|
||||
min-height: 180rpx;
|
||||
border: 2rpx solid #e8eef8;
|
||||
border-radius: 12rpx;
|
||||
padding: 12rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 18rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
.btn {
|
||||
padding: 10rpx 22rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f3f6fb;
|
||||
color: #334155;
|
||||
border: 2rpx solid #e2e8f0;
|
||||
font-weight: 700;
|
||||
}
|
||||
.btn.primary {
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
border-color: #4C8DFF;
|
||||
}
|
||||
|
||||
/* KPI 卡片化布局:横向铺满 */
|
||||
.kpi {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16rpx;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 12rpx;
|
||||
}
|
||||
.kpi-item {
|
||||
text-align: center;
|
||||
@@ -175,19 +240,21 @@
|
||||
|
||||
/* KPI 卡片(更扁平,降低高度) */
|
||||
.kpi-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16rpx;
|
||||
gap: 12rpx;
|
||||
}
|
||||
.kpi-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
gap: 8rpx;
|
||||
text-align: left;
|
||||
padding: 12rpx 14rpx;
|
||||
border-radius: 12rpx;
|
||||
border-radius: 14rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #eef2f6;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
min-height: 120rpx;
|
||||
}
|
||||
.kpi-icon {
|
||||
width: 44rpx;
|
||||
@@ -206,8 +273,8 @@
|
||||
}
|
||||
.kpi-value {
|
||||
color: #4C8DFF;
|
||||
font-size: 36rpx;
|
||||
line-height: 40rpx;
|
||||
font-size: 34rpx;
|
||||
line-height: 38rpx;
|
||||
margin-top: 0;
|
||||
font-weight: 800;
|
||||
}
|
||||
@@ -241,45 +308,56 @@
|
||||
|
||||
/* 功能容器:更轻的留白 */
|
||||
.grid-wrap {
|
||||
margin: 8rpx 12rpx 24rpx;
|
||||
padding: 8rpx 8rpx 0;
|
||||
border-radius: 20rpx;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
margin: 16rpx 20rpx 28rpx;
|
||||
padding: 32rpx 30rpx;
|
||||
border-radius: 26rpx;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border: 2rpx solid #edf2f9;
|
||||
box-shadow: 0 12rpx 28rpx rgba(32, 75, 143, 0.1);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 功能卡片宫格:方形竖排,图标在上文字在下(与截图一致) */
|
||||
.feature-grid {
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 14rpx;
|
||||
padding: 8rpx 8rpx 18rpx;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
grid-auto-rows: 1fr;
|
||||
gap: 32rpx 28rpx;
|
||||
align-content: space-evenly;
|
||||
justify-items: center;
|
||||
}
|
||||
.feature-card {
|
||||
height: 164rpx;
|
||||
width: 168rpx;
|
||||
height: 176rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #eef2f6;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
padding: 12rpx;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 10rpx 24rpx rgba(0, 0, 0, 0.05);
|
||||
padding: 18rpx 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.fc-icon {
|
||||
width: 86rpx;
|
||||
height: 86rpx;
|
||||
width: 78rpx;
|
||||
height: 78rpx;
|
||||
border-radius: 18rpx;
|
||||
background: #f7faff;
|
||||
border: 2rpx solid #e8eef8;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.fc-img {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
width: 54rpx;
|
||||
height: 54rpx;
|
||||
opacity: 0.95;
|
||||
}
|
||||
.fc-emoji {
|
||||
@@ -293,10 +371,11 @@
|
||||
border: 2rpx solid #e8eef8;
|
||||
}
|
||||
.fc-title {
|
||||
margin-top: 10rpx;
|
||||
font-size: 26rpx;
|
||||
margin-top: 12rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* 底部操作条:浅色半透明 + 金色主按钮 */
|
||||
|
||||
@@ -16,7 +16,7 @@ const _sfc_main = {
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return {
|
||||
a: common_assets._imports_0$1,
|
||||
a: common_assets._imports_0$2,
|
||||
b: common_vendor.o((...args) => $options.openPolicy && $options.openPolicy(...args)),
|
||||
c: common_vendor.o((...args) => $options.openTerms && $options.openTerms(...args)),
|
||||
d: common_vendor.o((...args) => $options.openComplaint && $options.openComplaint(...args))
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const common_config = require("../../common/config.js");
|
||||
const common_assets = require("../../common/assets.js");
|
||||
function normalizeAvatar(url) {
|
||||
if (!url)
|
||||
return "/static/icons/icons8-mitt-24.png";
|
||||
const s = String(url);
|
||||
if (/^https?:\/\//i.test(s))
|
||||
return s;
|
||||
if (!common_config.API_BASE_URL)
|
||||
return s;
|
||||
if (s.startsWith("/"))
|
||||
return `${common_config.API_BASE_URL}${s}`;
|
||||
return `${common_config.API_BASE_URL}/${s}`;
|
||||
}
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return {
|
||||
avatarUrl: "/static/logo.png",
|
||||
avatarUrl: "/static/icons/icons8-mitt-24.png",
|
||||
shopName: "未登录",
|
||||
mobile: "",
|
||||
pendingJsCode: "",
|
||||
@@ -16,7 +30,7 @@ const _sfc_main = {
|
||||
},
|
||||
onShow() {
|
||||
this.fetchProfile();
|
||||
this.loadVipFromStorage();
|
||||
this.loadVip();
|
||||
try {
|
||||
if (common_vendor.index.getStorageSync("TOKEN")) {
|
||||
this.$forceUpdate && this.$forceUpdate();
|
||||
@@ -32,9 +46,22 @@ const _sfc_main = {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
mobileDisplay() {
|
||||
const m = String(this.mobile || "");
|
||||
return m.length === 11 ? m.slice(0, 3) + "****" + m.slice(7) : m || "未绑定手机号";
|
||||
avatarDisplay() {
|
||||
return normalizeAvatar(this.avatarUrl);
|
||||
},
|
||||
emailDisplay() {
|
||||
if (!this.isLoggedIn)
|
||||
return "";
|
||||
const e = String(common_vendor.index.getStorageSync("USER_EMAIL") || "");
|
||||
if (!e)
|
||||
return "未绑定邮箱";
|
||||
const at = e.indexOf("@");
|
||||
if (at > 1) {
|
||||
const name = e.slice(0, at);
|
||||
const domain = e.slice(at);
|
||||
return (name.length <= 2 ? name[0] + "*" : name.slice(0, 2) + "***") + domain;
|
||||
}
|
||||
return e;
|
||||
},
|
||||
vipStartDisplay() {
|
||||
return this.formatDisplay(this.vipStart);
|
||||
@@ -55,35 +82,100 @@ const _sfc_main = {
|
||||
})();
|
||||
if (!hasToken) {
|
||||
this.shopName = "未登录";
|
||||
this.avatarUrl = "/static/logo.png";
|
||||
this.avatarUrl = "/static/icons/icons8-mitt-24.png";
|
||||
this.mobile = "";
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await common_http.get("/api/dashboard/overview");
|
||||
} catch (e) {
|
||||
}
|
||||
try {
|
||||
const storeName = common_vendor.index.getStorageSync("SHOP_NAME") || "";
|
||||
const avatar = common_vendor.index.getStorageSync("USER_AVATAR") || "";
|
||||
const phone = common_vendor.index.getStorageSync("USER_MOBILE") || "";
|
||||
if (storeName)
|
||||
this.shopName = storeName;
|
||||
if (avatar)
|
||||
this.avatarUrl = avatar;
|
||||
const profile = await common_http.get("/api/user/me");
|
||||
const latestAvatar = (profile == null ? void 0 : profile.avatarUrl) || "";
|
||||
if (latestAvatar) {
|
||||
const bust = `${latestAvatar}${latestAvatar.includes("?") ? "&" : "?"}t=${Date.now()}`;
|
||||
this.avatarUrl = bust;
|
||||
try {
|
||||
common_vendor.index.setStorageSync("USER_AVATAR_RAW", latestAvatar);
|
||||
common_vendor.index.setStorageSync("USER_AVATAR", latestAvatar);
|
||||
} catch (_) {
|
||||
}
|
||||
} else {
|
||||
const cached = common_vendor.index.getStorageSync("USER_AVATAR") || "";
|
||||
this.avatarUrl = cached || "/static/icons/icons8-mitt-24.png";
|
||||
}
|
||||
const storeName = (profile == null ? void 0 : profile.name) || common_vendor.index.getStorageSync("SHOP_NAME") || "未命名店铺";
|
||||
this.shopName = storeName;
|
||||
const phone = (profile == null ? void 0 : profile.phone) || common_vendor.index.getStorageSync("USER_MOBILE") || "";
|
||||
this.mobile = phone;
|
||||
} catch (e) {
|
||||
try {
|
||||
const storeName = common_vendor.index.getStorageSync("SHOP_NAME") || "";
|
||||
const avatar = common_vendor.index.getStorageSync("USER_AVATAR") || "";
|
||||
const phone = common_vendor.index.getStorageSync("USER_MOBILE") || "";
|
||||
if (storeName)
|
||||
this.shopName = storeName;
|
||||
if (avatar)
|
||||
this.avatarUrl = avatar;
|
||||
this.mobile = phone;
|
||||
} catch (_) {
|
||||
}
|
||||
}
|
||||
},
|
||||
loadVipFromStorage() {
|
||||
async loadVip() {
|
||||
try {
|
||||
const isVip = String(common_vendor.index.getStorageSync("USER_VIP_IS_VIP") || "false").toLowerCase() === "true";
|
||||
const start = common_vendor.index.getStorageSync("USER_VIP_START") || "";
|
||||
const end = common_vendor.index.getStorageSync("USER_VIP_END") || "";
|
||||
this.vipIsVip = isVip;
|
||||
this.vipStart = start;
|
||||
this.vipEnd = end;
|
||||
const hasToken = (() => {
|
||||
try {
|
||||
return !!common_vendor.index.getStorageSync("TOKEN");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
if (!hasToken) {
|
||||
this.vipIsVip = false;
|
||||
this.vipStart = "";
|
||||
this.vipEnd = "";
|
||||
return;
|
||||
}
|
||||
const data = await common_http.get("/api/vip/status");
|
||||
const active = !!(data == null ? void 0 : data.isVip);
|
||||
this.vipIsVip = active;
|
||||
this.vipEnd = (data == null ? void 0 : data.expireAt) || "";
|
||||
let computedStart = "";
|
||||
const exp = this.vipEnd;
|
||||
if (exp) {
|
||||
const m = String(exp).match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?/);
|
||||
if (m) {
|
||||
const y = Number(m[1]);
|
||||
const mo = Number(m[2]) - 1;
|
||||
const da = Number(m[3]);
|
||||
const hh = Number(m[4] || "0");
|
||||
const mm = Number(m[5] || "0");
|
||||
const ss = Number(m[6] || "0");
|
||||
const startDate = new Date(y, mo - 1, da, hh, mm, ss);
|
||||
const y2 = startDate.getFullYear();
|
||||
const m2 = (startDate.getMonth() + 1).toString().padStart(2, "0");
|
||||
const d2 = startDate.getDate().toString().padStart(2, "0");
|
||||
const h2 = startDate.getHours().toString().padStart(2, "0");
|
||||
const i2 = startDate.getMinutes().toString().padStart(2, "0");
|
||||
computedStart = `${y2}-${m2}-${d2} ${h2}:${i2}`;
|
||||
}
|
||||
}
|
||||
this.vipStart = computedStart;
|
||||
try {
|
||||
common_vendor.index.setStorageSync("USER_VIP_IS_VIP", String(active));
|
||||
common_vendor.index.setStorageSync("USER_VIP_END", this.vipEnd);
|
||||
if (this.vipStart)
|
||||
common_vendor.index.setStorageSync("USER_VIP_START", this.vipStart);
|
||||
else
|
||||
common_vendor.index.removeStorageSync("USER_VIP_START");
|
||||
} catch (_) {
|
||||
}
|
||||
} catch (e) {
|
||||
try {
|
||||
const isVip = String(common_vendor.index.getStorageSync("USER_VIP_IS_VIP") || "false").toLowerCase() === "true";
|
||||
this.vipIsVip = isVip;
|
||||
this.vipStart = common_vendor.index.getStorageSync("USER_VIP_START") || "";
|
||||
this.vipEnd = common_vendor.index.getStorageSync("USER_VIP_END") || "";
|
||||
} catch (_) {
|
||||
}
|
||||
}
|
||||
},
|
||||
formatDisplay(value) {
|
||||
@@ -136,9 +228,6 @@ const _sfc_main = {
|
||||
goLogin() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/auth/login" });
|
||||
},
|
||||
goRegister() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/auth/register" });
|
||||
},
|
||||
onGetPhoneNumber(e) {
|
||||
if (this.logging)
|
||||
return;
|
||||
@@ -161,34 +250,16 @@ const _sfc_main = {
|
||||
common_vendor.index.navigateTo({ url: "/pages/my/sms-login" });
|
||||
},
|
||||
onAvatarError() {
|
||||
this.avatarUrl = "/static/logo.png";
|
||||
this.avatarUrl = "/static/icons/icons8-mitt-24.png";
|
||||
},
|
||||
goVip() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/my/vip" });
|
||||
},
|
||||
goMyOrders() {
|
||||
common_vendor.index.switchTab({ url: "/pages/detail/index" });
|
||||
},
|
||||
goSupplier() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/supplier/select" });
|
||||
},
|
||||
goCustomer() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/customer/select" });
|
||||
},
|
||||
goCustomerQuote() {
|
||||
common_vendor.index.showToast({ title: "客户报价(开发中)", icon: "none" });
|
||||
},
|
||||
goShop() {
|
||||
common_vendor.index.showToast({ title: "店铺管理(开发中)", icon: "none" });
|
||||
common_vendor.index.navigateTo({ url: "/pages/my/orders" });
|
||||
},
|
||||
editProfile() {
|
||||
common_vendor.index.showToast({ title: "账号与安全(开发中)", icon: "none" });
|
||||
},
|
||||
goProductSettings() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/product/settings" });
|
||||
},
|
||||
goSystemParams() {
|
||||
common_vendor.index.showToast({ title: "系统参数(开发中)", icon: "none" });
|
||||
common_vendor.index.navigateTo({ url: "/pages/my/security" });
|
||||
},
|
||||
goAbout() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/my/about" });
|
||||
@@ -201,9 +272,14 @@ const _sfc_main = {
|
||||
common_vendor.index.removeStorageSync("DEFAULT_USER_ID");
|
||||
common_vendor.index.setStorageSync("ENABLE_DEFAULT_USER", "false");
|
||||
common_vendor.index.removeStorageSync("USER_AVATAR");
|
||||
common_vendor.index.removeStorageSync("USER_AVATAR_RAW");
|
||||
common_vendor.index.removeStorageSync("USER_NAME");
|
||||
common_vendor.index.removeStorageSync("USER_MOBILE");
|
||||
common_vendor.index.removeStorageSync("USER_EMAIL");
|
||||
common_vendor.index.removeStorageSync("SHOP_NAME");
|
||||
common_vendor.index.removeStorageSync("USER_VIP_IS_VIP");
|
||||
common_vendor.index.removeStorageSync("USER_VIP_START");
|
||||
common_vendor.index.removeStorageSync("USER_VIP_END");
|
||||
common_vendor.index.showToast({ title: "已清理本地信息", icon: "none" });
|
||||
setTimeout(() => {
|
||||
common_vendor.index.reLaunch({ url: "/pages/index/index" });
|
||||
@@ -216,32 +292,32 @@ const _sfc_main = {
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return common_vendor.e({
|
||||
a: !$options.isLoggedIn
|
||||
}, !$options.isLoggedIn ? {
|
||||
b: common_vendor.o((...args) => $options.goLogin && $options.goLogin(...args)),
|
||||
c: common_vendor.o((...args) => $options.goRegister && $options.goRegister(...args))
|
||||
} : {}, {
|
||||
d: $data.avatarUrl,
|
||||
e: common_vendor.o((...args) => $options.onAvatarError && $options.onAvatarError(...args)),
|
||||
f: common_vendor.t($data.shopName),
|
||||
g: common_vendor.t($options.mobileDisplay),
|
||||
h: common_vendor.t($data.vipIsVip ? "VIP" : "非VIP"),
|
||||
i: common_vendor.t($options.vipStartDisplay),
|
||||
j: common_vendor.t($options.vipEndDisplay),
|
||||
k: $data.vipIsVip ? 1 : "",
|
||||
l: common_vendor.o((...args) => $options.goVip && $options.goVip(...args)),
|
||||
m: common_vendor.o((...args) => $options.goMyOrders && $options.goMyOrders(...args)),
|
||||
n: common_vendor.o((...args) => $options.goSupplier && $options.goSupplier(...args)),
|
||||
o: common_vendor.o((...args) => $options.goCustomer && $options.goCustomer(...args)),
|
||||
p: common_vendor.o((...args) => $options.goCustomerQuote && $options.goCustomerQuote(...args)),
|
||||
q: common_vendor.o((...args) => $options.goShop && $options.goShop(...args)),
|
||||
r: common_vendor.o((...args) => $options.editProfile && $options.editProfile(...args)),
|
||||
s: common_vendor.o((...args) => $options.goProductSettings && $options.goProductSettings(...args)),
|
||||
t: common_vendor.o((...args) => $options.goSystemParams && $options.goSystemParams(...args)),
|
||||
v: common_vendor.o((...args) => $options.goAbout && $options.goAbout(...args)),
|
||||
w: $options.isLoggedIn
|
||||
a: $options.isLoggedIn
|
||||
}, $options.isLoggedIn ? {
|
||||
x: common_vendor.o((...args) => $options.logout && $options.logout(...args))
|
||||
b: $options.avatarDisplay,
|
||||
c: common_vendor.o((...args) => $options.onAvatarError && $options.onAvatarError(...args)),
|
||||
d: common_vendor.t($data.shopName),
|
||||
e: common_vendor.t($options.emailDisplay)
|
||||
} : {
|
||||
f: common_assets._imports_0$1,
|
||||
g: common_vendor.o((...args) => $options.goLogin && $options.goLogin(...args))
|
||||
}, {
|
||||
h: $options.isLoggedIn
|
||||
}, $options.isLoggedIn ? {
|
||||
i: common_vendor.t($data.vipIsVip ? "VIP" : "非VIP"),
|
||||
j: common_vendor.t($options.vipStartDisplay),
|
||||
k: common_vendor.t($options.vipEndDisplay),
|
||||
l: $data.vipIsVip ? 1 : ""
|
||||
} : {}, {
|
||||
m: $data.vipIsVip
|
||||
}, $data.vipIsVip ? {} : {}, {
|
||||
n: common_vendor.o((...args) => $options.goVip && $options.goVip(...args)),
|
||||
o: common_vendor.o((...args) => $options.goMyOrders && $options.goMyOrders(...args)),
|
||||
p: common_vendor.o((...args) => $options.editProfile && $options.editProfile(...args)),
|
||||
q: common_vendor.o((...args) => $options.goAbout && $options.goAbout(...args)),
|
||||
r: $options.isLoggedIn
|
||||
}, $options.isLoggedIn ? {
|
||||
s: common_vendor.o((...args) => $options.logout && $options.logout(...args))
|
||||
} : {});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="me"><view wx:if="{{a}}" class="card login"><view class="login-title">登录/注册以同步数据</view><button class="login-btn" type="primary" bindtap="{{b}}">登录</button><button class="login-btn minor" bindtap="{{c}}">注册</button></view><view class="card user"><image class="avatar" src="{{d}}" mode="aspectFill" binderror="{{e}}"/><view class="meta"><text class="name">{{f}}</text><text class="phone">{{g}}</text><text class="role">老板</text></view></view><view class="{{['card', 'vip', k && 'active']}}"><view class="vip-row"><text class="vip-badge">{{h}}</text><text class="vip-title">会员状态</text></view><view class="vip-meta"><view class="item"><text class="label">开始</text><text class="value">{{i}}</text></view><view class="item"><text class="label">结束</text><text class="value">{{j}}</text></view></view></view><view class="group"><view class="group-title">会员与订单</view><view class="cell" bindtap="{{l}}"><text>VIP会员</text><text class="arrow">›</text></view><view class="cell" bindtap="{{m}}"><text>我的订单</text><text class="arrow">›</text></view></view><view class="group"><view class="group-title">基础管理</view><view class="cell" bindtap="{{n}}"><text>供应商管理</text><text class="arrow">›</text></view><view class="cell" bindtap="{{o}}"><text>客户管理</text><text class="arrow">›</text></view><view class="cell" bindtap="{{p}}"><text>客户报价</text><text class="arrow">›</text></view><view class="cell" bindtap="{{q}}"><text>店铺管理</text><text class="arrow">›</text></view></view><view class="group"><view class="group-title">设置中心</view><view class="cell" bindtap="{{r}}"><text>账号与安全</text><text class="desc">修改头像、姓名、密码</text><text class="arrow">›</text></view><view class="cell" bindtap="{{s}}"><text>商品设置</text><text class="arrow">›</text></view><view class="cell" bindtap="{{t}}"><text>系统参数</text><text class="desc">低价提示、默认收款、单行折扣等</text><text class="arrow">›</text></view><view class="cell" bindtap="{{v}}"><text>关于与协议</text><text class="arrow">›</text></view><view wx:if="{{w}}" class="cell danger" bindtap="{{x}}"><text>退出登录</text></view></view></view>
|
||||
<view class="me"><view wx:if="{{a}}" class="card user"><image class="avatar" src="{{b}}" mode="aspectFill" binderror="{{c}}"/><view class="meta"><text class="name">{{d}}</text><text class="phone">{{e}}</text><text class="role">老板</text></view></view><view wx:else class="card user guest"><image class="avatar" src="{{f}}" mode="aspectFill"/><view class="meta"><text class="name">未登录</text><text class="phone">登录后同步数据</text><text class="role">访客</text></view><button class="login-entry" bindtap="{{g}}">登录</button></view><view wx:if="{{h}}" class="{{['card', 'vip', l && 'active']}}"><view class="vip-row"><text class="vip-badge">{{i}}</text><text class="vip-title">会员状态</text></view><view class="vip-meta"><view class="item"><text class="label">开始</text><text class="value">{{j}}</text></view><view class="item"><text class="label">结束</text><text class="value">{{k}}</text></view></view></view><view class="group"><view class="group-title">会员与订单</view><view class="cell" bindtap="{{n}}"><view class="cell-left"><text>VIP会员</text><text wx:if="{{m}}" class="vip-tag">已开通</text><text wx:else class="vip-tag pending">待开通</text></view><text class="arrow">›</text></view><view class="cell" bindtap="{{o}}"><text>我的订单</text><text class="arrow">›</text></view></view><view class="group"><view class="group-title">设置中心</view><view class="cell" bindtap="{{p}}"><text>账号与安全</text><text class="desc">修改头像、姓名、密码、电话</text><text class="arrow">›</text></view><view class="cell" bindtap="{{q}}"><text>关于与协议</text><text class="arrow">›</text></view><view wx:if="{{r}}" class="cell danger" bindtap="{{s}}"><text>退出登录</text></view></view></view>
|
||||
@@ -57,6 +57,20 @@
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.16);
|
||||
align-items: center;
|
||||
}
|
||||
.card.user.guest {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.card.user.guest .meta {
|
||||
flex: 1;
|
||||
}
|
||||
.card.user.guest .login-entry {
|
||||
padding: 12rpx 30rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
@@ -151,6 +165,23 @@
|
||||
padding: 26rpx 22rpx;
|
||||
border-top: 1rpx solid #e5e7eb;
|
||||
color: #111;
|
||||
gap: 18rpx;
|
||||
}
|
||||
.cell-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14rpx;
|
||||
}
|
||||
.vip-tag {
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(76, 141, 255, 0.15);
|
||||
color: #4C8DFF;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
.vip-tag.pending {
|
||||
background: rgba(76, 141, 255, 0.06);
|
||||
color: #99a2b3;
|
||||
}
|
||||
.cell .desc {
|
||||
margin-left: auto;
|
||||
|
||||
75
frontend/unpackage/dist/dev/mp-weixin/pages/my/orders.js
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return { list: [], page: 1, size: 20, loading: false };
|
||||
},
|
||||
onShow() {
|
||||
this.fetch(true);
|
||||
},
|
||||
computed: {
|
||||
isLoggedIn() {
|
||||
try {
|
||||
return !!common_vendor.index.getStorageSync("TOKEN");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async fetch(reset = false) {
|
||||
if (!this.isLoggedIn)
|
||||
return;
|
||||
if (this.loading)
|
||||
return;
|
||||
this.loading = true;
|
||||
try {
|
||||
const p = reset ? 1 : this.page;
|
||||
const data = await common_http.get("/api/vip/recharges", { page: p, size: this.size });
|
||||
const arr = Array.isArray(data == null ? void 0 : data.list) ? data.list : [];
|
||||
this.list = reset ? arr : (this.list || []).concat(arr);
|
||||
this.page = p + 1;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
fmt(v) {
|
||||
if (!v)
|
||||
return "";
|
||||
const s = String(v);
|
||||
const m = s.match(/^(\d{4}-\d{2}-\d{2})([ T](\d{2}:\d{2}))/);
|
||||
return m ? `${m[1]} ${m[3]}` : s;
|
||||
},
|
||||
toMoney(v) {
|
||||
try {
|
||||
return Number(v).toFixed(2);
|
||||
} catch (_) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return common_vendor.e({
|
||||
a: !$options.isLoggedIn
|
||||
}, !$options.isLoggedIn ? {} : common_vendor.e({
|
||||
b: common_vendor.f($data.list, (it, k0, i0) => {
|
||||
return common_vendor.e({
|
||||
a: common_vendor.t($options.toMoney(it.price)),
|
||||
b: common_vendor.t(it.channel || "支付"),
|
||||
c: common_vendor.t($options.fmt(it.createdAt)),
|
||||
d: common_vendor.t(it.durationDays),
|
||||
e: it.expireTo
|
||||
}, it.expireTo ? {
|
||||
f: common_vendor.t($options.fmt(it.expireTo))
|
||||
} : {}, {
|
||||
g: it.id
|
||||
});
|
||||
}),
|
||||
c: $data.list.length === 0
|
||||
}, $data.list.length === 0 ? {} : {}));
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/my/orders.js.map
|
||||
4
frontend/unpackage/dist/dev/mp-weixin/pages/my/orders.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "我的订单",
|
||||
"usingComponents": {}
|
||||
}
|
||||
1
frontend/unpackage/dist/dev/mp-weixin/pages/my/orders.wxml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<view class="orders"><view wx:if="{{a}}" class="hint">请先登录后查看VIP支付记录</view><view wx:else><view wx:for="{{b}}" wx:for-item="it" wx:key="g" class="item"><view class="row1"><text class="price">¥ {{it.a}}</text><text class="channel">{{it.b}}</text></view><view class="row2"><text class="date">{{it.c}}</text><text class="duration">{{it.d}} 天</text></view><view wx:if="{{it.e}}" class="row3"><text class="expire">有效期至 {{it.f}}</text></view></view><view wx:if="{{c}}" class="empty">暂无支付记录</view></view></view>
|
||||
@@ -24,58 +24,49 @@
|
||||
/* 垂直间距 */
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
.login {
|
||||
min-height: 100vh;
|
||||
padding: 24rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.card {
|
||||
margin-top: 60rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 800;
|
||||
margin-bottom: 16rpx;
|
||||
color: #111;
|
||||
}
|
||||
.field {
|
||||
position: relative;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.label {
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
color: #444;
|
||||
}
|
||||
.input {
|
||||
width: 100%;
|
||||
background: #f1f1f1;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border-radius: 12rpx;
|
||||
padding: 14rpx;
|
||||
color: #111;
|
||||
}
|
||||
.toggle {
|
||||
position: absolute;
|
||||
right: 12rpx;
|
||||
top: 64rpx;
|
||||
color: #4C8DFF;
|
||||
font-size: 26rpx;
|
||||
.orders {
|
||||
padding: 16rpx 16rpx calc(env(safe-area-inset-bottom) + 16rpx);
|
||||
}
|
||||
.hint {
|
||||
color: #444;
|
||||
font-size: 24rpx;
|
||||
margin: 8rpx 0 16rpx;
|
||||
padding: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.primary {
|
||||
width: 100%;
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
border-radius: 999rpx;
|
||||
padding: 20rpx 0;
|
||||
.item {
|
||||
background: #fff;
|
||||
border: 1rpx solid #e5e7eb;
|
||||
border-radius: 16rpx;
|
||||
padding: 18rpx;
|
||||
margin: 12rpx 0;
|
||||
}
|
||||
.row1 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
.price {
|
||||
color: #111;
|
||||
font-weight: 800;
|
||||
font-size: 34rpx;
|
||||
}
|
||||
.channel {
|
||||
color: #666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.row2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.row3 {
|
||||
margin-top: 6rpx;
|
||||
color: #4C8DFF;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.empty {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return {
|
||||
form: { phone: "", password: "" },
|
||||
showPwd: false,
|
||||
submitting: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
validatePhone(p) {
|
||||
return /^1\d{10}$/.test(String(p || ""));
|
||||
},
|
||||
validate() {
|
||||
if (!this.validatePhone(this.form.phone)) {
|
||||
common_vendor.index.showToast({ title: "请输入有效手机号", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
if (!this.form.password) {
|
||||
common_vendor.index.showToast({ title: "请输入密码", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
if (this.form.password.length < 6) {
|
||||
common_vendor.index.showToast({ title: "密码至少6位", icon: "none" });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
submit() {
|
||||
if (this.submitting)
|
||||
return;
|
||||
if (!this.validate())
|
||||
return;
|
||||
this.submitting = true;
|
||||
try {
|
||||
common_vendor.index.setStorageSync("LOGIN_STATUS", "logged_in");
|
||||
common_vendor.index.setStorageSync("LOGIN_PHONE", this.form.phone);
|
||||
try {
|
||||
const uid = common_vendor.index.getStorageSync("DEFAULT_USER_ID") || "";
|
||||
const enable = common_vendor.index.getStorageSync("ENABLE_DEFAULT_USER") || "";
|
||||
if (!enable)
|
||||
common_vendor.index.setStorageSync("ENABLE_DEFAULT_USER", "true");
|
||||
if (!uid)
|
||||
common_vendor.index.setStorageSync("DEFAULT_USER_ID", "2");
|
||||
} catch (e) {
|
||||
}
|
||||
common_vendor.index.showToast({ title: "登录成功(本地)", icon: "none" });
|
||||
setTimeout(() => {
|
||||
common_vendor.index.reLaunch({ url: "/pages/index/index" });
|
||||
}, 500);
|
||||
} finally {
|
||||
this.submitting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return {
|
||||
a: $data.form.phone,
|
||||
b: common_vendor.o(common_vendor.m(($event) => $data.form.phone = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
c: !$data.showPwd,
|
||||
d: $data.form.password,
|
||||
e: common_vendor.o(common_vendor.m(($event) => $data.form.password = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
f: common_vendor.t($data.showPwd ? "隐藏" : "显示"),
|
||||
g: common_vendor.o(($event) => $data.showPwd = !$data.showPwd),
|
||||
h: $data.submitting,
|
||||
i: common_vendor.o((...args) => $options.submit && $options.submit(...args))
|
||||
};
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/my/password-login.js.map
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "账号登录",
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<view class="login"><view class="card"><view class="title">手机号登录</view><view class="field"><text class="label">手机号</text><input class="input" type="number" placeholder="请输入手机号" maxlength="11" value="{{a}}" bindinput="{{b}}"/></view><view class="field"><text class="label">密码</text><input class="input" password="{{c}}" placeholder="请输入密码" maxlength="32" value="{{d}}" bindinput="{{e}}"/><view class="toggle" bindtap="{{g}}">{{f}}</view></view><view class="hint">本页面为静态实现,不调用后端接口,仅做本地校验与存储。</view><button class="primary" disabled="{{h}}" bindtap="{{i}}">登录</button></view></view>
|
||||
196
frontend/unpackage/dist/dev/mp-weixin/pages/my/security.js
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const common_config = require("../../common/config.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return {
|
||||
form: { name: "", avatarUrl: "" },
|
||||
pwd: { oldPassword: "", newPassword: "" },
|
||||
phone: { phone: "" },
|
||||
savingProfile: false,
|
||||
savingPwd: false,
|
||||
savingPhone: false,
|
||||
sendingCode: false,
|
||||
originalAvatarUrl: ""
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
this.loadProfile();
|
||||
},
|
||||
computed: {
|
||||
avatarPreview() {
|
||||
return this.normalizeAvatar(this.form.avatarUrl);
|
||||
},
|
||||
canSendPhone() {
|
||||
const p = String(this.phone.phone || "").trim();
|
||||
return /^1\d{10}$/.test(p);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadProfile() {
|
||||
try {
|
||||
const data = await common_http.get("/api/user/me");
|
||||
const rawAvatar = (data == null ? void 0 : data.avatarUrl) || (common_vendor.index.getStorageSync("USER_AVATAR_RAW") || "");
|
||||
this.originalAvatarUrl = rawAvatar;
|
||||
this.form.name = (data == null ? void 0 : data.name) || (common_vendor.index.getStorageSync("USER_NAME") || "");
|
||||
this.form.avatarUrl = rawAvatar;
|
||||
} catch (e) {
|
||||
}
|
||||
},
|
||||
normalizeAvatar(url) {
|
||||
if (!url)
|
||||
return "/static/icons/icons8-mitt-24.png";
|
||||
const s = String(url);
|
||||
if (/^https?:\/\//i.test(s))
|
||||
return s;
|
||||
const base = common_config.API_BASE_URL || "";
|
||||
if (!base)
|
||||
return s;
|
||||
if (s.startsWith("/"))
|
||||
return `${base}${s}`;
|
||||
return `${base}/${s}`;
|
||||
},
|
||||
openAvatarDialog() {
|
||||
common_vendor.index.showActionSheet({
|
||||
itemList: ["粘贴图片URL", "从相册选择并上传"],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
common_vendor.index.showModal({
|
||||
title: "头像URL",
|
||||
editable: true,
|
||||
placeholderText: "https://...",
|
||||
success: async (m) => {
|
||||
if (m.confirm && m.content) {
|
||||
this.form.avatarUrl = m.content.trim();
|
||||
await this.saveProfile({ auto: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (res.tapIndex === 1) {
|
||||
common_vendor.index.chooseImage({ count: 1, sizeType: ["compressed"], success: (ci) => {
|
||||
const filePath = ci.tempFilePaths && ci.tempFilePaths[0] || "";
|
||||
if (!filePath)
|
||||
return;
|
||||
common_vendor.index.showLoading({ title: "上传中..." });
|
||||
common_http.upload("/api/attachments", filePath, { ownerType: "user_avatar", ownerId: 0 }).then(async (data) => {
|
||||
const url = data && (data.url || data.path);
|
||||
if (url) {
|
||||
this.form.avatarUrl = url;
|
||||
await this.saveProfile({ auto: true });
|
||||
}
|
||||
common_vendor.index.showToast({ title: "已上传", icon: "success" });
|
||||
}).catch((e) => {
|
||||
common_vendor.index.showToast({ title: e && e.message || "上传失败", icon: "none" });
|
||||
}).finally(() => {
|
||||
common_vendor.index.hideLoading();
|
||||
});
|
||||
} });
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
async saveProfile(opts = {}) {
|
||||
const auto = opts && opts.auto;
|
||||
const payload = {};
|
||||
if (this.form.name && this.form.name !== common_vendor.index.getStorageSync("USER_NAME"))
|
||||
payload.name = this.form.name;
|
||||
if (this.form.avatarUrl && this.form.avatarUrl !== this.originalAvatarUrl)
|
||||
payload.avatarUrl = this.form.avatarUrl;
|
||||
if (Object.keys(payload).length === 0) {
|
||||
if (!auto)
|
||||
common_vendor.index.showToast({ title: "无需修改", icon: "none" });
|
||||
return;
|
||||
}
|
||||
if (this.savingProfile)
|
||||
return;
|
||||
this.savingProfile = true;
|
||||
try {
|
||||
await common_http.put("/api/user/me", payload);
|
||||
try {
|
||||
if (payload.name)
|
||||
common_vendor.index.setStorageSync("USER_NAME", payload.name);
|
||||
if (payload.avatarUrl) {
|
||||
const rawUrl = payload.avatarUrl;
|
||||
const displayUrl = `${rawUrl}${rawUrl.includes("?") ? "&" : "?"}t=${Date.now()}`;
|
||||
common_vendor.index.setStorageSync("USER_AVATAR_RAW", rawUrl);
|
||||
common_vendor.index.setStorageSync("USER_AVATAR", rawUrl);
|
||||
this.originalAvatarUrl = rawUrl;
|
||||
this.form.avatarUrl = rawUrl;
|
||||
}
|
||||
} catch (_) {
|
||||
}
|
||||
if (!payload.avatarUrl && this.form.avatarUrl) {
|
||||
common_vendor.index.setStorageSync("USER_AVATAR_RAW", this.form.avatarUrl);
|
||||
common_vendor.index.setStorageSync("USER_AVATAR", this.form.avatarUrl);
|
||||
}
|
||||
common_vendor.index.showToast({ title: auto ? "头像已更新" : "已保存", icon: "success" });
|
||||
} catch (e) {
|
||||
const msg = e && e.message || "保存失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.savingProfile = false;
|
||||
}
|
||||
},
|
||||
async changePassword() {
|
||||
if (!this.pwd.newPassword || this.pwd.newPassword.length < 6)
|
||||
return common_vendor.index.showToast({ title: "新密码至少6位", icon: "none" });
|
||||
this.savingPwd = true;
|
||||
try {
|
||||
await common_http.put("/api/user/me/password", { oldPassword: this.pwd.oldPassword || void 0, newPassword: this.pwd.newPassword });
|
||||
this.pwd.oldPassword = "";
|
||||
this.pwd.newPassword = "";
|
||||
common_vendor.index.showToast({ title: "密码已修改", icon: "success" });
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: e && e.message || "修改失败", icon: "none" });
|
||||
} finally {
|
||||
this.savingPwd = false;
|
||||
}
|
||||
},
|
||||
async changePhoneDirect() {
|
||||
if (!this.canSendPhone)
|
||||
return common_vendor.index.showToast({ title: "请输入正确手机号", icon: "none" });
|
||||
this.savingPhone = true;
|
||||
try {
|
||||
await common_http.put("/api/user/me/phone", { phone: this.phone.phone });
|
||||
common_vendor.index.setStorageSync("USER_MOBILE", this.phone.phone);
|
||||
common_vendor.index.showToast({ title: "手机号已保存", icon: "success" });
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: e && e.message || "保存失败", icon: "none" });
|
||||
} finally {
|
||||
this.savingPhone = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return {
|
||||
a: $options.avatarPreview,
|
||||
b: common_vendor.o((...args) => $options.openAvatarDialog && $options.openAvatarDialog(...args)),
|
||||
c: $data.form.name,
|
||||
d: common_vendor.o(common_vendor.m(($event) => $data.form.name = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
e: $data.savingProfile,
|
||||
f: common_vendor.o((...args) => $options.saveProfile && $options.saveProfile(...args)),
|
||||
g: $data.pwd.oldPassword,
|
||||
h: common_vendor.o(common_vendor.m(($event) => $data.pwd.oldPassword = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
i: $data.pwd.newPassword,
|
||||
j: common_vendor.o(common_vendor.m(($event) => $data.pwd.newPassword = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
k: $data.savingPwd,
|
||||
l: common_vendor.o((...args) => $options.changePassword && $options.changePassword(...args)),
|
||||
m: $data.phone.phone,
|
||||
n: common_vendor.o(common_vendor.m(($event) => $data.phone.phone = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
o: $data.savingPhone,
|
||||
p: common_vendor.o((...args) => $options.changePhoneDirect && $options.changePhoneDirect(...args))
|
||||
};
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/my/security.js.map
|
||||
4
frontend/unpackage/dist/dev/mp-weixin/pages/my/security.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "账号与安全",
|
||||
"usingComponents": {}
|
||||
}
|
||||
1
frontend/unpackage/dist/dev/mp-weixin/pages/my/security.wxml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<view class="security"><view class="card"><view class="cell" bindtap="{{b}}"><text class="cell-label">头像</text><image class="avatar-preview" src="{{a}}" mode="aspectFill"/><text class="arrow">›</text></view><view class="cell"><text class="cell-label">姓名</text><input class="cell-input" type="text" placeholder="请输入姓名" value="{{c}}" bindinput="{{d}}"/></view><button class="btn" type="primary" loading="{{e}}" bindtap="{{f}}">保存资料</button></view><view class="card"><view class="row"><text class="label">旧密码</text><input class="input" password placeholder="如从未设置可留空" value="{{g}}" bindinput="{{h}}"/></view><view class="row"><text class="label">新密码</text><input class="input" password placeholder="至少6位" value="{{i}}" bindinput="{{j}}"/></view><button class="btn" loading="{{k}}" bindtap="{{l}}">修改密码</button></view><view class="card"><view class="row"><text class="label">手机号</text><input class="input" type="text" placeholder="11位手机号" value="{{m}}" bindinput="{{n}}"/></view><button class="btn" loading="{{o}}" bindtap="{{p}}">保存手机号</button></view></view>
|
||||
@@ -24,81 +24,75 @@
|
||||
/* 垂直间距 */
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
.sms-login {
|
||||
.security {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 28rpx;
|
||||
padding: 22rpx;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.form {
|
||||
.cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #e5e7eb;
|
||||
}
|
||||
.cell:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
.cell-label {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #111;
|
||||
}
|
||||
.cell-input {
|
||||
flex: 2;
|
||||
height: 72rpx;
|
||||
padding: 0 16rpx;
|
||||
border: 1rpx solid #e5e7eb;
|
||||
border-radius: 10rpx;
|
||||
background: #fff;
|
||||
color: #111;
|
||||
}
|
||||
.avatar-preview {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f1f1f1;
|
||||
}
|
||||
.arrow {
|
||||
margin-left: 12rpx;
|
||||
color: #99a2b3;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.label {
|
||||
width: 160rpx;
|
||||
color: #111;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.input {
|
||||
background: #fff;
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
padding: 0 16rpx;
|
||||
border: 1rpx solid #e5e7eb;
|
||||
border-radius: 12rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
flex: 1;
|
||||
border-radius: 10rpx;
|
||||
background: #fff;
|
||||
color: #111;
|
||||
}
|
||||
.input.code {
|
||||
flex: 1;
|
||||
}
|
||||
.send {
|
||||
min-width: 220rpx;
|
||||
}
|
||||
.login {
|
||||
.btn {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
.hint {
|
||||
margin-top: 12rpx;
|
||||
font-size: 22rpx;
|
||||
color: #444;
|
||||
}
|
||||
.debug {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.debug-title {
|
||||
font-size: 26rpx;
|
||||
color: #444;
|
||||
}
|
||||
.debug-body {
|
||||
margin-top: 12rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
.code-title {
|
||||
font-size: 24rpx;
|
||||
color: #444;
|
||||
}
|
||||
.code-wrap {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border: 1rpx solid #e5e7eb;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx;
|
||||
}
|
||||
.code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 24rpx;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.copy {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
.btn.minor {
|
||||
background: #f1f1f1;
|
||||
color: #111;
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return { phone: "", code: "", countdown: 0, timer: null, sending: false, logging: false, showDebug: true };
|
||||
},
|
||||
computed: {
|
||||
btnText() {
|
||||
return this.countdown > 0 ? `${this.countdown}s` : this.sending ? "发送中..." : "获取验证码";
|
||||
},
|
||||
trimmedPhone() {
|
||||
return String(this.phone || "").trim();
|
||||
},
|
||||
sendBodyJson() {
|
||||
return JSON.stringify({ phone: this.trimmedPhone, scene: "login" }, null, 2);
|
||||
},
|
||||
loginBodyJson() {
|
||||
return JSON.stringify({ phone: this.trimmedPhone, code: String(this.code || "").trim() }, null, 2);
|
||||
}
|
||||
},
|
||||
onUnload() {
|
||||
if (this.timer)
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
methods: {
|
||||
validatePhone(p) {
|
||||
return /^1\d{10}$/.test(String(p || "").trim());
|
||||
},
|
||||
startCountdown(sec) {
|
||||
this.countdown = sec;
|
||||
if (this.timer)
|
||||
clearInterval(this.timer);
|
||||
this.timer = setInterval(() => {
|
||||
if (this.countdown <= 1) {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
this.countdown = 0;
|
||||
return;
|
||||
}
|
||||
this.countdown--;
|
||||
}, 1e3);
|
||||
},
|
||||
async sendCode() {
|
||||
if (this.sending || this.countdown > 0)
|
||||
return;
|
||||
const p = String(this.phone || "").trim();
|
||||
if (!this.validatePhone(p))
|
||||
return common_vendor.index.showToast({ title: "请输入正确的手机号", icon: "none" });
|
||||
this.sending = true;
|
||||
try {
|
||||
const res = await common_http.post("/api/auth/sms/send", { phone: p, scene: "login" });
|
||||
const cd = Number(res && res.cooldownSec || 60);
|
||||
this.startCountdown(cd);
|
||||
common_vendor.index.showToast({ title: "验证码已发送", icon: "none" });
|
||||
} catch (e) {
|
||||
const msg = e && e.message || "发送失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.sending = false;
|
||||
}
|
||||
},
|
||||
async doLogin() {
|
||||
if (this.logging)
|
||||
return;
|
||||
const p = String(this.phone || "").trim();
|
||||
const c = String(this.code || "").trim();
|
||||
if (!this.validatePhone(p))
|
||||
return common_vendor.index.showToast({ title: "请输入正确的手机号", icon: "none" });
|
||||
if (!/^\d{6}$/.test(c))
|
||||
return common_vendor.index.showToast({ title: "验证码格式不正确", icon: "none" });
|
||||
this.logging = true;
|
||||
try {
|
||||
const data = await common_http.post("/api/auth/sms/login", { phone: p, code: c });
|
||||
if (data && data.token) {
|
||||
common_vendor.index.setStorageSync("TOKEN", data.token);
|
||||
if (data.user && data.user.phone)
|
||||
common_vendor.index.setStorageSync("USER_MOBILE", data.user.phone);
|
||||
common_vendor.index.showToast({ title: "登录成功", icon: "none" });
|
||||
setTimeout(() => {
|
||||
common_vendor.index.reLaunch({ url: "/pages/index/index" });
|
||||
}, 300);
|
||||
}
|
||||
} catch (e) {
|
||||
const msg = e && e.message || "登录失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.logging = false;
|
||||
}
|
||||
},
|
||||
async quickRegister() {
|
||||
if (this.logging)
|
||||
return;
|
||||
const p = String(this.phone || "").trim();
|
||||
if (!this.validatePhone(p))
|
||||
return common_vendor.index.showToast({ title: "请输入正确的手机号", icon: "none" });
|
||||
this.logging = true;
|
||||
try {
|
||||
const data = await common_http.post("/api/auth/register", { phone: p });
|
||||
if (data && data.token) {
|
||||
common_vendor.index.setStorageSync("TOKEN", data.token);
|
||||
if (data.user && data.user.phone)
|
||||
common_vendor.index.setStorageSync("USER_MOBILE", data.user.phone);
|
||||
common_vendor.index.showToast({ title: "注册成功", icon: "none" });
|
||||
setTimeout(() => {
|
||||
common_vendor.index.reLaunch({ url: "/pages/index/index" });
|
||||
}, 300);
|
||||
}
|
||||
} catch (e) {
|
||||
const msg = e && e.message || "注册失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.logging = false;
|
||||
}
|
||||
},
|
||||
copy(text) {
|
||||
try {
|
||||
common_vendor.index.setClipboardData({ data: String(text || "") });
|
||||
common_vendor.index.showToast({ title: "已复制", icon: "none" });
|
||||
} catch (e) {
|
||||
}
|
||||
},
|
||||
toggleDebug() {
|
||||
this.showDebug = !this.showDebug;
|
||||
}
|
||||
}
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return common_vendor.e({
|
||||
a: $data.phone,
|
||||
b: common_vendor.o(($event) => $data.phone = $event.detail.value),
|
||||
c: $data.code,
|
||||
d: common_vendor.o(($event) => $data.code = $event.detail.value),
|
||||
e: common_vendor.t($options.btnText),
|
||||
f: $data.countdown > 0 || $data.sending,
|
||||
g: common_vendor.o((...args) => $options.sendCode && $options.sendCode(...args)),
|
||||
h: $data.logging,
|
||||
i: common_vendor.o((...args) => $options.doLogin && $options.doLogin(...args)),
|
||||
j: $data.logging,
|
||||
k: common_vendor.o((...args) => $options.quickRegister && $options.quickRegister(...args)),
|
||||
l: common_vendor.t($data.showDebug ? "收起" : "展开"),
|
||||
m: common_vendor.o((...args) => $options.toggleDebug && $options.toggleDebug(...args)),
|
||||
n: $data.showDebug
|
||||
}, $data.showDebug ? {
|
||||
o: common_vendor.t($options.sendBodyJson),
|
||||
p: common_vendor.o(($event) => $options.copy($options.sendBodyJson)),
|
||||
q: common_vendor.t($options.loginBodyJson),
|
||||
r: common_vendor.o(($event) => $options.copy($options.loginBodyJson))
|
||||
} : {});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/my/sms-login.js.map
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "短信验证码登录",
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<view class="page sms-login"><view class="card"><view class="title">短信验证码登录</view><view class="form"><input class="input" type="number" maxlength="11" placeholder="请输入手机号" value="{{a}}" bindinput="{{b}}"/><view class="row"><input class="input code" type="number" maxlength="6" placeholder="请输入验证码" value="{{c}}" bindinput="{{d}}"/><button class="send" disabled="{{f}}" bindtap="{{g}}">{{e}}</button></view><button class="login" type="primary" disabled="{{h}}" bindtap="{{i}}">登录/注册</button><button class="login" disabled="{{j}}" bindtap="{{k}}">注册为店主</button></view><view class="hint">首次登录将自动创建店铺与店主用户。</view><view class="debug"><view class="debug-title" bindtap="{{m}}">请求体示例(点击{{l}})</view><view wx:if="{{n}}" class="debug-body"><view class="code-title">POST /api/auth/sms/send</view><view class="code-wrap"><text class="code">{{o}}</text><button size="mini" class="copy" bindtap="{{p}}">复制</button></view><view class="code-title">POST /api/auth/sms/login</view><view class="code-wrap"><text class="code">{{q}}</text><button size="mini" class="copy" bindtap="{{r}}">复制</button></view></view></view></view></view>
|
||||
@@ -1,50 +1,87 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_config = require("../../common/config.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const common_assets = require("../../common/assets.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return {
|
||||
isVip: false,
|
||||
expire: "",
|
||||
price: common_config.VIP_PRICE_PER_MONTH
|
||||
price: 0,
|
||||
benefits: []
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
this.loadVip();
|
||||
this.composeBenefits();
|
||||
},
|
||||
computed: {
|
||||
expireDisplay() {
|
||||
const s = String(this.expire || "");
|
||||
return s || "11年11月11日";
|
||||
},
|
||||
priceDisplay() {
|
||||
const n = Number(this.price);
|
||||
return Number.isFinite(n) && n > 0 ? n.toFixed(2) : "0.00";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadVip() {
|
||||
composeBenefits() {
|
||||
this.benefits = [
|
||||
{ key: "history", title: "完整历史留存", desc: "无限期保留交易、库存与客户数据", icon: "/static/icons/icons8-graph-report-50.png" },
|
||||
{ key: "analysis", title: "高级统计面板", desc: "秒级汇总销售毛利,掌握生意节奏", icon: "/static/icons/icons8-profit-50.png" },
|
||||
{ key: "priority", title: "优先客服支持", desc: "遇到问题优先处理,响应更迅速", icon: "/static/icons/icons8-account-male-100.png" }
|
||||
];
|
||||
},
|
||||
async loadVip() {
|
||||
try {
|
||||
this.isVip = String(common_vendor.index.getStorageSync("USER_VIP_IS_VIP") || "false").toLowerCase() === "true";
|
||||
this.expire = common_vendor.index.getStorageSync("USER_VIP_END") || "";
|
||||
const data = await common_http.get("/api/vip/status");
|
||||
this.isVip = !!(data == null ? void 0 : data.isVip);
|
||||
this.expire = (data == null ? void 0 : data.expireAt) || "";
|
||||
if (typeof (data == null ? void 0 : data.price) === "number")
|
||||
this.price = data.price;
|
||||
} catch (e) {
|
||||
this.isVip = false;
|
||||
}
|
||||
},
|
||||
onPay() {
|
||||
common_vendor.index.showToast({ title: "静态页面演示:支付功能未接入", icon: "none" });
|
||||
async onPay() {
|
||||
try {
|
||||
await common_http.post("/api/vip/pay", {});
|
||||
common_vendor.index.showToast({ title: "已开通VIP", icon: "success" });
|
||||
await this.loadVip();
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: String(e.message || "开通失败"), icon: "none" });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return common_vendor.e({
|
||||
a: common_vendor.t($data.isVip ? "VIP会员" : "成为VIP会员"),
|
||||
b: common_vendor.t($data.isVip ? "尊享专属特权" : "解锁更多权益"),
|
||||
c: common_vendor.t($data.isVip ? "VIP会员" : "普通用户"),
|
||||
d: $data.isVip ? 1 : "",
|
||||
e: $data.isVip
|
||||
a: common_assets._imports_0$3,
|
||||
b: common_vendor.t($data.isVip ? "VIP会员" : "升级 VIP 会员"),
|
||||
c: common_vendor.t($data.isVip ? "尊享完整数据与高效体验" : "开通后可查看全部历史数据并解锁高级功能"),
|
||||
d: common_vendor.t($data.isVip ? "已开通" : "普通用户"),
|
||||
e: $data.isVip ? 1 : "",
|
||||
f: $data.isVip
|
||||
}, $data.isVip ? {
|
||||
f: common_vendor.t($options.expireDisplay)
|
||||
} : {}, {
|
||||
g: !$data.isVip
|
||||
g: common_vendor.t($options.expireDisplay)
|
||||
} : {
|
||||
h: common_vendor.t($options.priceDisplay)
|
||||
}, {
|
||||
i: common_vendor.f($data.benefits, (item, k0, i0) => {
|
||||
return common_vendor.e({
|
||||
a: item.icon
|
||||
}, item.icon ? {
|
||||
b: item.icon
|
||||
} : {}, {
|
||||
c: common_vendor.t(item.title),
|
||||
d: common_vendor.t(item.desc),
|
||||
e: item.key
|
||||
});
|
||||
}),
|
||||
j: !$data.isVip
|
||||
}, !$data.isVip ? {
|
||||
h: common_vendor.t($data.price),
|
||||
i: common_vendor.o((...args) => $options.onPay && $options.onPay(...args))
|
||||
k: common_vendor.o((...args) => $options.onPay && $options.onPay(...args))
|
||||
} : {});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="vip-page" style="background:linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);min-height:100vh"><view class="main-content"><view class="vip-header"><view class="vip-crown"><text class="crown-icon">👑</text></view><text class="vip-title">{{a}}</text><text class="vip-subtitle">{{b}}</text><view class="{{['vip-status', d && 'active']}}"><text class="status-text">{{c}}</text></view></view><view class="features-section"><text class="section-title">会员功能</text><view class="feature-card"><view class="feature-icon">💾</view><text class="feature-text">永久存储数据</text></view></view><view wx:if="{{e}}" class="vip-info"><view class="info-card"><text class="info-label">会员状态</text><text class="info-value active">已激活</text></view><view class="info-card"><text class="info-label">有效期至</text><text class="info-value">{{f}}</text></view></view><view wx:if="{{g}}" class="purchase-section"><view class="price-card"><text class="price-label">会员价格</text><view class="price-display"><text class="price-symbol">¥</text><text class="price-amount">{{h}}</text><text class="price-period">/月</text></view></view><button class="purchase-btn" bindtap="{{i}}"><text class="btn-text">立即开通VIP</text></button></view></view><view class="bg-decoration"><view class="decoration-circle circle-1"></view><view class="decoration-circle circle-2"></view><view class="decoration-circle circle-3"></view></view></view>
|
||||
<view class="vip-page"><view class="vip-hero"><image class="hero-icon" src="{{a}}" mode="aspectFit"/><view class="hero-text"><text class="hero-title">{{b}}</text><text class="hero-subtitle">{{c}}</text></view><view class="{{['status-pill', e && 'active']}}"><text>{{d}}</text></view></view><view wx:if="{{f}}" class="vip-summary"><view class="summary-item"><text class="summary-label">会员状态</text><text class="summary-value success">已激活</text></view><view class="summary-item"><text class="summary-label">有效期至</text><text class="summary-value">{{g}}</text></view></view><view wx:else class="vip-summary"><view class="summary-item"><text class="summary-label">当前身份</text><text class="summary-value">普通用户</text></view><view class="summary-item"><text class="summary-label">会员价格</text><text class="summary-value highlight">¥{{h}}/月</text></view></view><view class="benefit-section"><view class="section-header"><text class="section-title">会员特权</text><text class="section-subtitle">聚焦数据留存与专业形象,让经营更有底气</text></view><view class="benefit-grid"><view wx:for="{{i}}" wx:for-item="item" wx:key="e" class="benefit-card"><image wx:if="{{item.a}}" src="{{item.b}}" class="benefit-icon" mode="aspectFit"/><text class="benefit-title">{{item.c}}</text><text class="benefit-desc">{{item.d}}</text></view></view></view><view wx:if="{{j}}" class="purchase-card"><view class="purchase-text"><text class="purchase-title">立即升级 VIP</text><text class="purchase-desc">不限历史数据、专属标识,助您高效管账</text></view><button class="purchase-btn" bindtap="{{k}}"><text>立即开通</text></button></view></view>
|
||||
@@ -25,240 +25,207 @@
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
page {
|
||||
background: #1a1a2e !important;
|
||||
background: linear-gradient(180deg, #f8fbff 0%, #ffffff 60%) !important;
|
||||
}
|
||||
.vip-page {
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%) !important;
|
||||
overflow: hidden;
|
||||
padding: 32rpx 24rpx 120rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 28rpx;
|
||||
}
|
||||
.main-content {
|
||||
flex: 1;
|
||||
padding: 60rpx 40rpx 40rpx;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* VIP头部区域 */
|
||||
.vip-header {
|
||||
text-align: center;
|
||||
margin-bottom: 80rpx;
|
||||
}
|
||||
.vip-header .vip-crown {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.vip-header .vip-crown .crown-icon {
|
||||
font-size: 80rpx;
|
||||
filter: drop-shadow(0 4rpx 12rpx rgba(255, 215, 0, 0.3));
|
||||
}
|
||||
.vip-header .vip-title {
|
||||
display: block;
|
||||
font-size: 48rpx;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.vip-header .vip-subtitle {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
.vip-header .vip-status {
|
||||
display: inline-block;
|
||||
padding: 16rpx 32rpx;
|
||||
border-radius: 50rpx;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
-webkit-backdrop-filter: blur(10rpx);
|
||||
backdrop-filter: blur(10rpx);
|
||||
border: 1rpx solid rgba(255, 215, 0, 0.4);
|
||||
}
|
||||
.vip-header .vip-status.active {
|
||||
background: linear-gradient(45deg, #ffd700, #ffed4e);
|
||||
border: 1rpx solid rgba(255, 215, 0, 0.3);
|
||||
}
|
||||
.vip-header .vip-status.active .status-text {
|
||||
color: #333;
|
||||
}
|
||||
.vip-header .vip-status .status-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 会员功能区域 */
|
||||
.features-section {
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
.features-section .section-title {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
.features-section .feature-card {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
-webkit-backdrop-filter: blur(15rpx);
|
||||
backdrop-filter: blur(15rpx);
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
border: 1rpx solid rgba(255, 215, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.features-section .feature-card:hover {
|
||||
transform: translateY(-4rpx);
|
||||
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.features-section .feature-card .feature-icon {
|
||||
font-size: 60rpx;
|
||||
margin-bottom: 24rpx;
|
||||
filter: drop-shadow(0 4rpx 12rpx rgba(255, 215, 0, 0.3));
|
||||
}
|
||||
.features-section .feature-card .feature-text {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* VIP信息卡片 */
|
||||
.vip-info {
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
.vip-info .info-card {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
-webkit-backdrop-filter: blur(15rpx);
|
||||
backdrop-filter: blur(15rpx);
|
||||
border-radius: 20rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border: 1rpx solid rgba(255, 215, 0, 0.3);
|
||||
.vip-hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.vip-info .info-card .info-label {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
.vip-info .info-card .info-value {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
.vip-info .info-card .info-value.active {
|
||||
color: #ffd700;
|
||||
}
|
||||
|
||||
/* 购买区域 */
|
||||
.purchase-section .price-card {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
-webkit-backdrop-filter: blur(15rpx);
|
||||
backdrop-filter: blur(15rpx);
|
||||
gap: 20rpx;
|
||||
padding: 26rpx 28rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
border: 1rpx solid rgba(255, 215, 0, 0.3);
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
border: 2rpx solid #edf2f9;
|
||||
box-shadow: 0 10rpx 30rpx rgba(76, 141, 255, 0.12);
|
||||
}
|
||||
.purchase-section .price-card .price-label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 16rpx;
|
||||
.hero-icon {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 24rpx;
|
||||
background: #f0f6ff;
|
||||
padding: 12rpx;
|
||||
}
|
||||
.purchase-section .price-card .price-display {
|
||||
.hero-text {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
.purchase-section .price-card .price-display .price-symbol {
|
||||
font-size: 32rpx;
|
||||
color: #ffd700;
|
||||
font-weight: 600;
|
||||
.hero-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 800;
|
||||
color: #4C8DFF;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
.purchase-section .price-card .price-display .price-amount {
|
||||
font-size: 60rpx;
|
||||
.hero-subtitle {
|
||||
font-size: 26rpx;
|
||||
color: #5175b5;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
.status-pill {
|
||||
flex: 0 0 auto;
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #e6edfb;
|
||||
color: #4463a6;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
color: #ffd700;
|
||||
border: 2rpx solid rgba(76, 141, 255, 0.2);
|
||||
}
|
||||
.purchase-section .price-card .price-display .price-period {
|
||||
.status-pill.active {
|
||||
background: #4c8dff;
|
||||
color: #fff;
|
||||
border-color: #4c8dff;
|
||||
}
|
||||
.vip-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16rpx;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
padding: 24rpx;
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid #eef3fb;
|
||||
box-shadow: 0 8rpx 24rpx rgba(99, 132, 191, 0.1);
|
||||
}
|
||||
.summary-item {
|
||||
background: #f6f9ff;
|
||||
border-radius: 18rpx;
|
||||
padding: 22rpx 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
border: 2rpx solid rgba(76, 141, 255, 0.12);
|
||||
}
|
||||
.summary-label {
|
||||
font-size: 24rpx;
|
||||
color: #5f7394;
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #1f2c3d;
|
||||
}
|
||||
.summary-value.success {
|
||||
color: #1ead91;
|
||||
}
|
||||
.summary-value.highlight {
|
||||
color: #2f58d1;
|
||||
}
|
||||
.benefit-section {
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
border: 2rpx solid #edf2f9;
|
||||
box-shadow: 0 12rpx 28rpx rgba(32, 75, 143, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.section-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 800;
|
||||
color: #111;
|
||||
}
|
||||
.section-subtitle {
|
||||
font-size: 24rpx;
|
||||
color: #5f7394;
|
||||
line-height: 34rpx;
|
||||
}
|
||||
.benefit-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 20rpx;
|
||||
}
|
||||
.benefit-card {
|
||||
background: #f7faff;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx 20rpx;
|
||||
border: 2rpx solid rgba(76, 141, 255, 0.12);
|
||||
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.04);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 14rpx;
|
||||
}
|
||||
.benefit-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
.benefit-title {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
}
|
||||
.purchase-section .purchase-btn {
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
background: linear-gradient(45deg, #ffd700, #ffed4e);
|
||||
border-radius: 50rpx;
|
||||
border: none;
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 215, 0, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
.benefit-desc {
|
||||
font-size: 24rpx;
|
||||
line-height: 34rpx;
|
||||
color: #5f7394;
|
||||
}
|
||||
.purchase-section .purchase-btn:active {
|
||||
transform: translateY(2rpx);
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 215, 0, 0.4);
|
||||
.purchase-card {
|
||||
margin-top: auto;
|
||||
background: linear-gradient(135deg, rgba(76, 141, 255, 0.14) 0%, rgba(76, 141, 255, 0.06) 100%);
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx 28rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
border: 2rpx solid rgba(76, 141, 255, 0.18);
|
||||
box-shadow: 0 10rpx 24rpx rgba(76, 141, 255, 0.15);
|
||||
}
|
||||
.purchase-section .purchase-btn .btn-text {
|
||||
.purchase-text {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
.purchase-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
font-weight: 800;
|
||||
color: #4C8DFF;
|
||||
}
|
||||
|
||||
/* 背景装饰 */
|
||||
.bg-decoration {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
.purchase-desc {
|
||||
font-size: 24rpx;
|
||||
color: #4463a6;
|
||||
line-height: 34rpx;
|
||||
}
|
||||
.bg-decoration .decoration-circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
.purchase-btn {
|
||||
flex: 0 0 auto;
|
||||
padding: 20rpx 36rpx;
|
||||
border-radius: 999rpx;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, #4788ff 0%, #2d6be6 100%);
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 10rpx 22rpx rgba(45, 107, 230, 0.2);
|
||||
}
|
||||
.bg-decoration .decoration-circle.circle-1 {
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
top: -150rpx;
|
||||
right: -100rpx;
|
||||
.purchase-btn:active {
|
||||
opacity: 0.88;
|
||||
}
|
||||
.bg-decoration .decoration-circle.circle-2 {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
bottom: 200rpx;
|
||||
left: -100rpx;
|
||||
}
|
||||
.bg-decoration .decoration-circle.circle-3 {
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
top: 50%;
|
||||
right: 50rpx;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 375px) {
|
||||
.benefits-grid {
|
||||
.vip-summary {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.vip-header .vip-title {
|
||||
font-size: 42rpx;
|
||||
.benefit-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.main-content {
|
||||
padding: 40rpx 30rpx;
|
||||
.purchase-card {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
.status-pill {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -37,14 +37,14 @@ const _sfc_main = {
|
||||
showMore: false,
|
||||
SEG_ICONS: {
|
||||
sale: {
|
||||
out: "/static/icons/sale.png",
|
||||
return: "/static/icons/other-pay.png",
|
||||
collect: "/static/icons/report.png"
|
||||
out: "/static/icons/icons8-shopping-cart-100.png",
|
||||
return: "/static/icons/icons8-return-purchase-50.png",
|
||||
collect: "/static/icons/icons8-profit-50.png"
|
||||
},
|
||||
purchase: {
|
||||
in: "/static/icons/purchase.png",
|
||||
return: "/static/icons/other-pay.png",
|
||||
pay: "/static/icons/account.png"
|
||||
in: "/static/icons/icons8-purchase-order-100.png",
|
||||
return: "/static/icons/icons8-return-purchase-50.png",
|
||||
pay: "/static/icons/icons8-dollar-ethereum-exchange-50.png"
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -120,13 +120,33 @@ const _sfc_main = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fixMojibake(s) {
|
||||
try {
|
||||
if (!s)
|
||||
return s;
|
||||
const bad = /[ÂÃæåé¼½¢]/.test(s);
|
||||
if (!bad)
|
||||
return s;
|
||||
return decodeURIComponent(escape(s));
|
||||
} catch (_) {
|
||||
return s;
|
||||
}
|
||||
},
|
||||
normalizeCats(list) {
|
||||
if (!Array.isArray(list))
|
||||
return [];
|
||||
return list.map((it) => ({
|
||||
key: it && it.key || "",
|
||||
label: this.fixMojibake(it && it.label || "")
|
||||
})).filter((it) => it.key && it.label);
|
||||
},
|
||||
async fetchCategories() {
|
||||
try {
|
||||
const res = await common_http.get("/api/finance/categories");
|
||||
if (res && Array.isArray(res.incomeCategories))
|
||||
this._incomeCategories = res.incomeCategories;
|
||||
this._incomeCategories = this.normalizeCats(res.incomeCategories);
|
||||
if (res && Array.isArray(res.expenseCategories))
|
||||
this._expenseCategories = res.expenseCategories;
|
||||
this._expenseCategories = this.normalizeCats(res.expenseCategories);
|
||||
this.ensureActiveCategory();
|
||||
} catch (_) {
|
||||
this.ensureActiveCategory();
|
||||
@@ -392,10 +412,8 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
}, {
|
||||
ag: $data.biz === "sale" || $data.biz === "purchase",
|
||||
aG: !$data.items.length
|
||||
}, !$data.items.length ? {
|
||||
aH: common_assets._imports_0
|
||||
} : {
|
||||
aI: common_vendor.f($data.items, (it, idx, i0) => {
|
||||
}, !$data.items.length ? {} : {
|
||||
aH: common_vendor.f($data.items, (it, idx, i0) => {
|
||||
return {
|
||||
a: common_vendor.t(it.productName),
|
||||
b: common_vendor.o([common_vendor.m(($event) => it.quantity = $event.detail.value, {
|
||||
@@ -411,8 +429,8 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
};
|
||||
})
|
||||
}, {
|
||||
aJ: common_vendor.o((...args) => $options.saveAndReset && $options.saveAndReset(...args)),
|
||||
aK: common_vendor.o((...args) => $options.submit && $options.submit(...args))
|
||||
aI: common_vendor.o((...args) => $options.saveAndReset && $options.saveAndReset(...args)),
|
||||
aJ: common_vendor.o((...args) => $options.submit && $options.submit(...args))
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -47,9 +47,8 @@
|
||||
margin: 12rpx 16rpx;
|
||||
padding: 6rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #e6ebf2;
|
||||
border-radius: 999rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.seg3-item {
|
||||
flex: 1;
|
||||
@@ -60,13 +59,14 @@
|
||||
padding: 12rpx 0;
|
||||
color: #111;
|
||||
border-radius: 999rpx;
|
||||
transition: box-shadow 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
/* 间隔通过内边距处理,避免空选择器 */
|
||||
.seg3-item.active {
|
||||
background: #fff;
|
||||
color: #4C8DFF;
|
||||
box-shadow: 0 4rpx 12rpx rgba(76, 141, 255, 0.2), 0 0 0 2rpx #4C8DFF inset;
|
||||
box-shadow: 0 3rpx 10rpx rgba(76, 141, 255, 0.16);
|
||||
}
|
||||
.seg3-icon {
|
||||
width: 28rpx;
|
||||
@@ -75,16 +75,20 @@
|
||||
}
|
||||
.field {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 22rpx 24rpx;
|
||||
background: #ffffff;
|
||||
border-bottom: 1rpx solid #e5e7eb;
|
||||
background: #f8faff;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.label {
|
||||
width: 160rpx;
|
||||
color: #444;
|
||||
}
|
||||
.value {
|
||||
flex: 1;
|
||||
color: #111;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 汇总卡片:白底卡片+主色按钮 */
|
||||
@@ -92,28 +96,27 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16rpx 18rpx;
|
||||
margin: 12rpx 16rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border-radius: 16rpx;
|
||||
padding: 18rpx 20rpx;
|
||||
margin: 16rpx 18rpx 10rpx;
|
||||
background: none;
|
||||
border-radius: 18rpx;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
/* 加号改为图标按钮 */
|
||||
.add {
|
||||
margin: 18rpx auto;
|
||||
margin: 24rpx auto 18rpx;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 24rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #4C8DFF;
|
||||
border-radius: 28rpx;
|
||||
background: none;
|
||||
border: 0;
|
||||
color: #4C8DFF;
|
||||
font-size: 72rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 6rpx 16rpx rgba(76, 141, 255, 0.12);
|
||||
box-shadow: none;
|
||||
}
|
||||
.empty {
|
||||
display: flex;
|
||||
@@ -131,18 +134,17 @@
|
||||
}
|
||||
.list {
|
||||
background: #fff;
|
||||
margin: 0 16rpx 12rpx;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border-radius: 16rpx;
|
||||
margin: 0 18rpx 20rpx;
|
||||
border-radius: 18rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr 1fr 1fr;
|
||||
gap: 12rpx;
|
||||
padding: 16rpx 12rpx;
|
||||
padding: 18rpx 16rpx;
|
||||
align-items: center;
|
||||
border-bottom: 1rpx solid #e5e7eb;
|
||||
}
|
||||
.col.name {
|
||||
padding-left: 12rpx;
|
||||
@@ -158,16 +160,30 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #ffffff;
|
||||
padding: 16rpx 24rpx calc(env(safe-area-inset-bottom) + 16rpx);
|
||||
padding: 6rpx 18rpx calc(env(safe-area-inset-bottom) + 2rpx);
|
||||
box-shadow: 0 -4rpx 12rpx rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
.primary {
|
||||
.order .bottom button {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 仅限开单页底部按钮样式(缩小高度) */
|
||||
.order .bottom .primary {
|
||||
width: 100%;
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
border-radius: 999rpx;
|
||||
padding: 20rpx 0;
|
||||
font-weight: 800;
|
||||
padding: 14rpx 0;
|
||||
font-weight: 700;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.order .bottom .ghost {
|
||||
background: transparent;
|
||||
color: #4C8DFF;
|
||||
border: 0;
|
||||
border-radius: 999rpx;
|
||||
padding: 12rpx 0;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 收款/付款页样式 */
|
||||
@@ -178,17 +194,16 @@
|
||||
.textarea {
|
||||
position: relative;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #ffffff;
|
||||
border-top: 1rpx solid #e5e7eb;
|
||||
background: #f8faff;
|
||||
}
|
||||
.amount-badge {
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
top: -36rpx;
|
||||
top: -32rpx;
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 14rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.date-mini {
|
||||
@@ -201,20 +216,21 @@
|
||||
|
||||
/* 分类chips样式:选中后文字变红 */
|
||||
.chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12rpx 16rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
}
|
||||
.chip {
|
||||
padding: 10rpx 20rpx;
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f1f1f1;
|
||||
color: #444;
|
||||
text-align: center;
|
||||
}
|
||||
.chip.active {
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
background: rgba(76, 141, 255, 0.15);
|
||||
color: #4C8DFF;
|
||||
}
|
||||
|
||||
/* 顶部业务 Tabs 显示 */
|
||||
@@ -231,10 +247,10 @@
|
||||
}
|
||||
.info-field {
|
||||
background: #fff;
|
||||
border: 2rpx solid #e6ebf2;
|
||||
border-radius: 12rpx;
|
||||
padding: 10rpx 12rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
border: 0;
|
||||
border-radius: 14rpx;
|
||||
padding: 12rpx 14rpx;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.info-label {
|
||||
color: #444;
|
||||
@@ -245,17 +261,20 @@
|
||||
color: #111;
|
||||
font-weight: 700;
|
||||
}
|
||||
.info-action {
|
||||
|
||||
/* 缩小“加商品”按钮尺寸,仅在本页卡片内 */
|
||||
.order .info-card .info-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 14rpx 16rpx;
|
||||
box-shadow: 0 8rpx 18rpx rgba(76, 141, 255, 0.26);
|
||||
padding: 8rpx 12rpx;
|
||||
box-shadow: 0 5rpx 12rpx rgba(76, 141, 255, 0.18);
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.info-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
.order .info-card .info-icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
}
|
||||
@@ -24,15 +24,22 @@ const _sfc_main = {
|
||||
wholesalePrice: null,
|
||||
bigClientPrice: null,
|
||||
images: [],
|
||||
remark: ""
|
||||
remark: "",
|
||||
platformStatus: "",
|
||||
sourceSubmissionId: ""
|
||||
},
|
||||
units: [],
|
||||
categories: []
|
||||
categories: [],
|
||||
keyboardHeight: 0
|
||||
};
|
||||
},
|
||||
onLoad(query) {
|
||||
this.id = (query == null ? void 0 : query.id) || "";
|
||||
this.bootstrap();
|
||||
this.initKeyboardListener();
|
||||
},
|
||||
onUnload() {
|
||||
this.disposeKeyboardListener();
|
||||
},
|
||||
computed: {
|
||||
unitNames() {
|
||||
@@ -56,6 +63,24 @@ const _sfc_main = {
|
||||
if (this.id)
|
||||
this.loadDetail();
|
||||
},
|
||||
initKeyboardListener() {
|
||||
try {
|
||||
this.__keyboardListener = (e) => {
|
||||
const h = e && (e.height || e.targetHeight || 0) || 0;
|
||||
this.keyboardHeight = h;
|
||||
};
|
||||
common_vendor.index.onKeyboardHeightChange && common_vendor.index.onKeyboardHeightChange(this.__keyboardListener);
|
||||
} catch (_) {
|
||||
}
|
||||
},
|
||||
disposeKeyboardListener() {
|
||||
try {
|
||||
if (this.__keyboardListener && common_vendor.index.offKeyboardHeightChange) {
|
||||
common_vendor.index.offKeyboardHeightChange(this.__keyboardListener);
|
||||
}
|
||||
} catch (_) {
|
||||
}
|
||||
},
|
||||
async fetchUnits() {
|
||||
try {
|
||||
const res = await common_http.get("/api/product-units");
|
||||
@@ -80,10 +105,27 @@ const _sfc_main = {
|
||||
const c = this.categories[idx];
|
||||
this.form.categoryId = c ? c.id : "";
|
||||
},
|
||||
scan() {
|
||||
common_vendor.index.scanCode({ onlyFromCamera: false, success: (res) => {
|
||||
this.form.barcode = res.result;
|
||||
} });
|
||||
async chooseAndScanBarcode() {
|
||||
try {
|
||||
const chooseRes = await common_vendor.index.chooseImage({ count: 1, sourceType: ["camera", "album"], sizeType: ["compressed"] });
|
||||
let filePath = chooseRes.tempFilePaths[0];
|
||||
try {
|
||||
const comp = await common_vendor.index.compressImage({ src: filePath, quality: 80 });
|
||||
filePath = comp.tempFilePath || filePath;
|
||||
} catch (e) {
|
||||
}
|
||||
const data = await common_http.upload("/api/barcode/scan", filePath, {}, "file");
|
||||
if (data && data.success && data.barcode) {
|
||||
this.form.barcode = data.barcode;
|
||||
common_vendor.index.showToast({ title: "识别成功", icon: "success", mask: false });
|
||||
return;
|
||||
}
|
||||
const msg = data && (data.message || data.error || data.msg) || "未识别";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none", mask: false });
|
||||
} catch (e) {
|
||||
const msg = e && e.message ? String(e.message) : "网络异常或服务不可用";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none", mask: false });
|
||||
}
|
||||
},
|
||||
async loadDetail() {
|
||||
try {
|
||||
@@ -104,7 +146,10 @@ const _sfc_main = {
|
||||
retailPrice: data.retailPrice,
|
||||
wholesalePrice: data.wholesalePrice,
|
||||
bigClientPrice: data.bigClientPrice,
|
||||
images: (data.images || []).map((i) => i.url || i)
|
||||
images: (data.images || []).map((i) => i.url || i),
|
||||
remark: data.remark || "",
|
||||
platformStatus: data.platformStatus || "",
|
||||
sourceSubmissionId: data.sourceSubmissionId || ""
|
||||
});
|
||||
} catch (_) {
|
||||
}
|
||||
@@ -145,6 +190,10 @@ const _sfc_main = {
|
||||
};
|
||||
},
|
||||
async save(goOn) {
|
||||
try {
|
||||
common_vendor.index.hideKeyboard && common_vendor.index.hideKeyboard();
|
||||
} catch (_) {
|
||||
}
|
||||
if (!this.validate())
|
||||
return;
|
||||
const payload = this.buildPayload();
|
||||
@@ -153,14 +202,14 @@ const _sfc_main = {
|
||||
await common_http.put("/api/products/" + this.id, payload);
|
||||
else
|
||||
await common_http.post("/api/products", payload);
|
||||
common_vendor.index.showToast({ title: "保存成功", icon: "success" });
|
||||
common_vendor.index.showToast({ title: "保存成功", icon: "success", mask: false });
|
||||
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: "" };
|
||||
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: "", platformStatus: "", sourceSubmissionId: "" };
|
||||
} else {
|
||||
setTimeout(() => common_vendor.index.navigateBack(), 400);
|
||||
}
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: "保存失败", icon: "none" });
|
||||
common_vendor.index.showToast({ title: "保存失败", icon: "none", mask: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,79 +219,84 @@ if (!Array) {
|
||||
_component_ImageUploader();
|
||||
}
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return {
|
||||
a: $data.form.name,
|
||||
b: common_vendor.o(common_vendor.m(($event) => $data.form.name = $event.detail.value, {
|
||||
return common_vendor.e({
|
||||
a: $data.form.platformStatus === "platform"
|
||||
}, $data.form.platformStatus === "platform" ? {} : $data.form.sourceSubmissionId ? {} : {}, {
|
||||
b: $data.form.sourceSubmissionId,
|
||||
c: $data.form.name,
|
||||
d: common_vendor.o(common_vendor.m(($event) => $data.form.name = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
c: $data.form.barcode,
|
||||
d: common_vendor.o(common_vendor.m(($event) => $data.form.barcode = $event.detail.value, {
|
||||
e: $data.form.barcode,
|
||||
f: common_vendor.o(common_vendor.m(($event) => $data.form.barcode = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
e: $data.form.brand,
|
||||
f: common_vendor.o(common_vendor.m(($event) => $data.form.brand = $event.detail.value, {
|
||||
g: common_vendor.o((...args) => $options.chooseAndScanBarcode && $options.chooseAndScanBarcode(...args)),
|
||||
h: $data.form.brand,
|
||||
i: common_vendor.o(common_vendor.m(($event) => $data.form.brand = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
g: $data.form.model,
|
||||
h: common_vendor.o(common_vendor.m(($event) => $data.form.model = $event.detail.value, {
|
||||
j: $data.form.model,
|
||||
k: common_vendor.o(common_vendor.m(($event) => $data.form.model = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
i: $data.form.spec,
|
||||
j: common_vendor.o(common_vendor.m(($event) => $data.form.spec = $event.detail.value, {
|
||||
l: $data.form.spec,
|
||||
m: common_vendor.o(common_vendor.m(($event) => $data.form.spec = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
k: $data.form.origin,
|
||||
l: common_vendor.o(common_vendor.m(($event) => $data.form.origin = $event.detail.value, {
|
||||
n: $data.form.origin,
|
||||
o: common_vendor.o(common_vendor.m(($event) => $data.form.origin = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
m: common_vendor.t($options.unitLabel),
|
||||
n: $options.unitNames,
|
||||
o: common_vendor.o((...args) => $options.onPickUnit && $options.onPickUnit(...args)),
|
||||
p: common_vendor.t($options.categoryLabel),
|
||||
q: $options.categoryNames,
|
||||
r: common_vendor.o((...args) => $options.onPickCategory && $options.onPickCategory(...args)),
|
||||
s: $data.form.stock,
|
||||
t: common_vendor.o(common_vendor.m(($event) => $data.form.stock = $event.detail.value, {
|
||||
p: common_vendor.t($options.unitLabel),
|
||||
q: $options.unitNames,
|
||||
r: common_vendor.o((...args) => $options.onPickUnit && $options.onPickUnit(...args)),
|
||||
s: common_vendor.t($options.categoryLabel),
|
||||
t: $options.categoryNames,
|
||||
v: common_vendor.o((...args) => $options.onPickCategory && $options.onPickCategory(...args)),
|
||||
w: $data.form.stock,
|
||||
x: common_vendor.o(common_vendor.m(($event) => $data.form.stock = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
v: $data.form.safeMin,
|
||||
w: common_vendor.o(common_vendor.m(($event) => $data.form.safeMin = $event.detail.value, {
|
||||
y: $data.form.safeMin,
|
||||
z: common_vendor.o(common_vendor.m(($event) => $data.form.safeMin = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
x: $data.form.safeMax,
|
||||
y: common_vendor.o(common_vendor.m(($event) => $data.form.safeMax = $event.detail.value, {
|
||||
A: $data.form.safeMax,
|
||||
B: common_vendor.o(common_vendor.m(($event) => $data.form.safeMax = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
z: $data.form.purchasePrice,
|
||||
A: common_vendor.o(common_vendor.m(($event) => $data.form.purchasePrice = $event.detail.value, {
|
||||
C: $data.form.purchasePrice,
|
||||
D: common_vendor.o(common_vendor.m(($event) => $data.form.purchasePrice = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
B: $data.form.retailPrice,
|
||||
C: common_vendor.o(common_vendor.m(($event) => $data.form.retailPrice = $event.detail.value, {
|
||||
E: $data.form.retailPrice,
|
||||
F: common_vendor.o(common_vendor.m(($event) => $data.form.retailPrice = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
D: $data.form.wholesalePrice,
|
||||
E: common_vendor.o(common_vendor.m(($event) => $data.form.wholesalePrice = $event.detail.value, {
|
||||
G: $data.form.wholesalePrice,
|
||||
H: common_vendor.o(common_vendor.m(($event) => $data.form.wholesalePrice = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
F: $data.form.bigClientPrice,
|
||||
G: common_vendor.o(common_vendor.m(($event) => $data.form.bigClientPrice = $event.detail.value, {
|
||||
I: $data.form.bigClientPrice,
|
||||
J: common_vendor.o(common_vendor.m(($event) => $data.form.bigClientPrice = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
H: common_vendor.o(($event) => $data.form.images = $event),
|
||||
I: common_vendor.p({
|
||||
K: common_vendor.o(($event) => $data.form.images = $event),
|
||||
L: common_vendor.p({
|
||||
formData: {
|
||||
ownerType: "product"
|
||||
},
|
||||
modelValue: $data.form.images
|
||||
}),
|
||||
J: $data.form.remark,
|
||||
K: common_vendor.o(common_vendor.m(($event) => $data.form.remark = $event.detail.value, {
|
||||
M: $data.form.remark,
|
||||
N: common_vendor.o(common_vendor.m(($event) => $data.form.remark = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
L: common_vendor.o(($event) => $options.save(false)),
|
||||
M: common_vendor.o(($event) => $options.save(true))
|
||||
};
|
||||
O: common_vendor.o(($event) => $options.save(false)),
|
||||
P: common_vendor.o(($event) => $options.save(true)),
|
||||
Q: ($data.keyboardHeight || 0) + "px"
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<scroll-view scroll-y class="page"><view class="hero small"><text class="title">编辑货品</text><text class="sub">完善基础信息与价格</text></view><view class="card"><view class="row"><text class="label">商品名称</text><input placeholder="必填" value="{{a}}" bindinput="{{b}}"/></view><view class="row"><text class="label">条形码</text><input placeholder="可扫码或输入" value="{{c}}" bindinput="{{d}}"/></view><view class="row"><text class="label">品牌/型号/规格/产地</text></view><view class="row"><input placeholder="品牌" value="{{e}}" bindinput="{{f}}"/></view><view class="row"><input placeholder="型号" value="{{g}}" bindinput="{{h}}"/></view><view class="row"><input placeholder="规格" value="{{i}}" bindinput="{{j}}"/></view><view class="row"><input placeholder="产地" value="{{k}}" bindinput="{{l}}"/></view><view class="row"><picker mode="selector" range="{{n}}" bindchange="{{o}}"><view class="picker">主单位:{{m}}</view></picker><picker mode="selector" range="{{q}}" bindchange="{{r}}"><view class="picker">类别:{{p}}</view></picker></view></view><view class="card"><view class="row"><text class="label">库存与安全库存</text></view><view class="row"><input type="number" placeholder="当前库存" value="{{s}}" bindinput="{{t}}"/><input type="number" placeholder="安全库存下限" value="{{v}}" bindinput="{{w}}"/><input type="number" placeholder="安全库存上限" value="{{x}}" bindinput="{{y}}"/></view></view><view class="card"><view class="row"><text class="label">价格(进价/零售/批发/大单)</text></view><view class="row prices"><input type="number" placeholder="进货价" value="{{z}}" bindinput="{{A}}"/><input type="number" placeholder="零售价" value="{{B}}" bindinput="{{C}}"/><input type="number" placeholder="批发价" value="{{D}}" bindinput="{{E}}"/><input type="number" placeholder="大单价" value="{{F}}" bindinput="{{G}}"/></view></view><view class="card"><text class="label">图片</text><image-uploader wx:if="{{I}}" u-i="4a3f460a-0" bind:__l="__l" bindupdateModelValue="{{H}}" u-p="{{I}}"/></view><view class="card"><text class="label">备注</text><block wx:if="{{r0}}"><textarea placeholder="可选" auto-height value="{{J}}" bindinput="{{K}}"/></block></view><view class="fixed"><button class="ghost" bindtap="{{L}}">保存</button><button class="primary" bindtap="{{M}}">保存并继续</button></view></scroll-view>
|
||||
<scroll-view scroll-y class="page"><view class="hero small"><text class="title">编辑货品</text><text class="sub">完善基础信息与价格</text></view><view wx:if="{{a}}" class="tip platform">平台推荐货品,建议谨慎修改核心字段</view><view wx:elif="{{b}}" class="tip custom">此货品源于我的提交,审核通过后已入库</view><view class="section"><view class="row"><text class="label">商品名称</text><input placeholder="必填" value="{{c}}" bindinput="{{d}}"/></view><view class="row"><text class="label">条形码</text><input class="input-long" placeholder="可扫码或输入" value="{{e}}" bindinput="{{f}}"/><button size="mini" class="picker-btn" bindtap="{{g}}">图片识码</button></view><view class="row"><input placeholder="品牌" value="{{h}}" bindinput="{{i}}"/></view><view class="row"><input placeholder="型号" value="{{j}}" bindinput="{{k}}"/></view><view class="row"><input placeholder="规格" value="{{l}}" bindinput="{{m}}"/></view><view class="row"><input placeholder="产地" value="{{n}}" bindinput="{{o}}"/></view><view class="row"><picker mode="selector" range="{{q}}" bindchange="{{r}}"><view class="picker">主单位:{{p}}</view></picker><picker mode="selector" range="{{t}}" bindchange="{{v}}"><view class="picker">类别:{{s}}</view></picker></view></view><view class="section"><view class="row"><text class="label">库存与安全库存</text></view><view class="row"><input type="number" placeholder="当前库存" value="{{w}}" bindinput="{{x}}"/><input type="number" placeholder="安全库存下限" value="{{y}}" bindinput="{{z}}"/><input type="number" placeholder="安全库存上限" value="{{A}}" bindinput="{{B}}"/></view></view><view class="section"><view class="row"><text class="label">价格(进价/零售/批发/大单)</text></view><view class="row prices"><input type="number" placeholder="进货价" value="{{C}}" bindinput="{{D}}"/><input type="number" placeholder="零售价" value="{{E}}" bindinput="{{F}}"/><input type="number" placeholder="批发价" value="{{G}}" bindinput="{{H}}"/><input type="number" placeholder="大单价" value="{{I}}" bindinput="{{J}}"/></view></view><view class="section"><text class="label">图片</text><image-uploader wx:if="{{L}}" u-i="4a3f460a-0" bind:__l="__l" bindupdateModelValue="{{K}}" u-p="{{L}}"/></view><view class="section"><text class="label">备注</text><block wx:if="{{r0}}"><textarea placeholder="可选" auto-height value="{{M}}" bindinput="{{N}}"/></block></view><view class="fixed" style="{{'bottom:' + Q}}"><button class="ghost" bindtap="{{O}}">保存</button><button class="primary" bindtap="{{P}}">保存并继续</button></view></scroll-view>
|
||||
@@ -26,71 +26,107 @@
|
||||
/* 文章场景相关 */
|
||||
.page {
|
||||
background: #ffffff;
|
||||
height: 100vh;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 160rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.hero.small {
|
||||
margin: 16rpx;
|
||||
padding: 16rpx;
|
||||
background: #ffffff;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border-radius: 16rpx;
|
||||
margin: 22rpx 24rpx 12rpx;
|
||||
padding: 0 4rpx 18rpx;
|
||||
color: #111;
|
||||
border-bottom: 2rpx solid rgba(94, 124, 174, 0.12);
|
||||
}
|
||||
.hero.small .title {
|
||||
font-size: 32rpx;
|
||||
font-size: 34rpx;
|
||||
font-weight: 800;
|
||||
color: #111;
|
||||
}
|
||||
.hero.small .sub {
|
||||
margin-left: 12rpx;
|
||||
display: block;
|
||||
margin-top: 6rpx;
|
||||
color: #444;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.card {
|
||||
background: #ffffff;
|
||||
margin: 16rpx;
|
||||
padding: 16rpx;
|
||||
border-radius: 16rpx;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
.section {
|
||||
margin: 0 24rpx 28rpx;
|
||||
padding-bottom: 6rpx;
|
||||
border-bottom: 2rpx solid rgba(94, 124, 174, 0.1);
|
||||
}
|
||||
.section:last-of-type {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.section .row:first-child .label {
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
gap: 8rpx;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.row .input-long {
|
||||
flex: 1.2;
|
||||
}
|
||||
.row:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.label {
|
||||
width: 180rpx;
|
||||
width: 150rpx;
|
||||
color: #444;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.row input {
|
||||
flex: 1;
|
||||
background: #f1f1f1;
|
||||
border-radius: 12rpx;
|
||||
padding: 14rpx;
|
||||
background: #f7f9fc;
|
||||
border-radius: 14rpx;
|
||||
padding: 18rpx 20rpx;
|
||||
color: #111;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border: 0;
|
||||
box-shadow: inset 0 0 0 2rpx rgba(134, 155, 191, 0.06);
|
||||
}
|
||||
.picker-btn {
|
||||
background: #ffffff;
|
||||
border: 2rpx solid rgba(76, 141, 255, 0.45);
|
||||
color: #4C8DFF;
|
||||
padding: 0 24rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.picker {
|
||||
padding: 10rpx 14rpx;
|
||||
background: #f1f1f1;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx 22rpx;
|
||||
background: #f7f9fc;
|
||||
border-radius: 14rpx;
|
||||
color: #444;
|
||||
margin-left: 8rpx;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
border: 0;
|
||||
box-shadow: inset 0 0 0 2rpx rgba(134, 155, 191, 0.06);
|
||||
}
|
||||
.prices input {
|
||||
width: 30%;
|
||||
}
|
||||
.section textarea {
|
||||
width: 100%;
|
||||
min-height: 160rpx;
|
||||
background: #f7f9fc;
|
||||
border-radius: 14rpx;
|
||||
padding: 20rpx 22rpx;
|
||||
box-sizing: border-box;
|
||||
color: #111;
|
||||
border: 0;
|
||||
box-shadow: inset 0 0 0 2rpx rgba(134, 155, 191, 0.06);
|
||||
}
|
||||
.fixed {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
bottom: env(safe-area-inset-bottom);
|
||||
background: #ffffff;
|
||||
padding: 12rpx 16rpx;
|
||||
padding: 16rpx 16rpx calc(16rpx + constant(safe-area-inset-bottom)) 16rpx;
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
border-top: 2rpx solid #e5e7eb;
|
||||
box-shadow: 0 -6rpx 18rpx rgba(24, 55, 105, 0.08);
|
||||
z-index: 999;
|
||||
}
|
||||
.fixed .primary {
|
||||
flex: 1;
|
||||
@@ -107,4 +143,18 @@
|
||||
border: 2rpx solid rgba(76, 141, 255, 0.45);
|
||||
border-radius: 999rpx;
|
||||
padding: 18rpx 0;
|
||||
}
|
||||
.tip {
|
||||
margin: 0 30rpx 20rpx;
|
||||
padding: 16rpx 20rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.tip.platform {
|
||||
background: rgba(45, 140, 240, 0.12);
|
||||
color: #2d8cf0;
|
||||
}
|
||||
.tip.custom {
|
||||
background: rgba(103, 194, 58, 0.12);
|
||||
color: #67c23a;
|
||||
}
|
||||
@@ -98,6 +98,9 @@ const _sfc_main = {
|
||||
openForm(id) {
|
||||
const url = "/pages/product/form" + (id ? "?id=" + id : "");
|
||||
common_vendor.index.navigateTo({ url });
|
||||
},
|
||||
goMySubmissions() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/product/submissions" });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -107,39 +110,42 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
b: common_vendor.o(($event) => $options.switchTab("all")),
|
||||
c: $data.tab === "category" ? 1 : "",
|
||||
d: common_vendor.o(($event) => $options.switchTab("category")),
|
||||
e: common_vendor.o((...args) => $options.reload && $options.reload(...args)),
|
||||
f: $data.query.kw,
|
||||
g: common_vendor.o(common_vendor.m(($event) => $data.query.kw = $event.detail.value, {
|
||||
e: common_vendor.o((...args) => $options.goMySubmissions && $options.goMySubmissions(...args)),
|
||||
f: common_vendor.o((...args) => $options.reload && $options.reload(...args)),
|
||||
g: $data.query.kw,
|
||||
h: common_vendor.o(common_vendor.m(($event) => $data.query.kw = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
h: $data.tab === "category"
|
||||
i: $data.tab === "category"
|
||||
}, $data.tab === "category" ? {
|
||||
i: common_vendor.t($options.categoryLabel),
|
||||
j: $options.categoryNames,
|
||||
k: common_vendor.o((...args) => $options.onPickCategory && $options.onPickCategory(...args))
|
||||
j: common_vendor.t($options.categoryLabel),
|
||||
k: $options.categoryNames,
|
||||
l: common_vendor.o((...args) => $options.onPickCategory && $options.onPickCategory(...args))
|
||||
} : {}, {
|
||||
l: common_vendor.o((...args) => $options.reload && $options.reload(...args)),
|
||||
m: $data.items.length
|
||||
m: common_vendor.o((...args) => $options.reload && $options.reload(...args)),
|
||||
n: $data.items.length
|
||||
}, $data.items.length ? {
|
||||
n: common_vendor.f($data.items, (it, k0, i0) => {
|
||||
o: common_vendor.f($data.items, (it, k0, i0) => {
|
||||
return common_vendor.e({
|
||||
a: it.cover
|
||||
}, it.cover ? {
|
||||
b: it.cover
|
||||
} : {}, {
|
||||
c: common_vendor.t(it.name),
|
||||
d: common_vendor.t(it.brand || "-"),
|
||||
e: common_vendor.t(it.model || ""),
|
||||
f: common_vendor.t(it.spec || ""),
|
||||
g: common_vendor.t(it.stock ?? 0),
|
||||
h: common_vendor.t((it.retailPrice ?? it.price ?? 0).toFixed(2)),
|
||||
i: it.id,
|
||||
j: common_vendor.o(($event) => $options.openForm(it.id), it.id)
|
||||
d: it.platformStatus === "platform"
|
||||
}, it.platformStatus === "platform" ? {} : it.sourceSubmissionId ? {} : {}, {
|
||||
e: it.sourceSubmissionId,
|
||||
f: common_vendor.t(it.brand || "-"),
|
||||
g: common_vendor.t(it.model || ""),
|
||||
h: common_vendor.t(it.spec || ""),
|
||||
i: common_vendor.t(it.stock ?? 0),
|
||||
j: common_vendor.t((it.retailPrice ?? it.price ?? 0).toFixed(2)),
|
||||
k: it.id,
|
||||
l: common_vendor.o(($event) => $options.openForm(it.id), it.id)
|
||||
});
|
||||
})
|
||||
} : {}, {
|
||||
o: common_vendor.o((...args) => $options.loadMore && $options.loadMore(...args)),
|
||||
p: common_vendor.o(($event) => $options.openForm())
|
||||
p: common_vendor.o((...args) => $options.loadMore && $options.loadMore(...args))
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="page"><view class="tabs"><view class="{{['tab', a && 'active']}}" bindtap="{{b}}">全部</view><view class="{{['tab', c && 'active']}}" bindtap="{{d}}">按类别</view></view><view class="search"><input placeholder="输入名称/条码/规格查询" bindconfirm="{{e}}" value="{{f}}" bindinput="{{g}}"/><picker wx:if="{{h}}" mode="selector" range="{{j}}" bindchange="{{k}}"><view class="picker">{{i}}</view></picker><button size="mini" bindtap="{{l}}">查询</button></view><scroll-view scroll-y class="list" bindscrolltolower="{{o}}"><block wx:if="{{m}}"><view wx:for="{{n}}" wx:for-item="it" wx:key="i" class="item" bindtap="{{it.j}}"><image wx:if="{{it.a}}" src="{{it.b}}" class="thumb" mode="aspectFill"/><view class="content"><view class="name">{{it.c}}</view><view class="meta">{{it.d}} {{it.e}} {{it.f}}</view><view class="meta">库存:{{it.g}} <text class="price">零售价:¥{{it.h}}</text></view></view></view></block><view wx:else class="empty"><text>暂无数据,点击右上角“+”新增</text></view></scroll-view><view class="fab" bindtap="{{p}}">+</view></view>
|
||||
<view class="page"><view class="tabs"><view class="{{['tab', a && 'active']}}" bindtap="{{b}}">全部</view><view class="{{['tab', c && 'active']}}" bindtap="{{d}}">按类别</view><view class="tab extra" bindtap="{{e}}">我的提交</view></view><view class="search"><input placeholder="输入名称/条码/规格查询" bindconfirm="{{f}}" value="{{g}}" bindinput="{{h}}"/><picker wx:if="{{i}}" mode="selector" range="{{k}}" bindchange="{{l}}"><view class="picker">{{j}}</view></picker><button size="mini" bindtap="{{m}}">查询</button></view><scroll-view scroll-y class="list" bindscrolltolower="{{p}}"><block wx:if="{{n}}"><view wx:for="{{o}}" wx:for-item="it" wx:key="k" class="item" bindtap="{{it.l}}"><image wx:if="{{it.a}}" src="{{it.b}}" class="thumb" mode="aspectFill"/><view class="content"><view class="name"><text>{{it.c}}</text><text wx:if="{{it.d}}" class="tag-platform">平台推荐</text><text wx:elif="{{it.e}}" class="tag-custom">我的提交</text></view><view class="meta">{{it.f}} {{it.g}} {{it.h}}</view><view class="meta">库存:{{it.i}} <text class="price">零售价:¥{{it.j}}</text></view></view></view></block><view wx:else class="empty"><text>暂无数据,点击右上角“+”新增</text></view></scroll-view></view>
|
||||
@@ -43,6 +43,11 @@
|
||||
color: #4C8DFF;
|
||||
font-weight: 600;
|
||||
}
|
||||
.tab.extra {
|
||||
flex: 0 0 180rpx;
|
||||
color: #4C8DFF;
|
||||
font-weight: 600;
|
||||
}
|
||||
.search {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
@@ -86,6 +91,23 @@
|
||||
color: #111;
|
||||
margin-bottom: 6rpx;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
.tag-platform {
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
background: #2d8cf0;
|
||||
padding: 4rpx 10rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
.tag-custom {
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
background: #67c23a;
|
||||
padding: 4rpx 10rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
.meta {
|
||||
color: #444;
|
||||
|
||||
180
frontend/unpackage/dist/dev/mp-weixin/pages/product/submissions.js
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const _sfc_main = {
|
||||
data() {
|
||||
return {
|
||||
status: "",
|
||||
items: [],
|
||||
page: 1,
|
||||
size: 20,
|
||||
total: 0,
|
||||
loading: false,
|
||||
finished: false,
|
||||
cacheUnitsLoaded: false,
|
||||
cacheCategoriesLoaded: false
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
this.preloadDictionaries();
|
||||
this.reload();
|
||||
},
|
||||
methods: {
|
||||
async preloadDictionaries() {
|
||||
try {
|
||||
const [units, categories] = await Promise.all([
|
||||
this.cacheUnitsLoaded ? Promise.resolve(null) : common_http.get("/api/product-units"),
|
||||
this.cacheCategoriesLoaded ? Promise.resolve(null) : common_http.get("/api/product-categories")
|
||||
]);
|
||||
if (units) {
|
||||
const list = Array.isArray(units == null ? void 0 : units.list) ? units.list : Array.isArray(units) ? units : [];
|
||||
common_vendor.index.setStorageSync("CACHE_UNITS", list);
|
||||
this.cacheUnitsLoaded = true;
|
||||
}
|
||||
if (categories) {
|
||||
const list = Array.isArray(categories == null ? void 0 : categories.list) ? categories.list : Array.isArray(categories) ? categories : [];
|
||||
common_vendor.index.setStorageSync("CACHE_CATEGORIES", list);
|
||||
this.cacheCategoriesLoaded = true;
|
||||
}
|
||||
} catch (_) {
|
||||
}
|
||||
},
|
||||
switchStatus(s) {
|
||||
if (this.status === s)
|
||||
return;
|
||||
this.status = s;
|
||||
this.reload();
|
||||
},
|
||||
async reload() {
|
||||
this.page = 1;
|
||||
this.items = [];
|
||||
this.finished = false;
|
||||
await this.loadMore();
|
||||
},
|
||||
async loadMore() {
|
||||
if (this.loading || this.finished)
|
||||
return;
|
||||
this.loading = true;
|
||||
try {
|
||||
const params = { page: this.page, size: this.size };
|
||||
if (this.status)
|
||||
params.status = this.status;
|
||||
const res = await common_http.get("/api/products/submissions", params);
|
||||
const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : [];
|
||||
this.items = this.items.concat(list);
|
||||
this.total = Number((res == null ? void 0 : res.total) || this.items.length);
|
||||
if (list.length < this.size)
|
||||
this.finished = true;
|
||||
this.page += 1;
|
||||
} catch (e) {
|
||||
common_vendor.index.__f__("warn", "at pages/product/submissions.vue:113", "加载提交记录失败", e);
|
||||
const msg = (e == null ? void 0 : e.message) || "加载失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
statusLabel(s) {
|
||||
if (s === "approved")
|
||||
return "已通过";
|
||||
if (s === "rejected")
|
||||
return "已驳回";
|
||||
return "待审核";
|
||||
},
|
||||
statusClass(s) {
|
||||
if (s === "approved")
|
||||
return "approved";
|
||||
if (s === "rejected")
|
||||
return "rejected";
|
||||
return "pending";
|
||||
},
|
||||
formatTime(value) {
|
||||
if (!value)
|
||||
return "-";
|
||||
try {
|
||||
const d = new Date(value);
|
||||
if (!Number.isFinite(d.getTime()))
|
||||
return value;
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
const hh = String(d.getHours()).padStart(2, "0");
|
||||
const mm = String(d.getMinutes()).padStart(2, "0");
|
||||
return `${y}-${m}-${day} ${hh}:${mm}`;
|
||||
} catch (_) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
viewDetail(id) {
|
||||
common_vendor.index.navigateTo({ url: `/pages/product/submission-detail?id=${id}` });
|
||||
},
|
||||
notifyPending() {
|
||||
common_vendor.index.showToast({ title: "审核中,请耐心等待", icon: "none" });
|
||||
},
|
||||
resubmit(item) {
|
||||
const payload = {
|
||||
model: item.model,
|
||||
name: item.name,
|
||||
brand: item.brand,
|
||||
spec: item.spec,
|
||||
origin: item.origin,
|
||||
unitId: item.unitId,
|
||||
categoryId: item.categoryId,
|
||||
remark: item.remark
|
||||
};
|
||||
const query = encodeURIComponent(JSON.stringify(payload));
|
||||
common_vendor.index.navigateTo({ url: `/pages/product/submit?prefill=${query}` });
|
||||
},
|
||||
goSubmit() {
|
||||
common_vendor.index.navigateTo({ url: "/pages/product/submit" });
|
||||
}
|
||||
}
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return common_vendor.e({
|
||||
a: $data.status === "" ? 1 : "",
|
||||
b: common_vendor.o(($event) => $options.switchStatus("")),
|
||||
c: $data.status === "pending" ? 1 : "",
|
||||
d: common_vendor.o(($event) => $options.switchStatus("pending")),
|
||||
e: $data.status === "approved" ? 1 : "",
|
||||
f: common_vendor.o(($event) => $options.switchStatus("approved")),
|
||||
g: $data.status === "rejected" ? 1 : "",
|
||||
h: common_vendor.o(($event) => $options.switchStatus("rejected")),
|
||||
i: $data.items.length
|
||||
}, $data.items.length ? {
|
||||
j: common_vendor.f($data.items, (item, k0, i0) => {
|
||||
return common_vendor.e({
|
||||
a: common_vendor.t(item.model || "-"),
|
||||
b: common_vendor.t($options.statusLabel(item.status)),
|
||||
c: common_vendor.n($options.statusClass(item.status)),
|
||||
d: common_vendor.t(item.name || "未填写名称"),
|
||||
e: common_vendor.t(item.brand || "-"),
|
||||
f: common_vendor.t($options.formatTime(item.createdAt)),
|
||||
g: item.reviewedAt
|
||||
}, item.reviewedAt ? {
|
||||
h: common_vendor.t($options.formatTime(item.reviewedAt))
|
||||
} : {}, {
|
||||
i: common_vendor.o(($event) => $options.viewDetail(item.id), item.id),
|
||||
j: item.status === "pending"
|
||||
}, item.status === "pending" ? {
|
||||
k: common_vendor.o((...args) => $options.notifyPending && $options.notifyPending(...args), item.id)
|
||||
} : item.status === "rejected" ? {
|
||||
m: common_vendor.o(($event) => $options.resubmit(item), item.id)
|
||||
} : {}, {
|
||||
l: item.status === "rejected",
|
||||
n: item.id
|
||||
});
|
||||
})
|
||||
} : {
|
||||
k: common_vendor.o((...args) => $options.goSubmit && $options.goSubmit(...args))
|
||||
}, {
|
||||
l: $data.loading
|
||||
}, $data.loading ? {} : $data.finished && $data.items.length ? {} : {}, {
|
||||
m: $data.finished && $data.items.length,
|
||||
n: common_vendor.o((...args) => $options.loadMore && $options.loadMore(...args)),
|
||||
o: common_vendor.o((...args) => $options.goSubmit && $options.goSubmit(...args))
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/product/submissions.js.map
|
||||
4
frontend/unpackage/dist/dev/mp-weixin/pages/product/submissions.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "我的提交",
|
||||
"usingComponents": {}
|
||||
}
|
||||
1
frontend/unpackage/dist/dev/mp-weixin/pages/product/submissions.wxml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<view class="page"><view class="hero"><text class="title">我的配件提交</text><text class="desc">查看待审核、已通过、已驳回的记录</text></view><view class="tabs"><view class="{{['tab', a && 'active']}}" bindtap="{{b}}">全部</view><view class="{{['tab', c && 'active']}}" bindtap="{{d}}">待审核</view><view class="{{['tab', e && 'active']}}" bindtap="{{f}}">已通过</view><view class="{{['tab', g && 'active']}}" bindtap="{{h}}">已驳回</view></view><scroll-view scroll-y class="list" bindscrolltolower="{{n}}"><view wx:if="{{i}}" class="cards"><view wx:for="{{j}}" wx:for-item="item" wx:key="n" class="card"><view class="card-header"><text class="model">{{item.a}}</text><text class="{{['status', item.c]}}">{{item.b}}</text></view><view class="card-body"><text class="name">{{item.d}}</text><text class="brand">品牌:{{item.e}}</text><text class="time">提交:{{item.f}}</text><text wx:if="{{item.g}}" class="time">审核:{{item.h}}</text></view><view class="card-footer"><button size="mini" bindtap="{{item.i}}">详情</button><button wx:if="{{item.j}}" size="mini" type="primary" bindtap="{{item.k}}">等待审核</button><button wx:elif="{{item.l}}" size="mini" type="warn" bindtap="{{item.m}}">重新提交</button></view></view></view><view wx:else class="empty"><text>暂无提交记录,快去提交新的配件吧</text><button size="mini" class="primary" bindtap="{{k}}">立即提交</button></view><view wx:if="{{l}}" class="loading">加载中...</view><view wx:elif="{{m}}" class="finished">没有更多了</view></scroll-view><view class="fab" bindtap="{{o}}">+</view></view>
|
||||
163
frontend/unpackage/dist/dev/mp-weixin/pages/product/submissions.wxss
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
/* 颜色变量 */
|
||||
/* 行为相关颜色 */
|
||||
/* 藏青系主色(高亮) */
|
||||
/* 文字基本颜色 */
|
||||
/* 背景颜色 */
|
||||
/* 边框颜色 */
|
||||
/* 尺寸变量 */
|
||||
/* 文字尺寸 */
|
||||
/* 图片尺寸 */
|
||||
/* Border Radius */
|
||||
/* 水平间距 */
|
||||
/* 垂直间距 */
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background: #f6f7fb;
|
||||
padding-bottom: 140rpx;
|
||||
}
|
||||
.hero {
|
||||
padding: 24rpx;
|
||||
background: #fff;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #2d3a4a;
|
||||
}
|
||||
.desc {
|
||||
font-size: 24rpx;
|
||||
color: #7a8899;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
.tabs {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
margin: 16rpx;
|
||||
border-radius: 999rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: inset 0 0 0 1rpx rgba(76, 141, 255, 0.1);
|
||||
}
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #7a8899;
|
||||
}
|
||||
.tab.active {
|
||||
background: linear-gradient(135deg, #4c8dff, #6ab7ff);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.list {
|
||||
flex: 1;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
.cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 18rpx;
|
||||
padding: 22rpx;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.model {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #2d3a4a;
|
||||
}
|
||||
.status {
|
||||
font-size: 24rpx;
|
||||
padding: 6rpx 18rpx;
|
||||
border-radius: 999rpx;
|
||||
}
|
||||
.status.pending {
|
||||
background: rgba(246, 190, 0, 0.15);
|
||||
color: #c47f00;
|
||||
}
|
||||
.status.approved {
|
||||
background: rgba(103, 194, 58, 0.15);
|
||||
color: #409eff;
|
||||
}
|
||||
.status.rejected {
|
||||
background: rgba(255, 87, 115, 0.18);
|
||||
color: #f56c6c;
|
||||
}
|
||||
.card-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
color: #4f5969;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.name {
|
||||
font-weight: 600;
|
||||
color: #2d3a4a;
|
||||
}
|
||||
.card-footer {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
.empty {
|
||||
height: 60vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #8894a3;
|
||||
gap: 20rpx;
|
||||
}
|
||||
.empty .primary {
|
||||
background: #4c8dff;
|
||||
color: #fff;
|
||||
border-radius: 999rpx;
|
||||
padding: 12rpx 30rpx;
|
||||
}
|
||||
.loading, .finished {
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
color: #7a8899;
|
||||
}
|
||||
.fab {
|
||||
position: fixed;
|
||||
right: 30rpx;
|
||||
bottom: 120rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
background: linear-gradient(135deg, #4c8dff, #6ab7ff);
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 48rpx;
|
||||
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
264
frontend/unpackage/dist/dev/mp-weixin/pages/product/submit.js
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const ImageUploader = () => "../../components/ImageUploader.js";
|
||||
const _sfc_main = {
|
||||
components: { ImageUploader },
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
model: "",
|
||||
brand: "",
|
||||
barcode: "",
|
||||
categoryId: "",
|
||||
templateId: "",
|
||||
parameters: {},
|
||||
images: [],
|
||||
remark: "",
|
||||
safeMin: null,
|
||||
safeMax: null
|
||||
},
|
||||
templates: [],
|
||||
paramValues: {},
|
||||
checking: false,
|
||||
parameterText: "",
|
||||
categories: [],
|
||||
submitting: false,
|
||||
paramPlaceholder: '可输入 JSON,如 {"颜色":"黑","材质":"钢"}'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
categoryNames() {
|
||||
return this.categories.map((c) => c.name);
|
||||
},
|
||||
templateNames() {
|
||||
return this.templates.map((t) => t.name);
|
||||
},
|
||||
categoryLabel() {
|
||||
const c = this.categories.find((x) => String(x.id) === String(this.form.categoryId));
|
||||
return c ? c.name : "选择类别";
|
||||
},
|
||||
selectedTemplate() {
|
||||
return this.templates.find((t) => String(t.id) === String(this.form.templateId));
|
||||
},
|
||||
templateLabel() {
|
||||
const t = this.selectedTemplate;
|
||||
return t ? `${t.name}` : "选择模板";
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.bootstrap();
|
||||
if (options && options.prefill) {
|
||||
try {
|
||||
const data = JSON.parse(decodeURIComponent(options.prefill));
|
||||
Object.assign(this.form, {
|
||||
model: data.model || "",
|
||||
brand: data.brand || "",
|
||||
barcode: data.barcode || "",
|
||||
categoryId: data.categoryId || "",
|
||||
remark: data.remark || ""
|
||||
});
|
||||
if (data.parameters && typeof data.parameters === "object") {
|
||||
this.parameterText = JSON.stringify(data.parameters, null, 2);
|
||||
}
|
||||
} catch (_) {
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async bootstrap() {
|
||||
await Promise.all([this.fetchCategories()]);
|
||||
await this.fetchTemplates();
|
||||
},
|
||||
async fetchCategories() {
|
||||
try {
|
||||
const res = await common_http.get("/api/product-categories");
|
||||
this.categories = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : [];
|
||||
} catch (_) {
|
||||
this.categories = [];
|
||||
}
|
||||
},
|
||||
async fetchTemplates() {
|
||||
try {
|
||||
const res = await common_http.get("/api/product-templates", this.form.categoryId ? { categoryId: this.form.categoryId } : {});
|
||||
const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : [];
|
||||
this.templates = list;
|
||||
} catch (_) {
|
||||
this.templates = [];
|
||||
}
|
||||
},
|
||||
onPickCategory(e) {
|
||||
const idx = Number(e.detail.value);
|
||||
const c = this.categories[idx];
|
||||
this.form.categoryId = c ? c.id : "";
|
||||
this.fetchTemplates();
|
||||
},
|
||||
onPickTemplate(e) {
|
||||
const idx = Number(e.detail.value);
|
||||
const t = this.templates[idx];
|
||||
this.form.templateId = t ? t.id : "";
|
||||
this.paramValues = {};
|
||||
},
|
||||
onPickEnum(p, e) {
|
||||
const idx = Number(e.detail.value);
|
||||
const arr = p.enumOptions || [];
|
||||
this.paramValues[p.fieldKey] = arr[idx];
|
||||
},
|
||||
async scanBarcode() {
|
||||
var _a;
|
||||
try {
|
||||
const chooseRes = await common_vendor.index.chooseImage({ count: 1, sourceType: ["camera", "album"], sizeType: ["compressed"] });
|
||||
let filePath = chooseRes.tempFilePaths[0];
|
||||
try {
|
||||
const comp = await common_vendor.index.compressImage({ src: filePath, quality: 80 });
|
||||
filePath = comp.tempFilePath || filePath;
|
||||
} catch (_) {
|
||||
}
|
||||
const data = await common_http.upload("/api/barcode/scan", filePath, {}, "file");
|
||||
const barcode = (data == null ? void 0 : data.barcode) || ((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.barcode);
|
||||
if (barcode) {
|
||||
this.form.barcode = barcode;
|
||||
common_vendor.index.showToast({ title: "识别成功", icon: "success" });
|
||||
} else {
|
||||
common_vendor.index.showToast({ title: "未识别到条码", icon: "none" });
|
||||
}
|
||||
} catch (e) {
|
||||
const msg = (e == null ? void 0 : e.message) || "识码失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
}
|
||||
},
|
||||
async checkModel() {
|
||||
if (!this.form.model)
|
||||
return common_vendor.index.showToast({ title: "请填写型号", icon: "none" });
|
||||
try {
|
||||
this.checking = true;
|
||||
const res = await common_http.post("/api/products/submissions/check-model", { templateId: this.form.templateId, model: this.form.model });
|
||||
if (res && res.available) {
|
||||
common_vendor.index.showToast({ title: "可用,无重复", icon: "success" });
|
||||
} else {
|
||||
common_vendor.index.showToast({ title: "已存在相同型号提交", icon: "none" });
|
||||
}
|
||||
} catch (e) {
|
||||
const msg = (e == null ? void 0 : e.message) || "校验失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.checking = false;
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
if (this.submitting)
|
||||
return;
|
||||
if (!this.form.model) {
|
||||
return common_vendor.index.showToast({ title: "请填写型号", icon: "none" });
|
||||
}
|
||||
let paramsObj = null;
|
||||
if (this.parameterText) {
|
||||
try {
|
||||
paramsObj = JSON.parse(this.parameterText);
|
||||
} catch (e) {
|
||||
return common_vendor.index.showToast({ title: "参数 JSON 不合法", icon: "none" });
|
||||
}
|
||||
}
|
||||
if (this.form.safeMin != null && this.form.safeMax != null && Number(this.form.safeMin) > Number(this.form.safeMax)) {
|
||||
return common_vendor.index.showToast({ title: "安全库存区间不合法", icon: "none" });
|
||||
}
|
||||
let paramsForSubmit = paramsObj;
|
||||
if (this.selectedTemplate) {
|
||||
for (const p of this.selectedTemplate.params || []) {
|
||||
if (p.required && (this.paramValues[p.fieldKey] === void 0 || this.paramValues[p.fieldKey] === null || this.paramValues[p.fieldKey] === "")) {
|
||||
return common_vendor.index.showToast({ title: `请填写 ${p.fieldLabel}`, icon: "none" });
|
||||
}
|
||||
}
|
||||
const shaped = {};
|
||||
for (const p of this.selectedTemplate.params || []) {
|
||||
let v = this.paramValues[p.fieldKey];
|
||||
if (p.type === "number" && v !== void 0 && v !== null && v !== "")
|
||||
v = Number(v);
|
||||
if (p.type === "boolean")
|
||||
v = !!v;
|
||||
shaped[p.fieldKey] = v;
|
||||
}
|
||||
paramsForSubmit = shaped;
|
||||
}
|
||||
const payload = {
|
||||
model: this.form.model,
|
||||
brand: this.form.brand,
|
||||
barcode: this.form.barcode,
|
||||
categoryId: this.form.categoryId || null,
|
||||
templateId: this.form.templateId || null,
|
||||
parameters: paramsForSubmit,
|
||||
images: this.form.images,
|
||||
remark: this.form.remark,
|
||||
safeMin: this.form.safeMin,
|
||||
safeMax: this.form.safeMax
|
||||
};
|
||||
this.submitting = true;
|
||||
try {
|
||||
await common_http.post("/api/products/submissions", payload);
|
||||
common_vendor.index.showToast({ title: "提交成功", icon: "success" });
|
||||
setTimeout(() => {
|
||||
common_vendor.index.redirectTo({ url: "/pages/product/submissions" });
|
||||
}, 400);
|
||||
} catch (e) {
|
||||
const msg = (e == null ? void 0 : e.message) || "提交失败";
|
||||
common_vendor.index.showToast({ title: msg, icon: "none" });
|
||||
} finally {
|
||||
this.submitting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!Array) {
|
||||
const _component_ImageUploader = common_vendor.resolveComponent("ImageUploader");
|
||||
_component_ImageUploader();
|
||||
}
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return {
|
||||
a: $data.form.model,
|
||||
b: common_vendor.o(common_vendor.m(($event) => $data.form.model = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
c: $data.form.brand,
|
||||
d: common_vendor.o(common_vendor.m(($event) => $data.form.brand = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
e: $data.form.barcode,
|
||||
f: common_vendor.o(common_vendor.m(($event) => $data.form.barcode = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
g: common_vendor.o((...args) => $options.scanBarcode && $options.scanBarcode(...args)),
|
||||
h: common_vendor.t($options.categoryLabel),
|
||||
i: $options.categoryNames,
|
||||
j: common_vendor.o((...args) => $options.onPickCategory && $options.onPickCategory(...args)),
|
||||
k: common_vendor.t($options.templateLabel),
|
||||
l: $options.templateNames,
|
||||
m: common_vendor.o((...args) => $options.onPickTemplate && $options.onPickTemplate(...args)),
|
||||
n: common_vendor.o(($event) => $data.form.images = $event),
|
||||
o: common_vendor.p({
|
||||
max: 9,
|
||||
formData: {
|
||||
ownerType: "submission"
|
||||
},
|
||||
modelValue: $data.form.images
|
||||
}),
|
||||
p: $data.form.remark,
|
||||
q: common_vendor.o(common_vendor.m(($event) => $data.form.remark = $event.detail.value, {
|
||||
trim: true
|
||||
})),
|
||||
r: $data.form.safeMin,
|
||||
s: common_vendor.o(common_vendor.m(($event) => $data.form.safeMin = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
t: $data.form.safeMax,
|
||||
v: common_vendor.o(common_vendor.m(($event) => $data.form.safeMax = $event.detail.value, {
|
||||
number: true
|
||||
})),
|
||||
w: $data.submitting,
|
||||
x: common_vendor.o((...args) => $options.submit && $options.submit(...args)),
|
||||
y: $data.checking,
|
||||
z: common_vendor.o((...args) => $options.checkModel && $options.checkModel(...args))
|
||||
};
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
wx.createPage(MiniProgramPage);
|
||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/product/submit.js.map
|
||||
7
frontend/unpackage/dist/dev/mp-weixin/pages/product/submit.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"navigationBarTitleText": "提交配件",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"usingComponents": {
|
||||
"image-uploader": "../../components/ImageUploader"
|
||||
}
|
||||
}
|
||||
1
frontend/unpackage/dist/dev/mp-weixin/pages/product/submit.wxml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<scroll-view scroll-y class="page"><view class="hero"><text class="title">提交配件</text><text class="desc">填写型号、名称、参数与图片,提交后进入待审核状态</text></view><view class="section"><view class="row required"><text class="label">型号</text><input placeholder="请输入型号(必填)" value="{{a}}" bindinput="{{b}}"/></view><view class="row"><text class="label">品牌</text><input placeholder="品牌/厂商" value="{{c}}" bindinput="{{d}}"/></view><view class="row"><text class="label">条码</text><input placeholder="可选,建议扫码录入" value="{{e}}" bindinput="{{f}}"/><button size="mini" class="picker-btn" bindtap="{{g}}">识码</button></view></view><view class="section"><view class="row"><text class="label">类别</text><picker mode="selector" range="{{i}}" bindchange="{{j}}"><view class="picker">{{h}}</view></picker></view></view><view class="section"><view class="row"><text class="label">模板</text></view><view class="row"><picker mode="selector" range="{{l}}" bindchange="{{m}}"><view class="picker">{{k}}</view></picker></view></view><view class="section"><view class="row"><text class="label">图片</text></view><image-uploader wx:if="{{o}}" u-i="7f3a3bde-0" bind:__l="__l" bindupdateModelValue="{{n}}" u-p="{{o}}"/></view><view class="section"><view class="row"><text class="label">备注</text></view><block wx:if="{{r0}}"><textarea class="textarea" placeholder="选填:补充说明" value="{{p}}" bindinput="{{q}}"/></block></view><view class="section"><view class="row"><text class="label">安全库存</text></view><view class="row triple"><input type="number" placeholder="下限" value="{{r}}" bindinput="{{s}}"/><input type="number" placeholder="上限" value="{{t}}" bindinput="{{v}}"/></view></view><view class="fixed"><button class="primary" loading="{{w}}" bindtap="{{x}}">提交审核</button><button class="primary" style="margin-top:16rpx;background:#7aa9ff" loading="{{y}}" bindtap="{{z}}">查重</button></view></scroll-view>
|
||||
125
frontend/unpackage/dist/dev/mp-weixin/pages/product/submit.wxss
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
/* 颜色变量 */
|
||||
/* 行为相关颜色 */
|
||||
/* 藏青系主色(高亮) */
|
||||
/* 文字基本颜色 */
|
||||
/* 背景颜色 */
|
||||
/* 边框颜色 */
|
||||
/* 尺寸变量 */
|
||||
/* 文字尺寸 */
|
||||
/* 图片尺寸 */
|
||||
/* Border Radius */
|
||||
/* 水平间距 */
|
||||
/* 垂直间距 */
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
.page {
|
||||
padding: 24rpx 24rpx 120rpx;
|
||||
background: #f6f7fb;
|
||||
}
|
||||
.hero {
|
||||
padding: 24rpx;
|
||||
background: linear-gradient(135deg, #4c8dff, #6ab7ff);
|
||||
border-radius: 20rpx;
|
||||
color: #fff;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.desc {
|
||||
font-size: 26rpx;
|
||||
margin-top: 8rpx;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.section {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx 22rpx;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 1rpx solid #f1f2f5;
|
||||
}
|
||||
.row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.row.required .label::after {
|
||||
content: "*";
|
||||
color: #ff5b5b;
|
||||
margin-left: 6rpx;
|
||||
}
|
||||
.label {
|
||||
width: 130rpx;
|
||||
font-size: 28rpx;
|
||||
color: #2d3a4a;
|
||||
}
|
||||
input {
|
||||
flex: 1;
|
||||
background: #f8f9fb;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx 18rpx;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
}
|
||||
.textarea {
|
||||
width: 100%;
|
||||
min-height: 160rpx;
|
||||
background: #f8f9fb;
|
||||
border-radius: 12rpx;
|
||||
padding: 18rpx;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
}
|
||||
.picker {
|
||||
flex: 1;
|
||||
background: #f8f9fb;
|
||||
border-radius: 12rpx;
|
||||
padding: 18rpx;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
}
|
||||
.picker-btn {
|
||||
background: #4c8dff;
|
||||
color: #fff;
|
||||
border-radius: 999rpx;
|
||||
padding: 10rpx 22rpx;
|
||||
}
|
||||
.triple input {
|
||||
flex: 1;
|
||||
}
|
||||
.fixed {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 20rpx 24rpx 40rpx;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
box-shadow: 0 -6rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.primary {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #4c8dff;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
const common_http = require("../../common/http.js");
|
||||
const common_vendor = require("../../common/vendor.js");
|
||||
function formatDate(d) {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
@@ -14,39 +14,62 @@ const _sfc_main = {
|
||||
return {
|
||||
startDate: formatDate(start),
|
||||
endDate: formatDate(now),
|
||||
mode: "sale",
|
||||
dim: "customer",
|
||||
rows: [],
|
||||
total: { sales: 0, cost: 0, profit: 0 }
|
||||
summary: { salesAmount: 0, costAmount: 0, profit: 0, profitRate: 0, itemCount: 0 },
|
||||
loading: false,
|
||||
error: ""
|
||||
};
|
||||
},
|
||||
onLoad(query) {
|
||||
try {
|
||||
const m = query && query.mode;
|
||||
const d = query && query.dim;
|
||||
if (m)
|
||||
this.mode = m;
|
||||
if (d)
|
||||
if (d === "product" || d === "customer")
|
||||
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) + "%";
|
||||
profitRateText() {
|
||||
var _a;
|
||||
const rate = Number(((_a = this.summary) == null ? void 0 : _a.profitRate) || 0);
|
||||
return rate.toFixed(2) + "%";
|
||||
},
|
||||
summaryItems() {
|
||||
if (!this.rows.length)
|
||||
return [];
|
||||
return [
|
||||
{ label: "销售额", value: `¥ ${this.fmt(this.summary.salesAmount)}` },
|
||||
{ label: "成本", value: `¥ ${this.fmt(this.summary.costAmount)}` },
|
||||
{ label: "利润", value: `¥ ${this.fmt(this.summary.profit)}` },
|
||||
{ label: "利润率", value: this.profitRateText }
|
||||
];
|
||||
}
|
||||
},
|
||||
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";
|
||||
showProductSpec(row) {
|
||||
return this.dim === "product" && row && row.spec;
|
||||
},
|
||||
rowMetrics(row) {
|
||||
if (!row)
|
||||
return [];
|
||||
return [
|
||||
{ label: "销售额", value: `¥ ${this.fmt(row.salesAmount)}` },
|
||||
{ label: "成本", value: `¥ ${this.fmt(row.costAmount)}` },
|
||||
{ label: "利润", value: `¥ ${this.fmt(row.profit)}` },
|
||||
{ label: "利润率", value: `${Number(row.profitRate || 0).toFixed(2)}%` }
|
||||
];
|
||||
},
|
||||
setDimension(d) {
|
||||
if (d !== "customer" && d !== "product")
|
||||
return;
|
||||
if (this.dim === d)
|
||||
return;
|
||||
this.dim = d;
|
||||
this.refresh();
|
||||
},
|
||||
onStartChange(e) {
|
||||
@@ -58,279 +81,85 @@ const _sfc_main = {
|
||||
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() {
|
||||
var _a, _b, _c, _d, _e;
|
||||
this.loading = true;
|
||||
this.error = "";
|
||||
try {
|
||||
const listResp = await common_http.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;
|
||||
const resp = await common_http.get("/api/report/sales", {
|
||||
dimension: this.dim,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate
|
||||
});
|
||||
const items = Array.isArray(resp == null ? void 0 : resp.items) ? resp.items : [];
|
||||
this.rows = items.map((it) => ({
|
||||
name: (it == null ? void 0 : it.name) || (this.dim === "product" ? "未命名商品" : "未指定客户"),
|
||||
spec: (it == null ? void 0 : it.spec) || "",
|
||||
salesAmount: Number((it == null ? void 0 : it.salesAmount) || 0),
|
||||
costAmount: Number((it == null ? void 0 : it.costAmount) || 0),
|
||||
profit: Number((it == null ? void 0 : it.profit) || 0),
|
||||
profitRate: Number((it == null ? void 0 : it.profitRate) || 0)
|
||||
}));
|
||||
this.summary = {
|
||||
salesAmount: Number(((_a = resp == null ? void 0 : resp.summary) == null ? void 0 : _a.salesAmount) || 0),
|
||||
costAmount: Number(((_b = resp == null ? void 0 : resp.summary) == null ? void 0 : _b.costAmount) || 0),
|
||||
profit: Number(((_c = resp == null ? void 0 : resp.summary) == null ? void 0 : _c.profit) || 0),
|
||||
profitRate: Number(((_d = resp == null ? void 0 : resp.summary) == null ? void 0 : _d.profitRate) || 0),
|
||||
itemCount: Number(((_e = resp == null ? void 0 : resp.summary) == null ? void 0 : _e.itemCount) || this.rows.length)
|
||||
};
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async loadByProduct() {
|
||||
try {
|
||||
const listResp = await common_http.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 common_http.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) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async loadPurchaseBySupplier() {
|
||||
try {
|
||||
const listResp = await common_http.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) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async loadPurchaseByProduct() {
|
||||
try {
|
||||
const listResp = await common_http.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 common_http.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) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async loadInventoryByQty() {
|
||||
try {
|
||||
const resp = await common_http.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) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async loadInventoryByAmount() {
|
||||
try {
|
||||
const resp = await common_http.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) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async loadAR() {
|
||||
try {
|
||||
const res = await common_http.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) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async loadAP() {
|
||||
try {
|
||||
const res = await common_http.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) {
|
||||
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
|
||||
this.error = e && e.message || "报表加载失败";
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||
return common_vendor.e({
|
||||
a: $data.mode === "sale" ? 1 : "",
|
||||
b: common_vendor.o(($event) => $options.setMode("sale")),
|
||||
c: $data.mode === "purchase" ? 1 : "",
|
||||
d: common_vendor.o(($event) => $options.setMode("purchase")),
|
||||
e: $data.mode === "inventory" ? 1 : "",
|
||||
f: common_vendor.o(($event) => $options.setMode("inventory")),
|
||||
g: $data.mode === "arap" ? 1 : "",
|
||||
h: common_vendor.o(($event) => $options.setMode("arap")),
|
||||
i: common_vendor.t($data.startDate),
|
||||
j: $data.startDate,
|
||||
k: common_vendor.o((...args) => $options.onStartChange && $options.onStartChange(...args)),
|
||||
l: common_vendor.t($data.endDate),
|
||||
m: $data.endDate,
|
||||
n: common_vendor.o((...args) => $options.onEndChange && $options.onEndChange(...args)),
|
||||
o: $data.mode === "sale"
|
||||
}, $data.mode === "sale" ? {
|
||||
p: $data.dim === "customer" ? 1 : "",
|
||||
q: common_vendor.o(($event) => {
|
||||
$data.dim = "customer";
|
||||
$options.refresh();
|
||||
}),
|
||||
r: $data.dim === "product" ? 1 : "",
|
||||
s: common_vendor.o(($event) => {
|
||||
$data.dim = "product";
|
||||
$options.refresh();
|
||||
})
|
||||
} : $data.mode === "purchase" ? {
|
||||
v: $data.dim === "supplier" ? 1 : "",
|
||||
w: common_vendor.o(($event) => {
|
||||
$data.dim = "supplier";
|
||||
$options.refresh();
|
||||
}),
|
||||
x: $data.dim === "product" ? 1 : "",
|
||||
y: common_vendor.o(($event) => {
|
||||
$data.dim = "product";
|
||||
$options.refresh();
|
||||
})
|
||||
} : $data.mode === "inventory" ? {
|
||||
A: $data.dim === "qty" ? 1 : "",
|
||||
B: common_vendor.o(($event) => {
|
||||
$data.dim = "qty";
|
||||
$options.refresh();
|
||||
}),
|
||||
C: $data.dim === "amount" ? 1 : "",
|
||||
D: common_vendor.o(($event) => {
|
||||
$data.dim = "amount";
|
||||
$options.refresh();
|
||||
})
|
||||
} : $data.mode === "arap" ? {
|
||||
F: $data.dim === "ar" ? 1 : "",
|
||||
G: common_vendor.o(($event) => {
|
||||
$data.dim = "ar";
|
||||
$options.refresh();
|
||||
}),
|
||||
H: $data.dim === "ap" ? 1 : "",
|
||||
I: common_vendor.o(($event) => {
|
||||
$data.dim = "ap";
|
||||
$options.refresh();
|
||||
a: common_vendor.t($data.startDate),
|
||||
b: $data.startDate,
|
||||
c: common_vendor.o((...args) => $options.onStartChange && $options.onStartChange(...args)),
|
||||
d: common_vendor.t($data.endDate),
|
||||
e: $data.endDate,
|
||||
f: common_vendor.o((...args) => $options.onEndChange && $options.onEndChange(...args)),
|
||||
g: $data.dim === "customer" ? 1 : "",
|
||||
h: common_vendor.o(($event) => $options.setDimension("customer")),
|
||||
i: $data.dim === "product" ? 1 : "",
|
||||
j: common_vendor.o(($event) => $options.setDimension("product")),
|
||||
k: $options.summaryItems.length
|
||||
}, $options.summaryItems.length ? {
|
||||
l: common_vendor.f($options.summaryItems, (item, ix, i0) => {
|
||||
return {
|
||||
a: common_vendor.t(item.label),
|
||||
b: common_vendor.t(item.value),
|
||||
c: ix
|
||||
};
|
||||
})
|
||||
} : {}, {
|
||||
t: $data.mode === "purchase",
|
||||
z: $data.mode === "inventory",
|
||||
E: $data.mode === "arap",
|
||||
J: common_vendor.t($options.fmt($data.total.sales)),
|
||||
K: common_vendor.t($options.fmt($data.total.cost)),
|
||||
L: common_vendor.t($options.fmt($data.total.profit)),
|
||||
M: common_vendor.t($options.profitRate),
|
||||
N: common_vendor.f($data.rows, (row, idx, i0) => {
|
||||
m: $data.loading
|
||||
}, $data.loading ? {} : $data.error ? {
|
||||
o: common_vendor.t($data.error)
|
||||
} : !$data.rows.length ? {} : {
|
||||
q: common_vendor.f($data.rows, (row, idx, i0) => {
|
||||
return common_vendor.e({
|
||||
a: row.avatar
|
||||
}, row.avatar ? {
|
||||
b: row.avatar
|
||||
a: common_vendor.t(row.name),
|
||||
b: $options.showProductSpec(row)
|
||||
}, $options.showProductSpec(row) ? {
|
||||
c: common_vendor.t(row.spec)
|
||||
} : {}, {
|
||||
c: common_vendor.t(row.name),
|
||||
d: common_vendor.t($options.fmt(row.sales)),
|
||||
e: common_vendor.t($options.fmt(row.cost)),
|
||||
f: common_vendor.t($options.fmt(row.profit)),
|
||||
g: idx
|
||||
d: common_vendor.f($options.rowMetrics(row), (metric, mIdx, i1) => {
|
||||
return {
|
||||
a: common_vendor.t(metric.label),
|
||||
b: common_vendor.t(metric.value),
|
||||
c: mIdx
|
||||
};
|
||||
}),
|
||||
e: idx
|
||||
});
|
||||
})
|
||||
}, {
|
||||
n: $data.error,
|
||||
p: !$data.rows.length
|
||||
});
|
||||
}
|
||||
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<view class="report"><view class="modes"><view class="{{['mode-tab', a && 'active']}}" bindtap="{{b}}">销售统计</view><view class="{{['mode-tab', c && 'active']}}" bindtap="{{d}}">进货统计</view><view class="{{['mode-tab', e && 'active']}}" bindtap="{{f}}">库存统计</view><view class="{{['mode-tab', g && 'active']}}" bindtap="{{h}}">应收/应付对账</view></view><view class="toolbar"><picker mode="date" value="{{j}}" bindchange="{{k}}"><view class="date">{{i}}</view></picker><text style="margin:0 8rpx">—</text><picker mode="date" value="{{m}}" bindchange="{{n}}"><view class="date">{{l}}</view></picker></view><view wx:if="{{o}}" class="tabs"><view class="{{['tab', p && 'active']}}" bindtap="{{q}}">按客户</view><view class="{{['tab', r && 'active']}}" bindtap="{{s}}">按货品</view></view><view wx:elif="{{t}}" class="tabs"><view class="{{['tab', v && 'active']}}" bindtap="{{w}}">按供应商</view><view class="{{['tab', x && 'active']}}" bindtap="{{y}}">按货品</view></view><view wx:elif="{{z}}" class="tabs"><view class="{{['tab', A && 'active']}}" bindtap="{{B}}">按数量</view><view class="{{['tab', C && 'active']}}" bindtap="{{D}}">按金额</view></view><view wx:elif="{{E}}" class="tabs"><view class="{{['tab', F && 'active']}}" bindtap="{{G}}">应收对账</view><view class="{{['tab', H && 'active']}}" bindtap="{{I}}">应付对账</view></view><view class="summary"><view class="item"><text class="label">销售额</text><text class="value">¥ {{J}}</text></view><view class="item"><text class="label">成本</text><text class="value">¥ {{K}}</text></view><view class="item"><text class="label">利润</text><text class="value">¥ {{L}}</text></view><view class="item"><text class="label">利润率</text><text class="value">{{M}}</text></view></view><view wx:for="{{N}}" wx:for-item="row" wx:key="g" class="card"><view class="row-head"><image wx:if="{{row.a}}" class="thumb" src="{{row.b}}"/><view class="title">{{row.c}}</view></view><view class="row-body"><text>销售额:¥ {{row.d}}</text><text style="margin-left:18rpx">成本:¥ {{row.e}}</text><text style="margin-left:18rpx">利润:¥ {{row.f}}</text></view></view></view>
|
||||
<view class="report"><view class="header">销售报表</view><view class="toolbar"><picker mode="date" value="{{b}}" bindchange="{{c}}"><view class="date">{{a}}</view></picker><text style="margin:0 8rpx">—</text><picker mode="date" value="{{e}}" bindchange="{{f}}"><view class="date">{{d}}</view></picker></view><view class="tabs"><view class="{{['tab', g && 'active']}}" bindtap="{{h}}">按客户</view><view class="{{['tab', i && 'active']}}" bindtap="{{j}}">按货品</view></view><view wx:if="{{k}}" class="summary"><view wx:for="{{l}}" wx:for-item="item" wx:key="c" class="summary-item"><text class="label">{{item.a}}</text><text class="value">{{item.b}}</text></view></view><view wx:if="{{m}}" class="loading">加载中...</view><view wx:elif="{{n}}" class="empty">{{o}}</view><view wx:elif="{{p}}" class="empty">暂无统计数据</view><view wx:else><view wx:for="{{q}}" wx:for-item="row" wx:key="e" class="card"><view class="row-head"><view class="row-title"><view class="title">{{row.a}}</view><view wx:if="{{row.b}}" class="subtitle">{{row.c}}</view></view></view><view class="row-body"><view wx:for="{{row.d}}" wx:for-item="metric" wx:key="c" class="metric"><text class="metric-label">{{metric.a}}</text><text class="metric-value">{{metric.b}}</text></view></view></view></view></view>
|
||||
@@ -25,101 +25,133 @@
|
||||
/* 透明度 */
|
||||
/* 文章场景相关 */
|
||||
.report {
|
||||
padding: 20rpx;
|
||||
}
|
||||
.modes {
|
||||
padding: 24rpx 20rpx 36rpx;
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 14rpx;
|
||||
flex-direction: column;
|
||||
gap: 18rpx;
|
||||
}
|
||||
.mode-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 16rpx 0;
|
||||
border-radius: 999rpx;
|
||||
background: #f1f1f1;
|
||||
color: #444;
|
||||
border: 1rpx solid #e5e7eb;
|
||||
}
|
||||
.mode-tab.active {
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
border-color: #4C8DFF;
|
||||
.header {
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #1f2a44;
|
||||
padding-left: 8rpx;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
background: #ffffff;
|
||||
padding: 14rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
background: #f7f9fc;
|
||||
border-radius: 16rpx;
|
||||
padding: 18rpx;
|
||||
}
|
||||
.date {
|
||||
padding: 10rpx 16rpx;
|
||||
border: 1rpx solid #e5e7eb;
|
||||
border-radius: 8rpx;
|
||||
color: #111;
|
||||
min-width: 200rpx;
|
||||
padding: 12rpx 18rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #fff;
|
||||
border: 1rpx solid rgba(91, 107, 139, 0.16);
|
||||
text-align: center;
|
||||
color: #32445b;
|
||||
}
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
margin-top: 14rpx;
|
||||
gap: 12rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
.tab {
|
||||
padding: 12rpx 18rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f1f1f1;
|
||||
color: #444;
|
||||
background: #f0f4ff;
|
||||
color: #5b6b8b;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.tab.active {
|
||||
background: #4C8DFF;
|
||||
color: #fff;
|
||||
background: rgba(76, 141, 255, 0.18);
|
||||
color: #3467d6;
|
||||
box-shadow: inset 0 0 0 2rpx rgba(76, 141, 255, 0.45);
|
||||
}
|
||||
.summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 8rpx;
|
||||
margin-top: 14rpx;
|
||||
grid-template-columns: repeat(auto-fill, minmax(240rpx, 1fr));
|
||||
gap: 12rpx;
|
||||
}
|
||||
.summary .item {
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx;
|
||||
.summary-item {
|
||||
background: #f7f9fc;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
.summary .label {
|
||||
font-size: 22rpx;
|
||||
color: #444;
|
||||
.summary-item .label {
|
||||
font-size: 24rpx;
|
||||
color: #6e7a96;
|
||||
}
|
||||
.summary .value {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
.summary-item .value {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
color: #1f2a44;
|
||||
}
|
||||
.card {
|
||||
margin-top: 16rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx;
|
||||
background: #fff;
|
||||
border-radius: 18rpx;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 8rpx 20rpx rgba(31, 42, 68, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14rpx;
|
||||
}
|
||||
.row-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.thumb {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #f1f1f1;
|
||||
.row-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
}
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
color: #1f2a44;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 24rpx;
|
||||
color: #6e7a96;
|
||||
}
|
||||
.row-body {
|
||||
margin-top: 10rpx;
|
||||
color: #444;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx 24rpx;
|
||||
}
|
||||
.metric {
|
||||
display: flex;
|
||||
gap: 8rpx;
|
||||
align-items: center;
|
||||
background: #f4f6fb;
|
||||
border-radius: 12rpx;
|
||||
padding: 10rpx 16rpx;
|
||||
}
|
||||
.metric-label {
|
||||
font-size: 24rpx;
|
||||
color: #6e7a96;
|
||||
}
|
||||
.metric-value {
|
||||
font-size: 28rpx;
|
||||
color: #1f2a44;
|
||||
font-weight: 600;
|
||||
}
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 80rpx 0;
|
||||
color: #9aa4be;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
color: #5b6b8b;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
@@ -11,9 +11,29 @@ const _sfc_main = {
|
||||
onLoad(query) {
|
||||
if (query && query.id) {
|
||||
this.id = Number(query.id);
|
||||
this.load();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async load() {
|
||||
if (!this.id)
|
||||
return;
|
||||
try {
|
||||
const d = await common_http.get(`/api/suppliers/${this.id}`);
|
||||
this.form = {
|
||||
name: (d == null ? void 0 : d.name) || "",
|
||||
contactName: (d == null ? void 0 : d.contactName) || "",
|
||||
mobile: (d == null ? void 0 : d.mobile) || "",
|
||||
phone: (d == null ? void 0 : d.phone) || "",
|
||||
address: (d == null ? void 0 : d.address) || "",
|
||||
apOpening: Number((d == null ? void 0 : d.apOpening) || 0),
|
||||
apPayable: Number((d == null ? void 0 : d.apPayable) || 0),
|
||||
remark: (d == null ? void 0 : d.remark) || ""
|
||||
};
|
||||
} catch (e) {
|
||||
common_vendor.index.showToast({ title: (e == null ? void 0 : e.message) || "加载失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
if (!this.form.name)
|
||||
return common_vendor.index.showToast({ title: "请填写供应商名称", icon: "none" });
|
||||
|
||||
@@ -25,12 +25,22 @@ const _sfc_main = {
|
||||
common_vendor.index.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;
|
||||
try {
|
||||
const pages = getCurrentPages();
|
||||
const opener = pages && pages.length >= 2 ? pages[pages.length - 2] : null;
|
||||
const vm = opener && opener.$vm ? opener.$vm : null;
|
||||
const canPick = !!(vm && vm.order);
|
||||
if (canPick) {
|
||||
vm.order.supplierId = s.id;
|
||||
if (Object.prototype.hasOwnProperty.call(vm, "supplierName"))
|
||||
vm.supplierName = s.name;
|
||||
common_vendor.index.navigateBack();
|
||||
} else {
|
||||
common_vendor.index.navigateTo({ url: `/pages/supplier/form?id=${s.id}` });
|
||||
}
|
||||
} catch (_) {
|
||||
common_vendor.index.navigateTo({ url: `/pages/supplier/form?id=${s.id}` });
|
||||
}
|
||||
common_vendor.index.navigateBack();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-close-48.png
vendored
Normal file
|
After Width: | Height: | Size: 397 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-dollar-ethereum-exchange-50.png
vendored
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-expenditure-64.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-graph-report-50.png
vendored
Normal file
|
After Width: | Height: | Size: 607 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-login-50.png
vendored
Normal file
|
After Width: | Height: | Size: 990 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-mitt-24.png
vendored
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-more-64.png
vendored
Normal file
|
After Width: | Height: | Size: 336 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-profile-50.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-profit-50.png
vendored
Normal file
|
After Width: | Height: | Size: 634 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-return-purchase-50.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-supplier-50.png
vendored
Normal file
|
After Width: | Height: | Size: 964 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-vip-48 (1).png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/icons8-vip-48.png
vendored
Normal file
|
After Width: | Height: | Size: 845 B |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/webwxgetmsgimg.jpg
vendored
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
frontend/unpackage/dist/dev/mp-weixin/static/icons/webwxgetmsgimg.png
vendored
Normal file
|
After Width: | Height: | Size: 2.1 KiB |