This commit is contained in:
18631081161 2026-02-21 16:18:01 +08:00
parent 420f0607bf
commit a927b930c1
38 changed files with 482 additions and 92 deletions

View File

@ -29,6 +29,8 @@ services:
DB_USER: root
DB_PASSWORD: jewelry123
DB_NAME: jewelry_mall
WX_APPID: wx58b02b73d9c26c10
WX_SECRET: 3b6cdaffa9ef92d877f79ebd739b47b0
JWT_SECRET: jewelry-mall-jwt-secret
PORT: 3000
volumes:

View File

@ -1,16 +1,7 @@
<script lang="ts">
import { autoLogin } from './utils/request'
export default {
onLaunch() {
console.log('App Launch')
// token
const token = uni.getStorageSync('token')
if (!token) {
autoLogin().catch((err) => {
console.error('自动登录失败:', err)
})
}
},
onShow() {
console.log('App Show')

View File

@ -50,7 +50,7 @@
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"appid" : "wx58b02b73d9c26c10",
"setting" : {
"urlCheck" : false,
"es6" : true,

View File

@ -59,6 +59,12 @@
"style": {
"navigationBarTitleText": "收货地址"
}
},
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "登录"
}
}
],
"globalStyle": {

View File

@ -76,6 +76,11 @@ function handleSettle() {
uni.showToast({ title: '请先选择商品', icon: 'none' })
return
}
const token = uni.getStorageSync('token')
if (!token) {
uni.navigateTo({ url: '/pages/login/index' })
return
}
uni.navigateTo({ url: '/pages/order/submit' })
}

View File

@ -0,0 +1,107 @@
<template>
<view class="login-page">
<view class="login-header">
<image class="login-logo" src="/static/logo.png" mode="aspectFit" />
<text class="login-title">珠宝商城</text>
<text class="login-desc">登录后享受完整购物体验</text>
</view>
<view class="login-actions">
<button class="login-btn" :loading="loading" @click="handleLogin">
微信一键登录
</button>
<view class="login-skip" @click="goBack">
<text>暂不登录先逛逛</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { autoLogin } from '../../utils/request'
import { useUserStore } from '../../store/user'
const loading = ref(false)
const userStore = useUserStore()
async function handleLogin() {
if (loading.value) return
loading.value = true
try {
await autoLogin()
await userStore.fetchProfile()
uni.showToast({ title: '登录成功', icon: 'success' })
setTimeout(() => {
uni.navigateBack({ delta: 1, fail: () => {
uni.switchTab({ url: '/pages/index/index' })
}})
}, 500)
} catch {
uni.showToast({ title: '登录失败,请重试', icon: 'none' })
} finally {
loading.value = false
}
}
function goBack() {
uni.navigateBack({ delta: 1, fail: () => {
uni.switchTab({ url: '/pages/index/index' })
}})
}
</script>
<style scoped>
.login-page {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #fff;
padding: 0 60rpx;
}
.login-header {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 120rpx;
}
.login-logo {
width: 160rpx;
height: 160rpx;
margin-bottom: 30rpx;
}
.login-title {
font-size: 40rpx;
font-weight: bold;
color: #333;
margin-bottom: 16rpx;
}
.login-desc {
font-size: 26rpx;
color: #999;
}
.login-actions {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.login-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: #e4393c;
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
border: none;
text-align: center;
}
.login-skip {
margin-top: 32rpx;
font-size: 26rpx;
color: #999;
}
</style>

View File

