diff --git a/src/app.config.ts b/src/app.config.ts index 2a7f0a5..61baa7e 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -30,6 +30,8 @@ export default defineAppConfig({ "downloadBill/index", // 下载账单 "downloadBillRecords/index", // 下载账单记录 "billDetail/index", // 账单详情 + "setTransactionPassword/index", // 设置交易密码 + "validPhone/index", // 验证手机号 ], }, // { diff --git a/src/user_pages/billDetail/index.tsx b/src/user_pages/billDetail/index.tsx index fa68f99..9a755e9 100644 --- a/src/user_pages/billDetail/index.tsx +++ b/src/user_pages/billDetail/index.tsx @@ -1,6 +1,10 @@ import React, { useEffect, useState } from "react"; -import { View, Text, Input, Button, Image } from "@tarojs/components"; +import { View, Text } from "@tarojs/components"; +import { useRouter } from '@tarojs/taro'; +import dayjs from 'dayjs'; +import Taro from '@tarojs/taro'; +import httpService from "@/services/httpService"; import { TransactionType, TransactionSubType } from "@/user_pages/wallet/index"; import "./index.scss"; @@ -10,51 +14,84 @@ enum FreezeActions { } interface BillDetail { - id: number; - transaction_type: TransactionType; - transaction_sub_type: TransactionSubType; - freeze_action: FreezeActions; - amount: number; - description: string; - related_id: number; - create_time: string; - order_no: string; - game_title: string; - order_amount: number; - type_text: string; - sub_type_text: string; - amount_yuan: string; + id?: number; + transaction_type?: TransactionType; + transaction_sub_type?: TransactionSubType; + freeze_action?: FreezeActions; + amount?: number; + description?: string; + related_id?: number; + create_time?: string; + order_no?: string; + game_title?: string; + order_amount?: number; + type_text?: string; + sub_type_text?: string; + amount_yuan?: string; } const BillDetail: React.FC = () => { - const [billDetail, setBillDetail] = useState(null); + const router = useRouter(); + const { id } = router.params; + const [billDetail, setBillDetail] = useState({}); + + const getBillDetail = async () => { + try { + const res = await httpService.post("/wallet/transaction_detail", { transaction_id: id }) + if (res.code === 0) { + setBillDetail(res.data); + } + } catch (error) { + console.log(error); + } + + }; + + const copyText = (text: string | undefined) => { + if (!text) { + return; + } + Taro.setClipboardData({ + data: text, + success: () => { + Taro.showToast({ + title: '复制成功', + icon: 'none' + }); + } + }); + }; + + useEffect(() => { + getBillDetail(); + }, [id]); return ( 现金交易 (元) - + - 65.00 + {billDetail.transaction_type === 'expense' ? '-' : '+'} + {billDetail.amount_yuan} 交易时间 - 2025-02-16 12:21:54 + {billDetail.create_time && dayjs(billDetail.create_time).format('YYYY-MM-DD HH:mm:ss')} 活动标题 - 女生轻松双打 + {billDetail.game_title} 现金余额 - ¥3890.00 + ¥{billDetail.amount} - 交易单号 + 商户单号 - 89172371293791273912 - 复制 + {billDetail.order_no} + copyText(billDetail.order_no)}>复制 diff --git a/src/user_pages/setTransactionPassword/index.config.ts b/src/user_pages/setTransactionPassword/index.config.ts new file mode 100644 index 0000000..5f2a473 --- /dev/null +++ b/src/user_pages/setTransactionPassword/index.config.ts @@ -0,0 +1,3 @@ +export default definePageConfig({ + navigationBarTitleText: '设置交易密码', +}) diff --git a/src/user_pages/setTransactionPassword/index.scss b/src/user_pages/setTransactionPassword/index.scss new file mode 100644 index 0000000..1e596ec --- /dev/null +++ b/src/user_pages/setTransactionPassword/index.scss @@ -0,0 +1,60 @@ +.set-transaction-password-page { + min-height: 100vh; + background-color: #f5f5f5; + padding: 20px; + + .form-item { + height: 50px; + display: flex; + gap: 10px; + align-items: center; + border-bottom: 1px solid #0000000D; + font-size: 14px; + + .form-label { + width: 56px; + text-align: right; + } + } + + .tips { + font-family: PingFang SC; + font-weight: 400; + font-style: Regular; + font-size: 12px; + line-height: 18px; + letter-spacing: 0px; + vertical-align: middle; + color: #3C3C4366; + } + + .btn { + height: 24px; + border: 1px solid rgba(0, 0, 0, 0.06); + display: flex; + align-items: center; + justify-content: center; + color: #fff; + background: #000; + box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.1); + backdrop-filter: blur(16px); + font-feature-settings: "liga" off, "clig" off; + font-family: "PingFang SC"; + font-size: 9.6px; + font-style: normal; + line-height: normal; + border-radius: 8px; + margin-right: 0; + } + + .bottom-btn { + position: fixed; + bottom: 40px; + height: 54px; + width: calc(100vw - 40px); + margin: 0 auto; + border-radius: 16px; + font-size: 16px; + font-weight: 600; + } +} \ No newline at end of file diff --git a/src/user_pages/setTransactionPassword/index.tsx b/src/user_pages/setTransactionPassword/index.tsx new file mode 100644 index 0000000..0a449ce --- /dev/null +++ b/src/user_pages/setTransactionPassword/index.tsx @@ -0,0 +1,114 @@ +import React, { useState, useEffect } from "react"; +import Taro, { useRouter } from '@tarojs/taro'; +import { View, Text, Input, Button } from "@tarojs/components"; + +import "./index.scss"; +import httpService from "@/services/httpService"; + +interface FormFields { + old_password?: string; + new_password: string; + confirm_password: string; + sms_code?: string; +} + +const SetTransactionPassword: React.FC = () => { + const [handleType, setHandleType] = useState("set"); + const router = useRouter(); + const { type } = router.params; + + useEffect(() => { + if (type) { + setHandleType(type); + } + }, [type]); + + const [formData, setFormData] = useState({ + old_password: "", + new_password: "", + confirm_password: "", + sms_code: "", + }); + + const handleInput = (e: any, field: string) => { + setFormData({ ...formData, [field]: e.detail.value }); + }; + + const handleConfirm = async () => { + const { new_password, confirm_password } = formData; + if (new_password !== confirm_password) { + Taro.showToast({ + title: "两次密码输入不一致", + icon: "none", + }); + return; + } + if (handleType === "set") { + const { sms_code } = formData; + try { + await httpService.post("/wallet/set_payment_password", { password: new_password, sms_code }); + Taro.showToast({ + title: "设置交易密码成功", + icon: "success", + }); + Taro.navigateBack(); + } catch (error) { + Taro.showToast({ + title: "设置交易密码失败", + icon: "none", + }); + return; + } + } else if (handleType === "reset") { + const { old_password } = formData; + try { + await httpService.post("/wallet/change_payment_password", { old_password, new_password }); + Taro.showToast({ + title: "修改交易密码成功", + icon: "success", + }); + Taro.navigateBack(); + } catch (error) { + Taro.showToast({ + title: "修改交易密码失败", + icon: "none", + }); + return; + } + } + }; + + return ( + + { + handleType === "reset" && ( + + 旧密码 + { handleInput(e, "old_password") }}> + + ) + } + + 交易密码 + { handleInput(e, "new_password") }}> + + + 重复密码 + { handleInput(e, "confirm_password") }}> + + { + handleType === "set" && ( + + 手机验证 + { handleInput(e, "sms_code") }}> + + + ) + } + * 密码由6位数字组成 + + + ); +}; + +export default SetTransactionPassword; diff --git a/src/user_pages/validPhone/index.config.ts b/src/user_pages/validPhone/index.config.ts new file mode 100644 index 0000000..6d6c0ff --- /dev/null +++ b/src/user_pages/validPhone/index.config.ts @@ -0,0 +1,3 @@ +export default definePageConfig({ + navigationBarTitleText: '验证手机号', +}) diff --git a/src/user_pages/validPhone/index.scss b/src/user_pages/validPhone/index.scss new file mode 100644 index 0000000..e231107 --- /dev/null +++ b/src/user_pages/validPhone/index.scss @@ -0,0 +1,49 @@ +.set-transaction-password-page { + min-height: 100vh; + background-color: #f5f5f5; + padding: 20px; + + .form-item { + height: 50px; + display: flex; + gap: 10px; + align-items: center; + border-bottom: 1px solid #0000000D; + font-size: 14px; + + .form-label { + width: 56px; + text-align: right; + } + } + + .btn { + height: 24px; + border: 1px solid rgba(0, 0, 0, 0.06); + display: flex; + align-items: center; + justify-content: center; + color: #fff; + background: #000; + box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.1); + backdrop-filter: blur(16px); + font-feature-settings: "liga" off, "clig" off; + font-family: "PingFang SC"; + font-size: 9.6px; + font-style: normal; + line-height: normal; + border-radius: 8px; + margin-right: 0; + } + + .bottom-btn { + position: fixed; + bottom: 40px; + height: 54px; + width: calc(100vw - 40px); + margin: 0 auto; + border-radius: 16px; + font-size: 16px; + font-weight: 600; + } +} \ No newline at end of file diff --git a/src/user_pages/validPhone/index.tsx b/src/user_pages/validPhone/index.tsx new file mode 100644 index 0000000..98f112c --- /dev/null +++ b/src/user_pages/validPhone/index.tsx @@ -0,0 +1,44 @@ +import React, { useState, useEffect } from "react"; +import Taro from '@tarojs/taro'; +import { View, Text, Input, Button } from "@tarojs/components"; + +import "./index.scss"; +import httpService from "@/services/httpService"; + +interface FormFields { + phone?: string; + sms_code?: string; +} + +const ValidPhone: React.FC = () => { + const [formData, setFormData] = useState({ + phone: "", + sms_code: "", + }); + + const handleInput = (e: any, field: string) => { + setFormData({ ...formData, [field]: e.detail.value }); + }; + + const handleConfirm = async () => { + // TODO: 校验验证码 + Taro.navigateTo({ url: "/user_pages/setTransactionPassword/index?type=find" }); + }; + + return ( + + + 手机号 + + + + 验证码 + { handleInput(e, "sms_code") }}> + + + + + ); +}; + +export default ValidPhone; diff --git a/src/user_pages/wallet/index.tsx b/src/user_pages/wallet/index.tsx index e08db38..3898a30 100644 --- a/src/user_pages/wallet/index.tsx +++ b/src/user_pages/wallet/index.tsx @@ -103,6 +103,7 @@ const WalletPage: React.FC = () => { const [show_withdraw_popup, set_show_withdraw_popup] = useState(false); const [withdraw_amount, set_withdraw_amount] = useState(""); const [submitting, set_submitting] = useState(false); + const [password_status, set_password_status] = useState(false); // 交易记录状态 const [transactions, set_transactions] = useState([]); @@ -125,8 +126,18 @@ const WalletPage: React.FC = () => { useDidShow(() => { load_wallet_data(); load_transactions(); + check_password_status(); }); + const check_password_status = async () => { + try { + const res = await httpService.post("/wallet/check_password_status"); + set_password_status(res.data.is_password_set); + } catch (e) { + console.error("检查交易密码状态失败:", e); + } + } + // 加载钱包数据 const load_wallet_data = async () => { try { @@ -216,8 +227,18 @@ const WalletPage: React.FC = () => { } }; + const navigateToSetTransactionPassword = (type: "set" | "reset") => { + Taro.navigateTo({ + url: `/user_pages/setTransactionPassword/index?type=${type}`, + }); + }; + // 处理提现 const handle_withdraw = () => { + if (!password_status) { + navigateToSetTransactionPassword("set"); + return; + } if (wallet_info.balance <= 0) { Taro.showToast({ title: "余额不足", @@ -357,7 +378,7 @@ const WalletPage: React.FC = () => { {/* 头部信息 */} 我的现金 - 修改交易密码 + navigateToSetTransactionPassword("reset")}>修改交易密码 {/* 余额显示 */} @@ -420,7 +441,8 @@ const WalletPage: React.FC = () => { /> 下载账单 - + {/* TODO 客服中心 */} + Taro.navigateTo({ url: "/user_pages/validPhone/index" })}> {