diff --git a/config/env.ts b/config/env.ts
index c92883b..edbcd70 100644
--- a/config/env.ts
+++ b/config/env.ts
@@ -9,7 +9,7 @@ export const ENV_CONFIG = {
// 生产环境
production: {
API_BASE_URL: 'https://cms-api.websoft.top/api',
- APP_NAME: '时里院子市集',
+ APP_NAME: '通源堂健康生态平台',
DEBUG: 'false',
},
// 测试环境
diff --git a/project.tt.json b/project.tt.json
index 71d3700..942b617 100644
--- a/project.tt.json
+++ b/project.tt.json
@@ -1,7 +1,7 @@
{
"miniprogramRoot": "./",
- "projectname": "mp-react",
- "description": "时里院子市集",
+ "projectname": "template-10559",
+ "description": "通源堂健康生态平台",
"appid": "touristappid",
"setting": {
"urlCheck": true,
diff --git a/src/admin/components/UserCell.tsx b/src/admin/components/UserCell.tsx
index 0928980..57bb70c 100644
--- a/src/admin/components/UserCell.tsx
+++ b/src/admin/components/UserCell.tsx
@@ -36,7 +36,7 @@ const UserCell = () => {
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
}}
title={
- navTo('/dealer/index', true)}>
+ navTo('/doctor/index', true)}>
开通会员
享优惠
diff --git a/src/api/cms/cmsAd/index.ts b/src/api/cms/cmsAd/index.ts
index a9b1ca7..37dae87 100644
--- a/src/api/cms/cmsAd/index.ts
+++ b/src/api/cms/cmsAd/index.ts
@@ -102,7 +102,7 @@ export async function getCmsAd(id: number) {
}
/**
- * 根据id查询广告位
+ * 根据code查询广告位
*/
export async function getCmsAdByCode(code: string) {
const res = await request.get>(
diff --git a/src/api/cms/cmsAd/model/index.ts b/src/api/cms/cmsAd/model/index.ts
index 76fd9a4..3f900a7 100644
--- a/src/api/cms/cmsAd/model/index.ts
+++ b/src/api/cms/cmsAd/model/index.ts
@@ -1,4 +1,4 @@
-import type { PageParam } from '@/api/index';
+import type { PageParam } from '@/api';
/**
* 广告位
diff --git a/src/api/cms/cmsArticle/index.ts b/src/api/cms/cmsArticle/index.ts
index 7bc2c44..94339ec 100644
--- a/src/api/cms/cmsArticle/index.ts
+++ b/src/api/cms/cmsArticle/index.ts
@@ -1,5 +1,5 @@
import request from '@/utils/request';
-import type {ApiResult, PageResult} from '@/api/index';
+import type {ApiResult, PageResult} from '@/api';
import type {CmsArticle, CmsArticleParam} from './model';
/**
@@ -204,3 +204,15 @@ export async function getByIds(params?: CmsArticleParam) {
return Promise.reject(new Error(res.message));
}
+/**
+ * 根据code查询文章
+ */
+export async function getCmsArticleByCode(code: string) {
+ const res = await request.get>(
+ '/cms/cms-article/getByCode/' + code
+ );
+ if (res.code === 0 && res.data) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
diff --git a/src/api/cms/cmsWebsiteField/model/index.ts b/src/api/cms/cmsWebsiteField/model/index.ts
index 3a13b4a..4863d36 100644
--- a/src/api/cms/cmsWebsiteField/model/index.ts
+++ b/src/api/cms/cmsWebsiteField/model/index.ts
@@ -1,4 +1,4 @@
-import type { PageParam } from '@/api/index';
+import type { PageParam } from '@/api';
/**
* 应用参数
@@ -48,10 +48,13 @@ export interface Config {
loginBgImg?: string;
address?: string;
tel?: string;
+ theme?: string;
workDay?: string;
kefu2?: string;
kefu1?: string;
email?: string;
loginTitle?: string;
sysLogo?: string;
+ vipText?: string;
+ vipComments?: string;
}
diff --git a/src/api/cmsArticle/index.ts b/src/api/cmsArticle/index.ts
new file mode 100644
index 0000000..608c0e5
--- /dev/null
+++ b/src/api/cmsArticle/index.ts
@@ -0,0 +1,218 @@
+import request from '@/utils/request';
+import type {ApiResult, PageResult} from '@/api';
+import type {CmsArticle, CmsArticleParam} from './model';
+
+/**
+ * 分页查询文章
+ */
+export async function pageCmsArticle(params: CmsArticleParam) {
+ const res = await request.get>>(
+ '/cms/cms-article/page',
+ params
+ );
+ if (res.code === 0) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 查询文章列表
+ */
+export async function listCmsArticle(params?: CmsArticleParam) {
+ const res = await request.get>(
+ '/cms/cms-article',
+ params
+ );
+ if (res.code === 0 && res.data) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 添加文章
+ */
+export async function addCmsArticle(data: CmsArticle) {
+ const res = await request.post>(
+ '/cms/cms-article',
+ data
+ );
+ if (res.code === 0) {
+ return res.message;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 修改文章
+ */
+export async function updateCmsArticle(data: CmsArticle) {
+ const res = await request.put>(
+ '/cms/cms-article',
+ data
+ );
+ if (res.code === 0) {
+ return res.message;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 删除文章
+ */
+export async function removeCmsArticle(id?: number) {
+ const res = await request.del>(
+ '/cms/cms-article/' + id
+ );
+ if (res.code === 0) {
+ return res.message;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 批量删除文章
+ */
+export async function removeBatchCmsArticle(data: (number | undefined)[]) {
+ const res = await request.del>(
+ '/cms/cms-article/batch',
+ {
+ data
+ }
+ );
+ if (res.code === 0) {
+ return res.message;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 根据id查询文章
+ */
+export async function getCmsArticle(id: number) {
+ const res = await request.get>(
+ '/cms/cms-article/' + id
+ );
+ if (res.code === 0 && res.data) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+export async function getCount(params?: CmsArticleParam) {
+ const res = await request.get>('/cms/cms-article/data', {
+ params
+ });
+ if (res.code === 0) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 上一篇
+ * @param params
+ */
+export async function getPrevious(params?: CmsArticleParam) {
+ const res = await request.get>(
+ '/cms/cms-article/getPrevious/' + params?.articleId,
+ {
+ params
+ }
+ );
+ if (res.code === 0) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 下一篇
+ * @param params
+ */
+export async function getNext(params?: CmsArticleParam) {
+ const res = await request.get>(
+ '/cms/cms-article/getNext/' + params?.articleId,
+ {
+ params
+ }
+ );
+ if (res.code === 0) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 验证文章密码
+ * @param params
+ */
+export async function checkArticlePassword(params?: CmsArticleParam) {
+ const res = await request.get>(
+ '/cms/cms-article/checkArticlePassword',
+ {
+ params
+ }
+ );
+ if (res.code === 0) {
+ return res.message;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+export async function findTags(params?: CmsArticleParam) {
+ const res = await request.get>(
+ '/cms/cms-article/findTags',
+ {
+ params
+ }
+ );
+ if (res.code === 0) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+export async function pageTags(params?: CmsArticleParam) {
+ const res = await request.get>(
+ '/cms/cms-article/pageTags',
+ {
+ params
+ }
+ );
+ if (res.code === 0) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 按IDS查询文章
+ * @param params
+ */
+export async function getByIds(params?: CmsArticleParam) {
+ const res = await request.get>(
+ '/cms/cms-article/getByIds',
+ {
+ params
+ }
+ );
+ if (res.code === 0) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
+
+/**
+ * 根据code查询文章
+ */
+export async function getByCode(code: string) {
+ const res = await request.get>(
+ '/cms/cms-article/getByCode/' + code
+ );
+ if (res.code === 0 && res.data) {
+ return res.data;
+ }
+ return Promise.reject(new Error(res.message));
+}
diff --git a/src/api/cmsArticle/model/index.ts b/src/api/cmsArticle/model/index.ts
new file mode 100644
index 0000000..5206b48
--- /dev/null
+++ b/src/api/cmsArticle/model/index.ts
@@ -0,0 +1,132 @@
+import type { PageParam } from '@/api/index';
+
+/**
+ * 文章
+ */
+export interface CmsArticle {
+ // 文章ID
+ articleId?: number;
+ // 文章标题
+ title?: string;
+ // 文章类型 0常规 1视频
+ type?: number;
+ // 文章模型
+ model?: string;
+ // 文章详情页模板
+ detail?: string;
+ // banner图片
+ banner?: string;
+ // 列表显示方式(10小图展示 20大图展示)
+ showType?: number;
+ // 话题
+ topic?: string;
+ // 标签
+ tags?: any;
+ // 栏目ID
+ categoryId?: number;
+ // 栏目名称
+ categoryName?: string;
+ // 封面图
+ image?: string;
+ // 价格
+ price?: number;
+ startTime?: any;
+ endTime?: any;
+ // 缩列图
+ thumbnail?: string;
+ // 来源
+ source?: string;
+ // 产品概述
+ overview?: string;
+ // 虚拟阅读量(仅用作展示)
+ virtualViews?: number;
+ // 实际阅读量
+ actualViews?: number;
+ // 购买人数
+ bmUsers?: number;
+ // 浏览权限(0公开 1会员 2密码)
+ permission?: number;
+ // 访问密码
+ password?: string;
+ // 确认密码
+ password2?: string;
+ // 发布来源客户端 (APP、H5、小程序等)
+ platform?: string;
+ // 文章附件
+ files?: string;
+ // 视频地址
+ video?: string;
+ // 接受的文件类型
+ accept?: string;
+ // 经度
+ longitude?: string;
+ // 纬度
+ latitude?: string;
+ // 所在省份
+ province?: string;
+ // 所在城市
+ city?: string;
+ // 所在辖区
+ region?: string;
+ // 街道地址
+ address?: string;
+ // 点赞数
+ likes?: number;
+ // pdf地址
+ pdfUrl?: string;
+ // 评论数
+ commentNumbers?: number;
+ // 提醒谁看
+ toUsers?: string;
+ // 文章内容
+ content?: string;
+ // 是否推荐
+ recommend?: number;
+ // 用户ID
+ userId?: number;
+ // 排序(数字越小越靠前)
+ sortNumber?: number;
+ // 备注
+ comments?: string;
+ // 状态, 0已发布, 1待审核 2已驳回 3违规内容
+ status?: number;
+ // 是否删除, 0否, 1是
+ deleted?: number;
+ // 租户id
+ tenantId?: number;
+ // 创建时间
+ createTime?: string;
+ // 修改时间
+ updateTime?: string;
+ // 父级id
+ parentId?: number;
+ nickname?: string;
+ username?: string;
+ author?: string;
+ shopId?: number;
+ tenantName?: string;
+ logo?: string;
+ fileList?: any;
+ // 编辑器类型
+ editor?: number;
+}
+
+/**
+ * 文章搜索条件
+ */
+export interface CmsArticleParam extends PageParam {
+ articleId?: number;
+ articleIds?: string;
+ categoryId?: number;
+ parentId?: number;
+ status?: number;
+ // 是否推荐
+ recommend?: number;
+ keywords?: string;
+ // 验证密码
+ password?: string;
+ password2?: string;
+ tags?: string;
+ detail?: string;
+ sceneType?: string;
+}
diff --git a/src/api/invite/index.ts b/src/api/invite/index.ts
index ba38f75..9dc508e 100644
--- a/src/api/invite/index.ts
+++ b/src/api/invite/index.ts
@@ -111,6 +111,7 @@ export interface InviteRecordParam {
*/
export async function generateMiniProgramCode(data: MiniProgramCodeParam) {
try {
+ // return 'http://127.0.0.1:9200/api/wx-login/getOrderQRCodeUnlimited/' + data.scene;
const url = '/wx-login/getOrderQRCodeUnlimited/' + data.scene;
// 由于接口直接返回图片buffer,我们直接构建完整的URL
return `${BaseUrl}${url}`;
diff --git a/src/api/shop/shopDealerApply/model/index.ts b/src/api/shop/shopDealerApply/model/index.ts
index 8ea27cc..3187633 100644
--- a/src/api/shop/shopDealerApply/model/index.ts
+++ b/src/api/shop/shopDealerApply/model/index.ts
@@ -1,4 +1,4 @@
-import type { PageParam } from '@/api/index';
+import type { PageParam } from '@/api';
/**
* 分销商申请记录表
@@ -10,6 +10,14 @@ export interface ShopDealerApply {
userId?: number;
// 姓名
realName?: string;
+ // 分销商名称
+ dealerName?: string;
+ // 分销商编号
+ dealerCode?: string;
+ // 详细地址
+ address?: string;
+ // 金额
+ money?: number;
// 手机号
mobile?: string;
// 推荐人用户ID
@@ -17,7 +25,9 @@ export interface ShopDealerApply {
// 申请方式(10需后台审核 20无需审核)
applyType?: number;
// 申请时间
- applyTime?: number;
+ applyTime?: string;
+ // 签单时间
+ contractTime?: string;
// 审核状态 (10待审核 20审核通过 30驳回)
applyStatus?: number;
// 审核时间
@@ -30,6 +40,14 @@ export interface ShopDealerApply {
createTime?: string;
// 修改时间
updateTime?: string;
+ // 过期时间
+ expirationTime?: string;
+ // 备注
+ comments?: string;
+ // 昵称
+ nickName?: string;
+ // 推荐人名称
+ refereeName?: string;
}
/**
@@ -37,7 +55,10 @@ export interface ShopDealerApply {
*/
export interface ShopDealerApplyParam extends PageParam {
applyId?: number;
+ type?: number;
+ dealerName?: string;
mobile?: string;
userId?: number;
keywords?: string;
+ applyStatus?: number; // 申请状态筛选 (10待审核 20审核通过 30驳回)
}
diff --git a/src/app.config.ts b/src/app.config.ts
index 3f49c23..5e83456 100644
--- a/src/app.config.ts
+++ b/src/app.config.ts
@@ -73,16 +73,20 @@ export default {
]
},
{
- "root": "dealer",
+ "root": "doctor",
"pages": [
"index",
"apply/add",
"withdraw/index",
"orders/index",
+ "orders/add",
"team/index",
"qrcode/index",
"invite-stats/index",
- "info"
+ "info",
+ "customer/index",
+ "customer/add",
+ "customer/trading",
]
},
{
diff --git a/src/app.ts b/src/app.ts
index 9eba816..41fd67b 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -7,6 +7,7 @@ import {loginByOpenId} from "@/api/layout";
import {TenantId} from "@/config/app";
import {saveStorageByLoginUser} from "@/utils/server";
import {parseInviteParams, saveInviteParams, trackInviteSource, handleInviteRelation, debugInviteInfo} from "@/utils/invite";
+import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
function App(props: { children: any; }) {
const reload = () => {
@@ -52,6 +53,7 @@ function App(props: { children: any; }) {
// 处理小程序启动参数中的邀请信息
const options = Taro.getLaunchOptionsSync()
handleLaunchOptions(options)
+ handleTheme()
})
// 处理启动参数
@@ -94,6 +96,15 @@ function App(props: { children: any; }) {
}
}
+ const handleTheme = () => {
+ configWebsiteField().then(data => {
+ // 设置主题
+ if(data.theme && !Taro.getStorageSync('user_theme')){
+ Taro.setStorageSync('user_theme', data.theme)
+ }
+ })
+ }
+
// 对应 onHide
useDidHide(() => {
})
diff --git a/src/cms/category/index.tsx b/src/cms/category/index.tsx
index fe81623..b6ccd89 100644
--- a/src/cms/category/index.tsx
+++ b/src/cms/category/index.tsx
@@ -44,7 +44,7 @@ function Category() {
useShareAppMessage(() => {
return {
- title: `${nav?.categoryName}_时里院子市集`,
+ title: `${nav?.categoryName}_通源堂健康生态平台`,
path: `/shop/category/index?id=${categoryId}`,
success: function () {
console.log('分享成功');
diff --git a/src/components/UnifiedQRButton.tsx b/src/components/UnifiedQRButton.tsx
index 18fee99..6c019d5 100644
--- a/src/components/UnifiedQRButton.tsx
+++ b/src/components/UnifiedQRButton.tsx
@@ -29,7 +29,7 @@ export interface UnifiedQRButtonProps {
* 支持登录和核销两种类型的二维码扫描
*/
const UnifiedQRButton: React.FC = ({
- type = 'default',
+ type = 'danger',
size = 'small',
text = '扫码',
showIcon = true,
diff --git a/src/dealer/apply/add.tsx b/src/dealer/apply/add.tsx
deleted file mode 100644
index f862bf3..0000000
--- a/src/dealer/apply/add.tsx
+++ /dev/null
@@ -1,433 +0,0 @@
-import {useEffect, useState, useRef} from "react";
-import {Loading, CellGroup, Input, Form, Avatar, Button, Space} from '@nutui/nutui-react-taro'
-import {Edit} from '@nutui/icons-react-taro'
-import Taro from '@tarojs/taro'
-import {View} from '@tarojs/components'
-import FixedButton from "@/components/FixedButton";
-import {useUser} from "@/hooks/useUser";
-import {TenantId} from "@/config/app";
-import {updateUser} from "@/api/system/user";
-import {User} from "@/api/system/user/model";
-import {getStoredInviteParams, handleInviteRelation} from "@/utils/invite";
-import {addShopDealerUser} from "@/api/shop/shopDealerUser";
-import {listUserRole, updateUserRole} from "@/api/system/userRole";
-
-// 类型定义
-interface ChooseAvatarEvent {
- detail: {
- avatarUrl: string;
- };
-}
-
-interface InputEvent {
- detail: {
- value: string;
- };
-}
-
-const AddUserAddress = () => {
- const {user, loginUser} = useUser()
- const [loading, setLoading] = useState(true)
- const [FormData, setFormData] = useState()
- const formRef = useRef(null)
-
- const reload = async () => {
- const inviteParams = getStoredInviteParams()
- if (inviteParams?.inviter) {
- setFormData({
- ...user,
- refereeId: Number(inviteParams.inviter),
- // 清空昵称,强制用户手动输入
- nickname: '',
- })
- } else {
- // 如果没有邀请参数,也要确保昵称为空
- setFormData({
- ...user,
- nickname: '',
- })
- }
- }
-
-
- const uploadAvatar = ({detail}: ChooseAvatarEvent) => {
- // 先更新本地显示的头像(临时显示)
- const tempFormData = {
- ...FormData,
- avatar: `${detail.avatarUrl}`,
- }
- setFormData(tempFormData)
-
- Taro.uploadFile({
- url: 'https://server.websoft.top/api/oss/upload',
- filePath: detail.avatarUrl,
- name: 'file',
- header: {
- 'content-type': 'application/json',
- TenantId
- },
- success: async (res) => {
- const data = JSON.parse(res.data);
- if (data.code === 0) {
- const finalAvatarUrl = `${data.data.thumbnail}`
-
- try {
- // 使用 useUser hook 的 updateUser 方法更新头像
- await updateUser({
- avatar: finalAvatarUrl
- })
-
- Taro.showToast({
- title: '头像上传成功',
- icon: 'success',
- duration: 1500
- })
- } catch (error) {
- console.error('更新用户头像失败:', error)
- }
-
- // 无论用户信息更新是否成功,都要更新本地FormData
- const finalFormData = {
- ...tempFormData,
- avatar: finalAvatarUrl
- }
- setFormData(finalFormData)
-
- // 同步更新表单字段
- if (formRef.current) {
- formRef.current.setFieldsValue({
- avatar: finalAvatarUrl
- })
- }
- } else {
- // 上传失败,恢复原来的头像
- setFormData({
- ...FormData,
- avatar: user?.avatar || ''
- })
- Taro.showToast({
- title: '上传失败',
- icon: 'error'
- })
- }
- },
- fail: (error) => {
- console.error('上传头像失败:', error)
- Taro.showToast({
- title: '上传失败',
- icon: 'error'
- })
- // 恢复原来的头像
- setFormData({
- ...FormData,
- avatar: user?.avatar || ''
- })
- }
- })
- }
-
- // 提交表单
- const submitSucceed = async (values: any) => {
- try {
- // 验证必填字段
- if (!values.phone && !FormData?.phone) {
- Taro.showToast({
- title: '请先获取手机号',
- icon: 'error'
- });
- return;
- }
-
- // 验证昵称:必须填写且不能是默认的微信昵称
- const nickname = values.realName || FormData?.nickname || '';
- if (!nickname || nickname.trim() === '') {
- Taro.showToast({
- title: '请填写昵称',
- icon: 'error'
- });
- return;
- }
-
- // 检查是否为默认的微信昵称(常见的默认昵称)
- const defaultNicknames = ['微信用户', 'WeChat User', '微信昵称'];
- if (defaultNicknames.includes(nickname.trim())) {
- Taro.showToast({
- title: '请填写真实昵称,不能使用默认昵称',
- icon: 'error'
- });
- return;
- }
-
- // 验证昵称长度
- if (nickname.trim().length < 2) {
- Taro.showToast({
- title: '昵称至少需要2个字符',
- icon: 'error'
- });
- return;
- }
-
- if (!values.avatar && !FormData?.avatar) {
- Taro.showToast({
- title: '请上传头像',
- icon: 'error'
- });
- return;
- }
- console.log(values,FormData)
-
- const roles = await listUserRole({userId: user?.userId})
- console.log(roles, 'roles...')
-
- // 准备提交的数据
- await updateUser({
- userId: user?.userId,
- nickname: values.realName || FormData?.nickname,
- phone: values.phone || FormData?.phone,
- avatar: values.avatar || FormData?.avatar,
- refereeId: values.refereeId || FormData?.refereeId
- });
-
- await addShopDealerUser({
- userId: user?.userId,
- realName: values.realName || FormData?.nickname,
- mobile: values.phone || FormData?.phone,
- refereeId: values.refereeId || FormData?.refereeId
- })
-
- if (roles.length > 0) {
- await updateUserRole({
- ...roles[0],
- roleId: 1848
- })
- }
-
-
- Taro.showToast({
- title: `注册成功`,
- icon: 'success'
- });
-
- setTimeout(() => {
- Taro.navigateBack();
- }, 1000);
-
- } catch (error) {
- console.error('验证邀请人失败:', error);
- }
- }
-
- // 获取微信昵称
- const getWxNickname = (nickname: string) => {
- // 更新表单数据
- const updatedFormData = {
- ...FormData,
- nickname: nickname
- }
- setFormData(updatedFormData);
-
- // 同步更新表单字段
- if (formRef.current) {
- formRef.current.setFieldsValue({
- realName: nickname
- })
- }
- }
-
- /* 获取用户手机号 */
- const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
- const {code, encryptedData, iv} = detail
- Taro.login({
- success: (loginRes) => {
- if (code) {
- Taro.request({
- url: 'https://server.websoft.top/api/wx-login/loginByMpWxPhone',
- method: 'POST',
- data: {
- authCode: loginRes.code,
- code,
- encryptedData,
- iv,
- notVerifyPhone: true,
- refereeId: 0,
- sceneType: 'save_referee',
- tenantId: TenantId
- },
- header: {
- 'content-type': 'application/json',
- TenantId
- },
- success: async function (res) {
- if (res.data.code == 1) {
- Taro.showToast({
- title: res.data.message,
- icon: 'error',
- duration: 2000
- })
- return false;
- }
- // 登录成功
- const token = res.data.data.access_token;
- const userData = res.data.data.user;
- console.log(userData, 'userData...')
- // 使用useUser Hook的loginUser方法更新状态
- loginUser(token, userData);
-
- if (userData.phone) {
- console.log('手机号已获取', userData.phone)
- const updatedFormData = {
- ...FormData,
- phone: userData.phone,
- // 不自动填充微信昵称,保持用户已输入的昵称
- nickname: FormData?.nickname || '',
- // 只在没有头像时才使用微信头像
- avatar: FormData?.avatar || userData.avatar
- }
- setFormData(updatedFormData)
-
- // 更新表单字段值
- if (formRef.current) {
- formRef.current.setFieldsValue({
- phone: userData.phone,
- // 不覆盖用户已输入的昵称
- realName: FormData?.nickname || '',
- avatar: FormData?.avatar || userData.avatar
- })
- }
-
- Taro.showToast({
- title: '手机号获取成功',
- icon: 'success',
- duration: 1500
- })
- }
-
-
- // 处理邀请关系
- if (userData?.userId) {
- try {
- const inviteSuccess = await handleInviteRelation(userData.userId)
- if (inviteSuccess) {
- Taro.showToast({
- title: '邀请关系建立成功',
- icon: 'success',
- duration: 2000
- })
- }
- } catch (error) {
- console.error('处理邀请关系失败:', error)
- }
- }
-
- // 显示登录成功提示
- // Taro.showToast({
- // title: '注册成功',
- // icon: 'success',
- // duration: 1500
- // })
-
- // 不需要重新启动小程序,状态已经通过useUser更新
- // 可以选择性地刷新当前页面数据
- // await reload();
- }
- })
- } else {
- console.log('登录失败!')
- }
- }
- })
- }
-
- // 处理固定按钮点击事件
- const handleFixedButtonClick = () => {
- // 触发表单提交
- formRef.current?.submit();
- };
-
- const submitFailed = (error: any) => {
- console.log(error, 'err...')
- }
-
- useEffect(() => {
- reload().then(() => {
- setLoading(false)
- })
- }, [user?.userId]); // 依赖用户ID,当用户变化时重新加载
-
- // 当FormData变化时,同步更新表单字段值
- useEffect(() => {
- if (formRef.current && FormData) {
- formRef.current.setFieldsValue({
- refereeId: FormData.refereeId,
- phone: FormData.phone,
- avatar: FormData.avatar,
- realName: FormData.nickname
- });
- }
- }, [FormData]);
-
- if (loading) {
- return 加载中
- }
-
- return (
- <>
-
-
- {/* 底部浮动按钮 */}
- }
- text={'立即注册'}
- onClick={handleFixedButtonClick}
- />
-
- >
- );
-};
-
-export default AddUserAddress;
diff --git a/src/dealer/customer/index.config.ts b/src/dealer/customer/index.config.ts
deleted file mode 100644
index 6e26749..0000000
--- a/src/dealer/customer/index.config.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default definePageConfig({
- navigationBarTitleText: '客户列表'
-})
diff --git a/src/dealer/index.config.ts b/src/dealer/index.config.ts
deleted file mode 100644
index d456dbd..0000000
--- a/src/dealer/index.config.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default definePageConfig({
- navigationBarTitleText: '分销中心'
-})
diff --git a/src/dealer/index.scss b/src/dealer/index.scss
deleted file mode 100644
index e69de29..0000000
diff --git a/src/dealer/index.tsx b/src/dealer/index.tsx
deleted file mode 100644
index 06c514f..0000000
--- a/src/dealer/index.tsx
+++ /dev/null
@@ -1,295 +0,0 @@
-import React from 'react'
-import {View, Text} from '@tarojs/components'
-import {ConfigProvider, Button, Grid, Avatar} from '@nutui/nutui-react-taro'
-import {
- User,
- Shopping,
- Dongdong,
- ArrowRight,
- Purse,
- People
-} from '@nutui/icons-react-taro'
-import {useDealerUser} from '@/hooks/useDealerUser'
-import { useThemeStyles } from '@/hooks/useTheme'
-import {businessGradients, cardGradients, gradientUtils} from '@/styles/gradients'
-import Taro from '@tarojs/taro'
-
-const DealerIndex: React.FC = () => {
- const {
- dealerUser,
- error,
- refresh,
- } = useDealerUser()
-
- // 使用主题样式
- const themeStyles = useThemeStyles()
-
- // 导航到各个功能页面
- const navigateToPage = (url: string) => {
- Taro.navigateTo({url})
- }
-
- // 格式化金额
- const formatMoney = (money?: string) => {
- if (!money) return '0.00'
- return parseFloat(money).toFixed(2)
- }
-
- // 格式化时间
- const formatTime = (time?: string) => {
- if (!time) return '-'
- return new Date(time).toLocaleDateString()
- }
-
- // 获取用户主题
- const userTheme = gradientUtils.getThemeByUserId(dealerUser?.userId)
-
- // 获取渐变背景
- const getGradientBackground = (themeColor?: string) => {
- if (themeColor) {
- const darkerColor = gradientUtils.adjustColorBrightness(themeColor, -30)
- return gradientUtils.createGradient(themeColor, darkerColor)
- }
- return userTheme.background
- }
-
- console.log(getGradientBackground(),'getGradientBackground()')
-
- if (error) {
- return (
-
-
- {error}
-
-
-
- )
- }
-
- return (
-
-
- {/*头部信息*/}
- {dealerUser && (
-
- {/* 装饰性背景元素 - 小程序兼容版本 */}
-
-
-
-
- }
- className="mr-4"
- style={{
- border: '2px solid rgba(255, 255, 255, 0.3)'
- }}
- />
-
-
- {dealerUser?.realName || '分销商'}
-
-
- ID: {dealerUser.userId} | 推荐人: {dealerUser.refereeId || '无'}
-
-
-
- 加入时间
-
- {formatTime(dealerUser.createTime)}
-
-
-
-
- )}
-
- {/* 佣金统计卡片 */}
- {dealerUser && (
-
-
- 佣金统计
-
-
-
-
- {formatMoney(dealerUser.money)}
-
- 可提现
-
-
-
- {formatMoney(dealerUser.freezeMoney)}
-
- 冻结中
-
-
-
- {formatMoney(dealerUser.totalMoney)}
-
- 累计收益
-
-
-
- )}
-
- {/* 团队统计 */}
- {dealerUser && (
-
-
- 我的邀请
- navigateToPage('/dealer/team/index')}
- >
- 查看详情
-
-
-
-
-
-
- {dealerUser.firstNum || 0}
-
- 一级成员
-
-
-
- {dealerUser.secondNum || 0}
-
- 二级成员
-
-
-
- {dealerUser.thirdNum || 0}
-
- 三级成员
-
-
-
- )}
-
- {/* 功能导航 */}
-
- 分销工具
-
-
- navigateToPage('/dealer/orders/index')}>
-
-
-
-
-
-
-
- navigateToPage('/dealer/withdraw/index')}>
-
-
-
-
-
-
-
- navigateToPage('/dealer/team/index')}>
-
-
-
-
-
-
-
- navigateToPage('/dealer/qrcode/index')}>
-
-
-
-
-
-
-
-
- {/* 第二行功能 */}
- {/**/}
- {/* navigateToPage('/dealer/invite-stats/index')}>*/}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
-
- {/* /!* 预留其他功能位置 *!/*/}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
-
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
-
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/**/}
-
-
-
-
- {/* 底部安全区域 */}
-
-
- )
-}
-
-export default DealerIndex
diff --git a/src/dealer/info.tsx b/src/dealer/info.tsx
deleted file mode 100644
index 0f18841..0000000
--- a/src/dealer/info.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import React from 'react'
-import { View, Text } from '@tarojs/components'
-import { Button, Cell, CellGroup, Tag } from '@nutui/nutui-react-taro'
-import { useDealerUser } from '@/hooks/useDealerUser'
-import Taro from '@tarojs/taro'
-
-const DealerInfo: React.FC = () => {
- const {
- dealerUser,
- loading,
- error,
- refresh,
- } = useDealerUser()
-
- // 跳转到申请页面
- const navigateToApply = () => {
- Taro.navigateTo({
- url: '/pages/dealer/apply/add'
- })
- }
-
- if (error) {
- return (
-
-
- {error}
-
-
-
- )
- }
-
- return (
-
- {/* 页面标题 */}
-
-
- 经销商信息
-
-
-
- {!dealerUser ? (
- // 非经销商状态
-
-
- 您还不是经销商
-
- 成为经销商后可享受专属价格和佣金收益
-
-
-
-
- ) : (
- // 经销商信息展示
-
- {/* 状态卡片 */}
-
-
- 经销商状态
-
- {dealerUser.realName}
-
-
-
- {/* 基本信息 */}
-
- |
- |
- |
-
-
-
- {/* 操作按钮 */}
-
-
-
-
-
- {/* 经销商权益 */}
-
- 经销商权益
-
-
- • 享受经销商专属价格
-
-
- • 获得推广佣金收益
-
-
- • 优先获得新品信息
-
-
- • 专属客服支持
-
-
-
-
- {/* 佣金统计 */}
-
- 佣金统计
-
-
- 0
- 今日佣金
-
-
- 0
- 本月佣金
-
-
- 0
- 累计佣金
-
-
-
-
- )}
-
- {/* 刷新按钮 */}
-
-
- 点击刷新数据
-
-
-
- )
-}
-
-export default DealerInfo
diff --git a/src/dealer/invite-stats/index.config.ts b/src/dealer/invite-stats/index.config.ts
deleted file mode 100644
index 246a9aa..0000000
--- a/src/dealer/invite-stats/index.config.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export default definePageConfig({
- navigationBarTitleText: '邀请统计',
- navigationBarBackgroundColor: '#ffffff',
- navigationBarTextStyle: 'black',
- backgroundColor: '#f5f5f5',
- enablePullDownRefresh: true
-})
diff --git a/src/dealer/invite-stats/index.tsx b/src/dealer/invite-stats/index.tsx
deleted file mode 100644
index 3139ad4..0000000
--- a/src/dealer/invite-stats/index.tsx
+++ /dev/null
@@ -1,336 +0,0 @@
-import React, { useState, useEffect, useCallback } from 'react'
-import { View, Text } from '@tarojs/components'
-import {
- Empty,
- Tabs,
- Loading,
- PullToRefresh,
- Card,
-} from '@nutui/nutui-react-taro'
-import {
- User,
- ArrowUp,
- Calendar,
- Share,
- Target,
- Gift
-} from '@nutui/icons-react-taro'
-import Taro from '@tarojs/taro'
-import { useDealerUser } from '@/hooks/useDealerUser'
-import {
- getInviteStats,
- getMyInviteRecords,
- getInviteRanking
-} from '@/api/invite'
-import type {
- InviteStats,
- InviteRecord
-} from '@/api/invite'
-import { businessGradients } from '@/styles/gradients'
-import {InviteRanking} from "@/api/invite/model";
-
-const InviteStatsPage: React.FC = () => {
- const [activeTab, setActiveTab] = useState('stats')
- const [loading, setLoading] = useState(false)
- const [inviteStats, setInviteStats] = useState(null)
- const [inviteRecords, setInviteRecords] = useState([])
- const [ranking, setRanking] = useState([])
- const [dateRange, setDateRange] = useState('month')
- const { dealerUser } = useDealerUser()
-
- // 获取邀请统计数据
- const fetchInviteStats = useCallback(async () => {
- if (!dealerUser?.userId) return
-
- try {
- setLoading(true)
- const stats = await getInviteStats(dealerUser.userId)
- stats && setInviteStats(stats)
- } catch (error) {
- console.error('获取邀请统计失败:', error)
- Taro.showToast({
- title: '获取统计数据失败',
- icon: 'error'
- })
- } finally {
- setLoading(false)
- }
- }, [dealerUser?.userId])
-
- // 获取邀请记录
- const fetchInviteRecords = useCallback(async () => {
- if (!dealerUser?.userId) return
-
- try {
- const result = await getMyInviteRecords({
- page: 1,
- limit: 50,
- inviterId: dealerUser.userId
- })
- setInviteRecords(result?.list || [])
- } catch (error) {
- console.error('获取邀请记录失败:', error)
- }
- }, [dealerUser?.userId])
-
- // 获取邀请排行榜
- const fetchRanking = useCallback(async () => {
- try {
- const result = await getInviteRanking({
- limit: 20,
- period: dateRange as 'day' | 'week' | 'month'
- })
- setRanking(result || [])
- } catch (error) {
- console.error('获取排行榜失败:', error)
- }
- }, [dateRange])
-
- // 刷新数据
- const handleRefresh = async () => {
- await Promise.all([
- fetchInviteStats(),
- fetchInviteRecords(),
- fetchRanking()
- ])
- }
-
- // 初始化数据
- useEffect(() => {
- if (dealerUser?.userId) {
- fetchInviteStats().then()
- fetchInviteRecords().then()
- fetchRanking().then()
- }
- }, [fetchInviteStats, fetchInviteRecords, fetchRanking])
-
- // 获取状态显示文本
- const getStatusText = (status: string) => {
- const statusMap: Record = {
- 'pending': '待注册',
- 'registered': '已注册',
- 'activated': '已激活'
- }
- return statusMap[status] || status
- }
-
- // 获取状态颜色
- const getStatusColor = (status: string) => {
- const colorMap: Record = {
- 'pending': 'text-orange-500',
- 'registered': 'text-blue-500',
- 'activated': 'text-green-500'
- }
- return colorMap[status] || 'text-gray-500'
- }
-
- // 渲染统计概览
- const renderStatsOverview = () => (
-
- {/* 核心数据卡片 */}
-
-
- 邀请概览
- {loading ? (
-
-
-
- ) : inviteStats ? (
-
-
-
-
- {inviteStats.totalInvites || 0}
-
- 总邀请数
-
-
-
-
-
- {inviteStats.successfulRegistrations || 0}
-
- 成功注册
-
-
-
-
-
- {inviteStats.conversionRate ? `${(inviteStats.conversionRate * 100).toFixed(1)}%` : '0%'}
-
- 转化率
-
-
-
-
-
- {inviteStats.todayInvites || 0}
-
- 今日邀请
-
-
- ) : (
-
- 暂无统计数据
-
- )}
-
-
-
- {/* 邀请来源分析 */}
- {inviteStats?.sourceStats && inviteStats.sourceStats.length > 0 && (
-
-
- 邀请来源分析
-
- {inviteStats.sourceStats.map((source, index) => (
-
-
-
- {source.source}
-
-
- {source.count}
-
- 转化率 {source.conversionRate ? `${(source.conversionRate * 100).toFixed(1)}%` : '0%'}
-
-
-
- ))}
-
-
-
- )}
-
- )
-
- // 渲染邀请记录
- const renderInviteRecords = () => (
-
- {inviteRecords.length > 0 ? (
-
- {inviteRecords.map((record, index) => (
-
-
-
-
- {record.inviteeName || `用户${record.inviteeId}`}
-
-
- {getStatusText(record.status || 'pending')}
-
-
-
-
- 来源: {record.source || '未知'}
- {record.inviteTime ? new Date(record.inviteTime).toLocaleDateString() : ''}
-
-
- {record.registerTime && (
-
- 注册时间: {new Date(record.registerTime).toLocaleString()}
-
- )}
-
-
- ))}
-
- ) : (
-
- )}
-
- )
-
- // 渲染排行榜
- const renderRanking = () => (
-
-
- setDateRange}>
-
-
-
-
-
-
- {ranking.length > 0 ? (
-
- {ranking.map((item, index) => (
-
-
-
- {index < 3 ? (
-
- ) : (
- {index + 1}
- )}
-
-
-
- {item.inviterName}
-
- 邀请 {item.inviteCount} 人 · 转化率 {item.conversionRate ? `${(item.conversionRate * 100).toFixed(1)}%` : '0%'}
-
-
-
- {item.successCount}
-
-
- ))}
-
- ) : (
-
- )}
-
- )
-
- if (!dealerUser) {
- return (
-
-
- 加载中...
-
- )
- }
-
- return (
-
- {/* 头部 */}
-
-
-
-
- 邀请统计
-
- 查看您的邀请效果和推广数据
-
-
-
-
- {/* 标签页 */}
-
- setActiveTab}>
-
-
-
-
-
-
- {/* 内容区域 */}
-
-
- {activeTab === 'stats' && renderStatsOverview()}
- {activeTab === 'records' && renderInviteRecords()}
- {activeTab === 'ranking' && renderRanking()}
-
-
-
- )
-}
-
-export default InviteStatsPage
diff --git a/src/dealer/orders/index.config.ts b/src/dealer/orders/index.config.ts
deleted file mode 100644
index 3bb5694..0000000
--- a/src/dealer/orders/index.config.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default definePageConfig({
- navigationBarTitleText: '分销订单'
-})
diff --git a/src/dealer/orders/index.tsx b/src/dealer/orders/index.tsx
deleted file mode 100644
index f3b6bbf..0000000
--- a/src/dealer/orders/index.tsx
+++ /dev/null
@@ -1,192 +0,0 @@
-import React, {useState, useEffect, useCallback} from 'react'
-import {View, Text, ScrollView} from '@tarojs/components'
-import {Empty, Tag, PullToRefresh, Loading} from '@nutui/nutui-react-taro'
-import Taro from '@tarojs/taro'
-import {pageShopDealerOrder} from '@/api/shop/shopDealerOrder'
-import {useDealerUser} from '@/hooks/useDealerUser'
-import type {ShopDealerOrder} from '@/api/shop/shopDealerOrder/model'
-
-interface OrderWithDetails extends ShopDealerOrder {
- orderNo?: string
- customerName?: string
- userCommission?: string
-}
-
-const DealerOrders: React.FC = () => {
- const [loading, setLoading] = useState(false)
- const [refreshing, setRefreshing] = useState(false)
- const [loadingMore, setLoadingMore] = useState(false)
- const [orders, setOrders] = useState([])
- const [currentPage, setCurrentPage] = useState(1)
- const [hasMore, setHasMore] = useState(true)
-
- const {dealerUser} = useDealerUser()
-
- // 获取订单数据
- const fetchOrders = useCallback(async (page: number = 1, isRefresh: boolean = false) => {
- if (!dealerUser?.userId) return
-
- try {
- if (isRefresh) {
- setRefreshing(true)
- } else if (page === 1) {
- setLoading(true)
- } else {
- setLoadingMore(true)
- }
-
- const result = await pageShopDealerOrder({
- page,
- limit: 10
- })
-
- if (result?.list) {
- const newOrders = result.list.map(order => ({
- ...order,
- orderNo: `${order.orderId}`,
- customerName: `用户${order.userId}`,
- userCommission: order.firstMoney || '0.00'
- }))
-
- if (page === 1) {
- setOrders(newOrders)
- } else {
- setOrders(prev => [...prev, ...newOrders])
- }
-
- setHasMore(newOrders.length === 10)
- setCurrentPage(page)
- }
-
- } catch (error) {
- console.error('获取分销订单失败:', error)
- Taro.showToast({
- title: '获取订单失败',
- icon: 'error'
- })
- } finally {
- setLoading(false)
- setRefreshing(false)
- setLoadingMore(false)
- }
- }, [dealerUser?.userId])
-
- // 下拉刷新
- const handleRefresh = async () => {
- await fetchOrders(1, true)
- }
-
- // 加载更多
- const handleLoadMore = async () => {
- if (!loadingMore && hasMore) {
- await fetchOrders(currentPage + 1)
- }
- }
-
- // 初始化加载数据
- useEffect(() => {
- if (dealerUser?.userId) {
- fetchOrders(1)
- }
- }, [fetchOrders])
-
- const getStatusText = (isSettled?: number, isInvalid?: number) => {
- if (isInvalid === 1) return '已失效'
- if (isSettled === 1) return '已结算'
- return '待结算'
- }
-
- const getStatusColor = (isSettled?: number, isInvalid?: number) => {
- if (isInvalid === 1) return 'danger'
- if (isSettled === 1) return 'success'
- return 'warning'
- }
-
- const renderOrderItem = (order: OrderWithDetails) => (
-
-
-
- 订单号:{order.orderNo}
-
-
- {getStatusText(order.isSettled, order.isInvalid)}
-
-
-
-
-
- 订单金额:¥{order.orderPrice || '0.00'}
-
-
- 我的佣金:¥{order.userCommission}
-
-
-
-
-
- 客户:{order.customerName}
-
-
- {order.createTime}
-
-
-
- )
-
- if (!dealerUser) {
- return (
-
-
- 加载中...
-
- )
- }
-
- return (
-
-
-
-
- {loading && orders.length === 0 ? (
-
-
- 加载中...
-
- ) : orders.length > 0 ? (
- <>
- {orders.map(renderOrderItem)}
- {loadingMore && (
-
-
- 加载更多...
-
- )}
- {!hasMore && orders.length > 0 && (
-
- 没有更多数据了
-
- )}
- >
- ) : (
-
- )}
-
-
-
-
- )
-}
-
-export default DealerOrders
diff --git a/src/dealer/qrcode/index.config.ts b/src/dealer/qrcode/index.config.ts
deleted file mode 100644
index b075b21..0000000
--- a/src/dealer/qrcode/index.config.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default definePageConfig({
- navigationBarTitleText: '推广二维码'
-})
diff --git a/src/dealer/qrcode/index.tsx b/src/dealer/qrcode/index.tsx
deleted file mode 100644
index 90edb58..0000000
--- a/src/dealer/qrcode/index.tsx
+++ /dev/null
@@ -1,398 +0,0 @@
-import React, {useState, useEffect} from 'react'
-import {View, Text, Image} from '@tarojs/components'
-import {Button, Loading} from '@nutui/nutui-react-taro'
-import {Download, QrCode} from '@nutui/icons-react-taro'
-import Taro from '@tarojs/taro'
-import {useDealerUser} from '@/hooks/useDealerUser'
-import {generateInviteCode} from '@/api/invite'
-// import type {InviteStats} from '@/api/invite'
-import {businessGradients} from '@/styles/gradients'
-
-const DealerQrcode: React.FC = () => {
- const [miniProgramCodeUrl, setMiniProgramCodeUrl] = useState('')
- const [loading, setLoading] = useState(false)
- // const [inviteStats, setInviteStats] = useState(null)
- // const [statsLoading, setStatsLoading] = useState(false)
- const {dealerUser} = useDealerUser()
-
- // 生成小程序码
- const generateMiniProgramCode = async () => {
- if (!dealerUser?.userId) {
- return
- }
-
- try {
- setLoading(true)
-
- // 生成邀请小程序码
- const codeUrl = await generateInviteCode(dealerUser.userId)
-
- if (codeUrl) {
- setMiniProgramCodeUrl(codeUrl)
- } else {
- throw new Error('返回的小程序码URL为空')
- }
- } catch (error: any) {
- Taro.showToast({
- title: error.message || '生成小程序码失败',
- icon: 'error'
- })
- // 清空之前的二维码
- setMiniProgramCodeUrl('')
- } finally {
- setLoading(false)
- }
- }
-
- // 获取邀请统计数据
- // const fetchInviteStats = async () => {
- // if (!dealerUser?.userId) return
- //
- // try {
- // setStatsLoading(true)
- // const stats = await getInviteStats(dealerUser.userId)
- // stats && setInviteStats(stats)
- // } catch (error) {
- // // 静默处理错误,不影响用户体验
- // } finally {
- // setStatsLoading(false)
- // }
- // }
-
- // 初始化生成小程序码和获取统计数据
- useEffect(() => {
- if (dealerUser?.userId) {
- generateMiniProgramCode()
- // fetchInviteStats()
- }
- }, [dealerUser?.userId])
-
- // 保存小程序码到相册
- const saveMiniProgramCode = async () => {
- if (!miniProgramCodeUrl) {
- Taro.showToast({
- title: '小程序码未生成',
- icon: 'error'
- })
- return
- }
-
- try {
- // 先下载图片到本地
- const res = await Taro.downloadFile({
- url: miniProgramCodeUrl
- })
-
- if (res.statusCode === 200) {
- // 保存到相册
- await Taro.saveImageToPhotosAlbum({
- filePath: res.tempFilePath
- })
-
- Taro.showToast({
- title: '保存成功',
- icon: 'success'
- })
- }
- } catch (error: any) {
- if (error.errMsg?.includes('auth deny')) {
- Taro.showModal({
- title: '提示',
- content: '需要您授权保存图片到相册',
- success: (res) => {
- if (res.confirm) {
- Taro.openSetting()
- }
- }
- })
- } else {
- Taro.showToast({
- title: '保存失败',
- icon: 'error'
- })
- }
- }
- }
-
- // 复制邀请信息
-// const copyInviteInfo = () => {
-// if (!dealerUser?.userId) {
-// Taro.showToast({
-// title: '用户信息未加载',
-// icon: 'error'
-// })
-// return
-// }
-//
-// const inviteText = `🎉 邀请您加入我的团队!
-//
-// 扫描小程序码或搜索"时里院子市集"小程序,即可享受优质商品和服务!
-//
-// 💰 成为我的团队成员,一起赚取丰厚佣金
-// 🎁 新用户专享优惠等你来拿
-//
-// 邀请码:${dealerUser.userId}
-// 快来加入我们吧!`
-//
-// Taro.setClipboardData({
-// data: inviteText,
-// success: () => {
-// Taro.showToast({
-// title: '邀请信息已复制',
-// icon: 'success'
-// })
-// }
-// })
-// }
-
- // 分享小程序码
- // const shareMiniProgramCode = () => {
- // if (!dealerUser?.userId) {
- // Taro.showToast({
- // title: '用户信息未加载',
- // icon: 'error'
- // })
- // return
- // }
- //
- // // 小程序分享
- // Taro.showShareMenu({
- // withShareTicket: true,
- // showShareItems: ['shareAppMessage']
- // })
- // }
-
- if (!dealerUser) {
- return (
-
-
- 加载中...
-
- )
- }
-
- return (
-
- {/* 头部卡片 */}
-
- {/* 装饰背景 */}
-
-
-
- 我的邀请小程序码
-
- 分享小程序码邀请好友,获得丰厚佣金奖励
-
-
-
-
-
- {/* 小程序码展示区 */}
-
-
- {loading ? (
-
-
- 生成中...
-
- ) : miniProgramCodeUrl ? (
-
- {
- Taro.showModal({
- title: '二维码加载失败',
- content: '请检查网络连接或联系管理员',
- showCancel: true,
- confirmText: '重新生成',
- success: (res) => {
- if (res.confirm) {
- generateMiniProgramCode();
- }
- }
- });
- }}
-
- />
-
- ) : (
-
-
- 小程序码生成失败
-
-
- )}
-
-
- 扫码加入我的团队
-
-
- 好友扫描小程序码即可直接进入小程序并建立邀请关系
-
-
-
-
-
-
- {/* 操作按钮 */}
-
-
-
-
- {/**/}
- {/* */}
- {/**/}
- {/**/}
- {/* */}
- {/**/}
-
-
- {/* 推广说明 */}
-
- 推广说明
-
-
-
-
- 好友通过您的二维码或链接注册成为您的团队成员
-
-
-
-
-
- 好友购买商品时,您可获得相应层级的分销佣金
-
-
-
-
-
- 支持三级分销,团队越大收益越多
-
-
-
-
-
- {/* 邀请统计数据 */}
- {/**/}
- {/* 我的邀请数据*/}
- {/* {statsLoading ? (*/}
- {/* */}
- {/* */}
- {/* 加载中...*/}
- {/* */}
- {/* ) : inviteStats ? (*/}
- {/* */}
- {/* */}
- {/* */}
- {/* */}
- {/* {inviteStats.totalInvites || 0}*/}
- {/* */}
- {/* 总邀请数*/}
- {/* */}
- {/* */}
- {/* */}
- {/* {inviteStats.successfulRegistrations || 0}*/}
- {/* */}
- {/* 成功注册*/}
- {/* */}
- {/* */}
-
- {/* */}
- {/* */}
- {/* */}
- {/* {inviteStats.conversionRate ? `${(inviteStats.conversionRate * 100).toFixed(1)}%` : '0%'}*/}
- {/* */}
- {/* 转化率*/}
- {/* */}
- {/* */}
- {/* */}
- {/* {inviteStats.todayInvites || 0}*/}
- {/* */}
- {/* 今日邀请*/}
- {/* */}
- {/* */}
-
- {/* /!* 邀请来源统计 *!/*/}
- {/* {inviteStats.sourceStats && inviteStats.sourceStats.length > 0 && (*/}
- {/* */}
- {/* 邀请来源分布*/}
- {/* */}
- {/* {inviteStats.sourceStats.map((source, index) => (*/}
- {/* */}
- {/* */}
- {/* */}
- {/* {source.source}*/}
- {/* */}
- {/* */}
- {/* {source.count}*/}
- {/* */}
- {/* {source.conversionRate ? `${(source.conversionRate * 100).toFixed(1)}%` : '0%'}*/}
- {/* */}
- {/* */}
- {/* */}
- {/* ))}*/}
- {/* */}
- {/* */}
- {/* )}*/}
- {/* */}
- {/* ) : (*/}
- {/* */}
- {/* 暂无邀请数据*/}
- {/* */}
- {/* */}
- {/* )}*/}
- {/**/}
-
-
- )
-}
-
-export default DealerQrcode
diff --git a/src/dealer/team/index.config.ts b/src/dealer/team/index.config.ts
deleted file mode 100644
index ddd6b66..0000000
--- a/src/dealer/team/index.config.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default definePageConfig({
- navigationBarTitleText: '邀请推广'
-})
diff --git a/src/dealer/team/index.tsx b/src/dealer/team/index.tsx
deleted file mode 100644
index af7d8e7..0000000
--- a/src/dealer/team/index.tsx
+++ /dev/null
@@ -1,439 +0,0 @@
-import React, {useState, useEffect, useCallback} from 'react'
-import {View, Text} from '@tarojs/components'
-import {Phone, Edit, Message} from '@nutui/icons-react-taro'
-import {Space, Empty, Avatar, Button} from '@nutui/nutui-react-taro'
-import Taro from '@tarojs/taro'
-import {useDealerUser} from '@/hooks/useDealerUser'
-import {listShopDealerReferee} from '@/api/shop/shopDealerReferee'
-import {pageShopDealerOrder} from '@/api/shop/shopDealerOrder'
-import type {ShopDealerReferee} from '@/api/shop/shopDealerReferee/model'
-import FixedButton from "@/components/FixedButton";
-import navTo from "@/utils/common";
-import {updateUser} from "@/api/system/user";
-
-interface TeamMemberWithStats extends ShopDealerReferee {
- name?: string
- avatar?: string
- nickname?: string;
- alias?: string;
- phone?: string;
- orderCount?: number
- commission?: string
- status?: 'active' | 'inactive'
- subMembers?: number
- joinTime?: string
- dealerAvatar?: string;
- dealerName?: string;
- dealerPhone?: string;
-}
-
-// 层级信息接口
-interface LevelInfo {
- dealerId: number
- dealerName?: string
- level: number
-}
-
-const DealerTeam: React.FC = () => {
- const [teamMembers, setTeamMembers] = useState([])
- const {dealerUser} = useDealerUser()
- const [dealerId, setDealerId] = useState()
- // 层级栈,用于支持返回上一层
- const [levelStack, setLevelStack] = useState([])
- const [loading, setLoading] = useState(false)
- // 当前查看的用户名称
- const [currentDealerName, setCurrentDealerName] = useState('')
-
- // 异步加载成员统计数据
- const loadMemberStats = async (members: TeamMemberWithStats[]) => {
- // 分批处理,避免过多并发请求
- const batchSize = 3
- for (let i = 0; i < members.length; i += batchSize) {
- const batch = members.slice(i, i + batchSize)
-
- const batchStats = await Promise.all(
- batch.map(async (member) => {
- try {
- // 并行获取订单统计和下级成员数量
- const [orderResult, subMembersResult] = await Promise.all([
- pageShopDealerOrder({
- page: 1,
- userId: member.userId
- }),
- listShopDealerReferee({
- dealerId: member.userId,
- deleted: 0
- })
- ])
-
- let orderCount = 0
- let commission = '0.00'
- let status: 'active' | 'inactive' = 'inactive'
-
- if (orderResult?.list) {
- const orders = orderResult.list
- orderCount = orders.length
- commission = orders.reduce((sum, order) => {
- const levelCommission = member.level === 1 ? order.firstMoney :
- member.level === 2 ? order.secondMoney :
- order.thirdMoney
- return sum + parseFloat(levelCommission || '0')
- }, 0).toFixed(2)
-
- // 判断活跃状态(30天内有订单为活跃)
- const thirtyDaysAgo = new Date()
- thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)
- const hasRecentOrder = orders.some(order =>
- new Date(order.createTime || '') > thirtyDaysAgo
- )
- status = hasRecentOrder ? 'active' : 'inactive'
- }
-
- return {
- ...member,
- orderCount,
- commission,
- status,
- subMembers: subMembersResult?.length || 0
- }
- } catch (error) {
- console.error(`获取成员${member.userId}数据失败:`, error)
- return {
- ...member,
- orderCount: 0,
- commission: '0.00',
- status: 'inactive' as const,
- subMembers: 0
- }
- }
- })
- )
-
- // 更新这一批成员的数据
- setTeamMembers(prevMembers => {
- const updatedMembers = [...prevMembers]
- batchStats.forEach(updatedMember => {
- const index = updatedMembers.findIndex(m => m.userId === updatedMember.userId)
- if (index !== -1) {
- updatedMembers[index] = updatedMember
- }
- })
- return updatedMembers
- })
-
- // 添加小延迟,避免请求过于密集
- if (i + batchSize < members.length) {
- await new Promise(resolve => setTimeout(resolve, 100))
- }
- }
- }
-
- // 获取团队数据
- const fetchTeamData = useCallback(async () => {
- if (!dealerUser?.userId && !dealerId) return
-
- try {
- setLoading(true)
- console.log(dealerId, 'dealerId>>>>>>>>>')
- // 获取团队成员关系
- const refereeResult = await listShopDealerReferee({
- dealerId: dealerId ? dealerId : dealerUser?.userId
- })
-
- if (refereeResult) {
- console.log('团队成员原始数据:', refereeResult)
- // 处理团队成员数据
- const processedMembers: TeamMemberWithStats[] = refereeResult.map(member => ({
- ...member,
- name: `${member.userId}`,
- orderCount: 0,
- commission: '0.00',
- status: 'active' as const,
- subMembers: 0,
- joinTime: member.createTime
- }))
-
- // 先显示基础数据,然后异步加载详细统计
- setTeamMembers(processedMembers)
- setLoading(false)
-
- // 异步加载每个成员的详细统计数据
- loadMemberStats(processedMembers)
-
- }
- } catch (error) {
- console.error('获取团队数据失败:', error)
- Taro.showToast({
- title: '获取团队数据失败',
- icon: 'error'
- })
- } finally {
- setLoading(false)
- }
- }, [dealerUser?.userId, dealerId])
-
- // 查看下级成员
- const getNextUser = (item: TeamMemberWithStats) => {
- // 检查层级限制:最多只能查看2层(levelStack.length >= 1 表示已经是第2层了)
- if (levelStack.length >= 1) {
- return
- }
-
- // 如果没有下级成员,不允许点击
- if (!item.subMembers || item.subMembers === 0) {
- return
- }
-
- console.log('点击用户:', item.userId, item.name)
-
- // 将当前层级信息推入栈中
- const currentLevel: LevelInfo = {
- dealerId: dealerId || dealerUser?.userId || 0,
- dealerName: currentDealerName || (dealerId ? '上级' : dealerUser?.realName || '我'),
- level: levelStack.length
- }
- setLevelStack(prev => [...prev, currentLevel])
-
- // 切换到下级
- setDealerId(item.userId)
- setCurrentDealerName(item.nickname || item.dealerName || `用户${item.userId}`)
- }
-
- // 返回上一层
- const goBack = () => {
- if (levelStack.length === 0) {
- // 如果栈为空,返回首页或上一页
- Taro.navigateBack()
- return
- }
-
- // 从栈中弹出上一层信息
- const prevLevel = levelStack[levelStack.length - 1]
- setLevelStack(prev => prev.slice(0, -1))
-
- if (prevLevel.dealerId === (dealerUser?.userId || 0)) {
- // 返回到根层级
- setDealerId(undefined)
- setCurrentDealerName('')
- } else {
- setDealerId(prevLevel.dealerId)
- setCurrentDealerName(prevLevel.dealerName || '')
- }
- }
-
- // 一键拨打
- const makePhoneCall = (phone: string) => {
- Taro.makePhoneCall({
- phoneNumber: phone,
- fail: () => {
- Taro.showToast({
- title: '拨打取消',
- icon: 'error'
- });
- }
- });
- };
-
- // 别名备注
- const editAlias = (item: any, index: number) => {
- Taro.showModal({
- title: '备注',
- // @ts-ignore
- editable: true,
- placeholderText: '真实姓名',
- content: item.alias || '',
- success: async (res: any) => {
- if (res.confirm && res.content !== undefined) {
- try {
- // 更新跟进情况
- await updateUser({
- userId: item.userId,
- alias: res.content.trim()
- });
- teamMembers[index].alias = res.content.trim()
- setTeamMembers(teamMembers)
- } catch (error) {
- console.error('备注失败:', error);
- Taro.showToast({
- title: '备注失败,请重试',
- icon: 'error'
- });
- }
- }
- }
- });
- };
-
- // 发送消息
- const sendMessage = (item: TeamMemberWithStats) => {
- return navTo(`/user/chat/message/add?id=${item.userId}`, true)
- }
-
- // 监听数据变化,获取团队数据
- useEffect(() => {
- if (dealerUser?.userId || dealerId) {
- fetchTeamData().then()
- }
- }, [fetchTeamData])
-
- // 初始化当前用户名称
- useEffect(() => {
- if (!dealerId && dealerUser?.realName && !currentDealerName) {
- setCurrentDealerName(dealerUser.realName)
- }
- }, [dealerUser, dealerId, currentDealerName])
-
- const renderMemberItem = (member: TeamMemberWithStats, index: number) => {
- // 判断是否可以点击:有下级成员且未达到层级限制
- const canClick = member.subMembers && member.subMembers > 0 && levelStack.length < 1
- // 判断是否显示手机号:只有本级(levelStack.length === 0)才显示
- const showPhone = levelStack.length === 0
- // 判断数据是否还在加载中(初始值都是0或'0.00')
- const isStatsLoading = member.orderCount === 0 && member.commission === '0.00' && member.subMembers === 0
-
- return (
- getNextUser(member)}
- >
-
-
-
-
-
-
- {member.alias ? {member.alias} :
- {member.nickname}}
- {/*别名备注*/}
- {
- e.stopPropagation()
- editAlias(member, index)
- }}/>
- {/*发送消息*/}
- {
- e.stopPropagation()
- sendMessage(member)
- }}/>
-
-
- {/* 显示手机号(仅本级可见) */}
- {showPhone && member.phone && (
- {
- e.stopPropagation();
- makePhoneCall(member.phone || '');
- }}>
- {member.phone}
-
-
- )}
-
-
- 加入时间:{member.joinTime}
-
-
-
-
-
-
- 订单数
-
- {isStatsLoading ? '-' : member.orderCount}
-
-
-
- 贡献佣金
-
- {isStatsLoading ? '-' : `¥${member.commission}`}
-
-
-
- 团队成员
-
- {isStatsLoading ? '-' : (member.subMembers || 0)}
-
-
-
-
- )
- }
-
- const renderOverview = () => (
-
-
- 我的团队成员
- 成员数:{teamMembers.length}
-
- {teamMembers.map(renderMemberItem)}
-
- )
-
- // 渲染顶部导航栏
- const renderHeader = () => {
- if (levelStack.length === 0) return null
-
- return (
-
-
-
-
- {currentDealerName}的团队成员
-
-
-
-
-
- )
- }
-
- if (!dealerUser) {
- return (
-
- navTo(`/dealer/apply/add`, true)}]}
- />
-
- )
- }
-
- return (
- <>
- {renderHeader()}
-
- {loading ? (
-
- 加载中...
-
- ) : teamMembers.length > 0 ? (
- renderOverview()
- ) : (
-
-
-
- )}
-
- navTo(`/dealer/qrcode/index`, true)}/>
- >
- )
-}
-
-export default DealerTeam;
diff --git a/src/dealer/withdraw/__tests__/withdraw.test.tsx b/src/dealer/withdraw/__tests__/withdraw.test.tsx
deleted file mode 100644
index c3aeab9..0000000
--- a/src/dealer/withdraw/__tests__/withdraw.test.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-import React from 'react'
-import { render, fireEvent, waitFor } from '@testing-library/react'
-import DealerWithdraw from '../index'
-import { useDealerUser } from '@/hooks/useDealerUser'
-import * as withdrawAPI from '@/api/shop/shopDealerWithdraw'
-
-// Mock dependencies
-jest.mock('@/hooks/useDealerUser')
-jest.mock('@/api/shop/shopDealerWithdraw')
-jest.mock('@tarojs/taro', () => ({
- showToast: jest.fn(),
- getStorageSync: jest.fn(() => 123),
-}))
-
-const mockUseDealerUser = useDealerUser as jest.MockedFunction
-const mockAddShopDealerWithdraw = withdrawAPI.addShopDealerWithdraw as jest.MockedFunction
-const mockPageShopDealerWithdraw = withdrawAPI.pageShopDealerWithdraw as jest.MockedFunction
-
-describe('DealerWithdraw', () => {
- const mockDealerUser = {
- userId: 123,
- money: '10000.00',
- realName: '测试用户',
- mobile: '13800138000'
- }
-
- beforeEach(() => {
- mockUseDealerUser.mockReturnValue({
- dealerUser: mockDealerUser,
- loading: false,
- error: null,
- refresh: jest.fn()
- })
-
- mockPageShopDealerWithdraw.mockResolvedValue({
- list: [],
- count: 0
- })
- })
-
- afterEach(() => {
- jest.clearAllMocks()
- })
-
- test('应该正确显示可提现余额', () => {
- const { getByText } = render()
- expect(getByText('10000.00')).toBeInTheDocument()
- expect(getByText('可提现余额')).toBeInTheDocument()
- })
-
- test('应该验证最低提现金额', async () => {
- mockAddShopDealerWithdraw.mockResolvedValue('success')
-
- const { getByPlaceholderText, getByText } = render()
-
- // 输入低于最低金额的数值
- const amountInput = getByPlaceholderText('请输入提现金额')
- fireEvent.change(amountInput, { target: { value: '50' } })
-
- // 选择提现方式
- const wechatRadio = getByText('微信钱包')
- fireEvent.click(wechatRadio)
-
- // 提交表单
- const submitButton = getByText('申请提现')
- fireEvent.click(submitButton)
-
- await waitFor(() => {
- expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
- title: '最低提现金额为100元',
- icon: 'error'
- })
- })
- })
-
- test('应该验证提现金额不超过可用余额', async () => {
- const { getByPlaceholderText, getByText } = render()
-
- // 输入超过可用余额的金额
- const amountInput = getByPlaceholderText('请输入提现金额')
- fireEvent.change(amountInput, { target: { value: '20000' } })
-
- // 选择提现方式
- const wechatRadio = getByText('微信钱包')
- fireEvent.click(wechatRadio)
-
- // 提交表单
- const submitButton = getByText('申请提现')
- fireEvent.click(submitButton)
-
- await waitFor(() => {
- expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
- title: '提现金额超过可用余额',
- icon: 'error'
- })
- })
- })
-
- test('应该验证支付宝账户信息完整性', async () => {
- const { getByPlaceholderText, getByText } = render()
-
- // 输入有效金额
- const amountInput = getByPlaceholderText('请输入提现金额')
- fireEvent.change(amountInput, { target: { value: '1000' } })
-
- // 选择支付宝提现
- const alipayRadio = getByText('支付宝')
- fireEvent.click(alipayRadio)
-
- // 只填写账号,不填写姓名
- const accountInput = getByPlaceholderText('请输入支付宝账号')
- fireEvent.change(accountInput, { target: { value: 'test@alipay.com' } })
-
- // 提交表单
- const submitButton = getByText('申请提现')
- fireEvent.click(submitButton)
-
- await waitFor(() => {
- expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
- title: '请填写完整的支付宝信息',
- icon: 'error'
- })
- })
- })
-
- test('应该成功提交微信提现申请', async () => {
- mockAddShopDealerWithdraw.mockResolvedValue('success')
-
- const { getByPlaceholderText, getByText } = render()
-
- // 输入有效金额
- const amountInput = getByPlaceholderText('请输入提现金额')
- fireEvent.change(amountInput, { target: { value: '1000' } })
-
- // 选择微信提现
- const wechatRadio = getByText('微信钱包')
- fireEvent.click(wechatRadio)
-
- // 提交表单
- const submitButton = getByText('申请提现')
- fireEvent.click(submitButton)
-
- await waitFor(() => {
- expect(mockAddShopDealerWithdraw).toHaveBeenCalledWith({
- userId: 123,
- money: '1000',
- payType: 10,
- applyStatus: 10,
- platform: 'MiniProgram'
- })
- })
-
- await waitFor(() => {
- expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
- title: '提现申请已提交',
- icon: 'success'
- })
- })
- })
-
- test('快捷金额按钮应该正常工作', () => {
- const { getByText, getByPlaceholderText } = render()
-
- // 点击快捷金额按钮
- const quickAmountButton = getByText('500')
- fireEvent.click(quickAmountButton)
-
- // 验证金额输入框的值
- const amountInput = getByPlaceholderText('请输入提现金额') as HTMLInputElement
- expect(amountInput.value).toBe('500')
- })
-
- test('全部按钮应该设置为可用余额', () => {
- const { getByText, getByPlaceholderText } = render()
-
- // 点击全部按钮
- const allButton = getByText('全部')
- fireEvent.click(allButton)
-
- // 验证金额输入框的值
- const amountInput = getByPlaceholderText('请输入提现金额') as HTMLInputElement
- expect(amountInput.value).toBe('10000.00')
- })
-})
diff --git a/src/dealer/withdraw/index.config.ts b/src/dealer/withdraw/index.config.ts
deleted file mode 100644
index 00a9f9b..0000000
--- a/src/dealer/withdraw/index.config.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default definePageConfig({
- navigationBarTitleText: '提现申请'
-})
diff --git a/src/dealer/withdraw/index.tsx b/src/dealer/withdraw/index.tsx
deleted file mode 100644
index 04a3cef..0000000
--- a/src/dealer/withdraw/index.tsx
+++ /dev/null
@@ -1,499 +0,0 @@
-import React, {useState, useRef, useEffect, useCallback} from 'react'
-import {View, Text} from '@tarojs/components'
-import {
- Cell,
- Space,
- Button,
- Form,
- Input,
- CellGroup,
- Radio,
- Tabs,
- Tag,
- Empty,
- Loading,
- PullToRefresh
-} from '@nutui/nutui-react-taro'
-import {Wallet} from '@nutui/icons-react-taro'
-import {businessGradients} from '@/styles/gradients'
-import Taro from '@tarojs/taro'
-import {useDealerUser} from '@/hooks/useDealerUser'
-import {pageShopDealerWithdraw, addShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw'
-import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model'
-
-interface WithdrawRecordWithDetails extends ShopDealerWithdraw {
- accountDisplay?: string
-}
-
-const DealerWithdraw: React.FC = () => {
- const [activeTab, setActiveTab] = useState('0')
- const [selectedAccount, setSelectedAccount] = useState('')
- const [loading, setLoading] = useState(false)
- const [refreshing, setRefreshing] = useState(false)
- const [submitting, setSubmitting] = useState(false)
- const [availableAmount, setAvailableAmount] = useState('0.00')
- const [withdrawRecords, setWithdrawRecords] = useState([])
- const formRef = useRef(null)
-
- const {dealerUser} = useDealerUser()
-
- // Tab 切换处理函数
- const handleTabChange = (value: string | number) => {
- console.log('Tab切换到:', value)
- setActiveTab(value)
-
- // 如果切换到提现记录页面,刷新数据
- if (String(value) === '1') {
- fetchWithdrawRecords()
- }
- }
-
- // 获取可提现余额
- const fetchBalance = useCallback(async () => {
- console.log(dealerUser, 'dealerUser...')
- try {
- setAvailableAmount(dealerUser?.money || '0.00')
- } catch (error) {
- console.error('获取余额失败:', error)
- }
- }, [dealerUser])
-
- // 获取提现记录
- const fetchWithdrawRecords = useCallback(async () => {
- if (!dealerUser?.userId) return
-
- try {
- setLoading(true)
- const result = await pageShopDealerWithdraw({
- page: 1,
- limit: 100,
- userId: dealerUser.userId
- })
-
- if (result?.list) {
- const processedRecords = result.list.map(record => ({
- ...record,
- accountDisplay: getAccountDisplay(record)
- }))
- setWithdrawRecords(processedRecords)
- }
- } catch (error) {
- console.error('获取提现记录失败:', error)
- Taro.showToast({
- title: '获取提现记录失败',
- icon: 'error'
- })
- } finally {
- setLoading(false)
- }
- }, [dealerUser?.userId])
-
- // 格式化账户显示
- const getAccountDisplay = (record: ShopDealerWithdraw) => {
- if (record.payType === 10) {
- return '微信钱包'
- } else if (record.payType === 20 && record.alipayAccount) {
- return `支付宝(${record.alipayAccount.slice(-4)})`
- } else if (record.payType === 30 && record.bankCard) {
- return `${record.bankName || '银行卡'}(尾号${record.bankCard.slice(-4)})`
- }
- return '未知账户'
- }
-
- // 刷新数据
- const handleRefresh = async () => {
- setRefreshing(true)
- await Promise.all([fetchBalance(), fetchWithdrawRecords()])
- setRefreshing(false)
- }
-
- // 初始化加载数据
- useEffect(() => {
- if (dealerUser?.userId) {
- fetchBalance().then()
- fetchWithdrawRecords().then()
- }
- }, [fetchBalance, fetchWithdrawRecords])
-
- const getStatusText = (status?: number) => {
- switch (status) {
- case 40:
- return '已到账'
- case 20:
- return '审核通过'
- case 10:
- return '待审核'
- case 30:
- return '已驳回'
- default:
- return '未知'
- }
- }
-
- const getStatusColor = (status?: number) => {
- switch (status) {
- case 40:
- return 'success'
- case 20:
- return 'success'
- case 10:
- return 'warning'
- case 30:
- return 'danger'
- default:
- return 'default'
- }
- }
-
- const handleSubmit = async (values: any) => {
- if (!dealerUser?.userId) {
- Taro.showToast({
- title: '用户信息获取失败',
- icon: 'error'
- })
- return
- }
-
- if (!values.accountType) {
- Taro.showToast({
- title: '请选择提现方式',
- icon: 'error'
- })
- return
- }
-
- // 验证提现金额
- const amount = parseFloat(values.amount)
- const available = parseFloat(availableAmount.replace(/,/g, ''))
-
- if (isNaN(amount) || amount <= 0) {
- Taro.showToast({
- title: '请输入有效的提现金额',
- icon: 'error'
- })
- return
- }
-
- if (amount < 100) {
- Taro.showToast({
- title: '最低提现金额为100元',
- icon: 'error'
- })
- return
- }
-
- if (amount > available) {
- Taro.showToast({
- title: '提现金额超过可用余额',
- icon: 'error'
- })
- return
- }
-
- // 验证账户信息
- if (values.accountType === 'alipay') {
- if (!values.account || !values.accountName) {
- Taro.showToast({
- title: '请填写完整的支付宝信息',
- icon: 'error'
- })
- return
- }
- } else if (values.accountType === 'bank') {
- if (!values.account || !values.accountName || !values.bankName) {
- Taro.showToast({
- title: '请填写完整的银行卡信息',
- icon: 'error'
- })
- return
- }
- }
-
- try {
- setSubmitting(true)
-
- const withdrawData: ShopDealerWithdraw = {
- userId: dealerUser.userId,
- money: values.amount,
- payType: values.accountType === 'wechat' ? 10 :
- values.accountType === 'alipay' ? 20 : 30,
- applyStatus: 10, // 待审核
- platform: 'MiniProgram'
- }
-
- // 根据提现方式设置账户信息
- if (values.accountType === 'alipay') {
- withdrawData.alipayAccount = values.account
- withdrawData.alipayName = values.accountName
- } else if (values.accountType === 'bank') {
- withdrawData.bankCard = values.account
- withdrawData.bankAccount = values.accountName
- withdrawData.bankName = values.bankName || '银行卡'
- }
-
- await addShopDealerWithdraw(withdrawData)
-
- Taro.showToast({
- title: '提现申请已提交',
- icon: 'success'
- })
-
- // 重置表单
- formRef.current?.resetFields()
- setSelectedAccount('')
-
- // 刷新数据
- await handleRefresh()
-
- // 切换到提现记录页面
- setActiveTab('1')
-
- } catch (error: any) {
- console.error('提现申请失败:', error)
- Taro.showToast({
- title: error.message || '提现申请失败',
- icon: 'error'
- })
- } finally {
- setSubmitting(false)
- }
- }
-
- const quickAmounts = ['100', '300', '500', '1000']
-
- const setQuickAmount = (amount: string) => {
- formRef.current?.setFieldsValue({amount})
- }
-
- const setAllAmount = () => {
- formRef.current?.setFieldsValue({amount: availableAmount.replace(/,/g, '')})
- }
-
- // 格式化金额
- const formatMoney = (money?: string) => {
- if (!money) return '0.00'
- return parseFloat(money).toFixed(2)
- }
-
- const renderWithdrawForm = () => (
-
- {/* 余额卡片 */}
-
- {/* 装饰背景 - 小程序兼容版本 */}
-
-
-
-
- {formatMoney(dealerUser?.money)}
- 可提现余额
-
-
-
-
-
-
-
- 最低提现金额:¥100 | 手续费:免费
-
-
-
-
-
-
- )
-
- const renderWithdrawRecords = () => {
- console.log('渲染提现记录:', {loading, recordsCount: withdrawRecords.length, dealerUserId: dealerUser?.userId})
-
- return (
-
-
- {loading ? (
-
-
- 加载中...
-
- ) : withdrawRecords.length > 0 ? (
- withdrawRecords.map(record => (
-
-
-
-
- 提现金额:¥{record.money}
-
-
- 提现账户:{record.accountDisplay}
-
-
-
- {getStatusText(record.applyStatus)}
-
-
-
-
- 申请时间:{record.createTime}
- {record.auditTime && (
-
- 审核时间:{new Date(record.auditTime).toLocaleString()}
-
- )}
- {record.rejectReason && (
-
- 驳回原因:{record.rejectReason}
-
- )}
-
-
- ))
- ) : (
-
- )}
-
-
- )
- }
-
- if (!dealerUser) {
- return (
-
-
- 加载中...
-
- )
- }
-
- return (
-
-
-
- {renderWithdrawForm()}
-
-
-
- {renderWithdrawRecords()}
-
-
-
- )
-}
-
-export default DealerWithdraw
diff --git a/src/doctor/apply/add.config.ts b/src/doctor/apply/add.config.ts
index 3f7f9ad..ac37521 100644
--- a/src/doctor/apply/add.config.ts
+++ b/src/doctor/apply/add.config.ts
@@ -1,4 +1,4 @@
export default definePageConfig({
- navigationBarTitleText: '医生入驻申请通道',
+ navigationBarTitleText: '邀请注册',
navigationBarTextStyle: 'black'
})
diff --git a/src/doctor/apply/add.tsx b/src/doctor/apply/add.tsx
index 08c2f15..f862bf3 100644
--- a/src/doctor/apply/add.tsx
+++ b/src/doctor/apply/add.tsx
@@ -1,96 +1,210 @@
import {useEffect, useState, useRef} from "react";
-import {Loading, CellGroup, Cell, Input, Form} from '@nutui/nutui-react-taro'
+import {Loading, CellGroup, Input, Form, Avatar, Button, Space} from '@nutui/nutui-react-taro'
import {Edit} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro'
import {View} from '@tarojs/components'
import FixedButton from "@/components/FixedButton";
import {useUser} from "@/hooks/useUser";
-import {ShopDealerApply} from "@/api/shop/shopDealerApply/model";
-import {
- addShopDealerApply,
- pageShopDealerApply,
- updateShopDealerApply
-} from "@/api/shop/shopDealerApply";
-import {getShopDealerUser} from "@/api/shop/shopDealerUser";
+import {TenantId} from "@/config/app";
+import {updateUser} from "@/api/system/user";
+import {User} from "@/api/system/user/model";
+import {getStoredInviteParams, handleInviteRelation} from "@/utils/invite";
+import {addShopDealerUser} from "@/api/shop/shopDealerUser";
+import {listUserRole, updateUserRole} from "@/api/system/userRole";
+
+// 类型定义
+interface ChooseAvatarEvent {
+ detail: {
+ avatarUrl: string;
+ };
+}
+
+interface InputEvent {
+ detail: {
+ value: string;
+ };
+}
const AddUserAddress = () => {
- const {user} = useUser()
+ const {user, loginUser} = useUser()
const [loading, setLoading] = useState(true)
- const [FormData, setFormData] = useState()
+ const [FormData, setFormData] = useState()
const formRef = useRef(null)
- const [isEditMode, setIsEditMode] = useState(false)
- const [existingApply, setExistingApply] = useState(null)
- // 获取审核状态文字
- const getApplyStatusText = (status?: number) => {
- switch (status) {
- case 10:
- return '待审核'
- case 20:
- return '审核通过'
- case 30:
- return '驳回'
- default:
- return '未知状态'
+ const reload = async () => {
+ const inviteParams = getStoredInviteParams()
+ if (inviteParams?.inviter) {
+ setFormData({
+ ...user,
+ refereeId: Number(inviteParams.inviter),
+ // 清空昵称,强制用户手动输入
+ nickname: '',
+ })
+ } else {
+ // 如果没有邀请参数,也要确保昵称为空
+ setFormData({
+ ...user,
+ nickname: '',
+ })
}
}
- const reload = async () => {
- // 判断用户是否登录
- if (!user?.userId) {
- return false;
+
+ const uploadAvatar = ({detail}: ChooseAvatarEvent) => {
+ // 先更新本地显示的头像(临时显示)
+ const tempFormData = {
+ ...FormData,
+ avatar: `${detail.avatarUrl}`,
}
- // 查询当前用户ID是否已有申请记录
- try {
- const res = await pageShopDealerApply({userId: user?.userId});
- if (res && res.count > 0) {
- setIsEditMode(true);
- setExistingApply(res.list[0]);
- // 如果有记录,填充表单数据
- setFormData(res.list[0]);
- setLoading(false)
- } else {
- setIsEditMode(false);
- setExistingApply(null);
- setLoading(false)
+ setFormData(tempFormData)
+
+ Taro.uploadFile({
+ url: 'https://server.websoft.top/api/oss/upload',
+ filePath: detail.avatarUrl,
+ name: 'file',
+ header: {
+ 'content-type': 'application/json',
+ TenantId
+ },
+ success: async (res) => {
+ const data = JSON.parse(res.data);
+ if (data.code === 0) {
+ const finalAvatarUrl = `${data.data.thumbnail}`
+
+ try {
+ // 使用 useUser hook 的 updateUser 方法更新头像
+ await updateUser({
+ avatar: finalAvatarUrl
+ })
+
+ Taro.showToast({
+ title: '头像上传成功',
+ icon: 'success',
+ duration: 1500
+ })
+ } catch (error) {
+ console.error('更新用户头像失败:', error)
+ }
+
+ // 无论用户信息更新是否成功,都要更新本地FormData
+ const finalFormData = {
+ ...tempFormData,
+ avatar: finalAvatarUrl
+ }
+ setFormData(finalFormData)
+
+ // 同步更新表单字段
+ if (formRef.current) {
+ formRef.current.setFieldsValue({
+ avatar: finalAvatarUrl
+ })
+ }
+ } else {
+ // 上传失败,恢复原来的头像
+ setFormData({
+ ...FormData,
+ avatar: user?.avatar || ''
+ })
+ Taro.showToast({
+ title: '上传失败',
+ icon: 'error'
+ })
+ }
+ },
+ fail: (error) => {
+ console.error('上传头像失败:', error)
+ Taro.showToast({
+ title: '上传失败',
+ icon: 'error'
+ })
+ // 恢复原来的头像
+ setFormData({
+ ...FormData,
+ avatar: user?.avatar || ''
+ })
}
- } catch (error) {
- setLoading(true)
- console.error('查询申请记录失败:', error);
- setIsEditMode(false);
- setExistingApply(null);
- }
+ })
}
// 提交表单
const submitSucceed = async (values: any) => {
try {
+ // 验证必填字段
+ if (!values.phone && !FormData?.phone) {
+ Taro.showToast({
+ title: '请先获取手机号',
+ icon: 'error'
+ });
+ return;
+ }
+
+ // 验证昵称:必须填写且不能是默认的微信昵称
+ const nickname = values.realName || FormData?.nickname || '';
+ if (!nickname || nickname.trim() === '') {
+ Taro.showToast({
+ title: '请填写昵称',
+ icon: 'error'
+ });
+ return;
+ }
+
+ // 检查是否为默认的微信昵称(常见的默认昵称)
+ const defaultNicknames = ['微信用户', 'WeChat User', '微信昵称'];
+ if (defaultNicknames.includes(nickname.trim())) {
+ Taro.showToast({
+ title: '请填写真实昵称,不能使用默认昵称',
+ icon: 'error'
+ });
+ return;
+ }
+
+ // 验证昵称长度
+ if (nickname.trim().length < 2) {
+ Taro.showToast({
+ title: '昵称至少需要2个字符',
+ icon: 'error'
+ });
+ return;
+ }
+
+ if (!values.avatar && !FormData?.avatar) {
+ Taro.showToast({
+ title: '请上传头像',
+ icon: 'error'
+ });
+ return;
+ }
+ console.log(values,FormData)
+
+ const roles = await listUserRole({userId: user?.userId})
+ console.log(roles, 'roles...')
// 准备提交的数据
- const submitData = {
- ...values,
- realName: values.realName || user?.nickname,
- mobile: user?.phone,
- refereeId: values.refereeId || FormData?.refereeId,
- applyStatus: 10,
- auditTime: undefined
- };
- await getShopDealerUser(submitData.refereeId);
+ await updateUser({
+ userId: user?.userId,
+ nickname: values.realName || FormData?.nickname,
+ phone: values.phone || FormData?.phone,
+ avatar: values.avatar || FormData?.avatar,
+ refereeId: values.refereeId || FormData?.refereeId
+ });
- // 如果是编辑模式,添加现有申请的id
- if (isEditMode && existingApply?.applyId) {
- submitData.applyId = existingApply.applyId;
+ await addShopDealerUser({
+ userId: user?.userId,
+ realName: values.realName || FormData?.nickname,
+ mobile: values.phone || FormData?.phone,
+ refereeId: values.refereeId || FormData?.refereeId
+ })
+
+ if (roles.length > 0) {
+ await updateUserRole({
+ ...roles[0],
+ roleId: 1848
+ })
}
- // 执行新增或更新操作
- if (isEditMode) {
- await updateShopDealerApply(submitData);
- } else {
- await addShopDealerApply(submitData);
- }
Taro.showToast({
- title: `${isEditMode ? '提交' : '提交'}成功`,
+ title: `注册成功`,
icon: 'success'
});
@@ -100,13 +214,130 @@ const AddUserAddress = () => {
} catch (error) {
console.error('验证邀请人失败:', error);
- return Taro.showToast({
- title: '邀请人ID不存在',
- icon: 'error'
- });
}
}
+ // 获取微信昵称
+ const getWxNickname = (nickname: string) => {
+ // 更新表单数据
+ const updatedFormData = {
+ ...FormData,
+ nickname: nickname
+ }
+ setFormData(updatedFormData);
+
+ // 同步更新表单字段
+ if (formRef.current) {
+ formRef.current.setFieldsValue({
+ realName: nickname
+ })
+ }
+ }
+
+ /* 获取用户手机号 */
+ const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
+ const {code, encryptedData, iv} = detail
+ Taro.login({
+ success: (loginRes) => {
+ if (code) {
+ Taro.request({
+ url: 'https://server.websoft.top/api/wx-login/loginByMpWxPhone',
+ method: 'POST',
+ data: {
+ authCode: loginRes.code,
+ code,
+ encryptedData,
+ iv,
+ notVerifyPhone: true,
+ refereeId: 0,
+ sceneType: 'save_referee',
+ tenantId: TenantId
+ },
+ header: {
+ 'content-type': 'application/json',
+ TenantId
+ },
+ success: async function (res) {
+ if (res.data.code == 1) {
+ Taro.showToast({
+ title: res.data.message,
+ icon: 'error',
+ duration: 2000
+ })
+ return false;
+ }
+ // 登录成功
+ const token = res.data.data.access_token;
+ const userData = res.data.data.user;
+ console.log(userData, 'userData...')
+ // 使用useUser Hook的loginUser方法更新状态
+ loginUser(token, userData);
+
+ if (userData.phone) {
+ console.log('手机号已获取', userData.phone)
+ const updatedFormData = {
+ ...FormData,
+ phone: userData.phone,
+ // 不自动填充微信昵称,保持用户已输入的昵称
+ nickname: FormData?.nickname || '',
+ // 只在没有头像时才使用微信头像
+ avatar: FormData?.avatar || userData.avatar
+ }
+ setFormData(updatedFormData)
+
+ // 更新表单字段值
+ if (formRef.current) {
+ formRef.current.setFieldsValue({
+ phone: userData.phone,
+ // 不覆盖用户已输入的昵称
+ realName: FormData?.nickname || '',
+ avatar: FormData?.avatar || userData.avatar
+ })
+ }
+
+ Taro.showToast({
+ title: '手机号获取成功',
+ icon: 'success',
+ duration: 1500
+ })
+ }
+
+
+ // 处理邀请关系
+ if (userData?.userId) {
+ try {
+ const inviteSuccess = await handleInviteRelation(userData.userId)
+ if (inviteSuccess) {
+ Taro.showToast({
+ title: '邀请关系建立成功',
+ icon: 'success',
+ duration: 2000
+ })
+ }
+ } catch (error) {
+ console.error('处理邀请关系失败:', error)
+ }
+ }
+
+ // 显示登录成功提示
+ // Taro.showToast({
+ // title: '注册成功',
+ // icon: 'success',
+ // duration: 1500
+ // })
+
+ // 不需要重新启动小程序,状态已经通过useUser更新
+ // 可以选择性地刷新当前页面数据
+ // await reload();
+ }
+ })
+ } else {
+ console.log('登录失败!')
+ }
+ }
+ })
+ }
+
// 处理固定按钮点击事件
const handleFixedButtonClick = () => {
// 触发表单提交
@@ -123,6 +354,18 @@ const AddUserAddress = () => {
})
}, [user?.userId]); // 依赖用户ID,当用户变化时重新加载
+ // 当FormData变化时,同步更新表单字段值
+ useEffect(() => {
+ if (formRef.current && FormData) {
+ formRef.current.setFieldsValue({
+ refereeId: FormData.refereeId,
+ phone: FormData.phone,
+ avatar: FormData.avatar,
+ realName: FormData.nickname
+ });
+ }
+ }, [FormData]);
+
if (loading) {
return 加载中
}
@@ -139,50 +382,49 @@ const AddUserAddress = () => {
>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ {
+ FormData?.phone &&
+
+
+
+
+ }
+
+ getWxNickname(e.detail.value)}
+ />
- {/* 审核状态显示(仅在编辑模式下显示) */}
- {isEditMode && (
-
-
- {getApplyStatusText(FormData?.applyStatus)}
-
- }
- />
- {FormData?.applyStatus === 20 && (
- |
- )}
- {FormData?.applyStatus === 30 && (
- |
- )}
- |
- )}
-
{/* 底部浮动按钮 */}
- {(!isEditMode || FormData?.applyStatus === 10 || FormData?.applyStatus === 30) && (
- }
- text={isEditMode ? '保存修改' : '提交申请'}
- disabled={FormData?.applyStatus === 10}
- onClick={handleFixedButtonClick}
- />
- )}
+ }
+ text={'立即注册'}
+ onClick={handleFixedButtonClick}
+ />
>
);
diff --git a/src/dealer/bank/add.config.ts b/src/doctor/bank/add.config.ts
similarity index 100%
rename from src/dealer/bank/add.config.ts
rename to src/doctor/bank/add.config.ts
diff --git a/src/dealer/bank/add.tsx b/src/doctor/bank/add.tsx
similarity index 100%
rename from src/dealer/bank/add.tsx
rename to src/doctor/bank/add.tsx
diff --git a/src/dealer/bank/index.config.ts b/src/doctor/bank/index.config.ts
similarity index 100%
rename from src/dealer/bank/index.config.ts
rename to src/doctor/bank/index.config.ts
diff --git a/src/dealer/bank/index.tsx b/src/doctor/bank/index.tsx
similarity index 95%
rename from src/dealer/bank/index.tsx
rename to src/doctor/bank/index.tsx
index 71046ff..9587c72 100644
--- a/src/dealer/bank/index.tsx
+++ b/src/doctor/bank/index.tsx
@@ -86,9 +86,9 @@ const DealerBank = () => {
description="您还没有地址哦"
/>
- Taro.navigateTo({url: '/dealer/bank/add'})}>新增地址
+ Taro.navigateTo({url: '/doctor/bank/add'})}>新增地址
Taro.navigateTo({url: '/dealer/bank/wxAddress'})}>获取微信地址
+ onClick={() => Taro.navigateTo({url: '/doctor/bank/wxAddress'})}>获取微信地址
@@ -126,7 +126,7 @@ const DealerBank = () => {
))}
{/* 底部浮动按钮 */}
- Taro.navigateTo({url: '/dealer/bank/add'})} />
+ Taro.navigateTo({url: '/doctor/bank/add'})} />
);
};
diff --git a/src/dealer/customer/README.md b/src/doctor/customer/README.md
similarity index 99%
rename from src/dealer/customer/README.md
rename to src/doctor/customer/README.md
index 20ccfd6..14cb5ef 100644
--- a/src/dealer/customer/README.md
+++ b/src/doctor/customer/README.md
@@ -99,7 +99,7 @@ CustomerManagement
## 文件结构
```
-src/dealer/customer/
+src/doctor/customer/
├── index.tsx # 主页面组件
└── README.md # 说明文档
diff --git a/src/dealer/apply/add.config.ts b/src/doctor/customer/add.config.ts
similarity index 62%
rename from src/dealer/apply/add.config.ts
rename to src/doctor/customer/add.config.ts
index ac37521..596fab1 100644
--- a/src/dealer/apply/add.config.ts
+++ b/src/doctor/customer/add.config.ts
@@ -1,4 +1,4 @@
export default definePageConfig({
- navigationBarTitleText: '邀请注册',
+ navigationBarTitleText: '患者报备',
navigationBarTextStyle: 'black'
})
diff --git a/src/dealer/customer/add.tsx b/src/doctor/customer/add.tsx
similarity index 100%
rename from src/dealer/customer/add.tsx
rename to src/doctor/customer/add.tsx
diff --git a/src/doctor/customer/index.config.ts b/src/doctor/customer/index.config.ts
new file mode 100644
index 0000000..539f8b2
--- /dev/null
+++ b/src/doctor/customer/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: '患者管理'
+})
diff --git a/src/dealer/customer/index.tsx b/src/doctor/customer/index.tsx
similarity index 85%
rename from src/dealer/customer/index.tsx
rename to src/doctor/customer/index.tsx
index bc316ec..14ec7dd 100644
--- a/src/dealer/customer/index.tsx
+++ b/src/doctor/customer/index.tsx
@@ -1,7 +1,7 @@
import {useState, useEffect, useCallback} from 'react'
import {View, Text} from '@tarojs/components'
import Taro, {useDidShow} from '@tarojs/taro'
-import {Loading, InfiniteLoading, Empty, Space, Tabs, TabPane, Tag, Button} from '@nutui/nutui-react-taro'
+import {Loading, InfiniteLoading, Empty, Space, Tabs, TabPane, Tag, Button, SearchBar} from '@nutui/nutui-react-taro'
import {Phone, AngleDoubleLeft} from '@nutui/icons-react-taro'
import type {ShopDealerApply, ShopDealerApply as UserType} from "@/api/shop/shopDealerApply/model";
import {
@@ -26,7 +26,8 @@ const CustomerIndex = () => {
const [list, setList] = useState([])
const [loading, setLoading] = useState(false)
const [activeTab, setActiveTab] = useState('all')
- const [searchValue, _] = useState('')
+ const [searchValue, setSearchValue] = useState('')
+ const [displaySearchValue, setDisplaySearchValue] = useState('')
const [page, setPage] = useState(1)
const [hasMore, setHasMore] = useState(true)
@@ -227,13 +228,22 @@ const CustomerIndex = () => {
}
+ // 防抖搜索功能
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setDisplaySearchValue(searchValue);
+ }, 300); // 300ms 防抖
+
+ return () => clearTimeout(timer);
+ }, [searchValue]);
+
// 根据搜索条件筛选数据(状态筛选已在API层面处理)
const getFilteredList = () => {
let filteredList = list;
// 按搜索关键词筛选
- if (searchValue.trim()) {
- const keyword = searchValue.trim().toLowerCase();
+ if (displaySearchValue.trim()) {
+ const keyword = displaySearchValue.trim().toLowerCase();
filteredList = filteredList.filter(customer =>
(customer.realName && customer.realName.toLowerCase().includes(keyword)) ||
(customer.dealerName && customer.dealerName.toLowerCase().includes(keyword)) ||
@@ -466,56 +476,81 @@ const CustomerIndex = () => {
// 渲染客户列表
const renderCustomerList = () => {
const filteredList = getFilteredList();
+ const isSearching = displaySearchValue.trim().length > 0;
return (
-
- {
- // 滚动事件处理
- }}
- onScrollToUpper={() => {
- // 滚动到顶部事件处理
- }}
- loadingText={
- <>
- 加载中...
- >
- }
- loadMoreText={
- filteredList.length === 0 ? (
-
- ) : (
-
- 没有更多了
+
+ {/* 搜索结果统计 */}
+ {isSearching && (
+
+
+ 搜索 "{displaySearchValue}" 的结果,共找到 {filteredList.length} 条记录
+
+
+ )}
+
+
+ {
+ // 滚动事件处理
+ }}
+ onScrollToUpper={() => {
+ // 滚动到顶部事件处理
+ }}
+ loadingText={
+ <>
+ 加载中...
+ >
+ }
+ loadMoreText={
+ filteredList.length === 0 ? (
+
+ ) : (
+
+ 没有更多了
+
+ )
+ }
+ >
+ {loading && filteredList.length === 0 ? (
+
+
+ 加载中...
- )
- }
- >
- {loading && filteredList.length === 0 ? (
-
-
- 加载中...
-
- ) : (
- filteredList.map(renderCustomerItem)
- )}
-
+ ) : (
+ filteredList.map(renderCustomerItem)
+ )}
+
+
);
};
return (
+ {/* 搜索栏 */}
+
+ setSearchValue(value)}
+ onClear={() => {
+ setSearchValue('');
+ setDisplaySearchValue('');
+ }}
+ clearable
+ />
+
{/* 顶部Tabs */}
diff --git a/src/dealer/customer/trading.config.ts b/src/doctor/customer/trading.config.ts
similarity index 100%
rename from src/dealer/customer/trading.config.ts
rename to src/doctor/customer/trading.config.ts
diff --git a/src/dealer/customer/trading.tsx b/src/doctor/customer/trading.tsx
similarity index 100%
rename from src/dealer/customer/trading.tsx
rename to src/doctor/customer/trading.tsx
diff --git a/src/doctor/index.config.ts b/src/doctor/index.config.ts
index bbd5ebc..f05d7ba 100644
--- a/src/doctor/index.config.ts
+++ b/src/doctor/index.config.ts
@@ -1,3 +1,3 @@
export default definePageConfig({
- navigationBarTitleText: '医生版'
+ navigationBarTitleText: '医生端'
})
diff --git a/src/doctor/index.tsx b/src/doctor/index.tsx
index da6ce5d..130c6fd 100644
--- a/src/doctor/index.tsx
+++ b/src/doctor/index.tsx
@@ -3,15 +3,18 @@ import {View, Text} from '@tarojs/components'
import {ConfigProvider, Button, Grid, Avatar} from '@nutui/nutui-react-taro'
import {
User,
- Shopping,
- Dongdong,
- ArrowRight,
- Purse,
- People
+ UserAdd,
+ Edit,
+ Comment,
+ QrCode,
+ Notice,
+ Orderlist,
+ Health,
+ PickedUp
} from '@nutui/icons-react-taro'
import {useDealerUser} from '@/hooks/useDealerUser'
import { useThemeStyles } from '@/hooks/useTheme'
-import {businessGradients, cardGradients, gradientUtils} from '@/styles/gradients'
+import {gradientUtils} from '@/styles/gradients'
import Taro from '@tarojs/taro'
const DealerIndex: React.FC = () => {
@@ -30,10 +33,10 @@ const DealerIndex: React.FC = () => {
}
// 格式化金额
- const formatMoney = (money?: string) => {
- if (!money) return '0.00'
- return parseFloat(money).toFixed(2)
- }
+ // const formatMoney = (money?: string) => {
+ // if (!money) return '0.00'
+ // return parseFloat(money).toFixed(2)
+ // }
// 格式化时间
const formatTime = (time?: string) => {
@@ -103,12 +106,12 @@ const DealerIndex: React.FC = () => {
- {dealerUser?.realName || '分销商'}
+ {dealerUser?.realName || '医生名称'}
- ID: {dealerUser.userId} | 推荐人: {dealerUser.refereeId || '无'}
+ 医生编号: {dealerUser.userId}
@@ -125,80 +128,9 @@ const DealerIndex: React.FC = () => {
)}
- {/* 佣金统计卡片 */}
- {dealerUser && (
-
-
- 佣金统计
-
-
-
-
- ¥{formatMoney(dealerUser.money)}
-
- 可提现
-
-
-
- ¥{formatMoney(dealerUser.freezeMoney)}
-
- 冻结中
-
-
-
- ¥{formatMoney(dealerUser.totalMoney)}
-
- 累计收益
-
-
-
- )}
-
- {/* 团队统计 */}
- {dealerUser && (
-
-
- 我的邀请
- navigateToPage('/dealer/team/index')}
- >
- 查看详情
-
-
-
-
-
-
- {dealerUser.firstNum || 0}
-
- 一级成员
-
-
-
- {dealerUser.secondNum || 0}
-
- 二级成员
-
-
-
- {dealerUser.thirdNum || 0}
-
- 三级成员
-
-
-
- )}
-
{/* 功能导航 */}
- 分销工具
+ 管理工具
{
border: 'none'
} as React.CSSProperties}
>
- navigateToPage('/dealer/orders/index')}>
+ navigateToPage('/doctor/customer/index')}>
-
+
- navigateToPage('/dealer/withdraw/index')}>
+ navigateToPage('/doctor/orders/add')}>
-
+
- navigateToPage('/dealer/team/index')}>
+ navigateToPage('/doctor/team/index')}>
-
+
- navigateToPage('/dealer/qrcode/index')}>
+ navigateToPage('/doctor/orders/index')}>
-
+
+
+
+
+
+
+
+
+
+
+ navigateToPage('/doctor/team/index')}>
+
+
+
+
+
+
+
+ navigateToPage('/doctor/qrcode/index')}>
+
+
+
+
+
+
+
+ navigateToPage('/doctor/apply/add')}>
+
+
+
+
+
+
+
{/* 第二行功能 */}
@@ -252,7 +217,7 @@ const DealerIndex: React.FC = () => {
{/* border: 'none'*/}
{/* } as React.CSSProperties}*/}
{/*>*/}
- {/* navigateToPage('/dealer/invite-stats/index')}>*/}
+ {/* navigateToPage('/doctor/invite-stats/index')}>*/}
{/* */}
{/* */}
{/* */}
diff --git a/src/doctor/info.tsx b/src/doctor/info.tsx
index 0f18841..8e03a69 100644
--- a/src/doctor/info.tsx
+++ b/src/doctor/info.tsx
@@ -15,7 +15,7 @@ const DealerInfo: React.FC = () => {
// 跳转到申请页面
const navigateToApply = () => {
Taro.navigateTo({
- url: '/pages/dealer/apply/add'
+ url: '/pages/doctor/apply/add'
})
}
diff --git a/src/dealer/customer/add.config.ts b/src/doctor/orders/add.config.ts
similarity index 62%
rename from src/dealer/customer/add.config.ts
rename to src/doctor/orders/add.config.ts
index fb7c4ce..00434e4 100644
--- a/src/dealer/customer/add.config.ts
+++ b/src/doctor/orders/add.config.ts
@@ -1,4 +1,4 @@
export default definePageConfig({
- navigationBarTitleText: '客户报备',
+ navigationBarTitleText: '在线开方',
navigationBarTextStyle: 'black'
})
diff --git a/src/doctor/orders/add.tsx b/src/doctor/orders/add.tsx
new file mode 100644
index 0000000..36126a3
--- /dev/null
+++ b/src/doctor/orders/add.tsx
@@ -0,0 +1,135 @@
+import {useEffect, useState, useRef} from "react";
+import {useRouter} from '@tarojs/taro'
+import {Loading, CellGroup, Input, Form, Cell, Avatar} from '@nutui/nutui-react-taro'
+import {ArrowRight} from '@nutui/icons-react-taro'
+import {View, Text} from '@tarojs/components'
+import Taro from '@tarojs/taro'
+import FixedButton from "@/components/FixedButton";
+import {addShopChatMessage} from "@/api/shop/shopChatMessage";
+import {ShopChatMessage} from "@/api/shop/shopChatMessage/model";
+import navTo from "@/utils/common";
+import {getUser} from "@/api/system/user";
+import {User} from "@/api/system/user/model";
+
+const AddMessage = () => {
+ const {params} = useRouter();
+ const [toUser, setToUser] = useState()
+ const [loading, setLoading] = useState(true)
+ const [FormData, _] = useState()
+ const formRef = useRef(null)
+
+ // 判断是编辑还是新增模式
+ const isEditMode = !!params.id
+ const toUserId = params.id ? Number(params.id) : undefined
+
+ const reload = async () => {
+ if(toUserId){
+ getUser(Number(toUserId)).then(data => {
+ setToUser(data)
+ })
+ }
+ }
+
+ // 提交表单
+ const submitSucceed = async (values: any) => {
+ try {
+ // 准备提交的数据
+ const submitData = {
+ ...values
+ };
+
+ console.log('提交数据:', submitData)
+
+ // 参数校验
+ if(!toUser){
+ Taro.showToast({
+ title: `请选择发送对象`,
+ icon: 'error'
+ });
+ return false;
+ }
+
+ // 判断内容是否为空
+ if (!values.content) {
+ Taro.showToast({
+ title: `请输入内容`,
+ icon: 'error'
+ });
+ return false;
+ }
+ // 执行新增或更新操作
+ await addShopChatMessage({
+ toUserId: toUserId,
+ formUserId: Taro.getStorageSync('UserId'),
+ type: 'text',
+ content: values.content
+ });
+
+ Taro.showToast({
+ title: `发送成功`,
+ icon: 'success'
+ });
+
+ setTimeout(() => {
+ Taro.navigateBack();
+ }, 1000);
+
+ } catch (error) {
+ console.error('发送失败:', error);
+ Taro.showToast({
+ title: `发送失败`,
+ icon: 'error'
+ });
+ }
+ }
+
+ const submitFailed = (error: any) => {
+ console.log(error, 'err...')
+ }
+
+ useEffect(() => {
+ reload().then(() => {
+ setLoading(false)
+ })
+ }, [isEditMode]);
+
+ if (loading) {
+ return 加载中
+ }
+
+ return (
+ <>
+
+
+
+ {toUser.alias || toUser.nickname}
+ {toUser.mobile}
+
+ |
+ ) : '选择患者'} extra={(
+
+ )}
+ onClick={() => navTo(`/doctor/customer/index`, true)}/>
+
+
+ {/* 底部浮动按钮 */}
+ formRef.current?.submit()}/>
+ >
+ );
+};
+
+export default AddMessage;
diff --git a/src/doctor/orders/index.config.ts b/src/doctor/orders/index.config.ts
index 3bb5694..ba927a9 100644
--- a/src/doctor/orders/index.config.ts
+++ b/src/doctor/orders/index.config.ts
@@ -1,3 +1,3 @@
export default definePageConfig({
- navigationBarTitleText: '分销订单'
+ navigationBarTitleText: '处方管理'
})
diff --git a/src/doctor/orders/index.tsx b/src/doctor/orders/index.tsx
index 1cc459b..196e715 100644
--- a/src/doctor/orders/index.tsx
+++ b/src/doctor/orders/index.tsx
@@ -1,161 +1,63 @@
-import React, { useState, useEffect, useCallback } from 'react'
-import { View, Text } from '@tarojs/components'
-import { Empty, Tabs, Tag, PullToRefresh, Loading } from '@nutui/nutui-react-taro'
+import React, {useState, useEffect, useCallback} from 'react'
+import {View, Text, ScrollView} from '@tarojs/components'
+import {Empty, Tag, PullToRefresh, Loading} from '@nutui/nutui-react-taro'
import Taro from '@tarojs/taro'
-import { pageShopDealerOrder } from '@/api/shop/shopDealerOrder'
-import { useDealerUser } from '@/hooks/useDealerUser'
-import type { ShopDealerOrder } from '@/api/shop/shopDealerOrder/model'
+import {pageShopDealerOrder} from '@/api/shop/shopDealerOrder'
+import {useDealerUser} from '@/hooks/useDealerUser'
+import type {ShopDealerOrder} from '@/api/shop/shopDealerOrder/model'
interface OrderWithDetails extends ShopDealerOrder {
orderNo?: string
customerName?: string
- totalCommission?: string
- // 当前用户在此订单中的层级和佣金
- userLevel?: 1 | 2 | 3
userCommission?: string
}
const DealerOrders: React.FC = () => {
- const [activeTab, setActiveTab] = useState('0')
const [loading, setLoading] = useState(false)
+ const [refreshing, setRefreshing] = useState(false)
+ const [loadingMore, setLoadingMore] = useState(false)
const [orders, setOrders] = useState([])
- const [statistics, setStatistics] = useState({
- totalOrders: 0,
- totalCommission: '0.00',
- pendingCommission: '0.00',
- // 分层统计
- level1: { orders: 0, commission: '0.00' },
- level2: { orders: 0, commission: '0.00' },
- level3: { orders: 0, commission: '0.00' }
- })
+ const [currentPage, setCurrentPage] = useState(1)
+ const [hasMore, setHasMore] = useState(true)
- const { dealerUser } = useDealerUser()
+ const {dealerUser} = useDealerUser()
- // 获取订单数据 - 查询当前用户作为各层级分销商的所有订单
- const fetchOrders = useCallback(async () => {
+ // 获取订单数据
+ const fetchOrders = useCallback(async (page: number = 1, isRefresh: boolean = false) => {
if (!dealerUser?.userId) return
try {
- setLoading(true)
-
- // 并行查询三个层级的订单
- const [level1Result, level2Result, level3Result] = await Promise.all([
- // 一级分销商订单
- pageShopDealerOrder({
- page: 1,
- limit: 100,
- firstUserId: dealerUser.userId
- }),
- // 二级分销商订单
- pageShopDealerOrder({
- page: 1,
- limit: 100,
- secondUserId: dealerUser.userId
- }),
- // 三级分销商订单
- pageShopDealerOrder({
- page: 1,
- limit: 100,
- thirdUserId: dealerUser.userId
- })
- ])
-
- const allOrders: OrderWithDetails[] = []
- const stats = {
- totalOrders: 0,
- totalCommission: '0.00',
- pendingCommission: '0.00',
- level1: { orders: 0, commission: '0.00' },
- level2: { orders: 0, commission: '0.00' },
- level3: { orders: 0, commission: '0.00' }
+ if (isRefresh) {
+ setRefreshing(true)
+ } else if (page === 1) {
+ setLoading(true)
+ } else {
+ setLoadingMore(true)
}
- // 处理一级分销订单
- if (level1Result?.list) {
- const level1Orders = level1Result.list.map(order => ({
+ const result = await pageShopDealerOrder({
+ page,
+ limit: 10
+ })
+
+ if (result?.list) {
+ const newOrders = result.list.map(order => ({
...order,
- orderNo: `DD${order.orderId}`,
+ orderNo: `${order.orderId}`,
customerName: `用户${order.userId}`,
- userLevel: 1 as const,
- userCommission: order.firstMoney || '0.00',
- totalCommission: (
- parseFloat(order.firstMoney || '0') +
- parseFloat(order.secondMoney || '0') +
- parseFloat(order.thirdMoney || '0')
- ).toFixed(2)
+ userCommission: order.firstMoney || '0.00'
}))
- allOrders.push(...level1Orders)
- stats.level1.orders = level1Orders.length
- stats.level1.commission = level1Orders.reduce((sum, order) =>
- sum + parseFloat(order.userCommission || '0'), 0
- ).toFixed(2)
+ if (page === 1) {
+ setOrders(newOrders)
+ } else {
+ setOrders(prev => [...prev, ...newOrders])
+ }
+
+ setHasMore(newOrders.length === 10)
+ setCurrentPage(page)
}
- // 处理二级分销订单
- if (level2Result?.list) {
- const level2Orders = level2Result.list.map(order => ({
- ...order,
- orderNo: `DD${order.orderId}`,
- customerName: `用户${order.userId}`,
- userLevel: 2 as const,
- userCommission: order.secondMoney || '0.00',
- totalCommission: (
- parseFloat(order.firstMoney || '0') +
- parseFloat(order.secondMoney || '0') +
- parseFloat(order.thirdMoney || '0')
- ).toFixed(2)
- }))
-
- allOrders.push(...level2Orders)
- stats.level2.orders = level2Orders.length
- stats.level2.commission = level2Orders.reduce((sum, order) =>
- sum + parseFloat(order.userCommission || '0'), 0
- ).toFixed(2)
- }
-
- // 处理三级分销订单
- if (level3Result?.list) {
- const level3Orders = level3Result.list.map(order => ({
- ...order,
- orderNo: `DD${order.orderId}`,
- customerName: `用户${order.userId}`,
- userLevel: 3 as const,
- userCommission: order.thirdMoney || '0.00',
- totalCommission: (
- parseFloat(order.firstMoney || '0') +
- parseFloat(order.secondMoney || '0') +
- parseFloat(order.thirdMoney || '0')
- ).toFixed(2)
- }))
-
- allOrders.push(...level3Orders)
- stats.level3.orders = level3Orders.length
- stats.level3.commission = level3Orders.reduce((sum, order) =>
- sum + parseFloat(order.userCommission || '0'), 0
- ).toFixed(2)
- }
-
- // 去重(同一个订单可能在多个层级中出现)
- const uniqueOrders = allOrders.filter((order, index, self) =>
- index === self.findIndex(o => o.orderId === order.orderId)
- )
-
- // 计算总统计
- stats.totalOrders = uniqueOrders.length
- stats.totalCommission = (
- parseFloat(stats.level1.commission) +
- parseFloat(stats.level2.commission) +
- parseFloat(stats.level3.commission)
- ).toFixed(2)
- stats.pendingCommission = allOrders
- .filter(order => order.isSettled === 0)
- .reduce((sum, order) => sum + parseFloat(order.userCommission || '0'), 0)
- .toFixed(2)
-
- setOrders(uniqueOrders)
- setStatistics(stats)
-
} catch (error) {
console.error('获取分销订单失败:', error)
Taro.showToast({
@@ -164,18 +66,27 @@ const DealerOrders: React.FC = () => {
})
} finally {
setLoading(false)
+ setRefreshing(false)
+ setLoadingMore(false)
}
}, [dealerUser?.userId])
- // 刷新数据
+ // 下拉刷新
const handleRefresh = async () => {
- await fetchOrders()
+ await fetchOrders(1, true)
+ }
+
+ // 加载更多
+ const handleLoadMore = async () => {
+ if (!loadingMore && hasMore) {
+ await fetchOrders(currentPage + 1)
+ }
}
// 初始化加载数据
useEffect(() => {
if (dealerUser?.userId) {
- fetchOrders().then()
+ fetchOrders(1)
}
}, [fetchOrders])
@@ -193,198 +104,80 @@ const DealerOrders: React.FC = () => {
const renderOrderItem = (order: OrderWithDetails) => (
-
-
-
- 订单号:{order.orderNo}
-
-
- 客户:{order.customerName}
-
- {/* 显示用户在此订单中的层级 */}
-
- {order.userLevel === 1 && '一级分销'}
- {order.userLevel === 2 && '二级分销'}
- {order.userLevel === 3 && '三级分销'}
-
-
+
+
+ 订单号:{order.orderNo}
+
{getStatusText(order.isSettled, order.isInvalid)}
+
+
+ 订单金额:¥{order.orderPrice || '0.00'}
+
+
+ 我的佣金:¥{order.userCommission}
+
+
+
-
-
- 订单金额:¥{order.orderPrice || '0.00'}
-
-
- 我的佣金:¥{order.userCommission}
-
-
- 总佣金:¥{order.totalCommission}
-
-
-
+
+ 客户:{order.customerName}
+
+
{order.createTime}
)
- // 根据状态和层级过滤订单
- const getFilteredOrders = (filter: string) => {
- switch (filter) {
- case '1': // 一级分销
- return orders.filter(order => order.userLevel === 1)
- case '2': // 二级分销
- return orders.filter(order => order.userLevel === 2)
- case '3': // 三级分销
- return orders.filter(order => order.userLevel === 3)
- case '4': // 待结算
- return orders.filter(order => order.isSettled === 0 && order.isInvalid === 0)
- case '5': // 已结算
- return orders.filter(order => order.isSettled === 1)
- case '6': // 已失效
- return orders.filter(order => order.isInvalid === 1)
- default: // 全部
- return orders
- }
- }
-
- if (!dealerUser) {
- return (
-
-
- 加载中...
-
- )
- }
-
return (
-
- {/* 统计卡片 */}
-
- {/* 总体统计 */}
-
-
- {statistics.totalOrders}
- 总订单
-
-
- ¥{statistics.totalCommission}
- 总佣金
-
-
- ¥{statistics.pendingCommission}
- 待结算
-
-
-
- {/* 分层统计 */}
-
- 分层统计
-
-
- {statistics.level1.orders}
- 一级订单
- ¥{statistics.level1.commission}
-
-
- {statistics.level2.orders}
- 二级订单
- ¥{statistics.level2.commission}
-
-
- {statistics.level3.orders}
- 三级订单
- ¥{statistics.level3.commission}
-
-
-
-
-
- {/* 订单列表 */}
- setActiveTab}>
-
-
-
- {loading ? (
-
-
- 加载中...
-
- ) : getFilteredOrders('0').length > 0 ? (
- getFilteredOrders('0').map(renderOrderItem)
- ) : (
-
- )}
-
-
-
-
-
+
+
+
- {getFilteredOrders('1').length > 0 ? (
- getFilteredOrders('1').map(renderOrderItem)
+ {loading && orders.length === 0 ? (
+
+
+ 加载中...
+
+ ) : orders.length > 0 ? (
+ <>
+ {orders.map(renderOrderItem)}
+ {loadingMore && (
+
+
+ 加载更多...
+
+ )}
+ {!hasMore && orders.length > 0 && (
+
+ 没有更多数据了
+
+ )}
+ >
) : (
-
+
)}
-
-
-
-
- {getFilteredOrders('2').length > 0 ? (
- getFilteredOrders('2').map(renderOrderItem)
- ) : (
-
- )}
-
-
-
-
-
- {getFilteredOrders('3').length > 0 ? (
- getFilteredOrders('3').map(renderOrderItem)
- ) : (
-
- )}
-
-
-
-
-
- {getFilteredOrders('4').length > 0 ? (
- getFilteredOrders('4').map(renderOrderItem)
- ) : (
-
- )}
-
-
-
-
-
- {getFilteredOrders('5').length > 0 ? (
- getFilteredOrders('5').map(renderOrderItem)
- ) : (
-
- )}
-
-
-
-
-
- {getFilteredOrders('6').length > 0 ? (
- getFilteredOrders('6').map(renderOrderItem)
- ) : (
-
- )}
-
-
-
+
+
)
}
diff --git a/src/doctor/qrcode/index.tsx b/src/doctor/qrcode/index.tsx
index c8d376a..268580a 100644
--- a/src/doctor/qrcode/index.tsx
+++ b/src/doctor/qrcode/index.tsx
@@ -1,7 +1,7 @@
import React, {useState, useEffect} from 'react'
import {View, Text, Image} from '@tarojs/components'
import {Button, Loading} from '@nutui/nutui-react-taro'
-import {Share, Download, Copy, QrCode} from '@nutui/icons-react-taro'
+import {Download, QrCode} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro'
import {useDealerUser} from '@/hooks/useDealerUser'
import {generateInviteCode} from '@/api/invite'
@@ -115,52 +115,52 @@ const DealerQrcode: React.FC = () => {
}
// 复制邀请信息
- const copyInviteInfo = () => {
- if (!dealerUser?.userId) {
- Taro.showToast({
- title: '用户信息未加载',
- icon: 'error'
- })
- return
- }
-
- const inviteText = `🎉 邀请您加入我的团队!
-
-扫描小程序码或搜索"通源堂健康生态平台"小程序,即可享受优质商品和服务!
-
-💰 成为我的团队成员,一起赚取丰厚佣金
-🎁 新用户专享优惠等你来拿
-
-邀请码:${dealerUser.userId}
-快来加入我们吧!`
-
- Taro.setClipboardData({
- data: inviteText,
- success: () => {
- Taro.showToast({
- title: '邀请信息已复制',
- icon: 'success'
- })
- }
- })
- }
+// const copyInviteInfo = () => {
+// if (!dealerUser?.userId) {
+// Taro.showToast({
+// title: '用户信息未加载',
+// icon: 'error'
+// })
+// return
+// }
+//
+// const inviteText = `🎉 邀请您加入我的团队!
+//
+// 扫描小程序码或搜索"九云售电云"小程序,即可享受优质商品和服务!
+//
+// 💰 成为我的团队成员,一起赚取丰厚佣金
+// 🎁 新用户专享优惠等你来拿
+//
+// 邀请码:${dealerUser.userId}
+// 快来加入我们吧!`
+//
+// Taro.setClipboardData({
+// data: inviteText,
+// success: () => {
+// Taro.showToast({
+// title: '邀请信息已复制',
+// icon: 'success'
+// })
+// }
+// })
+// }
// 分享小程序码
- const shareMiniProgramCode = () => {
- if (!dealerUser?.userId) {
- Taro.showToast({
- title: '用户信息未加载',
- icon: 'error'
- })
- return
- }
-
- // 小程序分享
- Taro.showShareMenu({
- withShareTicket: true,
- showShareItems: ['shareAppMessage', 'shareTimeline']
- })
- }
+ // const shareMiniProgramCode = () => {
+ // if (!dealerUser?.userId) {
+ // Taro.showToast({
+ // title: '用户信息未加载',
+ // icon: 'error'
+ // })
+ // return
+ // }
+ //
+ // // 小程序分享
+ // Taro.showShareMenu({
+ // withShareTicket: true,
+ // showShareItems: ['shareAppMessage']
+ // })
+ // }
if (!dealerUser) {
return (
@@ -263,29 +263,29 @@ const DealerQrcode: React.FC = () => {
保存小程序码到相册
-
- }
- onClick={copyInviteInfo}
- disabled={!dealerUser?.userId || loading}
- >
- 复制邀请信息
-
-
-
- }
- onClick={shareMiniProgramCode}
- disabled={!dealerUser?.userId || loading}
- >
- 分享给好友
-
-
+ {/**/}
+ {/* }*/}
+ {/* onClick={copyInviteInfo}*/}
+ {/* disabled={!dealerUser?.userId || loading}*/}
+ {/* >*/}
+ {/* 复制邀请信息*/}
+ {/* */}
+ {/**/}
+ {/**/}
+ {/* }*/}
+ {/* onClick={shareMiniProgramCode}*/}
+ {/* disabled={!dealerUser?.userId || loading}*/}
+ {/* >*/}
+ {/* 分享给好友*/}
+ {/* */}
+ {/**/}
{/* 推广说明 */}
diff --git a/src/doctor/team/index.config.ts b/src/doctor/team/index.config.ts
index 926f186..539f8b2 100644
--- a/src/doctor/team/index.config.ts
+++ b/src/doctor/team/index.config.ts
@@ -1,3 +1,3 @@
export default definePageConfig({
- navigationBarTitleText: '我的团队'
+ navigationBarTitleText: '患者管理'
})
diff --git a/src/doctor/team/index.tsx b/src/doctor/team/index.tsx
index 923aa17..36f6b14 100644
--- a/src/doctor/team/index.tsx
+++ b/src/doctor/team/index.tsx
@@ -1,56 +1,151 @@
-import React, { useState, useEffect, useCallback } from 'react'
-import { View, Text } from '@tarojs/components'
-import { Empty, Tabs, Avatar, Tag, Progress, Loading, PullToRefresh } from '@nutui/nutui-react-taro'
-import { User, Star, StarFill } from '@nutui/icons-react-taro'
+import React, {useState, useEffect, useCallback} from 'react'
+import {View, Text} from '@tarojs/components'
+import {Phone, Edit, Message} from '@nutui/icons-react-taro'
+import {Space, Empty, Avatar, Button} from '@nutui/nutui-react-taro'
import Taro from '@tarojs/taro'
-import { useDealerUser } from '@/hooks/useDealerUser'
-import { listShopDealerReferee } from '@/api/shop/shopDealerReferee'
-import { pageShopDealerOrder } from '@/api/shop/shopDealerOrder'
-import type { ShopDealerReferee } from '@/api/shop/shopDealerReferee/model'
+import {useDealerUser} from '@/hooks/useDealerUser'
+import {listShopDealerReferee} from '@/api/shop/shopDealerReferee'
+import {pageShopDealerOrder} from '@/api/shop/shopDealerOrder'
+import type {ShopDealerReferee} from '@/api/shop/shopDealerReferee/model'
+import FixedButton from "@/components/FixedButton";
+import navTo from "@/utils/common";
+import {updateUser} from "@/api/system/user";
interface TeamMemberWithStats extends ShopDealerReferee {
name?: string
avatar?: string
+ nickname?: string;
+ alias?: string;
+ phone?: string;
orderCount?: number
commission?: string
status?: 'active' | 'inactive'
subMembers?: number
joinTime?: string
+ dealerAvatar?: string;
+ dealerName?: string;
+ dealerPhone?: string;
+}
+
+// 层级信息接口
+interface LevelInfo {
+ dealerId: number
+ dealerName?: string
+ level: number
}
const DealerTeam: React.FC = () => {
- const [activeTab, setActiveTab] = useState('0')
- const [loading, setLoading] = useState(false)
- const [refreshing, setRefreshing] = useState(false)
const [teamMembers, setTeamMembers] = useState([])
- const [teamStats, setTeamStats] = useState({
- total: 0,
- firstLevel: 0,
- secondLevel: 0,
- thirdLevel: 0,
- monthlyCommission: '0.00'
- })
+ const {dealerUser} = useDealerUser()
+ const [dealerId, setDealerId] = useState()
+ // 层级栈,用于支持返回上一层
+ const [levelStack, setLevelStack] = useState([])
+ const [loading, setLoading] = useState(false)
+ // 当前查看的用户名称
+ const [currentDealerName, setCurrentDealerName] = useState('')
- const { dealerUser } = useDealerUser()
+ // 异步加载成员统计数据
+ const loadMemberStats = async (members: TeamMemberWithStats[]) => {
+ // 分批处理,避免过多并发请求
+ const batchSize = 3
+ for (let i = 0; i < members.length; i += batchSize) {
+ const batch = members.slice(i, i + batchSize)
+
+ const batchStats = await Promise.all(
+ batch.map(async (member) => {
+ try {
+ // 并行获取订单统计和下级成员数量
+ const [orderResult, subMembersResult] = await Promise.all([
+ pageShopDealerOrder({
+ page: 1,
+ userId: member.userId
+ }),
+ listShopDealerReferee({
+ dealerId: member.userId,
+ deleted: 0
+ })
+ ])
+
+ let orderCount = 0
+ let commission = '0.00'
+ let status: 'active' | 'inactive' = 'inactive'
+
+ if (orderResult?.list) {
+ const orders = orderResult.list
+ orderCount = orders.length
+ commission = orders.reduce((sum, order) => {
+ const levelCommission = member.level === 1 ? order.firstMoney :
+ member.level === 2 ? order.secondMoney :
+ order.thirdMoney
+ return sum + parseFloat(levelCommission || '0')
+ }, 0).toFixed(2)
+
+ // 判断活跃状态(30天内有订单为活跃)
+ const thirtyDaysAgo = new Date()
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)
+ const hasRecentOrder = orders.some(order =>
+ new Date(order.createTime || '') > thirtyDaysAgo
+ )
+ status = hasRecentOrder ? 'active' : 'inactive'
+ }
+
+ return {
+ ...member,
+ orderCount,
+ commission,
+ status,
+ subMembers: subMembersResult?.length || 0
+ }
+ } catch (error) {
+ console.error(`获取成员${member.userId}数据失败:`, error)
+ return {
+ ...member,
+ orderCount: 0,
+ commission: '0.00',
+ status: 'inactive' as const,
+ subMembers: 0
+ }
+ }
+ })
+ )
+
+ // 更新这一批成员的数据
+ setTeamMembers(prevMembers => {
+ const updatedMembers = [...prevMembers]
+ batchStats.forEach(updatedMember => {
+ const index = updatedMembers.findIndex(m => m.userId === updatedMember.userId)
+ if (index !== -1) {
+ updatedMembers[index] = updatedMember
+ }
+ })
+ return updatedMembers
+ })
+
+ // 添加小延迟,避免请求过于密集
+ if (i + batchSize < members.length) {
+ await new Promise(resolve => setTimeout(resolve, 100))
+ }
+ }
+ }
// 获取团队数据
const fetchTeamData = useCallback(async () => {
- if (!dealerUser?.userId) return
+ if (!dealerUser?.userId && !dealerId) return
try {
setLoading(true)
-
+ console.log(dealerId, 'dealerId>>>>>>>>>')
// 获取团队成员关系
const refereeResult = await listShopDealerReferee({
- dealerId: dealerUser.userId
+ dealerId: dealerId ? dealerId : dealerUser?.userId
})
if (refereeResult) {
+ console.log('团队成员原始数据:', refereeResult)
// 处理团队成员数据
const processedMembers: TeamMemberWithStats[] = refereeResult.map(member => ({
...member,
- name: `用户${member.userId}`,
- avatar: '',
+ name: `${member.userId}`,
orderCount: 0,
commission: '0.00',
status: 'active' as const,
@@ -58,62 +153,13 @@ const DealerTeam: React.FC = () => {
joinTime: member.createTime
}))
- // 并行获取每个成员的订单统计
- const memberStats = await Promise.all(
- processedMembers.map(async (member) => {
- try {
- const orderResult = await pageShopDealerOrder({
- page: 1,
- limit: 100,
- userId: member.userId
- })
+ // 先显示基础数据,然后异步加载详细统计
+ setTeamMembers(processedMembers)
+ setLoading(false)
- if (orderResult?.list) {
- const orders = orderResult.list
- const orderCount = orders.length
- const commission = orders.reduce((sum, order) => {
- const levelCommission = member.level === 1 ? order.firstMoney :
- member.level === 2 ? order.secondMoney :
- order.thirdMoney
- return sum + parseFloat(levelCommission || '0')
- }, 0).toFixed(2)
+ // 异步加载每个成员的详细统计数据
+ loadMemberStats(processedMembers)
- // 判断活跃状态(30天内有订单为活跃)
- const thirtyDaysAgo = new Date()
- thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)
- const hasRecentOrder = orders.some(order =>
- new Date(order.createTime || '') > thirtyDaysAgo
- )
-
- return {
- ...member,
- orderCount,
- commission,
- status: hasRecentOrder ? 'active' as const : 'inactive' as const
- }
- }
- return member
- } catch (error) {
- console.error(`获取成员${member.userId}订单失败:`, error)
- return member
- }
- })
- )
-
- setTeamMembers(memberStats)
-
- // 计算统计数据
- const stats = {
- total: memberStats.length,
- firstLevel: memberStats.filter(m => m.level === 1).length,
- secondLevel: memberStats.filter(m => m.level === 2).length,
- thirdLevel: memberStats.filter(m => m.level === 3).length,
- monthlyCommission: memberStats.reduce((sum, member) =>
- sum + parseFloat(member.commission || '0'), 0
- ).toFixed(2)
- }
-
- setTeamStats(stats)
}
} catch (error) {
console.error('获取团队数据失败:', error)
@@ -124,244 +170,270 @@ const DealerTeam: React.FC = () => {
} finally {
setLoading(false)
}
- }, [dealerUser?.userId])
+ }, [dealerUser?.userId, dealerId])
- // 刷新数据
- const handleRefresh = async () => {
- setRefreshing(true)
- await fetchTeamData()
- setRefreshing(false)
+ // 查看下级成员
+ const getNextUser = (item: TeamMemberWithStats) => {
+ // 检查层级限制:最多只能查看2层(levelStack.length >= 1 表示已经是第2层了)
+ if (levelStack.length >= 1) {
+ return
+ }
+
+ // 如果没有下级成员,不允许点击
+ if (!item.subMembers || item.subMembers === 0) {
+ return
+ }
+
+ console.log('点击用户:', item.userId, item.name)
+
+ // 将当前层级信息推入栈中
+ const currentLevel: LevelInfo = {
+ dealerId: dealerId || dealerUser?.userId || 0,
+ dealerName: currentDealerName || (dealerId ? '上级' : dealerUser?.realName || '我'),
+ level: levelStack.length
+ }
+ setLevelStack(prev => [...prev, currentLevel])
+
+ // 切换到下级
+ setDealerId(item.userId)
+ setCurrentDealerName(item.nickname || item.dealerName || `用户${item.userId}`)
}
- // 初始化加载数据
+ // 返回上一层
+ const goBack = () => {
+ if (levelStack.length === 0) {
+ // 如果栈为空,返回首页或上一页
+ Taro.navigateBack()
+ return
+ }
+
+ // 从栈中弹出上一层信息
+ const prevLevel = levelStack[levelStack.length - 1]
+ setLevelStack(prev => prev.slice(0, -1))
+
+ if (prevLevel.dealerId === (dealerUser?.userId || 0)) {
+ // 返回到根层级
+ setDealerId(undefined)
+ setCurrentDealerName('')
+ } else {
+ setDealerId(prevLevel.dealerId)
+ setCurrentDealerName(prevLevel.dealerName || '')
+ }
+ }
+
+ // 一键拨打
+ const makePhoneCall = (phone: string) => {
+ Taro.makePhoneCall({
+ phoneNumber: phone,
+ fail: () => {
+ Taro.showToast({
+ title: '拨打取消',
+ icon: 'error'
+ });
+ }
+ });
+ };
+
+ // 别名备注
+ const editAlias = (item: any, index: number) => {
+ Taro.showModal({
+ title: '备注',
+ // @ts-ignore
+ editable: true,
+ placeholderText: '真实姓名',
+ content: item.alias || '',
+ success: async (res: any) => {
+ if (res.confirm && res.content !== undefined) {
+ try {
+ // 更新跟进情况
+ await updateUser({
+ userId: item.userId,
+ alias: res.content.trim()
+ });
+ teamMembers[index].alias = res.content.trim()
+ setTeamMembers(teamMembers)
+ } catch (error) {
+ console.error('备注失败:', error);
+ Taro.showToast({
+ title: '备注失败,请重试',
+ icon: 'error'
+ });
+ }
+ }
+ }
+ });
+ };
+
+ // 发送消息
+ const sendMessage = (item: TeamMemberWithStats) => {
+ return navTo(`/user/chat/message/add?id=${item.userId}`, true)
+ }
+
+ // 监听数据变化,获取团队数据
useEffect(() => {
- if (dealerUser?.userId) {
+ if (dealerUser?.userId || dealerId) {
fetchTeamData().then()
}
}, [fetchTeamData])
- const getLevelColor = (level: number) => {
- switch (level) {
- case 1: return '#f59e0b'
- case 2: return '#8b5cf6'
- case 3: return '#ec4899'
- default: return '#6b7280'
+ // 初始化当前用户名称
+ useEffect(() => {
+ if (!dealerId && dealerUser?.realName && !currentDealerName) {
+ setCurrentDealerName(dealerUser.realName)
}
- }
+ }, [dealerUser, dealerId, currentDealerName])
- const getLevelIcon = (level: number) => {
- switch (level) {
- case 1: return
- case 2: return
- case 3: return
- default: return
- }
- }
+ const renderMemberItem = (member: TeamMemberWithStats, index: number) => {
+ // 判断是否可以点击:有下级成员且未达到层级限制
+ const canClick = member.subMembers && member.subMembers > 0 && levelStack.length < 1
+ // 判断是否显示手机号:只有本级(levelStack.length === 0)才显示
+ const showPhone = levelStack.length === 0
+ // 判断数据是否还在加载中(初始值都是0或'0.00')
+ const isStatsLoading = member.orderCount === 0 && member.commission === '0.00' && member.subMembers === 0
- const renderMemberItem = (member: TeamMemberWithStats) => (
-
-
- }
- className="mr-3"
- />
-
-
-
- {member.name}
-
- {getLevelIcon(Number(member.level))}
-
- {member.level}级
-
-
-
- 加入时间:{member.joinTime}
-
-
-
-
- {member.status === 'active' ? '活跃' : '沉默'}
-
-
-
-
-
-
-
- {member.orderCount}
-
- 订单数
-
-
-
- ¥{member.commission}
-
- 贡献佣金
-
-
-
- {member.subMembers}
-
- 团队成员
-
-
-
- )
-
- const renderOverview = () => (
-
- {/* 团队统计卡片 */}
-
- {/* 装饰背景 - 小程序兼容版本 */}
-
-
-
-
- 团队总览
-
-
- {teamStats.total}
- 团队总人数
-
-
- ¥{teamStats.monthlyCommission}
- 本月团队佣金
-
-
-
-
-
- {/* 层级分布 */}
-
- 层级分布
-
-
-
-
- 一级成员
-
-
- {teamStats.firstLevel}
-
-
-
-
-
-
-
- 二级成员
-
-
- {teamStats.secondLevel}
-
-
-
-
-
-
-
- 三级成员
-
-
- {teamStats.thirdLevel}
-
-
-
-
-
-
- {/* 最新成员 */}
-
- 最新成员
- {teamMembers.slice(0, 3).map(renderMemberItem)}
-
-
- )
-
- const renderMemberList = (level?: number) => (
-
-
- {loading ? (
-
-
- 加载中...
-
- ) : teamMembers
- .filter(member => !level || member.level === level)
- .length > 0 ? (
- teamMembers
- .filter(member => !level || member.level === level)
- .map(renderMemberItem)
- ) : (
-
- )}
-
-
- )
-
- if (!dealerUser) {
return (
-
-
- 加载中...
+ getNextUser(member)}
+ >
+
+
+
+
+
+
+ {member.alias ? {member.alias} :
+ {member.nickname}}
+ {/*别名备注*/}
+ {
+ e.stopPropagation()
+ editAlias(member, index)
+ }}/>
+ {/*发送消息*/}
+ {
+ e.stopPropagation()
+ sendMessage(member)
+ }}/>
+
+
+ {/* 显示手机号(仅本级可见) */}
+ {showPhone && member.phone && (
+ {
+ e.stopPropagation();
+ makePhoneCall(member.phone || '');
+ }}>
+ {member.phone}
+
+
+ )}
+
+
+ 加入时间:{member.joinTime}
+
+
+
+
+
+
+ 订单数
+
+ {isStatsLoading ? '-' : member.orderCount}
+
+
+
+ 贡献佣金
+
+ {isStatsLoading ? '-' : `¥${member.commission}`}
+
+
+
+ 团队成员
+
+ {isStatsLoading ? '-' : (member.subMembers || 0)}
+
+
+
)
}
- return (
-
- setActiveTab}>
-
- {renderOverview()}
-
-
-
- {renderMemberList(1)}
-
-
-
- {renderMemberList(2)}
-
-
-
- {renderMemberList(3)}
-
-
+ const renderOverview = () => (
+
+
+ 我的团队成员
+ 成员数:{teamMembers.length}
+
+ {teamMembers.map(renderMemberItem)}
)
+
+ // 渲染顶部导航栏
+ const renderHeader = () => {
+ if (levelStack.length === 0) return null
+
+ return (
+
+
+
+
+ {currentDealerName}的团队成员
+
+
+
+ 返回上一层
+
+
+
+ )
+ }
+
+ if (!dealerUser) {
+ return (
+
+ navTo(`/doctor/apply/add`, true)}]}
+ />
+
+ )
+ }
+
+ return (
+ <>
+ {renderHeader()}
+
+ {loading ? (
+
+ 加载中...
+
+ ) : teamMembers.length > 0 ? (
+ renderOverview()
+ ) : (
+
+
+
+ )}
+
+ navTo(`/doctor/qrcode/index`, true)}/>
+ >
+ )
}
-export default DealerTeam
+export default DealerTeam;
diff --git a/src/dealer/wechat/index.config.ts b/src/doctor/wechat/index.config.ts
similarity index 100%
rename from src/dealer/wechat/index.config.ts
rename to src/doctor/wechat/index.config.ts
diff --git a/src/dealer/wechat/index.scss b/src/doctor/wechat/index.scss
similarity index 100%
rename from src/dealer/wechat/index.scss
rename to src/doctor/wechat/index.scss
diff --git a/src/dealer/wechat/index.tsx b/src/doctor/wechat/index.tsx
similarity index 100%
rename from src/dealer/wechat/index.tsx
rename to src/doctor/wechat/index.tsx
diff --git a/src/dealer/withdraw/debug.tsx b/src/doctor/withdraw/debug.tsx
similarity index 100%
rename from src/dealer/withdraw/debug.tsx
rename to src/doctor/withdraw/debug.tsx
diff --git a/src/doctor/withdraw/index.tsx b/src/doctor/withdraw/index.tsx
index 9ef56f5..18f257b 100644
--- a/src/doctor/withdraw/index.tsx
+++ b/src/doctor/withdraw/index.tsx
@@ -1,49 +1,67 @@
-import React, { useState, useRef, useEffect, useCallback } from 'react'
-import { View, Text } from '@tarojs/components'
+import React, {useState, useEffect, useCallback} from 'react'
+import {View, Text} from '@tarojs/components'
import {
Cell,
+ Space,
Button,
- Form,
Input,
CellGroup,
- Radio,
Tabs,
Tag,
Empty,
+ ActionSheet,
Loading,
PullToRefresh
} from '@nutui/nutui-react-taro'
-import { Wallet } from '@nutui/icons-react-taro'
-import { businessGradients } from '@/styles/gradients'
+import {Wallet, ArrowRight} from '@nutui/icons-react-taro'
+import {businessGradients} from '@/styles/gradients'
import Taro from '@tarojs/taro'
-import { useDealerUser } from '@/hooks/useDealerUser'
-import { pageShopDealerWithdraw, addShopDealerWithdraw } from '@/api/shop/shopDealerWithdraw'
-import type { ShopDealerWithdraw } from '@/api/shop/shopDealerWithdraw/model'
+import {useDealerUser} from '@/hooks/useDealerUser'
+import {pageShopDealerWithdraw, addShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw'
+import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model'
+import {ShopDealerBank} from "@/api/shop/shopDealerBank/model";
+import {listShopDealerBank} from "@/api/shop/shopDealerBank";
+import {listCmsWebsiteField} from "@/api/cms/cmsWebsiteField";
interface WithdrawRecordWithDetails extends ShopDealerWithdraw {
accountDisplay?: string
}
const DealerWithdraw: React.FC = () => {
- const [activeTab, setActiveTab] = useState('0')
- const [selectedAccount, setSelectedAccount] = useState('')
+ const [activeTab, setActiveTab] = useState('0')
const [loading, setLoading] = useState(false)
const [refreshing, setRefreshing] = useState(false)
const [submitting, setSubmitting] = useState(false)
+ const [banks, setBanks] = useState([])
+ const [bank, setBank] = useState()
+ const [isVisible, setIsVisible] = useState(false)
const [availableAmount, setAvailableAmount] = useState('0.00')
const [withdrawRecords, setWithdrawRecords] = useState([])
- const formRef = useRef(null)
+ const [withdrawAmount, setWithdrawAmount] = useState('')
+ const [withdrawValue, setWithdrawValue] = useState('')
- const { dealerUser } = useDealerUser()
+ const {dealerUser} = useDealerUser()
+
+ // Tab 切换处理函数
+ const handleTabChange = (value: string | number) => {
+ console.log('Tab切换到:', value)
+ setActiveTab(value)
+
+ // 如果切换到提现记录页面,刷新数据
+ if (String(value) === '1') {
+ fetchWithdrawRecords().then()
+ }
+ }
// 获取可提现余额
const fetchBalance = useCallback(async () => {
+ console.log(dealerUser, 'dealerUser...')
try {
- setAvailableAmount(dealerUser?.money || '0.00')
+ setAvailableAmount(String(dealerUser?.money || '0.00'))
} catch (error) {
console.error('获取余额失败:', error)
}
- }, [])
+ }, [dealerUser])
// 获取提现记录
const fetchWithdrawRecords = useCallback(async () => {
@@ -75,6 +93,21 @@ const DealerWithdraw: React.FC = () => {
}
}, [dealerUser?.userId])
+ function fetchBanks() {
+ listShopDealerBank({}).then(data => {
+ const list = data.map(d => {
+ d.name = d.bankName;
+ d.type = d.bankName;
+ return d;
+ })
+ setBanks(list.concat({
+ name: '管理银行卡',
+ type: 'add'
+ }))
+ setBank(data[0])
+ })
+ }
+
// 格式化账户显示
const getAccountDisplay = (record: ShopDealerWithdraw) => {
if (record.payType === 10) {
@@ -94,35 +127,66 @@ const DealerWithdraw: React.FC = () => {
setRefreshing(false)
}
+ const handleSelect = (item: ShopDealerBank) => {
+ if(item.type === 'add'){
+ return Taro.navigateTo({
+ url: '/doctor/bank/index'
+ })
+ }
+ setBank(item)
+ setIsVisible(false)
+ }
+
+ function fetchCmsField() {
+ listCmsWebsiteField({ name: 'WithdrawValue'}).then(res => {
+ if(res && res.length > 0){
+ const text = res[0].value;
+ setWithdrawValue(text || '')
+ }
+ })
+ }
+
// 初始化加载数据
useEffect(() => {
if (dealerUser?.userId) {
fetchBalance().then()
fetchWithdrawRecords().then()
+ fetchBanks()
+ fetchCmsField()
}
}, [fetchBalance, fetchWithdrawRecords])
const getStatusText = (status?: number) => {
switch (status) {
- case 40: return '已到账'
- case 20: return '审核通过'
- case 10: return '待审核'
- case 30: return '已驳回'
- default: return '未知'
+ case 40:
+ return '已到账'
+ case 20:
+ return '审核通过'
+ case 10:
+ return '待审核'
+ case 30:
+ return '已驳回'
+ default:
+ return '未知'
}
}
const getStatusColor = (status?: number) => {
switch (status) {
- case 40: return 'success'
- case 20: return 'success'
- case 10: return 'warning'
- case 30: return 'danger'
- default: return 'default'
+ case 40:
+ return 'success'
+ case 20:
+ return 'success'
+ case 10:
+ return 'warning'
+ case 30:
+ return 'danger'
+ default:
+ return 'default'
}
}
- const handleSubmit = async (values: any) => {
+ const handleSubmit = async () => {
if (!dealerUser?.userId) {
Taro.showToast({
title: '用户信息获取失败',
@@ -131,9 +195,26 @@ const DealerWithdraw: React.FC = () => {
return
}
+ if (!bank) {
+ Taro.showToast({
+ title: '请选择提现银行卡',
+ icon: 'error'
+ })
+ return
+ }
+
// 验证提现金额
- const amount = parseFloat(values.amount)
- const available = parseFloat(availableAmount.replace(',', ''))
+ const amount = parseFloat(withdrawAmount)
+ const availableStr = String(availableAmount || '0')
+ const available = parseFloat(availableStr.replace(/,/g, ''))
+
+ if (isNaN(amount) || amount <= 0) {
+ Taro.showToast({
+ title: '请输入有效的提现金额',
+ icon: 'error'
+ })
+ return
+ }
if (amount < 100) {
Taro.showToast({
@@ -151,26 +232,27 @@ const DealerWithdraw: React.FC = () => {
return
}
+ // 验证银行卡信息
+ if (!bank.bankCard || !bank.bankAccount || !bank.bankName) {
+ Taro.showToast({
+ title: '银行卡信息不完整',
+ icon: 'error'
+ })
+ return
+ }
+
try {
setSubmitting(true)
const withdrawData: ShopDealerWithdraw = {
userId: dealerUser.userId,
- money: values.amount,
- payType: values.accountType === 'wechat' ? 10 :
- values.accountType === 'alipay' ? 20 : 30,
+ money: withdrawAmount,
+ payType: 30, // 银行卡提现
applyStatus: 10, // 待审核
- platform: 'MiniProgram'
- }
-
- // 根据提现方式设置账户信息
- if (values.accountType === 'alipay') {
- withdrawData.alipayAccount = values.account
- withdrawData.alipayName = values.accountName
- } else if (values.accountType === 'bank') {
- withdrawData.bankCard = values.account
- withdrawData.bankAccount = values.accountName
- withdrawData.bankName = values.bankName || '银行卡'
+ platform: 'MiniProgram',
+ bankCard: bank.bankCard,
+ bankAccount: bank.bankAccount,
+ bankName: bank.bankName
}
await addShopDealerWithdraw(withdrawData)
@@ -181,8 +263,7 @@ const DealerWithdraw: React.FC = () => {
})
// 重置表单
- formRef.current?.resetFields()
- setSelectedAccount('')
+ setWithdrawAmount('')
// 刷新数据
await handleRefresh()
@@ -201,18 +282,26 @@ const DealerWithdraw: React.FC = () => {
}
}
- const quickAmounts = ['100', '300', '500', '1000']
-
- const setQuickAmount = (amount: string) => {
- formRef.current?.setFieldsValue({ amount })
+ // 格式化金额
+ const formatMoney = (money?: string) => {
+ if (!money) return '0.00'
+ return parseFloat(money).toFixed(2)
}
- const setAllAmount = () => {
- formRef.current?.setFieldsValue({ amount: availableAmount.replace(',', '') })
+ // 计算预计到账金额
+ const calculateExpectedAmount = (amount: string) => {
+ if (!amount || isNaN(parseFloat(amount))) return '0.00'
+ const withdrawAmount = parseFloat(amount)
+ // 提现费率 16% + 3元
+ const feeRate = 0.16
+ const fixedFee = 3
+ const totalFee = withdrawAmount * feeRate + fixedFee
+ const expectedAmount = withdrawAmount - totalFee
+ return Math.max(0, expectedAmount).toFixed(2)
}
const renderWithdrawForm = () => (
-
+
{/* 余额卡片 */}
{
}}>
-
+
+ {formatMoney(dealerUser?.money)}
可提现余额
- ¥{availableAmount}
-
+
- 最低提现金额:¥100 | 手续费:免费
+ 最低提现金额:¥100
-
+ }/>
+ 说明:{withdrawValue}}/>
+
-
- setSelectedAccount}>
-
- |
- 微信钱包
- |
-
- 支付宝
- |
-
- 银行卡
- |
-
-
-
-
- {selectedAccount === 'alipay' && (
- <>
-
-
-
-
-
-
- >
- )}
-
- {selectedAccount === 'bank' && (
- <>
-
-
-
-
-
-
-
-
-
- >
- )}
-
- {selectedAccount === 'wechat' && (
-
-
- 微信钱包提现将直接转入您的微信零钱
-
-
- )}
-
-
-
-
- {submitting ? '提交中...' : '申请提现'}
-
-
-
+
+
+ {submitting ? '提交中...' : '申请提现'}
+
+
|
)
- const renderWithdrawRecords = () => (
-
-
- {loading ? (
-
-
- 加载中...
-
- ) : withdrawRecords.length > 0 ? (
- withdrawRecords.map(record => (
-
-
-
-
- 提现金额:¥{record.money}
-
-
- 提现账户:{record.accountDisplay}
-
-
-
- {getStatusText(record.applyStatus)}
-
-
+ const renderWithdrawRecords = () => {
+ console.log('渲染提现记录:', {loading, recordsCount: withdrawRecords.length, dealerUserId: dealerUser?.userId})
-
- 申请时间:{record.createTime}
- {record.auditTime && (
-
- 审核时间:{new Date(record.auditTime).toLocaleString()}
-
- )}
- {record.rejectReason && (
-
- 驳回原因:{record.rejectReason}
-
- )}
-
-
- ))
- ) : (
-
- )}
-
-
- )
-
- if (!dealerUser) {
return (
-
-
- 加载中...
-
+
+
+ {loading ? (
+
+
+ 加载中...
+
+ ) : withdrawRecords.length > 0 ? (
+ withdrawRecords.map(record => (
+
+
+
+
+ 提现金额:¥{record.money}
+
+
+ 提现账户:{record.accountDisplay}
+
+
+
+ {getStatusText(record.applyStatus)}
+
+
+
+
+ 申请时间:{record.createTime}
+ {record.auditTime && (
+
+ 审核时间:{new Date(record.auditTime).toLocaleString()}
+
+ )}
+ {record.rejectReason && (
+
+ 驳回原因:{record.rejectReason}
+
+ )}
+
+
+ ))
+ ) : (
+
+ )}
+
+
)
}
return (
- setActiveTab}>
+
{renderWithdrawForm()}
@@ -417,6 +448,12 @@ const DealerWithdraw: React.FC = () => {
{renderWithdrawRecords()}
+ setIsVisible(false)}
+ />
)
}
diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts
index 479a0f3..1a662e0 100644
--- a/src/hooks/useUser.ts
+++ b/src/hooks/useUser.ts
@@ -50,7 +50,7 @@ export const useUser = () => {
const inviteParams = getStoredInviteParams()
if (currentPage?.route !== 'dealer/apply/add' && inviteParams?.inviter) {
return Taro.navigateTo({
- url: '/dealer/apply/add'
+ url: '/doctor/apply/add'
});
}
});
diff --git a/src/pages/cart/cart.tsx b/src/pages/cart/cart.tsx
index e415a03..0feed41 100644
--- a/src/pages/cart/cart.tsx
+++ b/src/pages/cart/cart.tsx
@@ -41,7 +41,7 @@ function Cart() {
useShareAppMessage(() => {
return {
- title: '购物车 - 时里院子市集',
+ title: '购物车 - 通源堂健康生态平台',
success: function () {
console.log('分享成功');
},
diff --git a/src/pages/cms/category/index.tsx b/src/pages/cms/category/index.tsx
index 6886cc3..17a632b 100644
--- a/src/pages/cms/category/index.tsx
+++ b/src/pages/cms/category/index.tsx
@@ -44,7 +44,7 @@ function Category() {
useShareAppMessage(() => {
return {
- title: `${nav?.categoryName}_时里院子市集`,
+ title: `${nav?.categoryName}_通源堂健康生态平台`,
path: `/shop/category/index?id=${categoryId}`,
success: function () {
console.log('分享成功');
diff --git a/src/pages/user/components/IsDealer.tsx b/src/pages/user/components/IsDealer.tsx
index 3d4ef65..32069ba 100644
--- a/src/pages/user/components/IsDealer.tsx
+++ b/src/pages/user/components/IsDealer.tsx
@@ -5,8 +5,10 @@ import {ArrowRight, Reward, Setting} from '@nutui/icons-react-taro'
import {useUser} from '@/hooks/useUser'
import {useEffect} from "react";
import {useDealerUser} from "@/hooks/useDealerUser";
+import {useThemeStyles} from "@/hooks/useTheme";
const IsDealer = () => {
+ const themeStyles = useThemeStyles();
const {isSuperAdmin} = useUser();
const {dealerUser} = useDealerUser()
@@ -23,9 +25,7 @@ const IsDealer = () => {
@@ -49,19 +49,17 @@ const IsDealer = () => {
|
分销中心
+ className={'pl-3 text-orange-100 font-medium'}>VIP申请
{/*门店核销*/}
|
}
extra={}
- onClick={() => navTo('/dealer/index', true)}
+ onClick={() => navTo('/doctor/index', true)}
/>
|
>
@@ -76,9 +74,7 @@ const IsDealer = () => {
@@ -87,7 +83,7 @@ const IsDealer = () => {
|
}
extra={}
- onClick={() => navTo('/dealer/apply/add', true)}
+ onClick={() => navTo('/doctor/apply/add', true)}
/>
>
diff --git a/src/pages/user/components/UserCard.tsx b/src/pages/user/components/UserCard.tsx
index f0f0268..0235e65 100644
--- a/src/pages/user/components/UserCard.tsx
+++ b/src/pages/user/components/UserCard.tsx
@@ -1,5 +1,5 @@
-import {Avatar, Tag, Space, Button} from '@nutui/nutui-react-taro'
-import {View, Text, Image} from '@tarojs/components'
+import {Avatar, Tag, Space} from '@nutui/nutui-react-taro'
+import {View, Text} from '@tarojs/components'
import {getUserInfo, getWxOpenId} from '@/api/layout';
import Taro from '@tarojs/taro';
import {useEffect, useState, forwardRef, useImperativeHandle} from "react";
@@ -10,6 +10,7 @@ import {useUser} from "@/hooks/useUser";
import {useUserData} from "@/hooks/useUserData";
import {getStoredInviteParams} from "@/utils/invite";
import UnifiedQRButton from "@/components/UnifiedQRButton";
+import {useThemeStyles} from "@/hooks/useTheme";
const UserCard = forwardRef((_, ref) => {
const {data, refresh} = useUserData()
@@ -17,6 +18,8 @@ const UserCard = forwardRef((_, ref) => {
const [IsLogin, setIsLogin] = useState(false)
const [userInfo, setUserInfo] = useState()
+ const themeStyles = useThemeStyles();
+
// 下拉刷新
const handleRefresh = async () => {
await refresh()
@@ -95,7 +98,6 @@ const UserCard = forwardRef((_, ref) => {
});
};
-
const openSetting = () => {
// Taro.openSetting:调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
Taro.openSetting({
@@ -118,6 +120,11 @@ const UserCard = forwardRef((_, ref) => {
const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
const {code, encryptedData, iv} = detail
+ // 判断用户是否已登录
+ if(IsLogin){
+ return navTo(`/user/profile/profile`)
+ }
+
// 获取存储的邀请参数
const inviteParams = getStoredInviteParams()
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
@@ -165,35 +172,19 @@ const UserCard = forwardRef((_, ref) => {
}
return (
-
-
+
{/* 使用相对定位容器,让个人资料图片可以绝对定位在右上角 */}
-
- {
- IsLogin ? (
-
- ) : (
-
-
-
- )
- }
+
+
- {getDisplayName()}
+ {getDisplayName()}
{IsLogin ? (
@@ -211,7 +202,7 @@ const UserCard = forwardRef((_, ref) => {
}}>
{/*统一扫码入口 - 支持登录和核销*/}
{
console.log('统一扫码成功:', result);
@@ -230,47 +221,31 @@ const UserCard = forwardRef((_, ref) => {
/>
-
- navTo('/user/wallet/wallet', true)}>
- 余额
- {data?.balance || '0.00'}
-
-
- 积分
- {data?.points || 0}
-
- navTo('/user/coupon/index', true)}>
- 优惠券
- {data?.coupons || 0}
-
- navTo('/user/gift/index', true)}>
- 礼品卡
- {data?.giftCards || 0}
+
+
+ navTo('/user/wallet/wallet', true)}>
+ 余额
+ {data?.balance || '0.00'}
+
+
+ 积分
+ {data?.points || 0}
+
+ navTo('/user/coupon/index', true)}>
+ 优惠券
+ {data?.coupons || 0}
+
+ navTo('/user/gift/index', true)}>
+ 礼品卡
+ {data?.giftCards || 0}
+
-
- {/* 个人资料图片,定位在右上角 */}
- navTo('/user/profile/profile', true)}
- >
-
-
-
)
})
diff --git a/src/pages/user/components/UserGrid.tsx b/src/pages/user/components/UserGrid.tsx
index 5c3e5da..dad57ca 100644
--- a/src/pages/user/components/UserGrid.tsx
+++ b/src/pages/user/components/UserGrid.tsx
@@ -87,7 +87,7 @@ const UserCell = () => {
- navTo('/dealer/team/index', true)}>
+ navTo('/doctor/team/index', true)}>
@@ -95,7 +95,7 @@ const UserCell = () => {
- {/* navTo('/dealer/qrcode/index', true)}>*/}
+ {/* navTo('/doctor/qrcode/index', true)}>*/}
{/* */}
{/* */}
{/* */}
diff --git a/src/pages/user/user.tsx b/src/pages/user/user.tsx
index 603a63d..9d49ce2 100644
--- a/src/pages/user/user.tsx
+++ b/src/pages/user/user.tsx
@@ -33,7 +33,25 @@ function User() {
onRefresh={handleRefresh}
headHeight={60}
>
-
+ {/* 装饰性背景 */}
+
+ {/* 装饰性背景元素 - 小程序兼容版本 */}
+
+
+
+
diff --git a/src/shop/category/index.tsx b/src/shop/category/index.tsx
index 4f81fd7..2f300a6 100644
--- a/src/shop/category/index.tsx
+++ b/src/shop/category/index.tsx
@@ -42,7 +42,7 @@ function Category() {
useShareAppMessage(() => {
return {
- title: `${nav?.categoryName}_时里院子市集`,
+ title: `${nav?.categoryName}_通源堂健康生态平台`,
path: `/shop/category/index?id=${categoryId}`,
success: function () {
console.log('分享成功');
diff --git a/src/user/chat/message/add.tsx b/src/user/chat/message/add.tsx
index a455fd0..cadf847 100644
--- a/src/user/chat/message/add.tsx
+++ b/src/user/chat/message/add.tsx
@@ -110,7 +110,7 @@ const AddMessage = () => {
) : '选择发送对象'} extra={(
)}
- onClick={() => navTo(`/dealer/team/index`, true)}/>
+ onClick={() => navTo(`/doctor/team/index`, true)}/>