feat(user): 合并切换开发者菜单项状态并更新开发者中心UI
- 用户菜单中根据 isDeveloper 字段条件展示“申请成为开发者”或“进入开发者中心” - 已审核通过用户菜单显示“进入开发者中心”,并设置高亮样式 - 去除冗余的独立“开发者中心”菜单条目,简化菜单结构 - 重新设计开发者中心页面UI,统一为门店中心风格 - 顶部展示开发者头像及昵称手机号信息 - 功能卡片展示“我的应用”、“API Key”和“我的工单”,异步加载数量角标 - 底部添加“开发者帮助与支持”入口,替代门店订阅消息卡片 - 未登录或非开发者状态显示相应空态提示及操作按钮 - 优化登录状态与权限校验逻辑,防止页面闪烁和无权限内容显示
This commit is contained in:
44
.idea/workspace.xml
generated
44
.idea/workspace.xml
generated
@@ -4,7 +4,7 @@
|
|||||||
<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): 补充开发者审核通过时添加店员记录功能 - 引入 addShopStoreUser 接口用于新增门店店员记录 - 新增 clerkStoreId 和 clerkTenantId 状态,保存当前审核店员的门店和租户信息 - 在审核通过后调用 addShopStoreUser,添加申请人为当前门店店员 - 保证只有当 clerkStoreId 存在时才执行新增操作 - 调整平台管理页 UI,使其与门店中心保持一致风格 - 门店中心及平台管理入口权限调整,仅超级管理员可访问 - 用户菜单中平台管理和门店中心入口现基于 isSuperAdmin 字段控制 - 优化登录及权限校验流程,避免权限不足时页面闪烁显示 - 更新工作记录文档,补充审核通过流程中新添加的店员记录步骤" />
|
<list default="true" id="2de94e4f-0587-4c9b-8bfd-e87e0ae95b81" name="更改" comment="fix(auth): 统一超级管理员标识为布尔值true - 将所有页面和菜单中超级管理员校验由数字1改为布尔true - 平台管理、门店中心菜单项仅在isSuperAdmin===true时显示 - 门店中心页面移除店员门槛,改为超级管理员访问限制 - 非超级管理员访问门店中心弹窗提示并返回 - 首页工作台入口及相关访问权限判定切换为布尔判断 - 优化首屏加载状态,避免权限校验闪烁和误判" />
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
@@ -116,23 +116,7 @@
|
|||||||
<workItem from="1784133736973" duration="4614000" />
|
<workItem from="1784133736973" duration="4614000" />
|
||||||
<workItem from="1784585070286" duration="3047000" />
|
<workItem from="1784585070286" duration="3047000" />
|
||||||
<workItem from="1784638429525" duration="16147000" />
|
<workItem from="1784638429525" duration="16147000" />
|
||||||
<workItem from="1784798575885" duration="2914000" />
|
<workItem from="1784798575885" duration="3338000" />
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00022" summary="feat(invite): 支持已登录用户直接加入应用 - 后端accept接口code参数改为可选,支持通过Authorization头识别登录用户 - 已登录用户加入时不再弹手机号授权,前端调用新增的doJoinAppForLoggedInUser方法 - 未注册用户仍通过手机号授权码code加入,调用doJoinAppForNewUser方法 - 拆分前端加入逻辑,新增handleConfirmJoin统一处理已登录加入流程 - 优化按钮交互,已登录状态下按钮变为普通点击,移除协议强制勾选 - 错误处理和状态提示完善,加入成功后自动跳转首页">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1775966172496</created>
|
|
||||||
<option name="number" value="00022" />
|
|
||||||
<option name="presentableId" value="LOCAL-00022" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1775966172496</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00023" summary="feat(developer): 完成小程序开发者中心和企业控制台改造 - 设计并实现了开发者中心与企业控制台两大模块 - 按用户角色区分开发者和企业客户,支持多项目类型及成员管理 - 新增项目管理、应用管理、API Key管理及成员邀请等多功能页面 - 实现应用版本发布、消息通知中心、权限审批与开发者申请流程 - 完成CI/CD流水线、运营监控、发票管理、SSO单点登录功能 - 搭建SDK下载中心、工单系统、FAQ系统、数据导入导出等模块 - 优化后端API,支持已登录和未注册用户不同加入应用流程 - 前端按钮统一采用微信手机号授权,完善用户授权体验 - 修复多个页面的JSX语法错误及依赖导入问题,替换部分组件库 - 增加详细的类型定义文件,提升项目类型安全 - 新增超过55个页面及60个API接口,扩展应用功能和服务体系 - 完成全面的样式设计,实现一致的视觉风格和交互体验">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1776018406658</created>
|
|
||||||
<option name="number" value="00023" />
|
|
||||||
<option name="presentableId" value="LOCAL-00023" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1776018406658</updated>
|
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00024" summary="feat(api-keys): 优化隐私协议同意逻辑及样式 - 修正api-keys样式导入路径,改为developer路径 - 在开发者申请页面增加服务协议和隐私政策勾选框 - 提交时校验协议是否已勾选,未勾选时提示用户 - 优化申请页面协议区域样式及交互 - 在用户验证页面添加隐私政策同意勾选框 - 提交用户验证表单时检查协议同意状态 - 增加打开服务协议和隐私政策的链接跳转 - 更新项目配置,增加passport/webview路由配置 - 修复createTicket函数中日期格式正则表达式问题">
|
<task id="LOCAL-00024" summary="feat(api-keys): 优化隐私协议同意逻辑及样式 - 修正api-keys样式导入路径,改为developer路径 - 在开发者申请页面增加服务协议和隐私政策勾选框 - 提交时校验协议是否已勾选,未勾选时提示用户 - 优化申请页面协议区域样式及交互 - 在用户验证页面添加隐私政策同意勾选框 - 提交用户验证表单时检查协议同意状态 - 增加打开服务协议和隐私政策的链接跳转 - 更新项目配置,增加passport/webview路由配置 - 修复createTicket函数中日期格式正则表达式问题">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -510,7 +494,23 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1784802336157</updated>
|
<updated>1784802336157</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="71" />
|
<task id="LOCAL-00071" summary="feat(user): 合并并切换“申请开发者”菜单项状态 - 在用户菜单中根据 isDeveloper 字段切换显示“申请成为开发者”或“进入开发者中心” - 已通过审核用户直接显示“进入开发者中心”且高亮显示 - 去除冗余的独立“开发者中心”菜单条目,简化菜单结构 - 调整平台管理页和门店中心入口权限为仅超级管理员可访问 - 优化登录与权限校验流程,防止权限不足时页面闪烁或无访问权限空白 - 更新相关文档,完善审核通过后店员记录添加流程">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1784802434477</created>
|
||||||
|
<option name="number" value="00071" />
|
||||||
|
<option name="presentableId" value="LOCAL-00071" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1784802434477</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00072" summary="fix(auth): 统一超级管理员标识为布尔值true - 将所有页面和菜单中超级管理员校验由数字1改为布尔true - 平台管理、门店中心菜单项仅在isSuperAdmin===true时显示 - 门店中心页面移除店员门槛,改为超级管理员访问限制 - 非超级管理员访问门店中心弹窗提示并返回 - 首页工作台入口及相关访问权限判定切换为布尔判断 - 优化首屏加载状态,避免权限校验闪烁和误判">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1784802589434</created>
|
||||||
|
<option name="number" value="00072" />
|
||||||
|
<option name="presentableId" value="LOCAL-00072" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1784802589434</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="73" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -530,8 +530,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(app): 添加应用入口文件和配置文件 - 新增 index.tsx 作为应用的主入口文件 - 新增 index.config.ts 用于应用的配置管理" />
|
|
||||||
<MESSAGE value="fix(tailwind): 更新配置以兼容微信小程序 - 启用 autoprefixer 并新增 postcss-nested 插件支持嵌套语法 - 扩展主题颜色,添加 primary 色系 - 更新 content 路径包含 public/index.html - 禁用 preflight 以移除默认样式重置 - 移除多数 corePlugins 禁用项,保留 preflight 禁用,简化兼容性配置" />
|
|
||||||
<MESSAGE value="feat(postcss): 添加插件移除微信小程序不兼容Tailwind规则 - 实现 postcss-remove-wxss-incompatible 插件 - 移除反斜杠转义的重要性修饰符类选择器(.\!xxx) - 删除依赖 :not 和兄弟选择器的 .space-[x|y]-* 规则 - 删除依赖 :not 和兄弟选择器的 .divide-[x|y]-* 规则 - 解决微信小程序 WXSS 不支持的 CSS 特性问题" />
|
<MESSAGE value="feat(postcss): 添加插件移除微信小程序不兼容Tailwind规则 - 实现 postcss-remove-wxss-incompatible 插件 - 移除反斜杠转义的重要性修饰符类选择器(.\!xxx) - 删除依赖 :not 和兄弟选择器的 .space-[x|y]-* 规则 - 删除依赖 :not 和兄弟选择器的 .divide-[x|y]-* 规则 - 解决微信小程序 WXSS 不支持的 CSS 特性问题" />
|
||||||
<MESSAGE value="fix(pay): 优化订阅号获取逻辑并调整支付组件样式 - 优先从小程序码 scene 参数读取 subscriptionNo,提升参数兼容性 - 对 scene 参数进行解码,避免编码引起的问题 - 移除支付组件价格显示处的固定颜色设置,增强样式灵活性" />
|
<MESSAGE value="fix(pay): 优化订阅号获取逻辑并调整支付组件样式 - 优先从小程序码 scene 参数读取 subscriptionNo,提升参数兼容性 - 对 scene 参数进行解码,避免编码引起的问题 - 移除支付组件价格显示处的固定颜色设置,增强样式灵活性" />
|
||||||
<MESSAGE value="fix(utils): 优化小程序端复制文本功能体验 - 小程序端直接调用原生 wx.setClipboardData,避免 Taro Promise 封装问题 - 避免微信小程序重复显示复制成功提示和误报复制失败 - 失败时仅在小程序端输出错误日志,非小程序端显示提示 - 修改首页外链跳转逻辑,支持相对路径跳转,小程序内外链复制提示提升用户体验 - 更新项目内剪切板使用规范文档,说明复制行为调整及符合相应规范要求" />
|
<MESSAGE value="fix(utils): 优化小程序端复制文本功能体验 - 小程序端直接调用原生 wx.setClipboardData,避免 Taro Promise 封装问题 - 避免微信小程序重复显示复制成功提示和误报复制失败 - 失败时仅在小程序端输出错误日志,非小程序端显示提示 - 修改首页外链跳转逻辑,支持相对路径跳转,小程序内外链复制提示提升用户体验 - 更新项目内剪切板使用规范文档,说明复制行为调整及符合相应规范要求" />
|
||||||
@@ -555,7 +553,9 @@
|
|||||||
<MESSAGE value="fix(weapp): 修复支付页nutui组件导致内容空白问题 - 替换支付页中nutui的Button、Cell、Price、Divider组件为Taro原生组件或项目自定义组件 - 修正商品名称、价格类型和支付金额显示,使用flex布局及Text组件自绘内容 - 调整按钮样式,统一为带蓝色背景和圆角的自定义样式 - 移除nutui Price组件中的thousands属性,使用项目自定义Price组件 - 解决微信小程序中nutui组件因div渲染缺失导致UI元素不显示的问题 - 保持支付流程及状态逻辑无改动,仅优化展示兼容性和稳定性" />
|
<MESSAGE value="fix(weapp): 修复支付页nutui组件导致内容空白问题 - 替换支付页中nutui的Button、Cell、Price、Divider组件为Taro原生组件或项目自定义组件 - 修正商品名称、价格类型和支付金额显示,使用flex布局及Text组件自绘内容 - 调整按钮样式,统一为带蓝色背景和圆角的自定义样式 - 移除nutui Price组件中的thousands属性,使用项目自定义Price组件 - 解决微信小程序中nutui组件因div渲染缺失导致UI元素不显示的问题 - 保持支付流程及状态逻辑无改动,仅优化展示兼容性和稳定性" />
|
||||||
<MESSAGE value="feat(user): 补充开发者审核通过时添加店员记录功能 - 引入 addShopStoreUser 接口用于新增门店店员记录 - 新增 clerkStoreId 和 clerkTenantId 状态,保存当前审核店员的门店和租户信息 - 在审核通过后调用 addShopStoreUser,添加申请人为当前门店店员 - 保证只有当 clerkStoreId 存在时才执行新增操作 - 更新工作记录文档,补充审核通过流程中新添加的店员记录步骤 - 保持原有升级开发者逻辑和接口调用不变" />
|
<MESSAGE value="feat(user): 补充开发者审核通过时添加店员记录功能 - 引入 addShopStoreUser 接口用于新增门店店员记录 - 新增 clerkStoreId 和 clerkTenantId 状态,保存当前审核店员的门店和租户信息 - 在审核通过后调用 addShopStoreUser,添加申请人为当前门店店员 - 保证只有当 clerkStoreId 存在时才执行新增操作 - 更新工作记录文档,补充审核通过流程中新添加的店员记录步骤 - 保持原有升级开发者逻辑和接口调用不变" />
|
||||||
<MESSAGE value="feat(user): 补充开发者审核通过时添加店员记录功能 - 引入 addShopStoreUser 接口用于新增门店店员记录 - 新增 clerkStoreId 和 clerkTenantId 状态,保存当前审核店员的门店和租户信息 - 在审核通过后调用 addShopStoreUser,添加申请人为当前门店店员 - 保证只有当 clerkStoreId 存在时才执行新增操作 - 调整平台管理页 UI,使其与门店中心保持一致风格 - 门店中心及平台管理入口权限调整,仅超级管理员可访问 - 用户菜单中平台管理和门店中心入口现基于 isSuperAdmin 字段控制 - 优化登录及权限校验流程,避免权限不足时页面闪烁显示 - 更新工作记录文档,补充审核通过流程中新添加的店员记录步骤" />
|
<MESSAGE value="feat(user): 补充开发者审核通过时添加店员记录功能 - 引入 addShopStoreUser 接口用于新增门店店员记录 - 新增 clerkStoreId 和 clerkTenantId 状态,保存当前审核店员的门店和租户信息 - 在审核通过后调用 addShopStoreUser,添加申请人为当前门店店员 - 保证只有当 clerkStoreId 存在时才执行新增操作 - 调整平台管理页 UI,使其与门店中心保持一致风格 - 门店中心及平台管理入口权限调整,仅超级管理员可访问 - 用户菜单中平台管理和门店中心入口现基于 isSuperAdmin 字段控制 - 优化登录及权限校验流程,避免权限不足时页面闪烁显示 - 更新工作记录文档,补充审核通过流程中新添加的店员记录步骤" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="feat(user): 补充开发者审核通过时添加店员记录功能 - 引入 addShopStoreUser 接口用于新增门店店员记录 - 新增 clerkStoreId 和 clerkTenantId 状态,保存当前审核店员的门店和租户信息 - 在审核通过后调用 addShopStoreUser,添加申请人为当前门店店员 - 保证只有当 clerkStoreId 存在时才执行新增操作 - 调整平台管理页 UI,使其与门店中心保持一致风格 - 门店中心及平台管理入口权限调整,仅超级管理员可访问 - 用户菜单中平台管理和门店中心入口现基于 isSuperAdmin 字段控制 - 优化登录及权限校验流程,避免权限不足时页面闪烁显示 - 更新工作记录文档,补充审核通过流程中新添加的店员记录步骤" />
|
<MESSAGE value="feat(user): 合并并切换“申请开发者”菜单项状态 - 在用户菜单中根据 isDeveloper 字段切换显示“申请成为开发者”或“进入开发者中心” - 已通过审核用户直接显示“进入开发者中心”且高亮显示 - 去除冗余的独立“开发者中心”菜单条目,简化菜单结构 - 调整平台管理页和门店中心入口权限为仅超级管理员可访问 - 优化登录与权限校验流程,防止权限不足时页面闪烁或无访问权限空白 - 更新相关文档,完善审核通过后店员记录添加流程" />
|
||||||
|
<MESSAGE value="fix(auth): 统一超级管理员标识为布尔值true - 将所有页面和菜单中超级管理员校验由数字1改为布尔true - 平台管理、门店中心菜单项仅在isSuperAdmin===true时显示 - 门店中心页面移除店员门槛,改为超级管理员访问限制 - 非超级管理员访问门店中心弹窗提示并返回 - 首页工作台入口及相关访问权限判定切换为布尔判断 - 优化首屏加载状态,避免权限校验闪烁和误判" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="fix(auth): 统一超级管理员标识为布尔值true - 将所有页面和菜单中超级管理员校验由数字1改为布尔true - 平台管理、门店中心菜单项仅在isSuperAdmin===true时显示 - 门店中心页面移除店员门槛,改为超级管理员访问限制 - 非超级管理员访问门店中心弹窗提示并返回 - 首页工作台入口及相关访问权限判定切换为布尔判断 - 优化首屏加载状态,避免权限校验闪烁和误判" />
|
||||||
<option name="NON_MODAL_COMMIT_POSTPONE_SLOW_CHECKS" value="false" />
|
<option name="NON_MODAL_COMMIT_POSTPONE_SLOW_CHECKS" value="false" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -66,3 +66,15 @@
|
|||||||
|
|
||||||
**改动**(`src/pages/user/user.tsx` 菜单 `menuItems`):
|
**改动**(`src/pages/user/user.tsx` 菜单 `menuItems`):
|
||||||
- 把原第 105 行固定「申请成为开发者」+ 第 107 行独立「开发者中心」(仅 isDeveloper 显示) 合并为条件式:`(user as any)?.isDeveloper ? { 进入开发者中心 → /pages/developer/index/index } : { 申请成为开发者 → /pages/user/vip-upgrade/index }`,两者均 `highlight: true`(醒目推荐样式)。去掉了冗余的独立「开发者中心」条目。
|
- 把原第 105 行固定「申请成为开发者」+ 第 107 行独立「开发者中心」(仅 isDeveloper 显示) 合并为条件式:`(user as any)?.isDeveloper ? { 进入开发者中心 → /pages/developer/index/index } : { 申请成为开发者 → /pages/user/vip-upgrade/index }`,两者均 `highlight: true`(醒目推荐样式)。去掉了冗余的独立「开发者中心」条目。
|
||||||
|
|
||||||
|
## 开发者中心 UI 对齐门店中心
|
||||||
|
|
||||||
|
**需求**:`pages/developer/index/index` 的 UI 改成和门店中心(`pages/store/center/index`)一模一样。
|
||||||
|
|
||||||
|
**改动**(仅 `src/pages/developer/index/index.tsx`,整体重写):
|
||||||
|
- 删除原 NavBar + StatCard 3列网格 + EntryGrid 老结构,改写为门店中心同款「渐变绿头部 + 白卡片列表(图标/标题/描述/角标/箭头)+ 底部卡片」。
|
||||||
|
- 头部:开发者 avatar + 「开发者中心」标题 + 昵称·手机号(取 `(user as any)`)。
|
||||||
|
- FEATURE_CARDS 三张:我的应用(📦/蓝)、API Key(🔑/绿)、我的工单(🎫/橙),各自 desc + url;角标沿用 `Badge`,展示各功能的计数(stats.apps/keys/tickets,由 getMyApps/getAppApiKeyStats/getMyTickets 的 total 取),卡片渲染后异步填充。
|
||||||
|
- 底部卡片改为「开发者帮助与支持」(💡 蓝圈)→ `/pages/user/help-center/index`(替代门店中心的订阅消息卡,订阅模板是门店专属,开发者无对应模板)。
|
||||||
|
- 保留两个空态:!isLoggedIn「请先登录」、!isDeveloper「尚未加入开发者中心」+ 申请按钮(保留原 apply 入口,store center 无此场景故无按钮);首屏用 `userLoading`(来自 useUser) 转圈防闪烁。
|
||||||
|
- 不再引入 NavBar/StatCard/EntryGrid/Loading(可能内部用 nutui,踩 weapp 空白坑),只用 `@tarojs/components` + 自定义 `Badge`,与门店中心一致。
|
||||||
@@ -1,26 +1,65 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react'
|
import React, { useState, useEffect, useCallback } from 'react'
|
||||||
import { View, Text, ScrollView } from '@tarojs/components'
|
import { View, Text, Image } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import NavBar from '@/components/NavBar'
|
import Badge from '@/components/common/Badge'
|
||||||
import StatCard from '@/components/common/StatCard'
|
|
||||||
import EntryGrid from '@/components/common/EntryGrid'
|
|
||||||
import Loading from '@/components/common/Loading'
|
|
||||||
import { useUser } from '@/hooks/useUser'
|
import { useUser } from '@/hooks/useUser'
|
||||||
import { getMyApps } from '@/api/app/appProduct'
|
import { getMyApps } from '@/api/app/appProduct'
|
||||||
import { getAppApiKeyStats } from '@/api/app/apikey'
|
import { getAppApiKeyStats } from '@/api/app/apikey'
|
||||||
import { getMyTickets } from '@/api/app/ticket'
|
import { getMyTickets } from '@/api/app/ticket'
|
||||||
import { getPageTotal } from '@/utils/devcenter'
|
import { getPageTotal } from '@/utils/devcenter'
|
||||||
|
|
||||||
definePageConfig({ navigationBarTitleText: '开发者中心' })
|
definePageConfig({
|
||||||
|
navigationBarTitleText: '开发者中心',
|
||||||
|
})
|
||||||
|
|
||||||
const DeveloperCenterPage: React.FC = () => {
|
// 功能卡片定义(未来新增功能只需在这里加一项)
|
||||||
const { user, isLoggedIn } = useUser()
|
const FEATURE_CARDS = [
|
||||||
|
{
|
||||||
|
key: 'apps',
|
||||||
|
icon: '📦',
|
||||||
|
title: '我的应用',
|
||||||
|
desc: '管理你开发并上架的应用',
|
||||||
|
url: '/pages/developer/apps/index',
|
||||||
|
color: '#3b82f6',
|
||||||
|
bgColor: '#dbeafe',
|
||||||
|
showBadge: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'apikeys',
|
||||||
|
icon: '🔑',
|
||||||
|
title: 'API Key',
|
||||||
|
desc: '查看与管理你的接口密钥',
|
||||||
|
url: '/pages/developer/apikeys/index',
|
||||||
|
color: '#10b981',
|
||||||
|
bgColor: '#dcfce7',
|
||||||
|
showBadge: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'tickets',
|
||||||
|
icon: '🎫',
|
||||||
|
title: '我的工单',
|
||||||
|
desc: '提交与跟踪你的工单',
|
||||||
|
url: '/pages/developer/tickets/index',
|
||||||
|
color: '#f59e0b',
|
||||||
|
bgColor: '#fef3c7',
|
||||||
|
showBadge: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export default function DeveloperCenterPage() {
|
||||||
|
const { user, isLoggedIn, loading: userLoading } = useUser()
|
||||||
const isDeveloper = !!(user as any)?.isDeveloper
|
const isDeveloper = !!(user as any)?.isDeveloper
|
||||||
const [loading, setLoading] = useState(true)
|
|
||||||
const [stats, setStats] = useState({ apps: 0, keys: 0, tickets: 0 })
|
const [stats, setStats] = useState({ apps: 0, keys: 0, tickets: 0 })
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isLoggedIn && isDeveloper) {
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isLoggedIn, isDeveloper])
|
||||||
|
|
||||||
|
/** 加载我的应用 / API Key / 工单数量 */
|
||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
setLoading(true)
|
|
||||||
try {
|
try {
|
||||||
const [appsR, keysR, ticketsR] = await Promise.allSettled([
|
const [appsR, keysR, ticketsR] = await Promise.allSettled([
|
||||||
getMyApps({ page: 1, limit: 1 }),
|
getMyApps({ page: 1, limit: 1 }),
|
||||||
@@ -31,84 +70,159 @@ const DeveloperCenterPage: React.FC = () => {
|
|||||||
const keys = keysR.status === 'fulfilled' ? getPageTotal(keysR.value) : 0
|
const keys = keysR.status === 'fulfilled' ? getPageTotal(keysR.value) : 0
|
||||||
const tickets = ticketsR.status === 'fulfilled' ? getPageTotal(ticketsR.value) : 0
|
const tickets = ticketsR.status === 'fulfilled' ? getPageTotal(ticketsR.value) : 0
|
||||||
setStats({ apps, keys, tickets })
|
setStats({ apps, keys, tickets })
|
||||||
} catch (e) {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
/** 获取卡片角标数字 */
|
||||||
if (isLoggedIn) load()
|
const getBadgeCount = (key: string) => {
|
||||||
}, [isLoggedIn, load])
|
if (key === 'apps') return stats.apps
|
||||||
|
if (key === 'apikeys') return stats.keys
|
||||||
|
if (key === 'tickets') return stats.tickets
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userLoading) {
|
||||||
|
return (
|
||||||
|
<View className='min-h-full bg-gray-50 flex items-center justify-center'>
|
||||||
|
<Text className='text-gray-400'>加载中...</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
return (
|
return (
|
||||||
<View className='min-h-screen bg-gray-100'>
|
<View className='min-h-full bg-gray-50 flex flex-col items-center justify-center py-24'>
|
||||||
<NavBar title='开发者中心' />
|
<Text className='text-5xl mb-3'>🔐</Text>
|
||||||
<View className='flex flex-col items-center justify-center py-24'>
|
<Text className='text-base text-gray-700 mb-2'>请先登录</Text>
|
||||||
<Text className='text-gray-400 text-sm'>请先登录后查看</Text>
|
<Text className='text-xs text-gray-400 text-center'>登录后方可进入开发者中心</Text>
|
||||||
<View
|
|
||||||
className='mt-4 px-6 py-2 rounded-full'
|
|
||||||
style={{ background: '#0e932e' }}
|
|
||||||
onClick={() => Taro.navigateTo({ url: '/passport/login' })}
|
|
||||||
>
|
|
||||||
<Text className='text-white text-sm'>去登录</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDeveloper) {
|
if (!isDeveloper) {
|
||||||
return (
|
return (
|
||||||
<View className='min-h-screen bg-gray-100'>
|
<View className='min-h-full bg-gray-50 flex flex-col items-center justify-center py-20 px-10'>
|
||||||
<NavBar title='开发者中心' />
|
<Text className='text-5xl mb-3'>🛠️</Text>
|
||||||
<View className='flex flex-col items-center justify-center py-20 px-10'>
|
<Text className='text-base text-gray-700 mb-2'>尚未加入开发者中心</Text>
|
||||||
<Text className='text-5xl mb-3'>🛠️</Text>
|
<Text className='text-xs text-gray-400 text-center mb-5 leading-relaxed'>
|
||||||
<Text className='text-base text-gray-700 mb-2'>尚未加入开发者中心</Text>
|
开发者中心提供应用管理、API Key、工单等能力,请先申请开发者资质
|
||||||
<Text className='text-xs text-gray-400 text-center mb-5 leading-relaxed'>
|
</Text>
|
||||||
开发者中心提供应用管理、API Key、工单等能力,请先申请开发者资质
|
<View
|
||||||
</Text>
|
className='px-6 py-2 rounded-full'
|
||||||
<View
|
style={{ background: '#2563eb' }}
|
||||||
className='px-6 py-2 rounded-full'
|
onClick={() => Taro.navigateTo({ url: '/pages/user/vip-upgrade/index' })}
|
||||||
style={{ background: '#2563eb' }}
|
>
|
||||||
onClick={() => Taro.navigateTo({ url: '/pages/user/vip-upgrade/index' })}
|
<Text className='text-white text-sm'>申请成为开发者</Text>
|
||||||
>
|
|
||||||
<Text className='text-white text-sm'>申请成为开发者</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const entries = [
|
// 头部展示信息
|
||||||
{ icon: '📦', label: '我的应用', url: '/pages/developer/apps/index' },
|
const header = {
|
||||||
{ icon: '🔑', label: 'API Key', url: '/pages/developer/apikeys/index' },
|
avatar: (user as any)?.avatar,
|
||||||
{ icon: '🎫', label: '我的工单', url: '/pages/developer/tickets/index' },
|
title: '开发者中心',
|
||||||
]
|
subtitle: `${((user as any)?.nickname || (user as any)?.username || '')}${((user as any)?.phone) ? ` · ${(user as any).phone}` : ''}`,
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className='min-h-screen bg-gray-100'>
|
<View className='min-h-full bg-gray-50'>
|
||||||
<NavBar title='开发者中心' />
|
|
||||||
<ScrollView scrollY>
|
{/* 顶部信息区:头像 + 名称 */}
|
||||||
{loading ? (
|
<View
|
||||||
<Loading />
|
className='pt-8 pb-12 px-5 rounded-b-3xl relative overflow-hidden'
|
||||||
) : (
|
style={{ background: 'linear-gradient(135deg, #15803d 0%, #22c55e 60%, #4ade80 100%)' }}
|
||||||
<View className='p-4'>
|
>
|
||||||
<View className='grid grid-cols-3 gap-3 mb-3'>
|
<View className='absolute -top-10 -right-10 w-40 h-40 rounded-full opacity-10'
|
||||||
<StatCard label='我的应用' value={stats.apps} color='#3b82f6' />
|
style={{ background: 'radial-gradient(circle, #ffffff, transparent)' }} />
|
||||||
<StatCard label='API Key' value={stats.keys} color='#10b981' />
|
<View className='absolute -bottom-6 -left-6 w-24 h-24 rounded-full opacity-15'
|
||||||
<StatCard label='我的工单' value={stats.tickets} color='#f59e0b' />
|
style={{ background: 'radial-gradient(circle, #ffffff, transparent)' }} />
|
||||||
</View>
|
<View className='relative z-10 flex items-center gap-4'>
|
||||||
<Text className='text-base font-medium mb-2 block'>常用功能</Text>
|
{/* 头像 */}
|
||||||
<EntryGrid items={entries} columns={3} />
|
<View className='w-16 h-16 rounded-full bg-white/20 border-2 border-white/40 overflow-hidden flex-shrink-0'>
|
||||||
<View className='h-6' />
|
{header.avatar ? (
|
||||||
|
<Image
|
||||||
|
className='w-full h-full'
|
||||||
|
src={header.avatar}
|
||||||
|
mode='aspectFill'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<View className='w-full h-full flex items-center justify-center'>
|
||||||
|
<Text className='text-2xl'>👤</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
)}
|
|
||||||
</ScrollView>
|
{/* 信息 */}
|
||||||
|
<View className='flex-1 min-w-0'>
|
||||||
|
<Text className='text-white text-lg font-bold block truncate'>
|
||||||
|
{header.title}
|
||||||
|
</Text>
|
||||||
|
<Text className='text-white text-opacity-80 text-sm mt-1 block truncate'>
|
||||||
|
{header.subtitle}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 功能卡片区 */}
|
||||||
|
<View className='mx-3 -mt-6 relative z-20'>
|
||||||
|
|
||||||
|
<View className='flex flex-col gap-3'>
|
||||||
|
{FEATURE_CARDS.map(card => (
|
||||||
|
<View
|
||||||
|
key={card.key}
|
||||||
|
className='bg-white rounded-xl p-4 flex items-center gap-4 active:opacity-80 relative'
|
||||||
|
onClick={() => Taro.navigateTo({ url: card.url })}
|
||||||
|
>
|
||||||
|
{/* 图标 */}
|
||||||
|
<View
|
||||||
|
className='w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0'
|
||||||
|
style={{ background: card.bgColor }}
|
||||||
|
>
|
||||||
|
<Text className='text-2xl'>{card.icon}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 文字 */}
|
||||||
|
<View className='flex-1 min-w-0'>
|
||||||
|
<Text className='text-gray-800 text-base font-medium block'>{card.title}</Text>
|
||||||
|
<Text className='text-gray-400 text-xs mt-0.5 block'>{card.desc}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 数量角标 */}
|
||||||
|
{card.showBadge && (
|
||||||
|
<Badge count={getBadgeCount(card.key)} className='absolute -top-1 -right-1' size={20} fontSize={11} fontWeight='bold' />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 箭头 */}
|
||||||
|
<Text className='text-gray-300 text-lg flex-shrink-0'>›</Text>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 底部提示 */}
|
||||||
|
<View className='mx-3 mt-6 mb-6'>
|
||||||
|
{/* 开发者帮助 */}
|
||||||
|
<View
|
||||||
|
className='bg-white rounded-xl p-4 flex items-center gap-3 active:opacity-80'
|
||||||
|
onClick={() => Taro.navigateTo({ url: '/pages/user/help-center/index' })}
|
||||||
|
>
|
||||||
|
<View className='w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0'
|
||||||
|
style={{ background: '#dbeafe' }}>
|
||||||
|
<Text className='text-xl'>💡</Text>
|
||||||
|
</View>
|
||||||
|
<View className='flex-1 min-w-0'>
|
||||||
|
<Text className='text-gray-800 text-sm font-medium block'>开发者帮助与支持</Text>
|
||||||
|
<Text className='text-gray-400 text-xs mt-0.5 block'>
|
||||||
|
查看接口文档、SDK 与常见问题
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Text className='text-blue-500 text-sm flex-shrink-0'>查看</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DeveloperCenterPage
|
|
||||||
|
|||||||
Reference in New Issue
Block a user