feat(user): 统一VIP概念为开发者并优化开发者登录及申请

- 将VIP相关文案、图标改为开发者,涉及用户中心、门店中心、审核页等
- 优化登录弹窗UI,改为红色系,提升视觉统一性和交互体验
- 关于我们页面品牌和公司信息内容更新,展示最新企业介绍和业务范围
- VIP升级页新增“所在城市”选择,使用微信原生地区选择器,完善地址信息
- 用户申请表单中新增城市字段及校验,提交时携带城市信息
- 优化审核页面文案,统称开发者身份,明确申请审核内容
- 修复UserRoleController.save接口bug,避免userId被无条件覆盖导致角色绑错
- 动态查询VIP角色ID,避免硬编码,支持多租户环境正确绑定角色
This commit is contained in:
2026-07-22 13:19:10 +08:00
parent 12d6bdfb06
commit 8d4b55098f
9 changed files with 221 additions and 102 deletions

34
.idea/workspace.xml generated
View File

@@ -4,10 +4,16 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="2de94e4f-0587-4c9b-8bfd-e87e0ae95b81" name="更改" comment="feat(user): 改为动态查询 VIP 角色ID避免写死角色ID&#10;&#10;- RoleParam 类型新增 tenantId 字段,支持按租户过滤角色&#10;- 新增 getCurrentTenantId 获取当前租户ID支持登录态默认租户回退&#10;- 实现 getVipRoleId 函数,按 roleCodetenantId 查询 VIP 角色ID&#10;- assignVipRole动态获取 VIP 角色ID避免硬编码&#10;- 添加用户角色时带上 tenantId确保多租户角色绑定正确&#10;- 移除写"> <list default="true" id="2de94e4f-0587-4c9b-8bfd-e87e0ae95b81" name="更改" comment="feat(user): 动态查询VIP角色ID避免硬编码绑定问题&#10;&#10;- RoleParam新增tenantId字段支持按租户过滤角色&#10;- 新增getCurrentTenantId函数,兼容登录态默认租户回退&#10;- 实现getVipRoleId函数按roleCodetenantId查询VIP角色ID&#10;- assignVipRole动态获取VIP角色ID移除写死的角色ID&#10;- 添加用户角色时">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.workbuddy/memory/2026-07-21.md" beforeDir="false" afterPath="$PROJECT_DIR$/.workbuddy/memory/2026-07-21.md" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.workbuddy/memory/2026-07-22.md" beforeDir="false" afterPath="$PROJECT_DIR$/.workbuddy/memory/2026-07-22.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/api/shop/shopDealerApply/model/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/api/shop/shopDealerApply/model/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/store/center/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/store/center/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/user/about/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/user/about/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/user/user.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/user/user.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/user/vip-review/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/user/vip-review/index.tsx" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/pages/user/vip-review/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/user/vip-review/index.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/user/vip-upgrade/index.config.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/user/vip-upgrade/index.config.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/pages/user/vip-upgrade/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/user/vip-upgrade/index.tsx" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -119,15 +125,7 @@
<workItem from="1784131049625" duration="2304000" /> <workItem from="1784131049625" duration="2304000" />
<workItem from="1784133736973" duration="4614000" /> <workItem from="1784133736973" duration="4614000" />
<workItem from="1784585070286" duration="3047000" /> <workItem from="1784585070286" duration="3047000" />
<workItem from="1784638429525" duration="1386000" /> <workItem from="1784638429525" duration="7110000" />
</task>
<task id="LOCAL-00009" summary="fix(invite): 修复邀请加入请求头TenantId传递问题&#10;&#10;- 从配置中引入TenantId常量&#10;- 将请求header中的TenantId字段由硬编码改为动态变量&#10;- 确保GET请求和加密数据请求均正确带上TenantId头信息&#10;- 提升接口调用的一致性和维护性">
<option name="closed" value="true" />
<created>1775905047844</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1775905047844</updated>
</task> </task>
<task id="LOCAL-00010" summary="fix(config): 修正环境配置中的API_BASE_URL地址&#10;&#10;- 将开发环境、生产环境和测试环境的API_BASE_URL统一更新为新的域名websopy-api.websoft.top&#10;- 更新SimpleQRCodeModal组件中二维码请求地址使用新的API域名&#10;- 在邀请信息请求函数fetchInviteInfo中添加详细的请求和响应日志&#10;- 增加接口错误日志打印,提高捕获异常时的信息丰富度"> <task id="LOCAL-00010" summary="fix(config): 修正环境配置中的API_BASE_URL地址&#10;&#10;- 将开发环境、生产环境和测试环境的API_BASE_URL统一更新为新的域名websopy-api.websoft.top&#10;- 更新SimpleQRCodeModal组件中二维码请求地址使用新的API域名&#10;- 在邀请信息请求函数fetchInviteInfo中添加详细的请求和响应日志&#10;- 增加接口错误日志打印,提高捕获异常时的信息丰富度">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -513,7 +511,15 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1784639229566</updated> <updated>1784639229566</updated>
</task> </task>
<option name="localTasksCounter" value="58" /> <task id="LOCAL-00058" summary="feat(user): 动态查询VIP角色ID避免硬编码绑定问题&#10;&#10;- RoleParam新增tenantId字段支持按租户过滤角色&#10;- 新增getCurrentTenantId函数兼容登录态及默认租户回退&#10;- 实现getVipRoleId函数按roleCode与tenantId查询VIP角色ID&#10;- assignVipRole动态获取VIP角色ID移除写死的角色ID&#10;- 添加用户角色时传入tenantId确保多租户环境中角色绑定正确&#10;- 修复后端UserRoleController.save接口bug避免userId被无条件覆盖&#10;- 用户角色绑定时正确使用申请人userId解决VIP审核角色误绑定问题">
<option name="closed" value="true" />
<created>1784653464775</created>
<option name="number" value="00058" />
<option name="presentableId" value="LOCAL-00058" />
<option name="project" value="LOCAL" />
<updated>1784653464775</updated>
</task>
<option name="localTasksCounter" value="59" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -533,7 +539,6 @@
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" /> <option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
<option name="CHECK_NEW_TODO" value="false" /> <option name="CHECK_NEW_TODO" value="false" />
<MESSAGE value="feat(passport-invite): 优化新用户扫码邀请加入流程&#10;&#10;- 扫码进入邀请页面时保存邀请 token 到本地存储&#10;- 新增登录状态检测,未登录用户点击快速加入时保存邀请信息并跳转登录页&#10;- 登录成功后返回邀请页自动执行加入应用操作,提升用户体验&#10;- 支持已登录用户直接加入应用,简化流程&#10;- 增加清理 pending 邀请数据的方法,防止数据残留&#10;- 监听页面显示事件,处理登录返回后自动操作&#10;- 调整接口请求逻辑,确保携带最新的邀请和授权数据&#10;- 更新项目配置,注册邀请页面路径信息" />
<MESSAGE value="feat(passport): 重写登录与邀请加入流程,支持微信手机号一键登录&#10;&#10;- 完全重写 passport/login.tsx实现微信手机号一键登录功能&#10;- 支持登录页面携带 redirect 参数,登录后自动跳转回原页面&#10;- 登录成功后自动处理邀请加入应用,支持邀请关系绑定&#10;- 重写 passport/invite/index.tsx实现扫码邀请加入应用完整流程&#10;- 支持调用 wx.login 获取 code使用 loginByOpenId 判断注册状态&#10;- 未注册用户自动跳转登录页完成微信手机号登录再加入应用&#10;- 已登录用户直接执行加入应用操作,加入接口支持 Authorization 头&#10;-" /> <MESSAGE value="feat(passport): 重写登录与邀请加入流程,支持微信手机号一键登录&#10;&#10;- 完全重写 passport/login.tsx实现微信手机号一键登录功能&#10;- 支持登录页面携带 redirect 参数,登录后自动跳转回原页面&#10;- 登录成功后自动处理邀请加入应用,支持邀请关系绑定&#10;- 重写 passport/invite/index.tsx实现扫码邀请加入应用完整流程&#10;- 支持调用 wx.login 获取 code使用 loginByOpenId 判断注册状态&#10;- 未注册用户自动跳转登录页完成微信手机号登录再加入应用&#10;- 已登录用户直接执行加入应用操作,加入接口支持 Authorization 头&#10;-" />
<MESSAGE value="feat(invite): 重构邀请加入流程,实现已登录用户免授权直接加入&#10;&#10;- 完全重写邀请页逻辑,区分已登录与未注册用户按钮显示&#10;- 已登录用户显示“确认加入”按钮,点击用 wx.login 获取 code 加入&#10;- 未注册用户显示“微信手机号快速加入”按钮,授权手机号后完成注册登录再加入&#10;- 移除跳转登录页面逻辑,所有流程在邀请页内完成&#10;- 加入接口统一使用 Authorization 头携带 token确保身份双重验证&#10;- 优化背景、粒子和扫描线效果,提升界面视觉体验&#10;- 增加错误处理提示,加入失败时显示详细原因并可返回首页&#10;- 协议勾选仅在未注册用户显示,确保合规授权流程" /> <MESSAGE value="feat(invite): 重构邀请加入流程,实现已登录用户免授权直接加入&#10;&#10;- 完全重写邀请页逻辑,区分已登录与未注册用户按钮显示&#10;- 已登录用户显示“确认加入”按钮,点击用 wx.login 获取 code 加入&#10;- 未注册用户显示“微信手机号快速加入”按钮,授权手机号后完成注册登录再加入&#10;- 移除跳转登录页面逻辑,所有流程在邀请页内完成&#10;- 加入接口统一使用 Authorization 头携带 token确保身份双重验证&#10;- 优化背景、粒子和扫描线效果,提升界面视觉体验&#10;- 增加错误处理提示,加入失败时显示详细原因并可返回首页&#10;- 协议勾选仅在未注册用户显示,确保合规授权流程" />
<MESSAGE value="feat(passport): 优化已登录用户加入时协议勾选逻辑&#10;&#10;- 已登录用户点击「确认加入」时不再强制勾选协议&#10;- 移除 handleConfirmJoin 中对协议勾选的检查&#10;- 未注册用户仍需勾选协议后才能授权手机号&#10;- 确保登录状态异常时有提示信息显示" /> <MESSAGE value="feat(passport): 优化已登录用户加入时协议勾选逻辑&#10;&#10;- 已登录用户点击「确认加入」时不再强制勾选协议&#10;- 移除 handleConfirmJoin 中对协议勾选的检查&#10;- 未注册用户仍需勾选协议后才能授权手机号&#10;- 确保登录状态异常时有提示信息显示" />
@@ -558,7 +563,8 @@
<MESSAGE value="feat(passport): 迁移并修复小程序支付页面访问 websopy API 问题&#10;&#10;- 迁移 src/passport/pay 相关代码至当前项目,无需替换文件&#10;- 新增环境变量 WEBSOPY_API_BASE_URL提供 websopy API 基础地址&#10;- 在 config/app.ts 导出 WebsopyBaseUrl供代码引用&#10;- 配置 env.d.ts 类型定义,消除 TypeScript 隐式 any 错误&#10;- request 请求方法支持自定义 baseUrl 以调用不同接口地址&#10;- passport/pay 页面调用订阅接口统一传入 WebsopyBaseUrl&#10;- 修正 tenantId 类型为 number调整登录用户类型断言&#10;- 确认编译成功dist 目录生成对应文件及正确请求地址&#10;- 说明 type-check 依赖库问题不影响正常构建和运行" /> <MESSAGE value="feat(passport): 迁移并修复小程序支付页面访问 websopy API 问题&#10;&#10;- 迁移 src/passport/pay 相关代码至当前项目,无需替换文件&#10;- 新增环境变量 WEBSOPY_API_BASE_URL提供 websopy API 基础地址&#10;- 在 config/app.ts 导出 WebsopyBaseUrl供代码引用&#10;- 配置 env.d.ts 类型定义,消除 TypeScript 隐式 any 错误&#10;- request 请求方法支持自定义 baseUrl 以调用不同接口地址&#10;- passport/pay 页面调用订阅接口统一传入 WebsopyBaseUrl&#10;- 修正 tenantId 类型为 number调整登录用户类型断言&#10;- 确认编译成功dist 目录生成对应文件及正确请求地址&#10;- 说明 type-check 依赖库问题不影响正常构建和运行" />
<MESSAGE value="feat(passport): 优化支付成功后页面跳转逻辑&#10;&#10;- 修改支付成功后的自动跳转目标,从已购产品页面改为我的页面&#10;- 使用 switchTab 替代 navigateTo 保证在 tabBar 页顺利跳转&#10;- 移除多余的跳转失败回退逻辑,简化跳转流程&#10;- 调整跳转延迟时间为 1500 毫秒,提升用户体验" /> <MESSAGE value="feat(passport): 优化支付成功后页面跳转逻辑&#10;&#10;- 修改支付成功后的自动跳转目标,从已购产品页面改为我的页面&#10;- 使用 switchTab 替代 navigateTo 保证在 tabBar 页顺利跳转&#10;- 移除多余的跳转失败回退逻辑,简化跳转流程&#10;- 调整跳转延迟时间为 1500 毫秒,提升用户体验" />
<MESSAGE value="feat(user): 改为动态查询 VIP 角色ID避免写死角色ID&#10;&#10;- RoleParam 类型新增 tenantId 字段,支持按租户过滤角色&#10;- 新增 getCurrentTenantId 获取当前租户ID支持登录态和默认租户回退&#10;- 实现 getVipRoleId 函数,按 roleCode 与 tenantId 查询 VIP 角色ID&#10;- assignVipRole 中动态获取 VIP 角色ID避免硬编码&#10;- 添加用户角色时带上 tenantId确保多租户角色绑定正确&#10;- 移除写" /> <MESSAGE value="feat(user): 改为动态查询 VIP 角色ID避免写死角色ID&#10;&#10;- RoleParam 类型新增 tenantId 字段,支持按租户过滤角色&#10;- 新增 getCurrentTenantId 获取当前租户ID支持登录态和默认租户回退&#10;- 实现 getVipRoleId 函数,按 roleCode 与 tenantId 查询 VIP 角色ID&#10;- assignVipRole 中动态获取 VIP 角色ID避免硬编码&#10;- 添加用户角色时带上 tenantId确保多租户角色绑定正确&#10;- 移除写" />
<option name="LAST_COMMIT_MESSAGE" value="feat(user): 改为动态查询 VIP 角色ID避免写死角色ID&#10;&#10;- RoleParam 类型新增 tenantId 字段,支持按租户过滤角色&#10;- 新增 getCurrentTenantId 获取当前租户ID支持登录态默认租户回退&#10;- 实现 getVipRoleId 函数,按 roleCodetenantId 查询 VIP 角色ID&#10;- assignVipRole动态获取 VIP 角色ID避免硬编码&#10;- 添加用户角色时带上 tenantId确保多租户角色绑定正确&#10;- 移除写" /> <MESSAGE value="feat(user): 动态查询VIP角色ID避免硬编码绑定问题&#10;&#10;- RoleParam新增tenantId字段支持按租户过滤角色&#10;- 新增getCurrentTenantId函数,兼容登录态默认租户回退&#10;- 实现getVipRoleId函数按roleCodetenantId查询VIP角色ID&#10;- assignVipRole动态获取VIP角色ID移除写死的角色ID&#10;- 添加用户角色时" />
<option name="LAST_COMMIT_MESSAGE" value="feat(user): 动态查询VIP角色ID避免硬编码绑定问题&#10;&#10;- RoleParam新增tenantId字段支持按租户过滤角色&#10;- 新增getCurrentTenantId函数兼容登录态及默认租户回退&#10;- 实现getVipRoleId函数按roleCode与tenantId查询VIP角色ID&#10;- assignVipRole动态获取VIP角色ID移除写死的角色ID&#10;- 添加用户角色时传" />
<option name="NON_MODAL_COMMIT_POSTPONE_SLOW_CHECKS" value="false" /> <option name="NON_MODAL_COMMIT_POSTPONE_SLOW_CHECKS" value="false" />
</component> </component>
</project> </project>

