文件
yjyf/pages/master/wallet.vue
linda 1d92202b1a feat: 微信授权登录 + 我的中心角色切换 + 师傅工作台全模块 + 图标美化
登录与角色:
- Auth::wxlogin 微信 code → jscode2session → 落库发 token(appid/secret 走 .env)
- 新增 fa_user_wechat 表,openid 幂等建号(CLI 已验证 is_new 1→0 不重复建号)
- Auth::switchRole 角色切换(未入驻 2001 / 审核中 2002 / 未通过 2003)
- pages/login 改为微信一键授权;pages/mine 我的中心(师傅入口 + 切换师傅端)

师傅工作台(对齐需求文档):
- pages/master/workbench 工作台:接单开关 / 待处理待验收 / 可提现 / 六宫格入口 / 信用四指标 / 技能标签
- pages/master/hall 订单大厅:类型筛选(一口价/报价) + 4 种排序 + 抢单倒计时 + 报价入口
- pages/master/quote 报价竞标:金额/说明/有效期 + 报价记录
- pages/master/wallet 钱包:可提现/今日/累计 + 账单明细 + 提现校验
- pages/master/credit 信用与申诉:五项指标 + 规则 + 申诉提交/记录
- 新增 fa_appeal 表

视觉:
- 15 个类目图标重画为双色扁平 SVG,用无头 Chrome 渲染为 192px 透明 PNG
- 首页改用 <image src=static/icons/*.png>,移除 200 行 CSS 图标数据

验证:page_flow 47 + e2e_flow 65 + phase2_verify 27 = 139 项断言全通过
2026-10-28 16:10:34 +08:00

106 行
4.5 KiB
Vue

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<view class="page">
<view class="hero">
<text class="hero-lab">可提现余额(元)</text>
<text class="hero-num">{{ income ? income.money : 0 }}</text>
<view class="hero-row">
<text class="hero-sub">今日收入 ¥{{ income ? income.today_income : 0 }}</text>
<text class="hero-sub">累计收入 ¥{{ income ? income.total_income : 0 }}</text>
</view>
<view class="hero-btn" @tap="openWithdraw">申请提现</view>
</view>
<view class="card">
<view class="card-head"><text class="card-title">账单明细</text></view>
<view class="log" v-for="(l, i) in logs" :key="i">
<view class="log-l">
<text class="log-t">{{ logTypeText(l.type) }}</text>
<text class="log-r">{{ l.remark }}</text>
<text class="log-time">{{ timeText(l.createtime) }}</text>
</view>
<view class="log-r2">
<text class="log-amt" :class="{ minus: Number(l.amount) < 0 }">{{ Number(l.amount) > 0 ? '+' : '' }}{{ l.amount }}</text>
<text class="log-bal">余额 {{ l.balance }}</text>
</view>
</view>
<view class="empty" v-if="!logs.length">暂无账单</view>
</view>
<view class="tips">提现 T+1 到账,手续费 0.6%;结算周期:客户验收后即时入账</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import api from '@/utils/api.js';
const income = ref(null);
const logs = ref([]);
function logTypeText(t) {
return { settle: '订单结算', withdraw: '提现', income: '收入', refund: '退款' }[t] || '账单';
}
function timeText(ts) {
const d = new Date(Number(ts) * 1000);
const p = (n) => (n < 10 ? '0' + n : n);
return `${d.getMonth() + 1}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
}
async function load() {
try {
const res = await api.masterIncome();
income.value = res;
logs.value = res.logs || [];
} catch (e) {}
}
function openWithdraw() {
uni.showModal({
title: '申请提现',
editable: true,
placeholderText: '请输入提现金额(≥10 元)',
success: async (r) => {
if (!r.confirm) return;
const amount = Number(r.content);
if (!amount || amount < 10) {
uni.showToast({ title: '单次不少于 10 元', icon: 'none' });
return;
}
try {
const res = await api.masterWithdraw({ amount: amount, channel: 'wechat' });
uni.showToast({ title: '已提交,预计到账 ¥' + res.arrive_amount, icon: 'none' });
load();
} catch (e) {}
}
});
}
onShow(() => load());
</script>
<style scoped>
.page { min-height: 100vh; background: #F5F6F8; padding-bottom: 60rpx; }
.hero { padding: 40rpx 36rpx 34rpx; background: linear-gradient(160deg,#FFB85C 0%,#F98D25 55%,#ED6F0E 100%); display: flex; flex-direction: column; }
.hero-lab { font-size: 22rpx; color: rgba(255,255,255,.9); }
.hero-num { margin-top: 10rpx; font-size: 68rpx; font-weight: 700; color: #fff; letter-spacing: 2rpx; }
.hero-row { display: flex; margin-top: 8rpx; }
.hero-sub { font-size: 22rpx; color: rgba(255,255,255,.88); margin-right: 26rpx; }
.hero-btn { margin-top: 26rpx; align-self: flex-start; height: 72rpx; padding: 0 40rpx; display: flex; align-items: center; border-radius: 36rpx; background: #fff; color: #E36B0C; font-size: 26rpx; font-weight: 700; }
.card { margin: 22rpx 28rpx 0; padding: 24rpx; background: #fff; border-radius: 20rpx; box-shadow: 0 6rpx 20rpx rgba(240,129,31,.06); }
.card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8rpx; }
.card-title { font-size: 28rpx; font-weight: 700; color: #1F1F1F; }
.log { display: flex; align-items: center; justify-content: space-between; padding: 18rpx 0; border-bottom: 1rpx solid #F4F4F4; }
.log:last-of-type { border-bottom: none; }
.log-l { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.log-t { font-size: 26rpx; font-weight: 600; color: #333; }
.log-r { margin-top: 4rpx; font-size: 22rpx; color: #9A9A9A; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.log-time { margin-top: 4rpx; font-size: 20rpx; color: #C4C4C4; }
.log-r2 { display: flex; flex-direction: column; align-items: flex-end; }
.log-amt { font-size: 30rpx; font-weight: 700; color: #2FA84F; }
.log-amt.minus { color: #E8331B; }
.log-bal { margin-top: 4rpx; font-size: 20rpx; color: #C4C4C4; }
.empty { padding: 60rpx 0; text-align: center; font-size: 24rpx; color: #9A9A9A; }
.tips { margin: 22rpx 28rpx 0; padding: 18rpx 22rpx; background: #FFF7F0; border-radius: 16rpx; font-size: 20rpx; color: #C4580A; line-height: 30rpx; }
</style>