diff --git a/App.vue b/App.vue
index 168b57a..8281a62 100644
--- a/App.vue
+++ b/App.vue
@@ -12,8 +12,9 @@
}
-
diff --git a/api/modules/user.ts b/api/modules/user.ts
new file mode 100644
index 0000000..dabd820
--- /dev/null
+++ b/api/modules/user.ts
@@ -0,0 +1,217 @@
+// api/modules/user.ts
+import { mainClient } from '@/api/clients/main'
+import type { IApiResponse } from '@/api/types'
+import type {
+ IUserInfo,
+ IVipInfo,
+ IOrder,
+ IVipPackage,
+ ITransaction,
+ IFeedbackForm,
+ IPageData
+} from '@/types/user'
+import { SERVICE_MAP } from '@/api/config'
+
+/**
+ * 获取用户信息
+ */
+export async function getUserInfo() {
+ const res = await mainClient.request>({
+ url: 'common/user/getUserInfo',
+ method: 'POST'
+ })
+ return res
+}
+
+/**
+ * 获取VIP信息
+ */
+export async function getVipInfo() {
+ const res = await mainClient.request>({
+ url: 'bookAbroad/home/getVipInfo',
+ method: 'POST'
+ })
+ return res
+}
+
+/**
+ * 获取订单列表
+ * @param current 当前页码
+ * @param limit 每页数量
+ */
+export async function getOrderList(current: number, limit: number) {
+ const res = await mainClient.request }>>({
+ url: 'bookAbroad/home/getAbroadOrderList',
+ method: 'POST',
+ data: { current, limit }
+ })
+ return res
+}
+
+/**
+ * 获取VIP套餐列表
+ */
+export async function getVipPackages() {
+ const res = await mainClient.request>({
+ url: 'book/sysdictdata/getData',
+ method: 'POST',
+ data: { dictLabel: 'googleVip' }
+ })
+ return res
+}
+
+/**
+ * 创建订单
+ * @param data 订单数据
+ */
+export async function createOrder(data: any) {
+ const res = await mainClient.request>({
+ url: 'bookAbroad/order/placeOrder',
+ method: 'POST',
+ data
+ })
+ return res
+}
+
+/**
+ * 获取交易记录列表
+ * @param userId 用户ID
+ */
+export async function getTransactionList(userId: number) {
+ const res = await mainClient.request>({
+ url: 'common/transactionDetails/getTransactionDetailsList',
+ method: 'POST',
+ data: { userId }
+ })
+ return res
+}
+
+/**
+ * 更新用户基本信息
+ * @param data 用户信息
+ */
+export async function updateUserInfo(data: Partial) {
+ const res = await mainClient.request({
+ url: 'book/user/update',
+ method: 'POST',
+ data
+ })
+ return res
+}
+
+/**
+ * 更新用户邮箱
+ * @param id 用户ID
+ * @param email 邮箱地址
+ * @param code 验证码
+ */
+export async function updateEmail(id: number, email: string, code: string) {
+ const res = await mainClient.request({
+ url: 'common/user/updateUserEmail',
+ method: 'POST',
+ data: { id, email, code }
+ })
+ return res
+}
+
+/**
+ * 更新用户密码
+ * @param id 用户ID
+ * @param password 新密码
+ */
+export async function updatePassword(id: number, password: string) {
+ const res = await mainClient.request({
+ url: 'common/user/setPasswordById',
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ data: { id, password }
+ })
+ return res
+}
+
+/**
+ * 发送邮箱验证码
+ * @param email 邮箱地址
+ */
+export async function sendEmailCode(email: string) {
+ const res = await mainClient.request({
+ url: 'common/user/getMailCaptcha',
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ data: { email }
+ })
+ return res
+}
+
+/**
+ * 上传图片
+ * @param filePath 本地文件路径
+ * @returns 图片URL
+ */
+export function uploadImage(filePath: string): Promise {
+ return new Promise((resolve, reject) => {
+ uni.uploadFile({
+ url: `${SERVICE_MAP.MAIN}oss/fileoss`,
+ filePath,
+ name: 'file',
+ success: (res) => {
+ try {
+ const data = JSON.parse(res.data)
+ if (data.url) {
+ resolve(data.url)
+ } else {
+ reject(new Error('上传失败'))
+ }
+ } catch (error) {
+ reject(error)
+ }
+ },
+ fail: reject
+ })
+ })
+}
+
+/**
+ * 提交问题反馈
+ * @param data 反馈表单数据
+ */
+export async function submitFeedback(data: IFeedbackForm) {
+ const res = await mainClient.request({
+ url: 'common/sysFeedback/addSysFeedback',
+ method: 'POST',
+ data
+ })
+ return res
+}
+
+/**
+ * 验证Google支付
+ * @param purchaseToken 购买令牌
+ * @param orderSn 订单号
+ * @param productId 产品ID
+ */
+export async function verifyGooglePay(purchaseToken: string, orderSn: string, productId: string) {
+ const res = await mainClient.request({
+ url: 'pay/googlepay/googleVerify',
+ method: 'POST',
+ data: { purchaseToken, orderSn, productId }
+ })
+ return res
+}
+
+/**
+ * 验证IAP支付
+ * @param data 支付数据
+ */
+export async function verifyIAP(data: any) {
+ const res = await mainClient.request({
+ url: 'Ipa/veri',
+ method: 'POST',
+ data
+ })
+ return res
+}
diff --git a/components/nav-bar/nav-bar.vue b/components/nav-bar/nav-bar.vue
new file mode 100644
index 0000000..c0c3de0
--- /dev/null
+++ b/components/nav-bar/nav-bar.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/locale/en.json b/locale/en.json
index d610f45..d5b973c 100644
--- a/locale/en.json
+++ b/locale/en.json
@@ -73,5 +73,120 @@
"passwordStrengthMedium": "Medium password strength.",
"passwordStrengthWeak": "please use a password consisting of at least two types: uppercase and lowercase letters, numbers, and symbols, with a length of 8 characters.",
"passwordChanged": "Password changed successfully"
+ },
+ "common": {
+ "confirm": "Confirm",
+ "cancel": "Cancel",
+ "submit": "Submit",
+ "save": "Save",
+ "delete": "Delete",
+ "edit": "Edit",
+ "back": "Back",
+ "loadMore": "Load More",
+ "noMore": "No More Data",
+ "noData": "No Data",
+ "loading": "Loading...",
+ "success": "Success",
+ "failed": "Failed",
+ "networkError": "Network Error",
+ "pleaseInput": "Please Input",
+ "pleaseSelect": "Please Select"
+ },
+ "user": {
+ "title": "My",
+ "myOrders": "My Orders",
+ "myBooklist": "My Booklist",
+ "profile": "Profile",
+ "about": "About Us",
+ "feedback": "Feedback",
+ "settings": "Settings",
+ "subscribe": "Subscribe",
+ "myAccount": "My Account",
+ "notSet": "Not Set",
+ "clickToSet": "Set",
+ "vip": "VIP Member",
+ "vipExpireTime": "Expire Time",
+ "nickname": "Nickname",
+ "name": "Name",
+ "email": "Email",
+ "phone": "Phone",
+ "age": "Age",
+ "sex": "Gender",
+ "male": "Male",
+ "female": "Female",
+ "avatar": "Avatar",
+ "changeAvatar": "Change Avatar",
+ "setAvatar": "Set Avatar",
+ "updateSuccess": "Update Success",
+ "updateFailed": "Update Failed",
+ "paymentMethod": "Payment Method",
+ "googlePay": "Google Pay",
+ "applePay": "Apple Pay",
+ "agreeText": "I have agreed",
+ "agreement": "Recharge Agreement",
+ "agreeFirst": "Please agree to the recharge agreement first",
+ "orderSn": "Order Number",
+ "createTime": "Create Time",
+ "amount": "Amount",
+ "paymentSuccess": "Payment Success",
+ "paymentFailed": "Payment Failed",
+ "paymentCanceled": "Payment Canceled",
+ "transactionType": "Transaction Type",
+ "recharge": "Recharge",
+ "consume": "Consume",
+ "remark": "Remark",
+ "hotline": "Hotline",
+ "customerEmail": "Customer Email",
+ "wechat": "WeChat",
+ "wechatTip": "Click on the image and long press to save it to your phone, or use WeChat to scan the QR code to add the customer service official WeChat.",
+ "checkVersion": "Check Version",
+ "version": "Version",
+ "logoff": "Delete Account",
+ "logout": "Logout",
+ "logoffConfirm": "Are you sure you want to delete your account? This action cannot be undone",
+ "logoffConfirmAgain": "The cancellation application has been submitted successfully, please contact customer service for follow-up operations: 022-24142321",
+ "logoutConfirm": "Are you sure you want to logout?",
+ "logoffSuccess": "Account Deleted",
+ "logoutSuccess": "Logout Success",
+ "copySuccess": "Copy Success",
+ "privacyPolicy": "Privacy Policy",
+ "appDescription": "An online ebook app offering a wide range of content, including medical literature, classical Chinese studies, literature, and ancient traditional Chinese medicine texts. It features 3D simulated page-flipping, eye-protection mode, and other advanced reading technologies for a comfortable reading experience. The app supports mixed text and image layouts, along with AI-powered voice narration for reading and listening. Some ebooks also have corresponding physical editions, providing users with more reading options.",
+ "issueType": "Issue Type",
+ "account": "Account",
+ "description": "Description",
+ "contactPhone": "Contact Phone",
+ "screenshots": "Screenshots",
+ "issueTypeAccount": "Account Issue",
+ "issueTypePayment": "Payment Issue",
+ "issueTypeOrder": "Order Related",
+ "issueTypeContent": "Content Issue",
+ "issueTypeSuggestion": "Feature Suggestion",
+ "issueTypeBug": "Bug Report",
+ "issueTypeOther": "Other",
+ "feedbackSuccess": "Feedback Submitted",
+ "feedbackFailed": "Feedback Failed",
+ "pleaseInputDescription": "Please enter description",
+ "pleaseInputPhone": "Please enter contact phone",
+ "pleaseInputOrderSn": "Please enter order number",
+ "uploadImageFailed": "Image upload failed",
+ "maxImagesCount": "Maximum 4 images",
+ "permissionDenied": "Permission Denied",
+ "cameraPermission": "Camera permission required",
+ "storagePermission": "Storage permission required",
+ "phonePermission": "Phone permission required",
+ "sendCodeSuccess": "Verification code sent",
+ "sendCodeFailed": "Failed to send code",
+ "countdown": "s to resend",
+ "emailFormat": "Please enter valid email",
+ "passwordFormat": "Invalid password format",
+ "passwordNotMatch": "Passwords do not match",
+ "pleaseInputCode": "Please enter verification code",
+ "pleaseInputPassword": "Please enter password",
+ "pleaseInputPasswordAgain": "Please enter password again",
+ "monthCard": "Monthly",
+ "seasonCard": "Quarterly",
+ "yearCard": "Yearly",
+ "days": "days",
+ "selectPackage": "Please select a package"
}
}
diff --git a/locale/zh-Hans.json b/locale/zh-Hans.json
index a706a62..e88b185 100644
--- a/locale/zh-Hans.json
+++ b/locale/zh-Hans.json
@@ -74,5 +74,120 @@
"passwordStrengthMedium": "密码强度中等",
"passwordStrengthWeak": "请使用至少包含大小写字母、数字、符号中的两种类型,长度为8个字符的密码",
"passwordChanged": "密码修改成功"
+ },
+ "common": {
+ "confirm": "确认",
+ "cancel": "取消",
+ "submit": "提交",
+ "save": "保存",
+ "delete": "删除",
+ "edit": "编辑",
+ "back": "返回",
+ "loadMore": "加载更多",
+ "noMore": "没有更多数据",
+ "noData": "暂无数据",
+ "loading": "加载中...",
+ "success": "操作成功",
+ "failed": "操作失败",
+ "networkError": "网络连接失败",
+ "pleaseInput": "请输入",
+ "pleaseSelect": "请选择"
+ },
+ "user": {
+ "title": "我的",
+ "myOrders": "我的订单",
+ "myBooklist": "我的书单",
+ "profile": "个人资料",
+ "about": "关于我们",
+ "feedback": "问题反馈",
+ "settings": "设置",
+ "subscribe": "订阅",
+ "myAccount": "我的账户",
+ "notSet": "未设置",
+ "clickToSet": "设置",
+ "vip": "VIP会员",
+ "vipExpireTime": "到期时间",
+ "nickname": "昵称",
+ "name": "姓名",
+ "email": "邮箱",
+ "phone": "手机号",
+ "age": "年龄",
+ "sex": "性别",
+ "male": "男",
+ "female": "女",
+ "avatar": "头像",
+ "changeAvatar": "更换头像",
+ "setAvatar": "设置头像",
+ "updateSuccess": "更新成功",
+ "updateFailed": "更新失败",
+ "paymentMethod": "支付方式",
+ "googlePay": "Google Pay",
+ "applePay": "Apple Pay",
+ "agreeText": "我已同意",
+ "agreement": "充值协议",
+ "agreeFirst": "请先同意充值协议",
+ "orderSn": "订单编号",
+ "createTime": "创建时间",
+ "amount": "金额",
+ "paymentSuccess": "支付成功",
+ "paymentFailed": "支付失败",
+ "paymentCanceled": "支付已取消",
+ "transactionType": "交易类型",
+ "recharge": "充值",
+ "consume": "消费",
+ "remark": "备注",
+ "hotline": "客服热线",
+ "customerEmail": "客服邮箱",
+ "wechat": "微信号",
+ "wechatTip": "点击图片并长按保存到手机,或使用微信扫描二维码添加客服官方微信。",
+ "checkVersion": "检查版本",
+ "version": "版本",
+ "logoff": "注销账户",
+ "logout": "退出登录",
+ "logoffConfirm": "确定要注销账户吗?此操作不可恢复",
+ "logoffConfirmAgain": "注销申请已提交成功,请联系客服进行后续操作:022-24142321",
+ "logoutConfirm": "确定要退出登录吗?",
+ "logoffSuccess": "注销成功",
+ "logoutSuccess": "退出成功",
+ "copySuccess": "复制成功",
+ "privacyPolicy": "隐私政策",
+ "appDescription": "一款线上电子书APP,包含医学类、国学类、文学类、中医古籍等各种类型。3D仿真翻页、护眼模式等阅读技术,打造舒适阅读体验。图文混排,AI人声读书听书。部分电子书也有对应的纸质书,给予用户更多的阅读选择。",
+ "issueType": "问题类型",
+ "account": "账号",
+ "description": "问题描述",
+ "contactPhone": "联系电话",
+ "screenshots": "截图",
+ "issueTypeAccount": "账号问题",
+ "issueTypePayment": "支付问题",
+ "issueTypeOrder": "订单相关",
+ "issueTypeContent": "内容问题",
+ "issueTypeSuggestion": "功能建议",
+ "issueTypeBug": "BUG反馈",
+ "issueTypeOther": "其他",
+ "feedbackSuccess": "反馈提交成功",
+ "feedbackFailed": "反馈提交失败",
+ "pleaseInputDescription": "请输入问题描述",
+ "pleaseInputPhone": "请输入联系电话",
+ "pleaseInputOrderSn": "请输入订单编号",
+ "uploadImageFailed": "图片上传失败",
+ "maxImagesCount": "最多上传4张图片",
+ "permissionDenied": "权限被拒绝",
+ "cameraPermission": "需要相机权限",
+ "storagePermission": "需要存储权限",
+ "phonePermission": "需要电话权限",
+ "sendCodeSuccess": "验证码发送成功",
+ "sendCodeFailed": "验证码发送失败",
+ "countdown": "秒后重新发送",
+ "emailFormat": "请输入正确的邮箱格式",
+ "passwordFormat": "密码格式不正确",
+ "passwordNotMatch": "两次密码不一致",
+ "pleaseInputCode": "请输入验证码",
+ "pleaseInputPassword": "请输入密码",
+ "pleaseInputPasswordAgain": "请再次输入密码",
+ "monthCard": "月卡",
+ "seasonCard": "季卡",
+ "yearCard": "年卡",
+ "days": "天",
+ "selectPackage": "请选择套餐"
}
}
diff --git a/pages.json b/pages.json
index a4155de..5d3b9c5 100644
--- a/pages.json
+++ b/pages.json
@@ -25,6 +25,54 @@
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
+ }, {
+ "path": "pages/user/index",
+ "style": {
+ "navigationBarTitleText": "%user.title%",
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/user/order/index",
+ "style": {
+ "navigationBarTitleText": "%user.myOrders%",
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/user/wallet/index",
+ "style": {
+ "navigationBarTitleText": "%user.subscribe%",
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/user/wallet/list",
+ "style": {
+ "navigationBarTitleText": "%user.myAccount%",
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/user/profile/index",
+ "style": {
+ "navigationBarTitleText": "%user.profile%",
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/user/settings/index",
+ "style": {
+ "navigationBarTitleText": "%user.settings%",
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/user/about/index",
+ "style": {
+ "navigationBarTitleText": "%user.about%",
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/user/feedback/index",
+ "style": {
+ "navigationBarTitleText": "%user.feedback%",
+ "navigationStyle": "custom"
+ }
}
],
// "tabBar": {
@@ -61,7 +109,7 @@
"text": "%tabar.book%"
},
{
- "pagePath": "pages/my/my",
+ "pagePath": "pages/user/index",
"iconPath": "static/tab/icon4_n.png",
"selectedIconPath": "static/tab/icon4_y.png",
"text": "%tabar.user%"
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 3227bfe..47ad80d 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -1,6 +1,6 @@
- 这是一个等待开发的首页
+ 这是一个等待开发的首页
首页的内容是在线课程
diff --git a/pages/login/login.vue b/pages/login/login.vue
index 04cf85e..e7a5057 100644
--- a/pages/login/login.vue
+++ b/pages/login/login.vue
@@ -99,9 +99,9 @@
-
- 登录遇到问题?去反馈
-
+
@@ -240,7 +240,6 @@ const isCodeEmpty = () => {
}
// 邮箱格式验证
const isEmailVerified = (email: string) => {
- console.log(email, validateEmail(email))
if (!validateEmail(email)) {
uni.showToast({
title: t('login.emailError'),
diff --git a/pages/user/about/index.vue b/pages/user/about/index.vue
new file mode 100644
index 0000000..af16d6f
--- /dev/null
+++ b/pages/user/about/index.vue
@@ -0,0 +1,239 @@
+
+
+
+
+
+
+
+
+
+
+ {{ $t('user.version') }} {{ appVersion }}
+
+
+
+ {{ $t('user.appDescription') }}
+
+
+
+
+
+
+
+ 022-24142321
+
+
+
+
+
+
+
+
+ {{ $t('user.privacyPolicy') }}
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/feedback/index.vue b/pages/user/feedback/index.vue
new file mode 100644
index 0000000..9d75852
--- /dev/null
+++ b/pages/user/feedback/index.vue
@@ -0,0 +1,363 @@
+
+
+
+
+
+
+
+
+
+ {{ $t('user.issueType') }}
+
+
+
+
+
+ {{ $t('user.account') }}
+
+
+
+
+
+ {{ $t('user.orderSn') }}
+
+
+
+
+
+ {{ $t('user.description') }}
+
+
+
+
+
+ {{ $t('user.contactPhone') }}
+
+
+
+
+
+ {{ $t('user.screenshots') }}
+
+ {{ $t('user.maxImagesCount') }}
+
+
+
+
+
+ {{ $t('common.submit') }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/index.vue b/pages/user/index.vue
new file mode 100644
index 0000000..09129ce
--- /dev/null
+++ b/pages/user/index.vue
@@ -0,0 +1,334 @@
+
+
+
+
+
+ {{ $t('user.settings') }}
+
+
+
+
+
+
+
+ {{ userInfo.nickname || $t('user.notSet') }}
+ {{ userInfo.email }}
+
+ VIP {{ vipInfo.endTime.split(' ')[0] }} {{ $t('user.vipExpireTime') }}
+
+
+
+
+
+
+
+
+
+ {{ $t('user.vip') }}
+ {{ vipInfo.endTime ? vipInfo.endTime.split(' ')[0] : '' }}
+
+
+ {{ $t('user.subscribe') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/order/index.vue b/pages/user/order/index.vue
new file mode 100644
index 0000000..f81bb3c
--- /dev/null
+++ b/pages/user/order/index.vue
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+
+ {{ $t('user.myOrders') }}
+
+
+
+
+
+
+
+
+
+ {{ $t('user.orderSn') }}
+ {{ order.orderSn }}
+
+ {{ order.createTime }}
+
+
+
+
+
+
+ {{ $t('common.loadMore') }}
+
+
+ {{ $t('common.noMore') }}
+
+
+
+
+
+
+ {{ $t('common.noData') }}
+
+
+
+
+
+
+
diff --git a/pages/user/profile/index.vue b/pages/user/profile/index.vue
new file mode 100644
index 0000000..922eba8
--- /dev/null
+++ b/pages/user/profile/index.vue
@@ -0,0 +1,645 @@
+
+
+
+
+
+
+
+
+
+
+ {{ userInfo.avatar ? $t('user.changeAvatar') : $t('user.setAvatar') }}
+
+
+
+
+
+
+
+
+ {{ formatValue(field, userInfo[field.key]) }}
+
+ {{ $t('user.notSet') }}
+
+
+
+
+
+
+
+
+
+ {{ editTitle }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ codeText }}
+
+
+
+
+
+
+
+
+ {{ passwordNote }}
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t('common.confirm') }}
+
+
+ {{ $t('common.cancel') }}
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/settings/index.vue b/pages/user/settings/index.vue
new file mode 100644
index 0000000..60c80ac
--- /dev/null
+++ b/pages/user/settings/index.vue
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+ {{ item.value }}
+
+
+
+
+
+
+
+ {{ $t('user.logoff') }}
+
+ {{ $t('user.logout') }}
+
+
+
+
+
+
+
+ {{ $t('user.wechatTip') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/wallet/index.vue b/pages/user/wallet/index.vue
new file mode 100644
index 0000000..3c517b8
--- /dev/null
+++ b/pages/user/wallet/index.vue
@@ -0,0 +1,523 @@
+
+
+
+
+
+
+
+
+ {{ $t('user.subscribe') }}
+
+
+
+
+ {{ pkg.dictType }}
+ NZD
+
+ {{ getDuration(pkg.remark) }}
+
+
+
+
+
+
+ {{ $t('user.paymentMethod') }}
+
+
+
+ {{ paymentName }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('user.agreeText') }}
+ {{ $t('user.agreement') }}
+
+
+
+
+
+
+
+ {{ $t('user.subscribe') }}
+
+
+
+
+
+
+
+ {{ agreementData.title }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/wallet/list.vue b/pages/user/wallet/list.vue
new file mode 100644
index 0000000..eb5ab6b
--- /dev/null
+++ b/pages/user/wallet/list.vue
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+ {{ $t('user.myAccount') }}
+
+
+
+
+
+
+
+
+ {{ item.createTime }}
+
+
+
+
+
+ {{ $t('common.noData') }}
+
+
+
+
+
+
+
diff --git a/static/tailwind.css b/static/tailwind.css
index 0ae3471..72f8032 100644
--- a/static/tailwind.css
+++ b/static/tailwind.css
@@ -8,7 +8,6 @@
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
--color-red-500: oklch(63.7% 0.237 25.331);
- --color-emerald-600: oklch(59.6% 0.145 163.225);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--default-transition-duration: 150ms;
@@ -187,9 +186,6 @@
.sticky {
position: sticky;
}
- .isolate {
- isolation: isolate;
- }
.container {
width: 100%;
@media (width >= 40rem) {
@@ -211,9 +207,6 @@
.block {
display: block;
}
- .contents {
- display: contents;
- }
.flex {
display: flex;
}
@@ -229,12 +222,15 @@
.inline-block {
display: inline-block;
}
- .list-item {
- display: list-item;
- }
.table {
display: table;
}
+ .w-\[100px\] {
+ width: 100px;
+ }
+ .flex-1 {
+ flex: 1;
+ }
.flex-shrink {
flex-shrink: 1;
}
@@ -244,6 +240,9 @@
.resize {
resize: both;
}
+ .flex-wrap {
+ flex-wrap: wrap;
+ }
.border {
border-style: var(--tw-border-style);
border-width: 1px;
@@ -251,35 +250,25 @@
.bg-\[red\] {
background-color: red;
}
+ .text-center {
+ text-align: center;
+ }
.text-left {
text-align: left;
}
.text-\[\#fff\] {
color: #fff;
}
- .capitalize {
- text-transform: capitalize;
- }
.lowercase {
text-transform: lowercase;
}
.uppercase {
text-transform: uppercase;
}
- .italic {
- font-style: italic;
- }
.ordinal {
--tw-ordinal: ordinal;
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
}
- .underline {
- text-decoration-line: underline;
- }
- .shadow {
- --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
- }
.ring {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -304,10 +293,6 @@
--tw-ease: var(--ease-in-out);
transition-timing-function: var(--ease-in-out);
}
- .ease-out {
- --tw-ease: var(--ease-out);
- transition-timing-function: var(--ease-out);
- }
.hover\:bg-red-500 {
&:hover {
@media (hover: hover) {
diff --git a/stores/user.ts b/stores/user.ts
index 57c7dfc..dcda25e 100644
--- a/stores/user.ts
+++ b/stores/user.ts
@@ -4,20 +4,22 @@ import { setAuthToken, clearAuthToken } from '@/utils/auth'
import type { IUserInfo } from '@/types/user'
export const useUserStore = defineStore('user', {
- state: (): IUserInfo => ({
+ state: (): IUserInfo => (uni.getStorageSync('userInfo') || {
id: 0,
name: '',
+ nickname: '',
avatar: '',
email: '',
- phone: '',
- token: uni.getStorageSync('token') || '',
+ token: '',
+ age: '',
+ tel: '',
+ sex: '',
}),
getters: {
isLoggedIn: (state: any) => Boolean(state.token),
userInfo: (state: any) => {
- const { id, name, avatar, email, phone } = state
- return { id, name, avatar, email, phone }
+ return state
},
},
@@ -54,7 +56,6 @@ export const useUserStore = defineStore('user', {
clearAuthToken()
uni.removeStorageSync('userInfo')
- uni.reLaunch({ url: '/pages/user/login' })
},
/** 从本地存储恢复用户信息 */
diff --git a/style/tailwind.css b/style/tailwind.css
new file mode 100644
index 0000000..0ae3471
--- /dev/null
+++ b/style/tailwind.css
@@ -0,0 +1,536 @@
+/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */
+@layer properties;
+@layer theme, base, components, utilities;
+@layer theme {
+ :root, :host {
+ --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+ "Courier New", monospace;
+ --color-red-500: oklch(63.7% 0.237 25.331);
+ --color-emerald-600: oklch(59.6% 0.145 163.225);
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
+ --default-transition-duration: 150ms;
+ --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ --default-font-family: var(--font-sans);
+ --default-mono-font-family: var(--font-mono);
+ }
+}
+@layer base {
+ *, ::after, ::before, ::backdrop, ::file-selector-button {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ border: 0 solid;
+ }
+ html, :host {
+ line-height: 1.5;
+ -webkit-text-size-adjust: 100%;
+ tab-size: 4;
+ font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
+ font-feature-settings: var(--default-font-feature-settings, normal);
+ font-variation-settings: var(--default-font-variation-settings, normal);
+ -webkit-tap-highlight-color: transparent;
+ }
+ hr {
+ height: 0;
+ color: inherit;
+ border-top-width: 1px;
+ }
+ abbr:where([title]) {
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+ }
+ h1, h2, h3, h4, h5, h6 {
+ font-size: inherit;
+ font-weight: inherit;
+ }
+ a {
+ color: inherit;
+ -webkit-text-decoration: inherit;
+ text-decoration: inherit;
+ }
+ b, strong {
+ font-weight: bolder;
+ }
+ code, kbd, samp, pre {
+ font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
+ font-feature-settings: var(--default-mono-font-feature-settings, normal);
+ font-variation-settings: var(--default-mono-font-variation-settings, normal);
+ font-size: 1em;
+ }
+ small {
+ font-size: 80%;
+ }
+ sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+ }
+ sub {
+ bottom: -0.25em;
+ }
+ sup {
+ top: -0.5em;
+ }
+ table {
+ text-indent: 0;
+ border-color: inherit;
+ border-collapse: collapse;
+ }
+ :-moz-focusring {
+ outline: auto;
+ }
+ progress {
+ vertical-align: baseline;
+ }
+ summary {
+ display: list-item;
+ }
+ ol, ul, menu {
+ list-style: none;
+ }
+ img, svg, video, canvas, audio, iframe, embed, object {
+ display: block;
+ vertical-align: middle;
+ }
+ img, video {
+ max-width: 100%;
+ height: auto;
+ }
+ button, input, select, optgroup, textarea, ::file-selector-button {
+ font: inherit;
+ font-feature-settings: inherit;
+ font-variation-settings: inherit;
+ letter-spacing: inherit;
+ color: inherit;
+ border-radius: 0;
+ background-color: transparent;
+ opacity: 1;
+ }
+ :where(select:is([multiple], [size])) optgroup {
+ font-weight: bolder;
+ }
+ :where(select:is([multiple], [size])) optgroup option {
+ padding-inline-start: 20px;
+ }
+ ::file-selector-button {
+ margin-inline-end: 4px;
+ }
+ ::placeholder {
+ opacity: 1;
+ }
+ @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
+ ::placeholder {
+ color: currentcolor;
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, currentcolor 50%, transparent);
+ }
+ }
+ }
+ textarea {
+ resize: vertical;
+ }
+ ::-webkit-search-decoration {
+ -webkit-appearance: none;
+ }
+ ::-webkit-date-and-time-value {
+ min-height: 1lh;
+ text-align: inherit;
+ }
+ ::-webkit-datetime-edit {
+ display: inline-flex;
+ }
+ ::-webkit-datetime-edit-fields-wrapper {
+ padding: 0;
+ }
+ ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
+ padding-block: 0;
+ }
+ ::-webkit-calendar-picker-indicator {
+ line-height: 1;
+ }
+ :-moz-ui-invalid {
+ box-shadow: none;
+ }
+ button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
+ appearance: button;
+ }
+ ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
+ height: auto;
+ }
+ [hidden]:where(:not([hidden="until-found"])) {
+ display: none !important;
+ }
+}
+@layer utilities {
+ .collapse {
+ visibility: collapse;
+ }
+ .visible {
+ visibility: visible;
+ }
+ .absolute {
+ position: absolute;
+ }
+ .fixed {
+ position: fixed;
+ }
+ .relative {
+ position: relative;
+ }
+ .static {
+ position: static;
+ }
+ .sticky {
+ position: sticky;
+ }
+ .isolate {
+ isolation: isolate;
+ }
+ .container {
+ width: 100%;
+ @media (width >= 40rem) {
+ max-width: 40rem;
+ }
+ @media (width >= 48rem) {
+ max-width: 48rem;
+ }
+ @media (width >= 64rem) {
+ max-width: 64rem;
+ }
+ @media (width >= 80rem) {
+ max-width: 80rem;
+ }
+ @media (width >= 96rem) {
+ max-width: 96rem;
+ }
+ }
+ .block {
+ display: block;
+ }
+ .contents {
+ display: contents;
+ }
+ .flex {
+ display: flex;
+ }
+ .grid {
+ display: grid;
+ }
+ .hidden {
+ display: none;
+ }
+ .inline {
+ display: inline;
+ }
+ .inline-block {
+ display: inline-block;
+ }
+ .list-item {
+ display: list-item;
+ }
+ .table {
+ display: table;
+ }
+ .flex-shrink {
+ flex-shrink: 1;
+ }
+ .transform {
+ transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
+ }
+ .resize {
+ resize: both;
+ }
+ .border {
+ border-style: var(--tw-border-style);
+ border-width: 1px;
+ }
+ .bg-\[red\] {
+ background-color: red;
+ }
+ .text-left {
+ text-align: left;
+ }
+ .text-\[\#fff\] {
+ color: #fff;
+ }
+ .capitalize {
+ text-transform: capitalize;
+ }
+ .lowercase {
+ text-transform: lowercase;
+ }
+ .uppercase {
+ text-transform: uppercase;
+ }
+ .italic {
+ font-style: italic;
+ }
+ .ordinal {
+ --tw-ordinal: ordinal;
+ font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
+ }
+ .underline {
+ text-decoration-line: underline;
+ }
+ .shadow {
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .ring {
+ --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .outline {
+ outline-style: var(--tw-outline-style);
+ outline-width: 1px;
+ }
+ .blur {
+ --tw-blur: blur(8px);
+ filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
+ }
+ .filter {
+ filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
+ }
+ .transition {
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ }
+ .ease-in-out {
+ --tw-ease: var(--ease-in-out);
+ transition-timing-function: var(--ease-in-out);
+ }
+ .ease-out {
+ --tw-ease: var(--ease-out);
+ transition-timing-function: var(--ease-out);
+ }
+ .hover\:bg-red-500 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-red-500);
+ }
+ }
+ }
+}
+@property --tw-rotate-x {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-rotate-y {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-rotate-z {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-skew-x {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-skew-y {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-border-style {
+ syntax: "*";
+ inherits: false;
+ initial-value: solid;
+}
+@property --tw-ordinal {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-slashed-zero {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-numeric-figure {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-numeric-spacing {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-numeric-fraction {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-shadow-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-shadow-alpha {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-inset-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-inset-shadow-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-inset-shadow-alpha {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-ring-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-ring-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-inset-ring-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-inset-ring-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-ring-inset {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-ring-offset-width {
+ syntax: "";
+ inherits: false;
+ initial-value: 0px;
+}
+@property --tw-ring-offset-color {
+ syntax: "*";
+ inherits: false;
+ initial-value: #fff;
+}
+@property --tw-ring-offset-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-outline-style {
+ syntax: "*";
+ inherits: false;
+ initial-value: solid;
+}
+@property --tw-blur {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-brightness {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-contrast {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-grayscale {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-hue-rotate {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-invert {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-opacity {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-saturate {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-sepia {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-drop-shadow {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-drop-shadow-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-drop-shadow-alpha {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-drop-shadow-size {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-ease {
+ syntax: "*";
+ inherits: false;
+}
+@layer properties {
+ @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
+ *, ::before, ::after, ::backdrop {
+ --tw-rotate-x: initial;
+ --tw-rotate-y: initial;
+ --tw-rotate-z: initial;
+ --tw-skew-x: initial;
+ --tw-skew-y: initial;
+ --tw-border-style: solid;
+ --tw-ordinal: initial;
+ --tw-slashed-zero: initial;
+ --tw-numeric-figure: initial;
+ --tw-numeric-spacing: initial;
+ --tw-numeric-fraction: initial;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-color: initial;
+ --tw-shadow-alpha: 100%;
+ --tw-inset-shadow: 0 0 #0000;
+ --tw-inset-shadow-color: initial;
+ --tw-inset-shadow-alpha: 100%;
+ --tw-ring-color: initial;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-inset-ring-color: initial;
+ --tw-inset-ring-shadow: 0 0 #0000;
+ --tw-ring-inset: initial;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-outline-style: solid;
+ --tw-blur: initial;
+ --tw-brightness: initial;
+ --tw-contrast: initial;
+ --tw-grayscale: initial;
+ --tw-hue-rotate: initial;
+ --tw-invert: initial;
+ --tw-opacity: initial;
+ --tw-saturate: initial;
+ --tw-sepia: initial;
+ --tw-drop-shadow: initial;
+ --tw-drop-shadow-color: initial;
+ --tw-drop-shadow-alpha: 100%;
+ --tw-drop-shadow-size: initial;
+ --tw-ease: initial;
+ }
+ }
+}
diff --git a/style/ui.scss b/style/ui.scss
new file mode 100644
index 0000000..366c063
--- /dev/null
+++ b/style/ui.scss
@@ -0,0 +1,137 @@
+:root,
+page {
+ /* 文字字号 */
+ --wot-fs-title: 18px; // 标题字号/重要正文字号
+ --wot-fs-content: 16px; // 普通正文
+ --wot-fs-secondary: 14px; // 次要信息,注释/补充/正文
+
+ // 导航栏
+ // --wot-navbar-background: #5355C8;
+ // --wot-navbar-color: #fff;
+ // --wot-navbar-hover-color: #4D4DB9;
+
+ // 底部tabbar
+ // --wot-tabbar-height: 60px;
+ // --wot-tabbar-item-title-font-size: 16px;
+
+ // cell
+ --wot-cell-title-fs: 16px;
+
+ // dropdown
+ // --wot-drop-menu-selected-color: #5355C8;
+
+ // collapse
+ --wot-collapse-body-padding: 0px 20px 15px;
+}
+uni-textarea {
+ height: 100px !important;
+}
+
+// 表单
+.wd-input__body, .wd-picker__body {
+ text-align: left;
+}
+.wd-input__error-message,
+.wd-picker__error-message,
+.wd-cell__error-message {
+ text-align: right !important;
+}
+.wd-input.is-cell{
+ padding-left: 5px !important;
+ padding-right: 5px !important;
+}
+.wd-textarea.is-cell {
+ display: block !important;
+ padding-left: 5px !important;
+ padding-right: 5px !important;
+}
+.wd-textarea.is-auto-height uni-textarea {
+ height: auto !important;
+}
+// 错误样式
+.wd-input.is-error {
+ &::after {
+ background: red !important;
+ }
+
+ .wd-input__icon {
+ color: red !important;
+ }
+}
+// 顶部对齐表单
+.label-position-top {
+ .wd-input {
+ display: block !important;
+ }
+ .wd-input__body {
+ text-align: left !important;
+ }
+ .wd-input__value {
+ border: 1px solid #eee;
+ padding: 2px 10px;
+ }
+ .wd-input__error-message {
+ text-align: left !important;
+ }
+}
+
+// cell 样式
+.wd-cell-group {
+ padding: 0 8px;
+}
+.wd-cell {
+ padding-left: 0 !important;
+}
+.wd-cell .wd-cell__wrapper {
+ padding-left: 5px !important;
+ padding-right: 5px !important;
+}
+.wd-cell__arrow-right {
+ margin-right: -5px;
+}
+.wd-picker.is-border .wd-picker__cell::after,
+.wd-input.is-cell.is-border::after,
+.wd-textarea.is-cell.is-border::after{
+ left: 0 !important;
+ width: 100% !important;
+}
+
+// picker
+.wd-picker__cell {
+ padding-left: 5px !important;
+ padding-right: 5px !important;
+}
+.wd-picker__arrow {
+ font-size: 18px !important;
+ margin-right: -5px;
+}
+
+// popup
+// .wd-popup {
+// z-index: 9999 !important;
+// }
+// .wd-overlay {
+// z-index: 9998 !important;
+// }
+
+// uni-ui form
+// .uni-forms-item {
+// margin-bottom: 10px !important;
+// }
+// .uni-forms-item__label {
+// height: auto !important;
+// padding-bottom: 0 !important;
+// font-size: var(--wot-fs-content) !important;
+// }
+// .uni-easyinput__content-input {
+// height: 30px !important;
+// }
+// .uni-easyinput__placeholder-class {
+// font-size: var(--wot-fs-content) !important;
+// }
+
+// // tag
+// .wd-tag {
+// font-size: var(--wot-fs-secondary) !important;
+// border-radius: 4px !important;
+// }
\ No newline at end of file
diff --git a/types/user.ts b/types/user.ts
index 39cad71..e319a5e 100644
--- a/types/user.ts
+++ b/types/user.ts
@@ -57,3 +57,79 @@ export interface IForgetPasswordForm {
password: string
confirmPassword: string
}
+
+/**
+ * VIP信息接口
+ */
+export interface IVipInfo {
+ id: number
+ endTime: string
+ vipType: number
+ [key: string]: any
+}
+
+/**
+ * 订单接口
+ */
+export interface IOrder {
+ id: number
+ orderSn: string
+ bookEntity: {
+ id: number
+ name: string
+ images: string
+ }
+ orderMoney: number
+ paymentMethod: string // '4'-虚拟货币, '5'-真实货币
+ createTime: string
+ [key: string]: any
+}
+
+/**
+ * VIP套餐接口
+ */
+export interface IVipPackage {
+ id: number
+ dictType: string // 价格
+ dictValue: string // 产品ID
+ money: number
+ priceTypeId: number
+ remark: string // 时长(天数)
+ [key: string]: any
+}
+
+/**
+ * 交易记录接口
+ */
+export interface ITransaction {
+ id: number
+ orderType: string // '充值' | '消费'
+ changeAmount: number
+ remark: string
+ createTime: string
+ [key: string]: any
+}
+
+/**
+ * 反馈表单接口
+ */
+export interface IFeedbackForm {
+ type: string // 问题类型
+ account: string // 账号
+ relation?: string // 订单编号(可选)
+ content: string // 问题描述
+ contactInformation: string // 联系电话
+ image?: string // 截图(多张用逗号分隔)
+}
+
+/**
+ * 分页数据接口
+ */
+export interface IPageData {
+ records: T[]
+ total: number
+ size: number
+ current: number
+ pages: number
+ [key: string]: any
+}
diff --git a/utils/index.ts b/utils/index.ts
index b2be9bb..1f3e68b 100644
--- a/utils/index.ts
+++ b/utils/index.ts
@@ -1,5 +1,51 @@
+/**
+ * 页面跳转
+ */
export const onPageJump = (path: string) => {
uni.navigateTo({
url: path
})
+}
+
+/**
+ * 拨打电话
+ */
+export const makePhoneCall = (phoneNumber: string, title: string, t: Function) => {
+ uni.showModal({
+ title: title,
+ content: phoneNumber,
+ confirmText: t('common.confirm'),
+ cancelText: t('common.cancel'),
+ success: (res: any) => {
+ if (res.confirm) {
+ uni.makePhoneCall({
+ phoneNumber: phoneNumber,
+ success: () => {
+ console.log('拨打电话成功')
+ },
+ fail: (error: any) => {
+ console.error('拨打电话失败:', error)
+ }
+ })
+ }
+ }
+ })
+}
+
+/**
+ * 复制到剪贴板
+ */
+export const copyToClipboard = (content: string, title: string, t: Function) => {
+ uni.setClipboardData({
+ data: content,
+ success: () => {
+ uni.showToast({
+ title: title + t('user.copySuccess'),
+ icon: 'none'
+ })
+ },
+ fail: (error) => {
+ console.error('复制失败:', error)
+ }
+ })
}
\ No newline at end of file
diff --git a/utils/system.ts b/utils/system.ts
new file mode 100644
index 0000000..a7602e3
--- /dev/null
+++ b/utils/system.ts
@@ -0,0 +1,54 @@
+interface SystemInfo {
+ statusBarHeight?: number;
+ [key: string]: any;
+}
+
+interface MenuButtonRect {
+ top: number;
+ height: number;
+ [key: string]: any;
+}
+
+interface LeftIcon {
+ left: string;
+ width: string;
+}
+
+const SYSTEM_INFO: SystemInfo = uni.getSystemInfoSync();
+
+export const getStatusBarHeight = (): number => SYSTEM_INFO.statusBarHeight || 0;
+
+export const getTitleBarHeight = (): number => {
+ if (uni.getMenuButtonBoundingClientRect) {
+ const { top, height }: MenuButtonRect = uni.getMenuButtonBoundingClientRect();
+ return height + (top - getStatusBarHeight()) * 2;
+ } else {
+ return 44;
+ }
+}
+
+export const getNavBarHeight = (): number => getStatusBarHeight() + getTitleBarHeight();
+
+export const getLeftIconLeft = (): number => {
+ // #ifdef MP-TOUTIAO
+ const { leftIcon: { left, width } }: { leftIcon: LeftIcon } = tt.getCustomButtonBoundingClientRect();
+ return left + parseInt(width);
+ // #endif
+
+ // #ifndef MP-TOUTIAO
+ return 0;
+ // #endif
+}
+
+export const getNavbarHeight2 = () => {
+ const systemInfo = uni.getSystemInfoSync()
+ statusBarHeight.value = systemInfo.statusBarHeight || 0
+
+ let navBarHeight = 44
+ if (systemInfo.model.indexOf('iPhone') !== -1 && parseInt(systemInfo.model.slice(-2)) >= 11) {
+ navBarHeight = 48
+ }
+
+ const totalHeight = statusBarHeight.value + navBarHeight
+ navbarHeight.value = totalHeight + 'px'
+}
\ No newline at end of file
diff --git a/vite.config.js b/vite.config.js
index b5a96ac..e7c1b3a 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -30,5 +30,10 @@ child_process.exec(
})
export default defineConfig({
- plugins: [uni()]
+ plugins: [uni()],
+ define: {
+ __VUE_I18N_FULL_INSTALL__: true,
+ __VUE_I18N_LEGACY_API__: false,
+ __INTLIFY_PROD_DEVTOOLS__: false
+ }
})
\ No newline at end of file