View File

@@ -1,8 +1,36 @@
# 2026-07-22 # 2026-07-22 工作日志
## 修复 UserRoleController.save 覆盖 userId 的 bug ## 开发者登录弹窗 UI 美化
- 文件:`com.gxwebsoft.core/.../system/controller/UserRoleController.java` - 文件:`src/pages/user/about/index.tsx`
- 问题:原 `save``getLoginUser().getUserId()` **无条件覆盖**请求体 userId导致 VIP 审核通过时角色绑到店员而非申请人。 - 美化了 Input圆角12px、高度48px、柔和背景色、Button蓝色渐变、阴影、圆角14px、验证码按钮与输入框等高、倒计时优化
- 修复:改为 `if (userRole.getUserId() == null && loginUser != null) userRole.setUserId(loginUser.getUserId());`(仅当请求体未传 userId 时回退到登录用户)。 - 弹窗整体:圆角加大、内边距增加、宽度收窄
- 影响VIP 审核 `addUserRole({ userId: item.userId, ... })` 现在能正确把角色绑给申请人;其它不传 userId 的调用方行为不变。
- 注意UserRole 的 `tenantId` 由 MyBatis-Plus 多租户插件按请求头自动写入 INSERT前端传的 tenantId 仅作冗余。 ## 开发者登录弹窗样式改为红色系
- 文件:`src/pages/user/about/index.tsx`
- Input 边框:`transparent``#e53e3e`(红色),背景 `#f7f8fa``#fff5f5`(淡红)
- 获取验证码按钮:激活态添加 `backgroundColor: #e53e3e``borderColor: #e53e3e`
- 登录按钮:渐变从蓝色 `#4f8cff→#3b6fd4` 改为红色 `#fc5c5c→#e53e3e`,阴影同步改为红色
## 关于我们页面介绍内容改写
- 文件:`src/pages/user/about/index.tsx`
- 公司南宁市网宿信息科技有限公司品牌威数谱软件websopy
- 重写品牌故事三个段落、核心业务6项软件相关、联系我们公司名称/总部/电话/邮箱/官网)、版权信息
- 头部 Logo 文字「鑫」→「威」,版本号显示 websopy v1.0.0
## VIP 概念替换为「开发者」(文案统一)
- 起因:用户要求把 `pages/user/vip-upgrade/index` 的 VIP 概念换成「开发者」。后台审核页 `vip-review` 已定义 `VIP_ROLE_NAME='开发者'`,概念本就一致。
- 改动文件与要点:
- `vip-upgrade/index.tsx` + `index.config.ts`:导航栏/分享标题/主副标题/状态说明/温馨提示/权益区块标题及权益项描述全部「VIP会员」→「开发者」顶部图标 👑→🔰;表单标签「门店名称/门店地址」→「开发团队/公司地址」placeholder、toast 同步),底层字段 realName/address 不变。
- `user.tsx`用户中心入口「升级VIP会员」👑→「申请开发者」🔰。
- `store/center/index.tsx`门店中心入口「VIP会员审核/审核客户VIP会员申请」👑→「开发者审核/审核客户开发者申请」🔰。
- `vip-review/index.tsx`:导航栏标题、通过/驳回弹窗文案、审核说明、列表字段标签(门店名称/门店地址→开发团队/公司地址)统一为「开发者」。
- 注意:仅改可见文案与图标,**未重命名**页面路由/文件夹vip-upgrade、vip-review、变量名VIP_ROLE_CODE、pendingVipCount 等及定价逻辑dealerPrice/VIP 状态判断仍保留原标识符,因对应后端角色与缓存 key
- 用户确认方式:先给文案对照表,经 AskUserQuestion 确认表单标签与图标及范围后执行。
## VIP 升级页新增「所在城市」选择
- 文件:`src/pages/user/vip-upgrade/index.tsx``src/api/shop/shopDealerApply/model/index.ts`
- 在「办公地址」上方新增「所在城市 *」字段:复用微信原生 `Picker mode='region'`(省市区三级),与 `pages/user/address-edit.tsx` 风格一致。
- 状态:`cityValue: string[]` + 派生 `cityText`(以空格连接);`Picker``disabled` 跟随 `isReadonly`(审核中/已通过只读)。
- `ShopDealerApply` 模型新增 `city?: string`(注释:省 市 区,空格分隔)。
- 提交时 `addShopDealerApply` 增加 `city: cityText`;读取历史申请时 `setCityValue(latest.city.split(' '))`;保存校验增加「请选择所在城市」。
- 注意:仅前端扩展字段,后端是否落库 `city` 存疑(模型此前只有 address需后端 schema 支持才能真正持久化。

View File

@@ -32,6 +32,8 @@ export interface ShopDealerApply {
updateTime?: string; updateTime?: string;
// 门店名称 // 门店名称
merchantName?: string; merchantName?: string;
// 所在城市(省 市 区,以空格分隔)
city?: string;
// 门店地址 // 门店地址
address?: string; address?: string;
} }