@ -1,40 +1,46 @@
<template>
<view class="mine-page">
<!-- 用户信息 -->
<view class="user-card">
<!-- 顶部用户卡片 -->
<view class="user-card" @click="handleUserCardClick">
<image class="user-card__avatar" :src="userStore.user?.avatar || '/static/logo.png'" mode="aspectFill" />
<view class="user-card__info">
<text class="user-card__name">{{ userStore.user?.nickname || '登录' }}</text>
<text class="user-card__name">{{ isLoggedIn ? (userStore.user?.nickname || '微信用户') : '点击注册/登录' }}</text>
</view>
<text class="user-card__arrow"></text>
</view>
<!-- 功能入口 -->
<view class="menu-group">
<view class="menu-item" @click="navigateTo('/pages/order/list')">
<text class="menu-item__label">我的订单</text>
<text class="menu-item__arrow"></text>
<!-- 我的订单 -->
<view class="order-entry" @click="navigateTo('/pages/order/list')">
<image class="order-entry__icon" src="/static/tab/me_s.png" mode="aspectFit" />
<text class="order-entry__text">我的订单 {{ orderCount }}</text>
<text class="order-entry__arrow"></text>
</view>
<!-- 功能菜单 -->
<view class="menu-group">
<view class="menu-item" @click="navigateTo('/pages/address/index')">
<image class="menu-item__icon" src="/static/ic_address.png" mode="aspectFit" />
<text class="menu-item__label">收货地址</text>
<text class="menu-item__arrow"></text>
</view>
<view class="menu-item" @click="showQrCode = true">
<image class="menu-item__icon" src="/static/ic_customer.png" mode="aspectFit" />
<text class="menu-item__label">联系客服</text>
<text class="menu-item__arrow"></text>
</view>
</view>
<view class="menu-group">
<view class="menu-item" @click="showAbout = true">
<image class="menu-item__icon" src="/static/ic_about.png" mode="aspectFit" />
<text class="menu-item__label">关于我们</text>
<text class="menu-item__arrow"></text>
</view>
<view class="menu-item" @click="showAgreement('user')">
<image class="menu-item__icon" src="/static/ic_agreement1.png" mode="aspectFit" />
<text class="menu-item__label">用户协议</text>
<text class="menu-item__arrow"></text>
</view>
<view class="menu-item" @click="showAgreement('privacy')">
<text class="menu-item__label">隐私政策</text>
<image class="menu-item__icon" src="/static/ic_agreement2.png" mode="aspectFit" />
<text class="menu-item__label">隐私协议</text>
<text class="menu-item__arrow"></text>
</view>
</view>
@ -54,25 +60,50 @@
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { ref } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useUserStore } from '../../store/user'
import { getOrderList } from '../../api/order'
import CustomerServiceBtn from '../../components/CustomerServiceBtn.vue'
const userStore = useUserStore()
const showQrCode = ref(false)
const showAbout = ref(false)
const orderCount = ref(0)
const isLoggedIn = ref(false)
onMounted(() => {
//
function refreshData() {
const token = uni.getStorageSync('token')
isLoggedIn.value = !!token
if (token) {
userStore.fetchProfile()
getOrderList().then((data: any) => {
orderCount.value = Array.isArray(data) ? data.length : (data?.total || 0)
}).catch(() => {})
}
}
onShow(() => {
refreshData()
})
function handleUserCardClick() {
if (!isLoggedIn.value) {
uni.navigateTo({ url: '/pages/login/index' })
}
}
function navigateTo(url: string) {
const token = uni.getStorageSync('token')
if (!token) {
uni.navigateTo({ url: '/pages/login/index' })
return
}
uni.navigateTo({ url })
}
function showAgreement(type: 'user' | 'privacy') {
const title = type === 'user' ? '用户协议' : '隐私政策'
const title = type === 'user' ? '用户协议' : '隐私协议'
uni.showModal({
title,
content: type === 'user'
@ -88,43 +119,87 @@ function showAgreement(type: 'user' | 'privacy') {
.mine-page {
min-height: 100vh;
background: #f5f5f5;
padding-top: 20rpx;
}
/* 用户卡片 */
.user-card {
display: flex;
align-items: center;
background: #e4393c;
padding: 60rpx 32rpx 40rpx;
background: #fff;
margin: 0 24rpx;
padding: 32rpx;
border-radius: 16rpx;
}
.user-card__avatar {
width: 120rpx;
height: 120rpx;
width: 96rpx;
height: 96rpx;
border-radius: 50%;
border: 4rpx solid rgba(255, 255, 255, 0.5);
background: #fff;
background: #f0f0f0;
flex-shrink: 0;
}
.user-card__info {
flex: 1;
margin-left: 24rpx;
}
.user-card__name {
font-size: 34rpx;
color: #fff;
font-size: 32rpx;
color: #333;
font-weight: bold;
}
.user-card__arrow {
font-size: 36rpx;
color: #ccc;
}
/* 我的订单入口 */
.order-entry {
display: flex;
align-items: center;
margin: 20rpx 24rpx 0;
padding: 24rpx 32rpx;
background: linear-gradient(135deg, #fce4ec, #f8bbd0);
border-radius: 16rpx;
}
.order-entry__icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.order-entry__text {
flex: 1;
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.order-entry__arrow {
font-size: 32rpx;
color: #999;
}
/* 功能菜单 */
.menu-group {
background: #fff;
margin-top: 16rpx;
margin: 20rpx 24rpx 0;
border-radius: 16rpx;
overflow: hidden;
}
.menu-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 28rpx 32rpx;
border-bottom: 1rpx solid #f0f0f0;
padding: 30rpx 32rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.menu-item:last-child {
border-bottom: none;
}
.menu-item__icon {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
.menu-item__label {
flex: 1;
font-size: 28rpx;
color: #333;
}
@ -132,6 +207,8 @@ function showAgreement(type: 'user' | 'privacy') {
font-size: 32rpx;
color: #ccc;
}
/* 弹窗 */
.modal-mask {
position: fixed;
top: 0;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1 +1 @@
{"version":3,"file":"app.js","sources":["App.vue","main.js"],"sourcesContent":["<script lang=\"ts\">\r\nimport { autoLogin } from './utils/request'\r\n\r\nexport default {\r\n onLaunch() {\r\n uni.__f__('log','at App.vue:6','App Launch')\r\n // 检查是否已有 token没有则自动登录\r\n const token = uni.getStorageSync('token')\r\n if (!token) {\r\n autoLogin().catch((err) => {\r\n uni.__f__('error','at App.vue:11','自动登录失败:', err)\r\n })\r\n }\r\n },\r\n onShow() {\r\n uni.__f__('log','at App.vue:16','App Show')\r\n },\r\n onHide() {\r\n uni.__f__('log','at App.vue:19','App Hide')\r\n },\r\n}\r\n</script>\r\n\r\n<style>\r\n/* 每个页面公共 css */\r\n</style>\r\n","import App from './App'\n\n// #ifndef VUE3\nimport Vue from 'vue'\nimport './uni.promisify.adaptor'\nVue.config.productionTip = false\nApp.mpType = 'app'\nconst app = new Vue({\n ...App\n})\napp.$mount()\n// #endif\n\n// #ifdef VUE3\nimport { createSSRApp } from 'vue'\nimport { createPinia } from 'pinia'\nexport function createApp() {\n const app = createSSRApp(App)\n const pinia = createPinia()\n app.use(pinia)\n return {\n app\n }\n}\n// #endif"],"names":["uni","autoLogin","createSSRApp","App","createPinia"],"mappings":";;;;;;;;;;;;;;;;AAGA,MAAe,YAAA;AAAA,EACb,WAAW;AACLA,kBAAAA,MAAA,MAAM,OAAM,gBAAe,YAAY;AAErC,UAAA,QAAQA,cAAAA,MAAI,eAAe,OAAO;AACxC,QAAI,CAAC,OAAO;AACAC,8BAAA,EAAE,MAAM,CAAC,QAAQ;AACzBD,sBAAA,MAAI,MAAM,SAAQ,iBAAgB,WAAW,GAAG;AAAA,MAAA,CACjD;AAAA,IACH;AAAA,EACF;AAAA,EACA,SAAS;AACHA,kBAAAA,MAAA,MAAM,OAAM,iBAAgB,UAAU;AAAA,EAC5C;AAAA,EACA,SAAS;AACHA,kBAAAA,MAAA,MAAM,OAAM,iBAAgB,UAAU;AAAA,EAC5C;AACF;ACJO,SAAS,YAAY;AAC1B,QAAM,MAAME,cAAY,aAACC,SAAG;AAC5B,QAAM,QAAQC,cAAAA,YAAa;AAC3B,MAAI,IAAI,KAAK;AACb,SAAO;AAAA,IACL;AAAA,EACD;AACH;;;"}
{"version":3,"file":"app.js","sources":["App.vue","main.js"],"sourcesContent":["<script lang=\"ts\">\r\nexport default {\r\n onLaunch() {\r\n uni.__f__('log','at App.vue:4','App Launch')\r\n },\r\n onShow() {\r\n uni.__f__('log','at App.vue:7','App Show')\r\n },\r\n onHide() {\r\n uni.__f__('log','at App.vue:10','App Hide')\r\n },\r\n}\r\n</script>\r\n\r\n<style>\r\n/* 每个页面公共 css */\r\n</style>\r\n","import App from './App'\n\n// #ifndef VUE3\nimport Vue from 'vue'\nimport './uni.promisify.adaptor'\nVue.config.productionTip = false\nApp.mpType = 'app'\nconst app = new Vue({\n ...App\n})\napp.$mount()\n// #endif\n\n// #ifdef VUE3\nimport { createSSRApp } from 'vue'\nimport { createPinia } from 'pinia'\nexport function createApp() {\n const app = createSSRApp(App)\n const pinia = createPinia()\n app.use(pinia)\n return {\n app\n }\n}\n// #endif"],"names":["uni","createSSRApp","App","createPinia"],"mappings":";;;;;;;;;;;;;;;;AACA,MAAe,YAAA;AAAA,EACb,WAAW;AACLA,kBAAAA,MAAA,MAAM,OAAM,gBAAe,YAAY;AAAA,EAC7C;AAAA,EACA,SAAS;AACHA,kBAAAA,MAAA,MAAM,OAAM,gBAAe,UAAU;AAAA,EAC3C;AAAA,EACA,SAAS;AACHA,kBAAAA,MAAA,MAAM,OAAM,iBAAgB,UAAU;AAAA,EAC5C;AACF;ACKO,SAAS,YAAY;AAC1B,QAAM,MAAMC,cAAY,aAACC,SAAG;AAC5B,QAAM,QAAQC,cAAAA,YAAa;AAC3B,MAAI,IAAI,KAAK;AACb,SAAO;AAAA,IACL;AAAA,EACD;AACH;;;"}

View File

@ -1 +1 @@
{"version":3,"file":"assets.js","sources":["static/logo.png"],"sourcesContent":["export default \"__VITE_ASSET__46719607__\""],"names":[],"mappings":";AAAA,MAAe,aAAA;;"}
{"version":3,"file":"assets.js","sources":["static/tab/me_s.png","static/ic_address.png","static/ic_customer.png","static/ic_about.png","static/ic_agreement1.png","static/ic_agreement2.png","static/logo.png"],"sourcesContent":["export default \"__VITE_ASSET__0724ec6f__\"","export default \"__VITE_ASSET__2fa96069__\"","export default \"__VITE_ASSET__834c867b__\"","export default \"__VITE_ASSET__53f234dc__\"","export default \"__VITE_ASSET__a736f8f4__\"","export default \"__VITE_ASSET__a25b5e1b__\"","export default \"__VITE_ASSET__46719607__\""],"names":[],"mappings":";AAAA,MAAe,eAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;;;;;;;;"}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["pages/login/index.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbG9naW4vaW5kZXgudnVl"],"sourcesContent":["<template>\r\n <view class=\"login-page\">\r\n <view class=\"login-header\">\r\n <image class=\"login-logo\" src=\"/static/logo.png\" mode=\"aspectFit\" />\r\n <text class=\"login-title\">珠宝商城</text>\r\n <text class=\"login-desc\">登录后享受完整购物体验</text>\r\n </view>\r\n\r\n <view class=\"login-actions\">\r\n <button class=\"login-btn\" :loading=\"loading\" @click=\"handleLogin\">\r\n 微信一键登录\r\n </button>\r\n <view class=\"login-skip\" @click=\"goBack\">\r\n <text>暂不登录,先逛逛</text>\r\n </view>\r\n </view>\r\n </view>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from 'vue'\r\nimport { autoLogin } from '../../utils/request'\r\nimport { useUserStore } from '../../store/user'\r\n\r\nconst loading = ref(false)\r\nconst userStore = useUserStore()\r\n\r\nasync function handleLogin() {\r\n if (loading.value) return\r\n loading.value = true\r\n try {\r\n await autoLogin()\r\n await userStore.fetchProfile()\r\n uni.showToast({ title: '登录成功', icon: 'success' })\r\n setTimeout(() => {\r\n uni.navigateBack({ delta: 1, fail: () => {\r\n uni.switchTab({ url: '/pages/index/index' })\r\n }})\r\n }, 500)\r\n } catch {\r\n uni.showToast({ title: '登录失败,请重试', icon: 'none' })\r\n } finally {\r\n loading.value = false\r\n }\r\n}\r\n\r\nfunction goBack() {\r\n uni.navigateBack({ delta: 1, fail: () => {\r\n uni.switchTab({ url: '/pages/index/index' })\r\n }})\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.login-page {\r\n min-height: 100vh;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n background: #fff;\r\n padding: 0 60rpx;\r\n}\r\n.login-header {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n margin-bottom: 120rpx;\r\n}\r\n.login-logo {\r\n width: 160rpx;\r\n height: 160rpx;\r\n margin-bottom: 30rpx;\r\n}\r\n.login-title {\r\n font-size: 40rpx;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 16rpx;\r\n}\r\n.login-desc {\r\n font-size: 26rpx;\r\n color: #999;\r\n}\r\n.login-actions {\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n}\r\n.login-btn {\r\n width: 100%;\r\n height: 88rpx;\r\n line-height: 88rpx;\r\n background: #e4393c;\r\n color: #fff;\r\n font-size: 32rpx;\r\n border-radius: 44rpx;\r\n border: none;\r\n text-align: center;\r\n}\r\n.login-skip {\r\n margin-top: 32rpx;\r\n font-size: 26rpx;\r\n color: #999;\r\n}\r\n</style>\r\n","import MiniProgramPage from 'F:/gitCode/uniapp/JewelryMall/miniprogram/pages/login/index.vue'\nwx.createPage(MiniProgramPage)"],"names":["ref","useUserStore","autoLogin","uni"],"mappings":";;;;;;;;AAwBM,UAAA,UAAUA,kBAAI,KAAK;AACzB,UAAM,YAAYC,WAAAA;AAElB,mBAAe,cAAc;AAC3B,UAAI,QAAQ;AAAO;AACnB,cAAQ,QAAQ;AACZ,UAAA;AACF,cAAMC,cAAU,UAAA;AAChB,cAAM,UAAU;AAChBC,sBAAA,MAAI,UAAU,EAAE,OAAO,QAAQ,MAAM,WAAW;AAChD,mBAAW,MAAM;AACfA,wBAAAA,MAAI,aAAa,EAAE,OAAO,GAAG,MAAM,MAAM;AACvCA,0BAAAA,MAAI,UAAU,EAAE,KAAK,qBAAsB,CAAA;AAAA,aAC3C;AAAA,WACD,GAAG;AAAA,MAAA,QACA;AACNA,sBAAA,MAAI,UAAU,EAAE,OAAO,YAAY,MAAM,QAAQ;AAAA,MAAA,UACjD;AACA,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAEA,aAAS,SAAS;AAChBA,oBAAAA,MAAI,aAAa,EAAE,OAAO,GAAG,MAAM,MAAM;AACvCA,sBAAAA,MAAI,UAAU,EAAE,KAAK,qBAAsB,CAAA;AAAA,SAC3C;AAAA,IACJ;;;;;;;;;;;;ACjDA,GAAG,WAAW,eAAe;"}

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,6 @@
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const common_vendor = require("./common/vendor.js");
const utils_request = require("./utils/request.js");
if (!Math) {
"./pages/index/index.js";
"./pages/product/detail.js";
@ -13,22 +12,17 @@ if (!Math) {
"./pages/calculator/index.js";
"./pages/mine/index.js";
"./pages/address/index.js";
"./pages/login/index.js";
}
const _sfc_main = {
onLaunch() {
common_vendor.index.__f__("log", "at App.vue:6", "App Launch");
const token = common_vendor.index.getStorageSync("token");
if (!token) {
utils_request.autoLogin().catch((err) => {
common_vendor.index.__f__("error", "at App.vue:11", "自动登录失败:", err);
});
}
common_vendor.index.__f__("log", "at App.vue:4", "App Launch");
},
onShow() {
common_vendor.index.__f__("log", "at App.vue:16", "App Show");
common_vendor.index.__f__("log", "at App.vue:7", "App Show");
},
onHide() {
common_vendor.index.__f__("log", "at App.vue:19", "App Hide");
common_vendor.index.__f__("log", "at App.vue:10", "App Hide");
}
};
function createApp() {

View File

@ -9,7 +9,8 @@
"pages/mold/index",
"pages/calculator/index",
"pages/mine/index",
"pages/address/index"
"pages/address/index",
"pages/login/index"
],
"window": {
"navigationBarTextStyle": "black",

View File

@ -1,4 +1,16 @@
"use strict";
const _imports_0$1 = "/static/tab/me_s.png";
const _imports_1 = "/static/ic_address.png";
const _imports_2 = "/static/ic_customer.png";
const _imports_3 = "/static/ic_about.png";
const _imports_4 = "/static/ic_agreement1.png";
const _imports_5 = "/static/ic_agreement2.png";
const _imports_0 = "/static/logo.png";
exports._imports_0 = _imports_0;
exports._imports_0 = _imports_0$1;
exports._imports_0$1 = _imports_0;
exports._imports_1 = _imports_1;
exports._imports_2 = _imports_2;
exports._imports_3 = _imports_3;
exports._imports_4 = _imports_4;
exports._imports_5 = _imports_5;
//# sourceMappingURL=../../.sourcemap/mp-weixin/common/assets.js.map

View File

@ -7041,7 +7041,7 @@ function isConsoleWritable() {
function initRuntimeSocketService() {
const hosts = "172.31.144.1,192.168.21.7,192.168.195.32,127.0.0.1";
const port = "8090";
const id = "mp-weixin_oR94fT";
const id = "mp-weixin_ucp1tM";
const lazy = typeof swan !== "undefined";
let restoreError = lazy ? () => {
} : initOnError();

View File

@ -12,7 +12,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
return common_vendor.e({
a: _ctx.mode === "qrcode"
}, _ctx.mode === "qrcode" ? {
b: common_assets._imports_0,
b: common_assets._imports_0$1,
c: common_vendor.o(($event) => _ctx.$emit("close")),
d: common_vendor.o(() => {
}),

View File

@ -23,6 +23,11 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
common_vendor.index.showToast({ title: "请先选择商品", icon: "none" });
return;
}
const token = common_vendor.index.getStorageSync("token");
if (!token) {
common_vendor.index.navigateTo({ url: "/pages/login/index" });
return;
}
common_vendor.index.navigateTo({ url: "/pages/order/submit" });
}
function goHome() {

View File

@ -0,0 +1,47 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const common_assets = require("../../common/assets.js");
const utils_request = require("../../utils/request.js");
const store_user = require("../../store/user.js");
const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
__name: "index",
setup(__props) {
const loading = common_vendor.ref(false);
const userStore = store_user.useUserStore();
async function handleLogin() {
if (loading.value)
return;
loading.value = true;
try {
await utils_request.autoLogin();
await userStore.fetchProfile();
common_vendor.index.showToast({ title: "登录成功", icon: "success" });
setTimeout(() => {
common_vendor.index.navigateBack({ delta: 1, fail: () => {
common_vendor.index.switchTab({ url: "/pages/index/index" });
} });
}, 500);
} catch {
common_vendor.index.showToast({ title: "登录失败,请重试", icon: "none" });
} finally {
loading.value = false;
}
}
function goBack() {
common_vendor.index.navigateBack({ delta: 1, fail: () => {
common_vendor.index.switchTab({ url: "/pages/index/index" });
} });
}
return (_ctx, _cache) => {
return {
a: common_assets._imports_0$1,
b: loading.value,
c: common_vendor.o(handleLogin),
d: common_vendor.o(goBack)
};
};
}
});
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-d08ef7d4"]]);
wx.createPage(MiniProgramPage);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/login/index.js.map

View File

@ -0,0 +1,4 @@
{
"navigationBarTitleText": "登录",
"usingComponents": {}
}

View File

@ -0,0 +1 @@
<view class="login-page data-v-d08ef7d4"><view class="login-header data-v-d08ef7d4"><image class="login-logo data-v-d08ef7d4" src="{{a}}" mode="aspectFit"/><text class="login-title data-v-d08ef7d4">珠宝商城</text><text class="login-desc data-v-d08ef7d4">登录后享受完整购物体验</text></view><view class="login-actions data-v-d08ef7d4"><button class="login-btn data-v-d08ef7d4" loading="{{b}}" bindtap="{{c}}"> 微信一键登录 </button><view class="login-skip data-v-d08ef7d4" bindtap="{{d}}"><text class="data-v-d08ef7d4">暂不登录,先逛逛</text></view></view></view>

View File

@ -0,0 +1,53 @@
.login-page.data-v-d08ef7d4 {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #fff;
padding: 0 60rpx;
}
.login-header.data-v-d08ef7d4 {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 120rpx;
}
.login-logo.data-v-d08ef7d4 {
width: 160rpx;
height: 160rpx;
margin-bottom: 30rpx;
}
.login-title.data-v-d08ef7d4 {
font-size: 40rpx;
font-weight: bold;
color: #333;
margin-bottom: 16rpx;
}
.login-desc.data-v-d08ef7d4 {
font-size: 26rpx;
color: #999;
}
.login-actions.data-v-d08ef7d4 {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.login-btn.data-v-d08ef7d4 {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: #e4393c;
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
border: none;
text-align: center;
}
.login-skip.data-v-d08ef7d4 {
margin-top: 32rpx;
font-size: 26rpx;
color: #999;
}

View File

@ -1,6 +1,8 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const common_assets = require("../../common/assets.js");
const store_user = require("../../store/user.js");
const api_order = require("../../api/order.js");
if (!Math) {
CustomerServiceBtn();
}
@ -11,14 +13,37 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
const userStore = store_user.useUserStore();
const showQrCode = common_vendor.ref(false);
const showAbout = common_vendor.ref(false);
common_vendor.onMounted(() => {
const orderCount = common_vendor.ref(0);
const isLoggedIn = common_vendor.ref(false);
function refreshData() {
const token = common_vendor.index.getStorageSync("token");
isLoggedIn.value = !!token;
if (token) {
userStore.fetchProfile();
api_order.getOrderList().then((data) => {
orderCount.value = Array.isArray(data) ? data.length : (data == null ? void 0 : data.total) || 0;
}).catch(() => {
});
}
}
common_vendor.onShow(() => {
refreshData();
});
function handleUserCardClick() {
if (!isLoggedIn.value) {
common_vendor.index.navigateTo({ url: "/pages/login/index" });
}
}
function navigateTo(url) {
const token = common_vendor.index.getStorageSync("token");
if (!token) {
common_vendor.index.navigateTo({ url: "/pages/login/index" });
return;
}
common_vendor.index.navigateTo({ url });
}
function showAgreement(type) {
const title = type === "user" ? "用户协议" : "隐私政策";
const title = type === "user" ? "用户协议" : "隐私协议";
common_vendor.index.showModal({
title,
content: type === "user" ? "欢迎使用珠宝商城小程序。使用本小程序即表示您同意遵守相关服务条款。" : "我们重视您的隐私保护。我们仅收集必要的信息以提供服务,不会向第三方泄露您的个人信息。",
@ -30,26 +55,34 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
var _a, _b;
return common_vendor.e({
a: ((_a = common_vendor.unref(userStore).user) == null ? void 0 : _a.avatar) || "/static/logo.png",
b: common_vendor.t(((_b = common_vendor.unref(userStore).user) == null ? void 0 : _b.nickname) || "未登录"),
c: common_vendor.o(($event) => navigateTo("/pages/order/list")),
d: common_vendor.o(($event) => navigateTo("/pages/address/index")),
e: common_vendor.o(($event) => showQrCode.value = true),
f: common_vendor.o(($event) => showAbout.value = true),
g: common_vendor.o(($event) => showAgreement("user")),
h: common_vendor.o(($event) => showAgreement("privacy")),
i: showQrCode.value
b: common_vendor.t(isLoggedIn.value ? ((_b = common_vendor.unref(userStore).user) == null ? void 0 : _b.nickname) || "微信用户" : "点击注册/登录"),
c: common_vendor.o(handleUserCardClick),
d: common_assets._imports_0,
e: common_vendor.t(orderCount.value),
f: common_vendor.o(($event) => navigateTo("/pages/order/list")),
g: common_assets._imports_1,
h: common_vendor.o(($event) => navigateTo("/pages/address/index")),
i: common_assets._imports_2,
j: common_vendor.o(($event) => showQrCode.value = true),
k: common_assets._imports_3,
l: common_vendor.o(($event) => showAbout.value = true),
m: common_assets._imports_4,
n: common_vendor.o(($event) => showAgreement("user")),
o: common_assets._imports_5,
p: common_vendor.o(($event) => showAgreement("privacy")),
q: showQrCode.value
}, showQrCode.value ? {
j: common_vendor.o(($event) => showQrCode.value = false),
k: common_vendor.p({
r: common_vendor.o(($event) => showQrCode.value = false),
s: common_vendor.p({
mode: "qrcode"
})
} : {}, {
l: showAbout.value
t: showAbout.value
}, showAbout.value ? {
m: common_vendor.o(($event) => showAbout.value = false),
n: common_vendor.o(() => {
v: common_vendor.o(($event) => showAbout.value = false),
w: common_vendor.o(() => {
}),
o: common_vendor.o(($event) => showAbout.value = false)
x: common_vendor.o(($event) => showAbout.value = false)
} : {});
};
}

View File

@ -1 +1 @@
<view class="mine-page data-v-569e925a"><view class="user-card data-v-569e925a"><image class="user-card__avatar data-v-569e925a" src="{{a}}" mode="aspectFill"/><view class="user-card__info data-v-569e925a"><text class="user-card__name data-v-569e925a">{{b}}</text></view></view><view class="menu-group data-v-569e925a"><view class="menu-item data-v-569e925a" bindtap="{{c}}"><text class="menu-item__label data-v-569e925a">我的订单</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{d}}"><text class="menu-item__label data-v-569e925a">收货地址</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{e}}"><text class="menu-item__label data-v-569e925a">联系客服</text><text class="menu-item__arrow data-v-569e925a"></text></view></view><view class="menu-group data-v-569e925a"><view class="menu-item data-v-569e925a" bindtap="{{f}}"><text class="menu-item__label data-v-569e925a">关于我们</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{g}}"><text class="menu-item__label data-v-569e925a">用户协议</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{h}}"><text class="menu-item__label data-v-569e925a">隐私政策</text><text class="menu-item__arrow data-v-569e925a"></text></view></view><customer-service-btn wx:if="{{i}}" class="data-v-569e925a" bindclose="{{j}}" u-i="569e925a-0" bind:__l="__l" u-p="{{k}}"/><view wx:if="{{l}}" class="modal-mask data-v-569e925a" bindtap="{{o}}"><view class="modal-popup data-v-569e925a" catchtap="{{n}}"><text class="modal-popup__title data-v-569e925a">关于我们</text><text class="modal-popup__content data-v-569e925a">珠宝商城 —— 专注珠宝零售,为您提供优质珠宝商品和贴心服务。</text><view class="modal-popup__close data-v-569e925a" bindtap="{{m}}">关闭</view></view></view></view>
<view class="mine-page data-v-569e925a"><view class="user-card data-v-569e925a" bindtap="{{c}}"><image class="user-card__avatar data-v-569e925a" src="{{a}}" mode="aspectFill"/><view class="user-card__info data-v-569e925a"><text class="user-card__name data-v-569e925a">{{b}}</text></view><text class="user-card__arrow data-v-569e925a"></text></view><view class="order-entry data-v-569e925a" bindtap="{{f}}"><image class="order-entry__icon data-v-569e925a" src="{{d}}" mode="aspectFit"/><text class="order-entry__text data-v-569e925a">我的订单 {{e}}</text><text class="order-entry__arrow data-v-569e925a"></text></view><view class="menu-group data-v-569e925a"><view class="menu-item data-v-569e925a" bindtap="{{h}}"><image class="menu-item__icon data-v-569e925a" src="{{g}}" mode="aspectFit"/><text class="menu-item__label data-v-569e925a">收货地址</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{j}}"><image class="menu-item__icon data-v-569e925a" src="{{i}}" mode="aspectFit"/><text class="menu-item__label data-v-569e925a">联系客服</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{l}}"><image class="menu-item__icon data-v-569e925a" src="{{k}}" mode="aspectFit"/><text class="menu-item__label data-v-569e925a">关于我们</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{n}}"><image class="menu-item__icon data-v-569e925a" src="{{m}}" mode="aspectFit"/><text class="menu-item__label data-v-569e925a">用户协议</text><text class="menu-item__arrow data-v-569e925a"></text></view><view class="menu-item data-v-569e925a" bindtap="{{p}}"><image class="menu-item__icon data-v-569e925a" src="{{o}}" mode="aspectFit"/><text class="menu-item__label data-v-569e925a">隐私协议</text><text class="menu-item__arrow data-v-569e925a"></text></view></view><customer-service-btn wx:if="{{q}}" class="data-v-569e925a" bindclose="{{r}}" u-i="569e925a-0" bind:__l="__l" u-p="{{s}}"/><view wx:if="{{t}}" class="modal-mask data-v-569e925a" bindtap="{{x}}"><view class="modal-popup data-v-569e925a" catchtap="{{w}}"><text class="modal-popup__title data-v-569e925a">关于我们</text><text class="modal-popup__content data-v-569e925a">珠宝商城 —— 专注珠宝零售,为您提供优质珠宝商品和贴心服务。</text><view class="modal-popup__close data-v-569e925a" bindtap="{{v}}">关闭</view></view></view></view>

View File

@ -2,43 +2,87 @@
.mine-page.data-v-569e925a {
min-height: 100vh;
background: #f5f5f5;
padding-top: 20rpx;
}
/* 用户卡片 */
.user-card.data-v-569e925a {
display: flex;
align-items: center;
background: #e4393c;
padding: 60rpx 32rpx 40rpx;
background: #fff;
margin: 0 24rpx;
padding: 32rpx;
border-radius: 16rpx;
}
.user-card__avatar.data-v-569e925a {
width: 120rpx;
height: 120rpx;
width: 96rpx;
height: 96rpx;
border-radius: 50%;
border: 4rpx solid rgba(255, 255, 255, 0.5);
background: #fff;
background: #f0f0f0;
flex-shrink: 0;
}
.user-card__info.data-v-569e925a {
flex: 1;
margin-left: 24rpx;
}
.user-card__name.data-v-569e925a {
font-size: 34rpx;
color: #fff;
font-size: 32rpx;
color: #333;
font-weight: bold;
}
.user-card__arrow.data-v-569e925a {
font-size: 36rpx;
color: #ccc;
}
/* 我的订单入口 */
.order-entry.data-v-569e925a {
display: flex;
align-items: center;
margin: 20rpx 24rpx 0;
padding: 24rpx 32rpx;
background: linear-gradient(135deg, #fce4ec, #f8bbd0);
border-radius: 16rpx;
}
.order-entry__icon.data-v-569e925a {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.order-entry__text.data-v-569e925a {
flex: 1;
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.order-entry__arrow.data-v-569e925a {
font-size: 32rpx;
color: #999;
}
/* 功能菜单 */
.menu-group.data-v-569e925a {
background: #fff;
margin-top: 16rpx;
margin: 20rpx 24rpx 0;
border-radius: 16rpx;
overflow: hidden;
}
.menu-item.data-v-569e925a {
display: flex;
justify-content: space-between;
align-items: center;
padding: 28rpx 32rpx;
border-bottom: 1rpx solid #f0f0f0;
padding: 30rpx 32rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.menu-item.data-v-569e925a:last-child {
border-bottom: none;
}
.menu-item__icon.data-v-569e925a {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
.menu-item__label.data-v-569e925a {
flex: 1;
font-size: 28rpx;
color: #333;
}
@ -46,6 +90,8 @@
font-size: 32rpx;
color: #ccc;
}
/* 弹窗 */
.modal-mask.data-v-569e925a {
position: fixed;
top: 0;

View File

@ -9,12 +9,11 @@
"postcss": false,
"minified": true,
"newFeature": true,
"bigPackageSizeSupport": true,
"minifyWXML": true
"bigPackageSizeSupport": true
},
"compileType": "miniprogram",
"libVersion": "",
"appid": "touristappid",
"appid": "wx58b02b73d9c26c10",
"projectname": "miniprogram",
"condition": {
"search": {

View File

@ -0,0 +1,5 @@
{
"setting": {
"urlCheck": false
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -25,9 +25,10 @@ export async function wxLogin(req: Request, res: Response): Promise<void> {
},
})
const { openid } = wxRes.data
const { openid, errcode, errmsg } = wxRes.data
if (!openid) {
res.status(400).json({ code: 400, message: '微信登录失败,请重试' })
console.error('WeChat jscode2session failed:', { errcode, errmsg })
res.status(400).json({ code: 400, message: errmsg || '微信登录失败,请重试' })
return
}