From 73cfc42a3876789e5a3a0d35ca1d2e4d9cffc91b Mon Sep 17 00:00:00 2001 From: zpc Date: Sat, 21 Jun 2025 23:03:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 + common/server/other.js | 33 + common/server/user.js | 45 +- common/system/router.js | 22 +- common/system/userInfo.js | 49 ++ common/utils.js | 79 +- common/yds.js | 14 + components.d.ts | 5 + components/youdas-container/loading-data.vue | 1 + .../youdas-container/news-list-item.vue | 2 +- .../youdas-container/order-list-item.vue | 153 ++++ .../youdas-container/page-base-container.vue | 100 +++ .../youdas-container/page-container.vue | 27 +- components/youdas-container/page-line.vue | 31 + .../youdas-container/page-no-container.vue | 119 +++ components/youdas-container/page-popup.vue | 229 +++++ components/z-tabs/config/index.js | 4 + components/z-tabs/z-tabs.vue | 791 ++++++++++++++++++ pages.json | 24 + pages/mall/mall.vue | 354 ++++++-- pages/mall/order-list.vue | 63 ++ pages/me/account-deletion.vue | 73 ++ pages/me/account-login.vue | 300 +++++++ pages/me/me.vue | 335 +++++--- pages/other/agreement.vue | 41 + vite.config.js | 31 +- 26 files changed, 2753 insertions(+), 188 deletions(-) create mode 100644 common/server/other.js create mode 100644 common/system/userInfo.js create mode 100644 common/yds.js create mode 100644 components/youdas-container/order-list-item.vue create mode 100644 components/youdas-container/page-base-container.vue create mode 100644 components/youdas-container/page-line.vue create mode 100644 components/youdas-container/page-no-container.vue create mode 100644 components/youdas-container/page-popup.vue create mode 100644 components/z-tabs/config/index.js create mode 100644 components/z-tabs/z-tabs.vue create mode 100644 pages/mall/order-list.vue create mode 100644 pages/me/account-deletion.vue create mode 100644 pages/me/account-login.vue create mode 100644 pages/other/agreement.vue diff --git a/README.md b/README.md index 73a7edd..5cece19 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,20 @@ let icon = ref("/static/app-plus/icon_108.png"); onLoad(() => { console.log('页面加载中'); }); +``` +# 新文件 +```vue + + + + + + ``` \ No newline at end of file diff --git a/common/server/other.js b/common/server/other.js new file mode 100644 index 0000000..6af944e --- /dev/null +++ b/common/server/other.js @@ -0,0 +1,33 @@ +import HttpRequest from "../system/request"; +/** + * 发送短信验证码 + * @param {String} phone 手机号 + * @returns {Promise} 发送短信验证码 + */ +export const sendSms = async (phone) => { + const res = await HttpRequest.post('v2/account/sendSms', { + phone: phone + }); + return res.status == 1; +} + +/** + * 获取协议内容 + * @param {String} type 协议类型 + * @returns {Promise} 获取协议 + */ +export const getAgreement = async (type) => { + let type_id = 0; + if (type == "user") { + type_id = 4; + } else if (type == "privacy") { + type_id = 5; + } + const res = await HttpRequest.get('/getAgreement', { + type: type_id + }); + if (res.status == 1) { + return res.data; + } + return null; +} \ No newline at end of file diff --git a/common/server/user.js b/common/server/user.js index fac8557..459fd6d 100644 --- a/common/server/user.js +++ b/common/server/user.js @@ -1,11 +1,52 @@ -import { HttpRequest } from "@/common/utils/request"; +import HttpRequest from "../system/request"; +import { decryptRouteMap } from "../system/routeMap"; /** * 获取用户信息 * @returns {Promise} 用户信息 */ export const getUserInfo = async () => { const res = await HttpRequest.get('/userInfo'); - return res.data; + if (res.status == 1) { + let userInfo = res.data; + if (userInfo.other != null && userInfo.other != undefined) { + userInfo.other = decryptRouteMap(userInfo.other); + userInfo['currency1'] = userInfo.other['a']; + userInfo['currency2'] = userInfo.other['b']; + userInfo['currency3'] = userInfo.other['c']; + userInfo['uid'] = userInfo.other['uid']; + userInfo['pid'] = userInfo.other['pid']; + delete userInfo.other; + } + console.log("userInfo", userInfo); + return userInfo; + } + return null; +} + +/** + * 申请注销账号 + * @returns {Promise} 是否成功 + */ +export const deleteAccount = async () => { + const res = await HttpRequest.post('/deleteAccount'); + return res; +} + +/** + * 手机号登录 + * @param {String} phone 手机号 + * @param {String} code 验证码 + * @param {String} pid 推广码 + * @returns {Promise} 是否成功 + */ +export const mobileLogin = async (phone, code, pid = 0) => { + const res = await HttpRequest.post('/mobileLogin', { + mobile: phone, + code: code, + pid: pid + }); + return res; } + diff --git a/common/system/router.js b/common/system/router.js index 410c65d..7ce777d 100644 --- a/common/system/router.js +++ b/common/system/router.js @@ -12,4 +12,24 @@ export const navigateTo = (url) => { } }); -} \ No newline at end of file +} + +/** + * 跳转登录页面 + * @param {String} page 跳转页面 + */ +export const navigateToAccountLogin = (page = "") => { + if (page == "") { + const _page = getCurrentPages()[0]; + page = _page.route; + } + navigateTo(`/pages/me/account-login?page=${encodeURIComponent(page)}`); +} + +/** + * 跳转协议页面 + * @param {String} type 协议类型 + */ +export const navigateToAgreement = (type) => { + navigateTo(`/pages/other/agreement?type=${type}`); +}; \ No newline at end of file diff --git a/common/system/userInfo.js b/common/system/userInfo.js new file mode 100644 index 0000000..12a9acd --- /dev/null +++ b/common/system/userInfo.js @@ -0,0 +1,49 @@ +import { getCache, getLocalStorage, setLocalStorage, removeCache, removeLocalStorage } from './cacheService'; +import { getUserInfo } from '@/common/server/user'; +import { navigateTo, navigateToAccountLogin } from './router'; +export const isAccountLogin = () => { + const token = getCache('token'); + if (token) { + return true; + } + return false; +} + +/** + * 获取用户信息 + * @returns {Promise} 用户信息 + */ +export const getAccountInfo = async () => { + return new Promise(async (resolve, reject) => { + const user = getLocalStorage('user'); + if (user) { + resolve(user); + return; + } + if (isAccountLogin()) { + const user_res = await getUserInfo(); + setLocalStorage("user", user_res, 60); + resolve(user_res); + } else { + resolve(null); + } + }); +} + +/** + * 判断用户是否登录,如果用户未登录,会跳转到登录页面 + * @returns {Boolean} 是否登录 + */ +export const IsUserLogin = () => { + if (!isAccountLogin()) { + navigateToAccountLogin(); + return false; + } + return true; +} + +export const logout = () => { + removeCache('token'); + removeCache('userInfo'); + removeLocalStorage('user'); +} \ No newline at end of file diff --git a/common/utils.js b/common/utils.js index 8849c0f..5a7830b 100644 --- a/common/utils.js +++ b/common/utils.js @@ -30,4 +30,81 @@ export function parseQueryString(urlOrQueryString) { } return params; -} \ No newline at end of file +} + +/** + * 显示确认弹窗 + * @param {Object} options 弹窗选项 + * @param {String} options.title 弹窗标题 + * @param {String} options.content 弹窗内容 + * @param {String} options.confirmText 确认按钮文字 + * @param {String} options.cancelText 取消按钮文字 + * @returns {Promise} 返回Promise对象,resolve中返回{confirm: Boolean},表示是否点击了确认按钮 + */ +export function showModal(options = {}) { + return new Promise((resolve) => { + uni.showModal({ + title: options.title || '提示', + content: options.content || '', + confirmText: options.confirmText || '确定', + cancelText: options.cancelText || '取消', + success(res) { + resolve(res); + }, + fail() { + resolve({ confirm: false }); + } + }); + }); +} + +/** + * 显示提示信息 + * @param {*} title 提示信息 + * @param {*} icon 图标 + * @param {*} duration 提示时长 + * @returns + */ +export function showToast(title, icon = "none", duration = 1500) { + return new Promise((resolve) => { + uni.showToast({ + title: title || '', + icon: icon || 'none', + duration: duration, + success: () => { + resolve(true); + } + }); + }); +} + +/** + * 显示加载中 + * @param {String} title 加载中文字 + * @returns {Promise} 返回Promise对象,resolve中返回true + */ +export function showLoading(title = "加载中...") { + return new Promise((resolve) => { + uni.showLoading({ + title: title, + success: () => { + resolve(true); + } + }); + }); +} + +/** + * 隐藏加载中 + * @returns {Promise} 返回Promise对象,resolve中返回true + */ +export function hideLoading() { + return new Promise((resolve) => { + uni.hideLoading({ + success: () => { + resolve(true); + } + }); + }); +} + diff --git a/common/yds.js b/common/yds.js new file mode 100644 index 0000000..be94f7b --- /dev/null +++ b/common/yds.js @@ -0,0 +1,14 @@ +import * as utils1 from './utils'; +import * as utils2 from './system/cacheService'; +import * as utils3 from './system/router'; +import * as utils4 from './system/request'; +import * as utils5 from './system/userInfo'; +// 动态合并所有导出到 yds 对象 +export const yds = { + userInfo: { ...utils5 }, + ...utils1, + ...utils2, + ...utils3, + ...utils4, + // 其他文件... +}; diff --git a/components.d.ts b/components.d.ts index 4c61e12..63a1989 100644 --- a/components.d.ts +++ b/components.d.ts @@ -11,7 +11,12 @@ declare module 'vue' { LoadingData: typeof import('./components/youdas-container/loading-data.vue')['default'] NewsListItem: typeof import('./components/youdas-container/news-list-item.vue')['default'] NoData: typeof import('./components/youdas-container/no-data.vue')['default'] + OrderListItem: typeof import('./components/youdas-container/order-list-item.vue')['default'] + PageBaseContainer: typeof import('./components/youdas-container/page-base-container.vue')['default'] PageContainer: typeof import('./components/youdas-container/page-container.vue')['default'] + PageLine: typeof import('./components/youdas-container/page-line.vue')['default'] + PageNoContainer: typeof import('./components/youdas-container/page-no-container.vue')['default'] + PagePopup: typeof import('./components/youdas-container/page-popup.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] UniNavBar: typeof import('./components/uni-nav-bar/uni-nav-bar.vue')['default'] diff --git a/components/youdas-container/loading-data.vue b/components/youdas-container/loading-data.vue index 15fa196..c8a3952 100644 --- a/components/youdas-container/loading-data.vue +++ b/components/youdas-container/loading-data.vue @@ -34,6 +34,7 @@ export default { justify-content: center; animation: emptyFadeIn 0.5s ease-out; // background-color: #F7F7F7; + } .loading-image { diff --git a/components/youdas-container/news-list-item.vue b/components/youdas-container/news-list-item.vue index 7084cb8..5e16b2e 100644 --- a/components/youdas-container/news-list-item.vue +++ b/components/youdas-container/news-list-item.vue @@ -86,7 +86,7 @@ watch(() => props.currentIndex, (newVal) => { }); const queryList = (pageNo, pageSize) => { - if (!props.responseCallback) return; + if (!props.responseCallback) { paging.value.complete(false); return; }; const params = { pageNo: pageNo, diff --git a/components/youdas-container/order-list-item.vue b/components/youdas-container/order-list-item.vue new file mode 100644 index 0000000..d030b46 --- /dev/null +++ b/components/youdas-container/order-list-item.vue @@ -0,0 +1,153 @@ + + + + + + diff --git a/components/youdas-container/page-base-container.vue b/components/youdas-container/page-base-container.vue new file mode 100644 index 0000000..28a953a --- /dev/null +++ b/components/youdas-container/page-base-container.vue @@ -0,0 +1,100 @@ + + + + + + \ No newline at end of file diff --git a/components/youdas-container/page-container.vue b/components/youdas-container/page-container.vue index 39cf628..de13d75 100644 --- a/components/youdas-container/page-container.vue +++ b/components/youdas-container/page-container.vue @@ -1,19 +1,20 @@ + + diff --git a/components/youdas-container/page-no-container.vue b/components/youdas-container/page-no-container.vue new file mode 100644 index 0000000..8d73b58 --- /dev/null +++ b/components/youdas-container/page-no-container.vue @@ -0,0 +1,119 @@ + + + + + + \ No newline at end of file diff --git a/components/youdas-container/page-popup.vue b/components/youdas-container/page-popup.vue new file mode 100644 index 0000000..2c8c50f --- /dev/null +++ b/components/youdas-container/page-popup.vue @@ -0,0 +1,229 @@ + + + + + + \ No newline at end of file diff --git a/components/z-tabs/config/index.js b/components/z-tabs/config/index.js new file mode 100644 index 0000000..56c953b --- /dev/null +++ b/components/z-tabs/config/index.js @@ -0,0 +1,4 @@ +// z-tabs全局配置文件,注意避免更新时此文件被覆盖,若被覆盖,可在此文件中右键->点击本地历史记录,找回覆盖前的配置 +export default { + +} \ No newline at end of file diff --git a/components/z-tabs/z-tabs.vue b/components/z-tabs/z-tabs.vue new file mode 100644 index 0000000..5c2a123 --- /dev/null +++ b/components/z-tabs/z-tabs.vue @@ -0,0 +1,791 @@ + + + + + + + + + + + diff --git a/pages.json b/pages.json index 1eb2ebb..f4c139c 100644 --- a/pages.json +++ b/pages.json @@ -33,6 +33,30 @@ "navigationStyle": "custom", "navigationBarTitleText": "" } + }, + { + "path": "pages/me/account-deletion", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/mall/order-list", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/me/account-login", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/other/agreement", + "style": { + "navigationStyle": "custom" + } } ], // "globalStyle": { diff --git a/pages/mall/mall.vue b/pages/mall/mall.vue index 9eb228e..96e3ecc 100644 --- a/pages/mall/mall.vue +++ b/pages/mall/mall.vue @@ -9,62 +9,55 @@ - + - + - - + + {{item.name}} - - - {{item.price}} - + + + + {{item.price}} + - - {{item.num}}/1 - + + {{item.num}}/1 + + - + - + + - + {{item.name}} - - {{item.num}}/1 - + + {{item.num}}/1 + - - - {{item.price}} + + + {{item.price}} - - 购买 + + 购买 @@ -80,57 +73,100 @@ data() { return { topDataList: [{ - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '1', + imgUrl: "/static/product1.png", + name: "英雄联盟K/DA系列阿卡丽手办", num: "1", - price: "69" + price: "69", + stock: 10 }, { - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '2', + imgUrl: "/static/product2.png", + name: "英雄联盟K/DA系列阿狸手办", num: "1", - price: "69" + price: "79", + stock: 5 }, { - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '3', + imgUrl: "/static/product3.png", + name: "英雄联盟K/DA系列伊芙琳手办", num: "1", - price: "69" + price: "89", + stock: 8 }, ], dataList: [{ - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '4', + imgUrl: "/static/product4.png", + name: "英雄联盟K/DA系列阿卡丽手办豪华版", num: "1", - price: "69" + price: "169", + stock: 3 }, { - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '5', + imgUrl: "/static/product5.png", + name: "英雄联盟K/DA系列阿狸手办豪华版", num: "1", - price: "69" + price: "179", + stock: 2 }, { - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '6', + imgUrl: "/static/product6.png", + name: "英雄联盟K/DA系列伊芙琳手办豪华版", num: "1", - price: "69" + price: "189", + stock: 6 }, { - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '7', + imgUrl: "/static/product7.png", + name: "英雄联盟K/DA系列卡莎手办", num: "1", - price: "69" + price: "99", + stock: 15 }, { - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '8', + imgUrl: "/static/product8.png", + name: "英雄联盟K/DA系列莎拉手办", num: "1", - price: "69" + price: "99", + stock: 12 }, { - imgUrl: "", - name: "英雄联盟K/DA系列…", + id: '9', + imgUrl: "/static/product9.png", + name: "英雄联盟K/DA系列套装收藏版", num: "1", - price: "69" + price: "599", + stock: 1 }, ] - } }, methods: { - + // 跳转到商品详情页 + goToDetail(item) { + uni.navigateTo({ + url: `/pages/mall/product-detail?id=${item.id}` + }); + }, + + // 购买商品 + buyProduct(item) { + // 阻止事件冒泡 + event.stopPropagation(); + + // 检查库存 + if (item.stock <= 0) { + uni.showToast({ + title: '商品已售罄', + icon: 'none' + }); + return; + } + + // 添加到购物车或直接购买的逻辑 + uni.showToast({ + title: '已添加到购物车', + icon: 'success' + }); + } } } @@ -150,6 +186,7 @@ justify-content: center; align-items: center; font-size: 32.44rpx; + font-weight: 600; position: absolute; bottom: 30rpx; } @@ -162,7 +199,6 @@ flex-direction: row; justify-content: space-between; - .item { width: 216.31rpx; height: 100%; @@ -170,15 +206,91 @@ border-radius: 15.27rpx; display: flex; flex-direction: column; + box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); + transition: transform 0.3s; + + &:active { + transform: scale(0.98); + } } .img { width: 100%; height: 216.31rpx; - background-color: #D8D8D8; + background-color: #F2F2F2; border-radius: 15.27rpx 15.27rpx 0rpx 0rpx; + overflow: hidden; + + .product-image { + width: 100%; + height: 100%; + } + } + + .item-info { + width: 100%; + height: 109.07rpx; + position: relative; + padding: 8rpx; + box-sizing: border-box; + } + + .item-name { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 19.08rpx; + color: #333333; + text-align: center; + margin-top: 6rpx; + } + + .item-bottom { + position: absolute; + width: 100%; + bottom: 12rpx; + left: 0; + padding: 0 13rpx; + box-sizing: border-box; + display: flex; + justify-content: space-between; + } + + .item-price { + display: flex; + flex-direction: row; + align-items: center; + } + + .price-symbol-small { + font-size: 15.27rpx; + margin-top: 6rpx; + color: #FF6A6A; + } + + .price-value-small { + font-size: 22.9rpx; + font-weight: bold; + color: #FF6A6A; + } + + .item-count { + display: flex; + flex-direction: row; + align-items: center; + } + + .count-text-small { + font-size: 15.27rpx; + color: #6C6C6C; + } + + .box-icon-small { + width: 17.39rpx; + height: 17.39rpx; + margin-left: 7rpx; } - } .view-list { @@ -186,4 +298,118 @@ height: 850rpx; margin: 0 auto; } + + .product-item { + width: 100%; + height: 261.45rpx; + background-color: #FFFFFF; + margin-bottom: 21rpx; + border-radius: 15.27rpx; + position: relative; + box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); + transition: transform 0.3s; + + &:active { + transform: scale(0.98); + } + } + + .product-image-container { + width: 216.31rpx; + height: 216.31rpx; + background-color: #F2F2F2; + border-radius: 15.27rpx; + position: absolute; + left: 22rpx; + top: 22rpx; + overflow: hidden; + + .product-image { + width: 100%; + height: 100%; + } + } + + .product-name { + width: 350rpx; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + position: absolute; + left: 269rpx; + top: 44rpx; + font-size: 26.72rpx; + font-weight: 600; + color: #333333; + } + + .product-count { + position: absolute; + display: flex; + flex-direction: row; + left: 269rpx; + top: 95rpx; + align-items: center; + + .count-text { + font-size: 15.27rpx; + color: #6C6C6C; + } + + .box-icon { + width: 17.39rpx; + height: 17.39rpx; + margin-left: 7rpx; + } + } + + .product-price { + position: absolute; + display: flex; + flex-direction: row; + left: 269rpx; + bottom: 44rpx; + align-items: center; + + .price-symbol { + font-size: 19.08rpx; + margin-top: 15rpx; + color: #FF6A6A; + } + + .price-value { + font-size: 34.35rpx; + font-weight: bold; + color: #FF6A6A; + } + } + + .buy-button { + width: 89.22rpx; + height: 42rpx; + border-radius: 20.99rpx; + border: 1rpx solid #FF6A6A; + background-color: white; + display: flex; + align-items: center; + justify-content: center; + position: absolute; + right: 38rpx; + bottom: 38rpx; + transition: all 0.3s; + + &:active { + background-color: #FF6A6A; + + .buy-text { + color: white; + } + } + + .buy-text { + font-size: 19.08rpx; + color: #FF6A6A; + font-weight: 500; + } + } \ No newline at end of file diff --git a/pages/mall/order-list.vue b/pages/mall/order-list.vue new file mode 100644 index 0000000..204f64b --- /dev/null +++ b/pages/mall/order-list.vue @@ -0,0 +1,63 @@ + + + + + + diff --git a/pages/me/account-deletion.vue b/pages/me/account-deletion.vue new file mode 100644 index 0000000..c51ead8 --- /dev/null +++ b/pages/me/account-deletion.vue @@ -0,0 +1,73 @@ + + + + + + \ No newline at end of file diff --git a/pages/me/account-login.vue b/pages/me/account-login.vue new file mode 100644 index 0000000..7b60f8d --- /dev/null +++ b/pages/me/account-login.vue @@ -0,0 +1,300 @@ + + + + + + \ No newline at end of file diff --git a/pages/me/me.vue b/pages/me/me.vue index 10103c4..2cacbdc 100644 --- a/pages/me/me.vue +++ b/pages/me/me.vue @@ -1,126 +1,253 @@ - \ No newline at end of file diff --git a/pages/other/agreement.vue b/pages/other/agreement.vue new file mode 100644 index 0000000..510330b --- /dev/null +++ b/pages/other/agreement.vue @@ -0,0 +1,41 @@ + + + + + + \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 83481f5..8978791 100644 --- a/vite.config.js +++ b/vite.config.js @@ -2,13 +2,32 @@ import { defineConfig } from 'vite'; import uni from "@dcloudio/vite-plugin-uni"; import AutoImport from 'unplugin-auto-import/vite'; import Components from 'unplugin-vue-components/vite'; - export default defineConfig({ plugins: [ uni(), // 自动导入 Vue 相关 API(如 ref, reactive) AutoImport({ - imports: ['vue'], + imports: ['vue', + { + '@dcloudio/uni-app': [ + 'onLoad', // 页面加载时触发 + 'onShow', // 页面显示时触发 + 'onHide', // 页面隐藏时触发 + 'onUnload', // 页面卸载时触发 + ], + }, + { + '@/common/utils': [ + 'showToast', // 明确列出方法名(推荐) + 'sleep', + ], + }, + { + '@/common/yds': [ + ['yds'], // 从 '@/common/index' 导入 yds 对象 + ], + } + ], }), // 自动导入组件 Components({ @@ -20,4 +39,12 @@ export default defineConfig({ dts: true, // 生成类型声明文件(可选) }), ], + build: { + minify: 'terser', + terserOptions: { + compress: { + drop_console: true, + }, + }, + } });