View File

@@ -45,9 +45,9 @@ const FEATURE_CARDS = [
}, },
{ {
key: 'vip-review', key: 'vip-review',
icon: '👑', icon: '🔰',
title: 'VIP会员审核', title: '开发者审核',
desc: '审核客户VIP会员申请', desc: '审核客户开发者身份的申请',
url: '/pages/user/vip-review/index', url: '/pages/user/vip-review/index',
color: '#7c3aed', color: '#7c3aed',
bgColor: '#ede9fe', bgColor: '#ede9fe',

View File

@@ -132,23 +132,29 @@ const AboutPage: React.FC = () => {
{/* 头部品牌区 */} {/* 头部品牌区 */}
<View className='bg-white py-10 flex flex-col items-center'> <View className='bg-white py-10 flex flex-col items-center'>
<View className='w-20 h-20 rounded-2xl bg-gradient-to-br from-blue-400 to-blue-600 flex items-center justify-center shadow-lg mb-4'> <View className='w-20 h-20 rounded-2xl bg-gradient-to-br from-blue-400 to-blue-600 flex items-center justify-center shadow-lg mb-4'>
<Text className='text-white text-4xl font-bold'></Text> <Text className='text-white text-4xl font-bold'></Text>
</View> </View>
<Text className='text-xl font-bold text-gray-800'></Text> <Text className='text-xl font-bold text-gray-800'></Text>
<Text className='text-sm text-gray-400 mt-1'> v1.0.0</Text> <Text className='text-sm text-gray-400 mt-1'>websopy v1.0.0</Text>
</View> </View>
{/* 公司简介 */} {/* 公司简介 / 品牌故事 */}
<View className='bg-white mx-3 mt-3 rounded-xl p-4' style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }}> <View className='bg-white mx-3 mt-3 rounded-xl p-4' style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }}>
<Text className='text-base font-medium text-gray-800 mb-3 block'></Text> <Text className='text-base font-medium text-gray-800 mb-3 block'></Text>
<Text className='text-sm text-gray-600 leading-relaxed'> <Text className='text-sm text-gray-600 leading-relaxed'>
websopy宿
"让每一家企业
都能轻松用上专业的软件"使
</Text> </Text>
<Text className='text-sm text-gray-600 leading-relaxed mt-2'> <Text className='text-sm text-gray-600 leading-relaxed mt-2'>
"诚信经营、服务至上" "专业、务实、共赢"
便
</Text>
<Text className='text-sm text-gray-600 leading-relaxed mt-2'>
</Text> </Text>
</View> </View>
@@ -156,19 +162,19 @@ const AboutPage: React.FC = () => {
<View className='bg-white mx-3 mt-3 rounded-xl p-4' style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }}> <View className='bg-white mx-3 mt-3 rounded-xl p-4' style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }}>
<Text className='text-base font-medium text-gray-800 mb-3 block'></Text> <Text className='text-base font-medium text-gray-800 mb-3 block'></Text>
{[ {[
{ icon: '📺', title: '家电零售', desc: '电视、冰箱、洗衣机等全品类家电销售' }, { icon: '🖥️', title: '企业管理软件', desc: 'ERP / CRM / OA 等数字化管理工具' },
{ icon: '❄️', title: '空调服务', desc: '空调销售、安装、加氟、清洗及维修' }, { icon: '🌐', title: '品牌官网建设', desc: '企业官网、品牌站、营销落地页定制' },
{ icon: '🍳', title: '厨房电器', desc: '油烟机、燃气灶、热水器等厨卫电器' }, { icon: '📱', title: '移动应用开发', desc: '微信小程序、跨端 APP 定制开发' },
{ icon: '🛠️', title: '安装维修', desc: '专业师傅上门安装、检测及故障维修' }, { icon: '🔗', title: '系统集成对接', desc: '第三方平台 API 对接与数据打通' },
{ icon: '🔧', title: '保养维护', desc: '定期清洗保养,延长家电使用寿命' }, { icon: '📊', title: '数据智能分析', desc: '经营数据可视化与业务洞察' },
{ icon: '✅', title: '品质保障', desc: '正品货源、透明报价、售后无忧' }, { icon: '✅', title: '技术服务支持', desc: '部署运维、培训陪跑、售后无忧' },
].map((item, idx) => ( ].map((item, idx) => (
<View <View
key={idx} key={idx}
className={`flex items-start gap-3 py-3 ${idx < 5 ? 'border-b border-gray-50' : ''}`} className={`flex items-start gap-3 py-3 ${idx < 5 ? 'border-b border-gray-50' : ''}`}
> >
<Text className='text-2xl mt-0.5'>{item.icon}</Text> <Text className='text-2xl mt-0.5'>{item.icon}</Text>
<View className='flex-1'> <View className='flex-1 flex flex-col'>
<Text className='text-sm font-medium text-gray-700'>{item.title}</Text> <Text className='text-sm font-medium text-gray-700'>{item.title}</Text>
<Text className='text-xs text-gray-400 mt-0.5'>{item.desc}</Text> <Text className='text-xs text-gray-400 mt-0.5'>{item.desc}</Text>
</View> </View>
@@ -181,10 +187,12 @@ const AboutPage: React.FC = () => {
<Text className='text-base font-medium text-gray-800 mb-3 block'></Text> <Text className='text-base font-medium text-gray-800 mb-3 block'></Text>
<View className='flex flex-col gap-2'> <View className='flex flex-col gap-2'>
{[ {[
{ label: '经营部名称', value: '威硕谱软件' }, { label: '公司名称', value: '南宁市网宿信息科技有限公司' },
{ label: '经营地址', value: '大新里南718号' }, { label: '品牌名称', value: '威数谱软件websopy' },
{ label: '联系电话', value: '18269229683' }, { label: '公司总部', value: '南宁市良庆区五象大道401号五象航洋城总部基地1号楼1226室' },
{ label: '营业时间', value: '9:00 ~ 18:00' }, { label: '联系电话', value: '0771-5386339' },
{ label: '电子邮箱', value: 'websopy@163.com' },
{ label: '官方网站', value: 'websoft.top / websopy.com' },
].map((item, idx) => ( ].map((item, idx) => (
<View key={idx} className='flex items-start justify-between'> <View key={idx} className='flex items-start justify-between'>
<Text className='text-sm text-gray-500 flex-shrink-0'>{item.label}</Text> <Text className='text-sm text-gray-500 flex-shrink-0'>{item.label}</Text>
@@ -196,78 +204,131 @@ const AboutPage: React.FC = () => {
{/* 底部版权 */} {/* 底部版权 */}
<View className='flex flex-col items-center py-8' onClick={handleCopyrightClick}> <View className='flex flex-col items-center py-8' onClick={handleCopyrightClick}>
<Text className='text-xs text-gray-400'>Copyright © 2024 </Text> <Text className='text-xs text-gray-400'>Copyright © 2024 宿</Text>
<Text className='text-xs text-gray-400 mt-1'>All Rights Reserved</Text> <Text className='text-xs text-gray-400 mt-1'> websopy · All Rights Reserved</Text>
</View> </View>
{/* 隐藏的开发者登录弹窗 */} {/* 隐藏的开发者登录弹窗 */}
{showLogin && ( {showLogin && (
<View <View
className='fixed inset-0 z-[9999] flex items-center justify-center' className='fixed inset-0 z-[9999] flex items-center justify-center'
style={{ backgroundColor: 'rgba(0,0,0,0.5)' }} style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}
onClick={handleCloseLogin} onClick={handleCloseLogin}
catchMove catchMove
> >
<View <View
className='rounded-2xl bg-white' className='rounded-3xl bg-white'
style={{ width: '340px', padding: '24px 20px' }} style={{ width: '320px', padding: '32px 24px' }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<View className='mb-3 flex items-center justify-between'> {/* 标题栏 */}
<Text className='text-lg font-bold text-gray-800'></Text> <View className='mb-2 flex items-center justify-between'>
<Text className='text-xl font-bold text-gray-800'></Text>
<Text <Text
className='text-lg text-gray-400' className='text-xl text-gray-300 leading-none cursor-pointer active:opacity-60'
style={{ padding: '4px 8px' }} style={{ padding: '6px', lineHeight: 1 }}
onClick={handleCloseLogin} onClick={handleCloseLogin}
> >
</Text> </Text>
</View> </View>
<Text className='mb-5 block text-xs text-gray-400'> <Text className='mb-6 block text-xs text-gray-400 leading-relaxed'>
使+ 使+
</Text> </Text>
<View className='mb-3'> {/* 手机号输入框 */}
<View className='mb-4'>
<Input <Input
type='number' type='number'
placeholder='请输入手机号码' placeholder='请输入手机号码'
maxLength={11} maxLength={11}
value={formData.phone || ''} value={formData.phone || ''}
onChange={(val) => setFormData({ ...formData, phone: val })} onChange={(val) => setFormData({ ...formData, phone: val })}
style={{ backgroundColor: '#f5f5f5', borderRadius: '8px' }} style={{
backgroundColor: '#fff5f5',
borderRadius: '12px',
height: '48px',
paddingLeft: '16px',
paddingRight: '16px',
fontSize: '15px',
border: '1.5px solid #e53e3e',
boxSizing: 'border-box',
}}
/> />
</View> </View>
<View className='mb-6 flex items-center bg-white rounded-lg pr-2'> {/* 验证码输入 + 获取按钮 */}
<View className='mb-8 flex items-center gap-3'>
<View className='flex-1'>
<Input <Input
type='number' type='number'
placeholder='请输入6位验证码' placeholder='请输入6位验证码'
maxLength={6} maxLength={6}
value={formData.code || ''} value={formData.code || ''}
onChange={(val) => setFormData({ ...formData, code: val })} onChange={(val) => setFormData({ ...formData, code: val })}
style={{ backgroundColor: '#f5f5f5', borderRadius: '8px' }} style={{
backgroundColor: '#fff5f5',
borderRadius: '12px',
height: '48px',
paddingLeft: '16px',
paddingRight: '12px',
fontSize: '15px',
border: '1.5px solid #e53e3e',
boxSizing: 'border-box',
}}
/> />
</View>
<Button <Button
size='small' size='small'
type={countdown > 0 ? 'default' : 'primary'} type={countdown > 0 ? 'default' : 'primary'}
loading={sendingCode} loading={sendingCode}
disabled={sendingCode || countdown > 0} disabled={sendingCode || countdown > 0}
onClick={handleSendCode} onClick={handleSendCode}
style={{
height: '48px',
minWidth: '110px',
borderRadius: '12px',
fontSize: '13px',
fontWeight: 500,
flexShrink: 0,
...(countdown > 0 ? {
backgroundColor: '#f0f0f0',
color: '#999',
} : {
backgroundColor: '#e53e3e',
borderColor: '#e53e3e',
}),
}}
> >
{countdown > 0 ? `${countdown}s` : sendingCode ? '发送中' : '获取验证码'} {countdown > 0 ? `${countdown}s 后重发` : sendingCode ? '发送中' : '获取验证码'}
</Button> </Button>
</View> </View>
{/* 登录按钮 */}
<View className='flex justify-center'> <View className='flex justify-center'>
<Button <Button
block
type='primary' type='primary'
size='large' size='large'
className='w-full rounded-lg p-2'
loading={loading} loading={loading}
disabled={loading} disabled={loading}
onClick={handleLogin} onClick={handleLogin}
style={{
height: '50px',
borderRadius: '14px',
fontSize: '17px',
fontWeight: 600,
letterSpacing: '2px',
background: loading
? '#c0c0c0'
: 'linear-gradient(135deg, #fc5c5c 0%, #e53e3e 100%)',
border: 'none',
boxShadow: loading
? 'none'
: '0 6px 20px rgba(229, 62, 62, 0.35)',
}}
> >
{loading ? '登录中...' : '登录'} {loading ? '登录中...' : '登 录'}
</Button> </Button>
</View> </View>
</View> </View>

View File

@@ -101,8 +101,8 @@ const UserPage: React.FC = () => {
}) })
const menuItems = [ const menuItems = [
// 升级VIP会员 - 醒目样式 // 申请成为开发者 - 醒目样式
{ icon: '👑', label: '升级VIP会员', url: '/pages/user/vip-upgrade/index', highlight: true, requireAuth: true }, { icon: '🔰', label: '申请成为开发者', url: '/pages/user/vip-upgrade/index', highlight: true, requireAuth: true },
// 门店中心:仅门店店员/店长显示(通过 /shop/shop-store-user/my 判断) // 门店中心:仅门店店员/店长显示(通过 /shop/shop-store-user/my 判断)
...(storeInfo ? [{ icon: '🏪', label: '门店中心', url: '/pages/store/center/index', requireAuth: true }] : []), ...(storeInfo ? [{ icon: '🏪', label: '门店中心', url: '/pages/store/center/index', requireAuth: true }] : []),
{ icon: '💰', label: '我的钱包', url: '/pages/user/wallet', requireAuth: true }, { icon: '💰', label: '我的钱包', url: '/pages/user/wallet', requireAuth: true },

View File

@@ -9,7 +9,7 @@ import { TenantId } from '@/config/app'
import { getMyClerk } from '@/api/shop/shopStoreUser' import { getMyClerk } from '@/api/shop/shopStoreUser'
definePageConfig({ definePageConfig({
navigationBarTitleText: 'VIP会员审核', navigationBarTitleText: '开发者审核',
}) })
// Tab 配置 // Tab 配置
@@ -24,7 +24,7 @@ const TABS: { key: TabKey; label: string; status: number }[] = [
// VIP 角色信息(对应 system/role 表) // VIP 角色信息(对应 system/role 表)
// 角色 ID 不写死,按 roleCode + 当前租户ID 动态查询 // 角色 ID 不写死,按 roleCode + 当前租户ID 动态查询
const VIP_ROLE_CODE = 'developer' const VIP_ROLE_CODE = 'developer'
const VIP_ROLE_NAME = '认证开发者' const VIP_ROLE_NAME = '开发者'
// 获取当前租户 ID登录时写入 storage未登录时回退到默认租户 // 获取当前租户 ID登录时写入 storage未登录时回退到默认租户
function getCurrentTenantId(): number | string | undefined { function getCurrentTenantId(): number | string | undefined {
@@ -181,7 +181,7 @@ const VipReviewPage: React.FC = () => {
const handleApprove = (item: ShopDealerApply) => { const handleApprove = (item: ShopDealerApply) => {
Taro.showModal({ Taro.showModal({
title: '确认通过', title: '确认通过',
content: `确认通过「${item.realName || item.merchantName || '该用户'}」的VIP会员申请?\n\n请确认已实地考察核实门店名称和地址。`, content: `确认通过「${item.realName || item.merchantName || '该用户'}」的开发者申请?\n\n请确认已实地考察核实开发团队名称与公司地址。`,
confirmColor: '#22c55e', confirmColor: '#22c55e',
success: async (res) => { success: async (res) => {
if (!res.confirm) return if (!res.confirm) return
@@ -216,7 +216,7 @@ const VipReviewPage: React.FC = () => {
const handleReject = (item: ShopDealerApply) => { const handleReject = (item: ShopDealerApply) => {
Taro.showModal({ Taro.showModal({
title: '驳回申请', title: '驳回申请',
content: `确认驳回「${item.realName || item.merchantName || '该用户'}」的VIP会员申请?`, content: `确认驳回「${item.realName || item.merchantName || '该用户'}」的开发者申请?`,
confirmColor: '#ef4444', confirmColor: '#ef4444',
success: async (res) => { success: async (res) => {
if (!res.confirm) return if (!res.confirm) return
@@ -291,12 +291,12 @@ const VipReviewPage: React.FC = () => {
{renderStatusTag(item.applyStatus!)} {renderStatusTag(item.applyStatus!)}
</View> </View>
{/* 门店信息 */} {/* 开发团队及公司信息 */}
<View className='bg-gray-50 rounded-lg p-3 mb-3'> <View className='bg-gray-50 rounded-lg p-3 mb-3'>
<View className='flex items-start gap-2 mb-2'> <View className='flex items-start gap-2 mb-2'>
<Text className='text-xs text-gray-400 mt-0.5'>🏪</Text> <Text className='text-xs text-gray-400 mt-0.5'>🏪</Text>
<View className='flex-1'> <View className='flex-1'>
<Text className='text-xs text-gray-400 block'></Text> <Text className='text-xs text-gray-400 block'></Text>
<Text className='text-sm text-gray-700 block mt-0.5'> <Text className='text-sm text-gray-700 block mt-0.5'>
{item.merchantName || item.realName || '-'} {item.merchantName || item.realName || '-'}
</Text> </Text>
@@ -305,7 +305,7 @@ const VipReviewPage: React.FC = () => {
<View className='flex items-start gap-2'> <View className='flex items-start gap-2'>
<Text className='text-xs text-gray-400 mt-0.5'>📍</Text> <Text className='text-xs text-gray-400 mt-0.5'>📍</Text>
<View className='flex-1'> <View className='flex-1'>
<Text className='text-xs text-gray-400 block'></Text> <Text className='text-xs text-gray-400 block'></Text>
<Text className='text-sm text-gray-700 block mt-0.5'> <Text className='text-sm text-gray-700 block mt-0.5'>
{item.address || '-'} {item.address || '-'}
</Text> </Text>
@@ -371,7 +371,7 @@ const VipReviewPage: React.FC = () => {
<View className='flex-1'> <View className='flex-1'>
<Text className='text-xs text-green-700 block font-medium'></Text> <Text className='text-xs text-green-700 block font-medium'></Text>
<Text className='text-xs text-green-600 block mt-1 leading-relaxed'> <Text className='text-xs text-green-600 block mt-1 leading-relaxed'>
VIP会员
</Text> </Text>
</View> </View>
</View> </View>

View File

@@ -1,5 +1,5 @@
export default { export default {
navigationBarTitleText: '升级VIP会员', navigationBarTitleText: '申请成为开发者',
enableShareAppMessage: true, enableShareAppMessage: true,
enableShareTimeline: true, enableShareTimeline: true,
} }

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { View, Text, Input } from '@tarojs/components' import { View, Text, Input, Picker } from '@tarojs/components'
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import { useUser } from '@/hooks/useUser' import { useUser } from '@/hooks/useUser'
import { useShare } from '@/hooks/useShare' import { useShare } from '@/hooks/useShare'
@@ -7,7 +7,7 @@ import { addShopDealerApply, listShopDealerApply } from '@/api/shop/shopDealerAp
import type { ShopDealerApply } from '@/api/shop/shopDealerApply/model' import type { ShopDealerApply } from '@/api/shop/shopDealerApply/model'
definePageConfig({ definePageConfig({
navigationBarTitleText: '升级VIP会员', navigationBarTitleText: '申请成为开发者',
enableShareAppMessage: true, enableShareAppMessage: true,
enableShareTimeline: true, enableShareTimeline: true,
}) })
@@ -16,11 +16,14 @@ const VipUpgradePage: React.FC = () => {
const { user, isLoggedIn } = useUser() const { user, isLoggedIn } = useUser()
// 分享 / 朋友圈 // 分享 / 朋友圈
useShare({ useShare({
title: '升级VIP会员,享专属优惠价', title: '成为认证开发者,享专属权益',
path: '/pages/user/vip-upgrade', path: '/pages/user/vip-upgrade',
}) })
const [realName, setRealName] = useState('') const [realName, setRealName] = useState('')
const [address, setAddress] = useState('') const [address, setAddress] = useState('')
// 所在城市(省市区三级,使用微信原生地区选择器)
const [cityValue, setCityValue] = useState<string[]>([])
const cityText = cityValue.join(' ')
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [existingApply, setExistingApply] = useState<ShopDealerApply | null>(null) const [existingApply, setExistingApply] = useState<ShopDealerApply | null>(null)
@@ -30,7 +33,7 @@ const VipUpgradePage: React.FC = () => {
return return
} }
if (user) { if (user) {
// 门店名称和地址统一从 shop-dealer-apply 表读取 // 开发团队名称与公司地址统一从 shop-dealer-apply 表读取
listShopDealerApply({ userId: (user as any)?.userId || (user as any)?.id }) listShopDealerApply({ userId: (user as any)?.userId || (user as any)?.id })
.then(data => { .then(data => {
if (!data || data.length === 0) return if (!data || data.length === 0) return
@@ -40,6 +43,7 @@ const VipUpgradePage: React.FC = () => {
setExistingApply(latest) setExistingApply(latest)
setRealName(latest.realName || '') setRealName(latest.realName || '')
setAddress(latest.address || '') setAddress(latest.address || '')
setCityValue(latest.city ? String(latest.city).split(' ').filter(Boolean) : [])
} }
}) })
.catch(() => {}) .catch(() => {})
@@ -48,11 +52,15 @@ const VipUpgradePage: React.FC = () => {
const handleSave = async () => { const handleSave = async () => {
if (!realName.trim()) { if (!realName.trim()) {
Taro.showToast({ title: '请输入门店名称', icon: 'none' }) Taro.showToast({ title: '请输入开发团队名称', icon: 'none' })
return
}
if (!cityText) {
Taro.showToast({ title: '请选择所在城市', icon: 'none' })
return return
} }
if (!address.trim()) { if (!address.trim()) {
Taro.showToast({ title: '请输入门店地址', icon: 'none' }) Taro.showToast({ title: '请输入公司地址', icon: 'none' })
return return
} }
setLoading(true) setLoading(true)
@@ -60,6 +68,7 @@ const VipUpgradePage: React.FC = () => {
await addShopDealerApply({ await addShopDealerApply({
userId: (user as any)?.userId || (user as any)?.id, userId: (user as any)?.userId || (user as any)?.id,
realName: realName.trim(), realName: realName.trim(),
city: cityText,
address: address.trim(), address: address.trim(),
applyType: 10, // 需后台审核 applyType: 10, // 需后台审核
applyStatus: 10, // 待审核 applyStatus: 10, // 待审核
@@ -91,11 +100,11 @@ const VipUpgradePage: React.FC = () => {
<View className='absolute -bottom-6 -left-6 w-24 h-24 rounded-full opacity-15' style={{ background: 'radial-gradient(circle, #ffffff, transparent)' }} /> <View className='absolute -bottom-6 -left-6 w-24 h-24 rounded-full opacity-15' style={{ background: 'radial-gradient(circle, #ffffff, transparent)' }} />
<View className='relative z-10 flex flex-col items-center'> <View className='relative z-10 flex flex-col items-center'>
<View className='w-16 h-16 rounded-full bg-white bg-opacity-20 flex items-center justify-center mb-3'> <View className='w-16 h-16 rounded-full bg-white bg-opacity-20 flex items-center justify-center mb-3'>
<Text className='text-3xl'>👑</Text> <Text className='text-3xl'>🔰</Text>
</View> </View>
<Text className='text-white text-xl font-bold'>VIP会员</Text> <Text className='text-white text-xl font-bold'></Text>
<Text className='text-white text-opacity-80 text-sm mt-1'> <Text className='text-white text-opacity-80 text-sm mt-1'>
{existingApply?.applyStatus === 20 ? '恭喜您已是VIP会员' : '填写门店信息申请VIP会员资格'} {existingApply?.applyStatus === 20 ? '恭喜您已成为开发者' : '填写开发团队及公司地址,申请成为开发者身份'}
</Text> </Text>
</View> </View>
</View> </View>
@@ -115,8 +124,8 @@ const VipUpgradePage: React.FC = () => {
</Text> </Text>
<Text className='text-gray-500 text-xs mt-1 block leading-relaxed'> <Text className='text-gray-500 text-xs mt-1 block leading-relaxed'>
{existingApply.applyStatus === 10 {existingApply.applyStatus === 10
? '您的VIP申请正在审核中,请耐心等待。审核结果将通过消息通知您。' ? '您的开发者申请正在审核中,请耐心等待。审核结果将通过消息通知您。'
: '恭喜!您的VIP会员申请已审核通过,现在可以享受全部VIP专属权益。'} : '恭喜!您的开发者申请已审核通过,现在可以享受全部开发者专属权益。'}
</Text> </Text>
</View> </View>
</View> </View>
@@ -133,7 +142,7 @@ const VipUpgradePage: React.FC = () => {
<View className='flex-1'> <View className='flex-1'>
<Text className='text-gray-800 text-sm font-medium block'></Text> <Text className='text-gray-800 text-sm font-medium block'></Text>
<Text className='text-gray-500 text-xs mt-1 block leading-relaxed'> <Text className='text-gray-500 text-xs mt-1 block leading-relaxed'>
VIP会员专属权
</Text> </Text>
</View> </View>
</View> </View>
@@ -142,12 +151,12 @@ const VipUpgradePage: React.FC = () => {
{/* 表单 */} {/* 表单 */}
<View className={`${existingApply ? 'mt-3' : ''} mx-3 mt-3 bg-white rounded-xl overflow-hidden`}> <View className={`${existingApply ? 'mt-3' : ''} mx-3 mt-3 bg-white rounded-xl overflow-hidden`}>
{/* 门店名称 */} {/* 开发团队 */}
<View className='px-4 py-4 border-b border-gray-50'> <View className='px-4 py-4 border-b border-gray-50'>
<Text className='text-sm text-gray-700 font-medium block mb-2'> <Text className='text-red-500'>*</Text></Text> <Text className='text-sm text-gray-700 font-medium block mb-2'> <Text className='text-red-500'>*</Text></Text>
<Input <Input
className='w-full text-sm text-gray-800 bg-gray-50 rounded-lg px-3 py-3' className='w-full text-sm text-gray-800 bg-gray-50 rounded-lg px-3 py-3'
placeholder='请输入您的门店名称' placeholder='请输入您的开发团队名称'
value={realName} value={realName}
onInput={(e: any) => setRealName(e.detail.value)} onInput={(e: any) => setRealName(e.detail.value)}
maxlength={50} maxlength={50}
@@ -155,12 +164,25 @@ const VipUpgradePage: React.FC = () => {
/> />
</View> </View>
{/* 门店地址 */} {/* 所在城市 */}
<Picker mode='region' value={cityValue} onChange={(e: any) => setCityValue(e.detail.value || [])} disabled={isReadonly}>
<View className='px-4 py-4 border-b border-gray-50'>
<Text className='text-sm text-gray-700 font-medium block mb-2'> <Text className='text-red-500'>*</Text></Text>
<View className='w-full text-sm bg-gray-50 rounded-lg px-3 py-3 flex items-center justify-between'>
<Text className={cityText ? 'text-gray-800' : 'text-gray-400'}>
{cityText || '请选择所在城市'}
</Text>
<Text className='text-gray-300 text-xs'></Text>
</View>
</View>
</Picker>
{/* 公司地址 */}
<View className='px-4 py-4'> <View className='px-4 py-4'>
<Text className='text-sm text-gray-700 font-medium block mb-2'> <Text className='text-red-500'>*</Text></Text> <Text className='text-sm text-gray-700 font-medium block mb-2'> <Text className='text-red-500'>*</Text></Text>
<Input <Input
className='w-full text-sm text-gray-800 bg-gray-50 rounded-lg px-3 py-3' className='w-full text-sm text-gray-800 bg-gray-50 rounded-lg px-3 py-3'
placeholder='请输入您的门店详细地址' placeholder='请输入您的办公地址'
value={address} value={address}
onInput={(e: any) => setAddress(e.detail.value)} onInput={(e: any) => setAddress(e.detail.value)}
maxlength={100} maxlength={100}
@@ -169,15 +191,15 @@ const VipUpgradePage: React.FC = () => {
</View> </View>
</View> </View>
{/* VIP权益预览 */} {/* 开发者权益预览 */}
<View className='mx-3 mt-4'> <View className='mx-3 mt-4'>
<Text className='text-base font-medium text-gray-800 mb-3 block'>VIP会员专属权</Text> <Text className='text-base font-medium text-gray-800 mb-3 block'></Text>
<View className='grid grid-cols-2 gap-3'> <View className='grid grid-cols-2 gap-3'>
{[ {[
{ icon: '💎', title: '更高佣金', desc: '享受高额团队佣金' }, { icon: '💎', title: '更高佣金', desc: '享受高额团队佣金' },
{ icon: '🎁', title: '专属折扣', desc: '购物享VIP专属价' }, { icon: '🎁', title: '专属折扣', desc: '购物享开发者专属价' },
{ icon: '⚡', title: '优先发货', desc: '订单优先处理配送' }, { icon: '⚡', title: '优先发货', desc: '订单优先处理配送' },
{ icon: '🎧', title: '专属客服', desc: '一对一VIP服务' }, { icon: '🎧', title: '专属客服', desc: '一对一开发者服务' },
].map(item => ( ].map(item => (
<View key={item.title} className='bg-white rounded-xl p-4 flex items-center gap-3'> <View key={item.title} className='bg-white rounded-xl p-4 flex items-center gap-3'>
<View className='w-10 h-10 rounded-full bg-green-50 flex items-center justify-center flex-shrink-0'> <View className='w-10 h-10 rounded-full bg-green-50 flex items-center justify-center flex-shrink-0'>