2
This commit is contained in:
@@ -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
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
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
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
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
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
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user