cloud hai 1 semana
pai
achega
6cad38316c
Modificáronse 52 ficheiros con 58 adicións e 36 borrados
  1. 7 5
      server/docs/WATER_MINI_API.md
  2. 7 9
      server/docs/openapi/water-mini-v1.json
  3. 7 9
      server/public/docs/mini/openapi.json
  4. 1 0
      server/public/water-mini/assets/BottomNav.C8EbEKD4.js
  5. 0 0
      server/public/water-mini/assets/CommandStatus.vue_vue_type_script_setup_true_lang.Dw2JtYZ8.js
  6. 0 0
      server/public/water-mini/assets/DevicePageHeader.BvIDJ-FC.js
  7. 1 0
      server/public/water-mini/assets/IdentityGuard.CwYBrUeO.js
  8. 0 0
      server/public/water-mini/assets/PackageCard.DSHwump1.js
  9. 1 0
      server/public/water-mini/assets/PageState._en-b4Fw.js
  10. 1 0
      server/public/water-mini/assets/PrivatePhotos.CEsbEFwG.js
  11. 1 0
      server/public/water-mini/assets/QuantityInput.zSdLHPsl.js
  12. 1 0
      server/public/water-mini/assets/TaskCard.vue_vue_type_script_setup_true_lang.Bqs_NGxC.js
  13. 1 0
      server/public/water-mini/assets/cart.ByCX-phQ.js
  14. 1 0
      server/public/water-mini/assets/format.DDNdx33k.js
  15. 2 0
      server/public/water-mini/assets/index-B8ag6Oin.js
  16. 1 0
      server/public/water-mini/assets/location.CMKgQ9k-.js
  17. 0 0
      server/public/water-mini/assets/login-B_g5LMYc.css
  18. 1 0
      server/public/water-mini/assets/pages-account-identities.cfGy7VoK.js
  19. 0 0
      server/public/water-mini/assets/pages-account-login.D8eq748L.js
  20. 0 0
      server/public/water-mini/assets/pages-account-profile.KHPfpwMf.js
  21. 0 0
      server/public/water-mini/assets/pages-account-rewards.C0e8pTTg.js
  22. 0 0
      server/public/water-mini/assets/pages-addresses-edit.DIpnioyg.js
  23. 0 0
      server/public/water-mini/assets/pages-addresses-index.DrwswDXb.js
  24. 0 0
      server/public/water-mini/assets/pages-agent-commissions.DbC6Tt6D.js
  25. 0 0
      server/public/water-mini/assets/pages-agent-customers.Dw8qBJq2.js
  26. 0 0
      server/public/water-mini/assets/pages-agent-dashboard.Ce45M_5p.js
  27. 1 0
      server/public/water-mini/assets/pages-agent-orders.DlU35ja-.js
  28. 0 0
      server/public/water-mini/assets/pages-common-map.CowYrrOr.js
  29. 1 0
      server/public/water-mini/assets/pages-common-web.CChBn1GC.js
  30. 1 0
      server/public/water-mini/assets/pages-devices-detail.BFGdXIhc.js
  31. 0 0
      server/public/water-mini/assets/pages-devices-index.pnN-j6iv.js
  32. 0 0
      server/public/water-mini/assets/pages-driver-dashboard.C7tGduXi.js
  33. 0 0
      server/public/water-mini/assets/pages-driver-device.WD62t6N_.js
  34. 0 0
      server/public/water-mini/assets/pages-driver-fulfill.T5spFN-0.js
  35. 0 0
      server/public/water-mini/assets/pages-driver-routes.C56E1maM.js
  36. 0 0
      server/public/water-mini/assets/pages-driver-task.CcySao9U.js
  37. 1 0
      server/public/water-mini/assets/pages-driver-tasks.OP0L5HJB.js
  38. 0 0
      server/public/water-mini/assets/pages-home-index.DgTCMZWA.js
  39. 0 0
      server/public/water-mini/assets/pages-orders-checkout.CA5Xwfqa.js
  40. 0 0
      server/public/water-mini/assets/pages-orders-index.BgjVvYkb.js
  41. 0 0
      server/public/water-mini/assets/pages-orders-tracking.DpR3Xhza.js
  42. 0 0
      server/public/water-mini/assets/pages-packages-cart.DnWDwS19.js
  43. 0 0
      server/public/water-mini/assets/pages-packages-detail.5MAfUSjI.js
  44. 0 0
      server/public/water-mini/assets/pages-packages-index.CvdaWGcY.js
  45. 0 0
      server/public/water-mini/assets/pages-rights-index.DdpNSARC.js
  46. 1 0
      server/public/water-mini/assets/pages-rights-ledger.B4nJXNjN.js
  47. 0 0
      server/public/water-mini/assets/uni.9e4445bb.css
  48. 1 0
      server/public/water-mini/assets/usePaged.Zh5X8qoD.js
  49. 1 0
      server/public/water-mini/assets/useResource.CaerzKS8.js
  50. 2 2
      server/public/water-mini/index.html
  51. 2 2
      water-mini/README.md
  52. 14 9
      water-mini/tests/login-agreement-dom.test.mjs

+ 7 - 5
server/docs/WATER_MINI_API.md

@@ -4,11 +4,13 @@ UI 依据:`D:\水后台UI\mobile\M01.png` 至 `M18.png`。后端接口持续
 
 前端交接使用 [WATER_MINI_FRONTEND.md](WATER_MINI_FRONTEND.md) 和 [OpenAPI 3.0.3 定义](openapi/water-mini-v1.json)。本文件保留架构、后台绑定和维护说明;规则整改及验证记录见 [WATER_MINI_REVIEW_FIXES.md](WATER_MINI_REVIEW_FIXES.md)。
 
-## 2026-10-24 测试手机号入口
+## 2026-10-26 测试手机号入口
 
-测试入口 `POST /auth/test-phone` 使用三个独立测试号:企业 `13012345678`、司机 `13012345679`、代理 `13012345680`,固定验证码均为 `66666`。返回与微信登录相同的 Login 结构。按用户明确要求,`MINI_TEST_PHONE_LOGIN=true` 时即可登录,不再限制客户端 IP,也不要求 `APP_ENV=local`。`MINI_TEST_PHONE_ALLOWED_IPS` 已移除,不再生效。`GET /config` 的 `capabilities.test_phone_login` 控制前端测试登录。正式短信登录单独校验,此测试接口不会验证手机号所有权或关联同号微信账号。
+测试入口 `POST /auth/test-phone` 使用三个独立测试号:企业 `13012345678`、司机 `13012345679`、代理 `13012345680`,仅提交 `phone` 即可登录,无需验证码,兼容旧客户端提交的 `code` 字段并忽略其值。返回与微信登录相同的 Login 结构。按用户明确要求,`MINI_TEST_PHONE_LOGIN=true` 时即可登录,不再限制客户端 IP,也不要求 `APP_ENV=local`。`MINI_TEST_PHONE_ALLOWED_IPS` 已移除,不再生效。`GET /config` 的 `capabilities.test_phone_login` 控制前端测试登录。正式短信登录单独校验,此测试接口不会验证手机号所有权或关联同号微信账号。
 
-测试登录仍保留来源 IP 限流、全局限流、指定号码/验证码校验、账号停用校验和现有业务授权。开启后,知道测试凭据的调用方可从任意来源访问对应测试账号;关闭开关并重载后端配置后,既有测试会话也失效。
+测试登录仍保留来源 IP 限流、全局限流、指定号码校验、账号停用校验和现有业务授权。开启后,知道测试手机号的调用方可从任意来源访问对应测试账号;关闭开关并重载后端配置后,既有测试会话也失效。
+
+后台管理登录同步移除图形验证码输入及校验,仍须提供有效账号密码,沿用账号停用、Token 与业务权限校验。数据库连接失败仍需修复数据库服务或连接配置,不能通过免验证码解决。
 
 ## 2026-10-21 微信登录失败分流
 
@@ -25,7 +27,7 @@ UI 依据:`D:\水后台UI\mobile\M01.png` 至 `M18.png`。后端接口持续
 
 先执行 `php -d extension=mbstring scripts/seed_mini_test_phone.php --apply` 初始化三个独立的 `local-test-phone` 账号及对应测试档案权限,同时停用原企业测试号上的司机和代理授权。脚本复跑不覆盖账号/授权停用状态,不创建业务收款、库存或订单。会话仍随机生成并只保存哈希,沿用账号停用、权限校验、限流与退出撤销。关闭开关并重新加载后端配置后,既有测试会话不能继续访问。
 
-`tests/mini_test_phone_test.php` 在事务回滚中覆盖固定凭据、production环境开启/关闭、账号停用、独立会话与注销;直接调用 HTTP 控制器,验证三个号码在局域网、公网、IPv6 和可信代理转发来源下均返回200并生成可校验的会话。前端运行、微信开发者工具导入目录和 API 地址配置见 `water-mini/README.md`。
+`tests/mini_test_phone_test.php` 在事务回滚中覆盖免验证码、旧客户端兼容、production环境开启/关闭、账号停用、独立会话与注销;直接调用 HTTP 控制器,验证三个号码在局域网、公网、IPv6 和可信代理转发来源下均返回200并生成可校验的会话。前端运行、微信开发者工具导入目录和 API 地址配置见 `water-mini/README.md`。
 
 ## 分层与设计模式
 
@@ -90,7 +92,7 @@ routes/mini_api.php
 
 ## 2026-10-21 短信验证码登录
 
-2026-10-24 按用户要求恢复测试账号与正式号码并存:三个指定测试号直接输入5位固定码 `66666`,调用 `/auth/test-phone`,页面不发送短信、不假报发送成功;其余号码调用 `/auth/send-sms` 和 `/auth/phone-login`,使用6位随机短信码。手机号入口在 `capabilities.sms_login` 或 `capabilities.test_phone_login` 任一开启时显示,每种方式分别校验自己的能力开关,测试关闭不会回退到短信登录。发送成功才启动60秒重发倒计时,短信有效期为120秒;失败提示实际错误并允许重试。获取验证码不要求先同意协议,登录时仍要求同意。下方 `123456` 仅为请求格式示例,实际必须填写本次短信中的随机验证码。
+三个指定测试号仅输入手机号调用 `/auth/test-phone`,页面隐藏验证码且不发送短信;其余号码调用 `/auth/send-sms` 和 `/auth/phone-login`,使用6位随机短信码。手机号入口在 `capabilities.sms_login` 或 `capabilities.test_phone_login` 任一开启时显示,每种方式分别校验自己的能力开关,测试关闭不会回退到短信登录。发送成功才启动60秒重发倒计时,短信有效期为120秒;失败提示实际错误并允许重试。获取验证码不要求先同意协议,登录时仍要求同意。下方 `123456` 仅为请求格式示例,实际必须填写本次短信中的随机验证码。
 
 短信登录是微信登录的**第二种凭据**,不是独立注册通道:手机号必须先由超级管理员在后台绑定到**已存在**的小程序账号,才会真正下发短信。校验通过后登录到该账号,`user_id`、业务身份与权限和同一账号的微信登录完全一致。不会因为发短信而新建账号,未绑定的号码登录后仍无业务身份,与「1 个账号 1 个身份」的规则一致。
 

+ 7 - 9
server/docs/openapi/water-mini-v1.json

@@ -4848,7 +4848,7 @@
         ],
         "summary": "本地测试手机号登录",
         "operationId": "post_auth_test_phone",
-        "description": "由 MINI_TEST_PHONE_LOGIN=true 显式开启,不限制 APP_ENV 或客户端 IP。仅三个指定测试号码可使用固定验证码 66666 登录,仍有来源 IP 及全局限流。固定测试身份与微信及真实手机身份隔离;账号须预先初始化且启用,仅获得已绑定权限。关闭开关后既有测试会话失效。开启时知道测试凭据的调用方可从任意来源访问对应测试账号。",
+        "description": "由 MINI_TEST_PHONE_LOGIN=true 显式开启,不限制 APP_ENV 或客户端 IP。三个指定测试号码无需验证码即可登录,仍有来源 IP 及全局限流。固定测试身份与微信及真实手机身份隔离;账号须预先初始化且启用,仅获得已绑定权限。关闭开关后既有测试会话失效。开启时知道测试手机号的调用方可从任意来源访问对应测试账号。",
         "parameters": [],
         "responses": {
           "200": {
@@ -4926,27 +4926,25 @@
                 "type": "object",
                 "additionalProperties": false,
                 "required": [
-                  "phone",
-                  "code"
+                  "phone"
                 ],
                 "properties": {
                   "phone": {
                     "type": "string",
                     "enum": [
-                      "13012345678"
+                      "13012345678",
+                      "13012345679",
+                      "13012345680"
                     ]
                   },
                   "code": {
                     "type": "string",
-                    "enum": [
-                      "66666"
-                    ]
+                    "description": "兼容旧客户端的可选字段,测试入口忽略此值。"
                   }
                 }
               },
               "example": {
-                "phone": "13012345678",
-                "code": "66666"
+                "phone": "13012345678"
               }
             }
           }

+ 7 - 9
server/public/docs/mini/openapi.json

@@ -4848,7 +4848,7 @@
         ],
         "summary": "本地测试手机号登录",
         "operationId": "post_auth_test_phone",
-        "description": "由 MINI_TEST_PHONE_LOGIN=true 显式开启,不限制 APP_ENV 或客户端 IP。仅三个指定测试号码可使用固定验证码 66666 登录,仍有来源 IP 及全局限流。固定测试身份与微信及真实手机身份隔离;账号须预先初始化且启用,仅获得已绑定权限。关闭开关后既有测试会话失效。开启时知道测试凭据的调用方可从任意来源访问对应测试账号。",
+        "description": "由 MINI_TEST_PHONE_LOGIN=true 显式开启,不限制 APP_ENV 或客户端 IP。三个指定测试号码无需验证码即可登录,仍有来源 IP 及全局限流。固定测试身份与微信及真实手机身份隔离;账号须预先初始化且启用,仅获得已绑定权限。关闭开关后既有测试会话失效。开启时知道测试手机号的调用方可从任意来源访问对应测试账号。",
         "parameters": [],
         "responses": {
           "200": {
@@ -4926,27 +4926,25 @@
                 "type": "object",
                 "additionalProperties": false,
                 "required": [
-                  "phone",
-                  "code"
+                  "phone"
                 ],
                 "properties": {
                   "phone": {
                     "type": "string",
                     "enum": [
-                      "13012345678"
+                      "13012345678",
+                      "13012345679",
+                      "13012345680"
                     ]
                   },
                   "code": {
                     "type": "string",
-                    "enum": [
-                      "66666"
-                    ]
+                    "description": "兼容旧客户端的可选字段,测试入口忽略此值。"
                   }
                 }
               },
               "example": {
-                "phone": "13012345678",
-                "code": "66666"
+                "phone": "13012345678"
               }
             }
           }

+ 1 - 0
server/public/water-mini/assets/BottomNav.C8EbEKD4.js

@@ -0,0 +1 @@
+import{d as a,c as e,b as s,e as t,w as r,h as o,i as l,F as n,p as i,n as c,f as p,g as d,t as v,s as g,r as u,af as m,q as f,v as _}from"./index-B8ag6Oin.js";import{_ as b}from"./_plugin-vue_export-helper.BCo6x5W8.js";const h=b(a({__name:"BottomNav",props:{active:{}},setup(a){const b=a;let h=!1;const x=e(()=>{var a,e;return"driver"===(null==(a=g.active)?void 0:a.role)?[["工作台","台","/pages/driver/dashboard"],["任务","务","/pages/driver/tasks"],["地图","图","/pages/driver/routes"],["我的","我","/pages/account/profile"]]:"agent"===(null==(e=g.active)?void 0:e.role)?[["工作台","台","/pages/agent/dashboard"],["用户","户","/pages/agent/customers"],["订单","单","/pages/agent/orders"],["佣金","佣","/pages/agent/commissions"]]:[["首页","首","/pages/home/index"],["订单","单","/pages/orders/index"],["水卡","卡","/pages/rights/index"],["我的","我","/pages/account/profile"]]});return(a,e)=>{const g=i,k=f,j=_;return s(),t(g,{class:"bottom-nav"},{default:r(()=>[(s(!0),o(n,null,l(x.value,e=>(s(),t(j,{key:e[2],class:c(["nav-item",{selected:a.active===e[2]}]),"aria-label":e[0]+(a.active===e[2]?",当前页面":""),onClick:a=>{var s;(s=e[2])===b.active||h||(h=!0,u({url:s,fail:()=>m({title:"页面打开失败,请重试",icon:"none"}),complete:()=>{h=!1}}))}},{default:r(()=>[p(g,{class:"nav-icon"},{default:r(()=>[d(v(e[1]),1)]),_:2},1024),p(k,{class:"nav-label"},{default:r(()=>[d(v(e[0]),1)]),_:2},1024)]),_:2},1032,["class","aria-label","onClick"]))),128))]),_:1})}}}),[["__scopeId","data-v-78314e07"]]);export{h as B};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/CommandStatus.vue_vue_type_script_setup_true_lang.Dw2JtYZ8.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/DevicePageHeader.BvIDJ-FC.js


+ 1 - 0
server/public/water-mini/assets/IdentityGuard.CwYBrUeO.js

@@ -0,0 +1 @@
+import{d as a,c as s,ai as e,b as t,e as r,w as o,f as n,g as i,t as l,u as d,p as u,v as c,s as p,I as _}from"./index-B8ag6Oin.js";import{g as k}from"./format.DDNdx33k.js";import{_ as f}from"./_plugin-vue_export-helper.BCo6x5W8.js";const m=f(a({__name:"IdentityGuard",props:{kind:{}},setup(a){const f=a,m=s(()=>{var a,s;return!!p.token&&(!f.kind||("enterprise"===f.kind?null==(a=p.active)?void 0:a.role.startsWith("enterprise_"):(null==(s=p.active)?void 0:s.role)===f.kind))});return(a,s)=>{const f=u,v=c;return m.value?e(a.$slots,"default",{key:0},void 0,!0):(t(),r(f,{key:1,class:"card guard"},{default:o(()=>[n(f,{class:"icon-tile"},{default:o(()=>[i("泉")]),_:1}),n(f,{class:"title"},{default:o(()=>[i(l(d(p).token?"当前账号无此页面权限":"登录后查看专属服务"),1)]),_:1}),n(f,{class:"muted"},{default:o(()=>[i(l(d(p).token?"请使用对应业务账号登录,或联系管理员开通。":"查看企业用水、预约送水与配送进度"),1)]),_:1}),n(v,{class:"primary guard-action",onClick:s[0]||(s[0]=a=>d(k)(d(p).token?d(_)():"/pages/account/login"))},{default:o(()=>[i(l(d(p).token?"返回我的页面":"前往登录"),1)]),_:1})]),_:1}))}}}),[["__scopeId","data-v-9887a078"]]);export{m as I};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/PackageCard.DSHwump1.js


+ 1 - 0
server/public/water-mini/assets/PageState._en-b4Fw.js

@@ -0,0 +1 @@
+import{d as e,b as a,e as s,w as t,f as l,g as r,t as o,m as n,p,q as u,v as d}from"./index-B8ag6Oin.js";import{_}from"./_plugin-vue_export-helper.BCo6x5W8.js";const m=_(e({__name:"PageState",props:{loading:{type:Boolean},error:{},empty:{type:Boolean},emptyText:{}},emits:["retry"],setup:e=>(e,_)=>{const m=p,y=u,c=d;return e.loading?(a(),s(m,{key:0,class:"state"},{default:t(()=>[l(m,{class:"spinner"}),l(y,null,{default:t(()=>[r("正在加载…")]),_:1})]),_:1})):e.error?(a(),s(m,{key:1,class:"state"},{default:t(()=>[l(m,{class:"state-symbol"},{default:t(()=>[r("!")]),_:1}),l(y,null,{default:t(()=>[r(o(e.error),1)]),_:1}),l(c,{class:"secondary button-small",onClick:_[0]||(_[0]=a=>e.$emit("retry"))},{default:t(()=>[r("重新加载")]),_:1})]),_:1})):e.empty?(a(),s(m,{key:2,class:"state"},{default:t(()=>[l(m,{class:"state-symbol"},{default:t(()=>[r("水")]),_:1}),l(y,null,{default:t(()=>[r(o(e.emptyText||"暂无记录"),1)]),_:1})]),_:1})):n("",!0)}}),[["__scopeId","data-v-3850482e"]]);export{m as P};

+ 1 - 0
server/public/water-mini/assets/PrivatePhotos.CEsbEFwG.js

@@ -0,0 +1 @@
+import{d as s,C as a,R as e,D as t,b as o,e as r,w as u,f as c,h as l,i as n,F as i,g as d,t as p,m as h,s as f,a9 as v,aa as m,ab as _,p as k,v as b,ac as C,z as w}from"./index-B8ag6Oin.js";import{_ as y}from"./_plugin-vue_export-helper.BCo6x5W8.js";const P=y(s({__name:"PrivatePhotos",props:{ids:{},scope:{},resourceId:{}},setup(s){const y=s,P=a([]),$=a("");let j=0;function x(s){s.startsWith("blob:")&&URL.revokeObjectURL(s)}function I(){P.value.forEach(s=>x(s.path)),P.value=[]}async function g(){const s=++j;if(I(),$.value="",!f.token)return;const a=f.token,e=f.epoch;for(const t of y.ids){if(s!==j||e!==f.epoch)return;try{const o=await new Promise((s,e)=>v({url:`${m}/photos/${t}?scope=${y.scope}&resource_id=${y.resourceId}`,header:{Authorization:`Bearer ${a}`},success(t){200===t.statusCode?s(t.tempFilePath):(401===t.statusCode&&a===f.token&&_(),e(new Error("照片读取失败")))},fail:()=>e(new Error("照片读取失败"))}));if(s!==j||e!==f.epoch)return void x(o);P.value.push({id:t,path:o})}catch{s===j&&($.value="部分照片加载失败,请重新加载")}}}return e(()=>[y.ids.join(","),y.resourceId,f.epoch],g,{immediate:!0,flush:"sync"}),t(()=>{j++,I()}),(s,a)=>{const e=w,t=k,f=b;return o(),r(t,null,{default:u(()=>[c(t,{class:"grid"},{default:u(()=>[(o(!0),l(i,null,n(P.value,s=>(o(),r(t,{key:s.id},{default:u(()=>[c(e,{src:s.path,class:"photo",mode:"aspectFill",onClick:a=>{return e=s.path,void C({current:e,urls:P.value.map(s=>s.path)});var e}},null,8,["src","onClick"]),c(t,{class:"muted small"},{default:u(()=>[d("照片 #"+p(s.id),1)]),_:2},1024)]),_:2},1024))),128))]),_:1}),$.value?(o(),r(f,{key:0,class:"text-button",onClick:g},{default:u(()=>[d(p($.value),1)]),_:1})):h("",!0)]),_:1})}}}),[["__scopeId","data-v-2d023a57"]]);export{P};

+ 1 - 0
server/public/water-mini/assets/QuantityInput.zSdLHPsl.js

@@ -0,0 +1 @@
+import{d as e,b as a,e as l,w as t,f as u,g as d,v as s,J as m,p as n}from"./index-B8ag6Oin.js";import{_ as o}from"./_plugin-vue_export-helper.BCo6x5W8.js";const i=o(e({__name:"QuantityInput",props:{modelValue:{},min:{default:1},max:{default:100}},emits:["update:modelValue"],setup(e,{emit:o}){const i=e,r=o;function p(e){r("update:modelValue",Math.min(i.max,Math.max(i.min,Math.trunc(e)||i.min)))}function c(e){p(Number(e.detail.value))}return(e,o)=>{const i=s,r=m,f=n;return a(),l(f,{class:"stepper"},{default:t(()=>[u(i,{disabled:e.modelValue<=e.min,onClick:o[0]||(o[0]=a=>p(e.modelValue-1))},{default:t(()=>[d("−")]),_:1},8,["disabled"]),u(r,{value:String(e.modelValue),type:"number",onBlur:c},null,8,["value"]),u(i,{disabled:e.modelValue>=e.max,onClick:o[1]||(o[1]=a=>p(e.modelValue+1))},{default:t(()=>[d("+")]),_:1},8,["disabled"])]),_:1})}}}),[["__scopeId","data-v-fc2725bb"]]);export{i as Q};

+ 1 - 0
server/public/water-mini/assets/TaskCard.vue_vue_type_script_setup_true_lang.Bqs_NGxC.js

@@ -0,0 +1 @@
+import{d as s,b as a,e,w as t,f as l,n as d,g as m,t as r,u,q as i,p as c}from"./index-B8ag6Oin.js";import{l as _,g as n}from"./format.DDNdx33k.js";const f=s({__name:"TaskCard",props:{item:{}},setup:s=>(s,f)=>{const o=i,p=c;return a(),e(p,{class:"card",onClick:f[0]||(f[0]=a=>u(n)("/pages/driver/task?id="+s.item.id))},{default:t(()=>[l(p,{class:"row"},{default:t(()=>[l(o,{class:d(["tag","completed"===s.item.status?"green":"orange"])},{default:t(()=>[m(r(u(_)(s.item.status)),1)]),_:1},8,["class"]),l(o,{class:"muted small"},{default:t(()=>[m(r(s.item.code),1)]),_:1})]),_:1}),l(p,{class:"title",style:{margin:"20rpx 0 10rpx"}},{default:t(()=>[m(r(s.item.enterprise_name||"企业配送任务"),1)]),_:1}),l(p,{class:"muted"},{default:t(()=>[m(r(s.item.address),1)]),_:1}),l(p,{class:"divider"}),l(p,{class:"row"},{default:t(()=>[l(p,null,{default:t(()=>[l(p,null,{default:t(()=>[m(r(s.item.sku_name)+" · "+r(s.item.quantity)+"桶",1)]),_:1}),l(p,{class:"muted"},{default:t(()=>[m(r(s.item.scheduled_date||"待安排日期"),1)]),_:1})]),_:1}),l(o,{class:"tag"},{default:t(()=>[m("查看任务 ›")]),_:1})]),_:1})]),_:1})}});export{f as _};

+ 1 - 0
server/public/water-mini/assets/cart.ByCX-phQ.js

@@ -0,0 +1 @@
+import{Z as t}from"./index-B8ag6Oin.js";import{t as i}from"./format.DDNdx33k.js";function n(t){return u.items.find(i=>i.product.id===t)}const u=t({items:[]});function s(t){const s=n(t.id);if(s)s.quantity<100&&s.quantity++;else{if(!(u.items.length<20))return void i("最多选择20种套餐");u.items.push({product:t,quantity:1})}i("已加入订单")}function o(t){return n(t.id)?(u.items=u.items.filter(i=>i.product.id!==t.id),i("已取消选择"),!1):u.items.length>=20?(i("最多选择20种套餐"),!1):(u.items.push({product:t,quantity:1}),i("已选择,可继续选择其他套餐"),!0)}function c(t){const i=n(t.id);i&&i.quantity<100&&i.quantity++}function e(t){const i=n(t.id);i&&(i.quantity>1?i.quantity--:o(t))}function r(t){var i;return(null==(i=n(t))?void 0:i.quantity)??0}function a(){return u.items.map(t=>({package_id:t.product.id,quantity:t.quantity}))}function d(t){for(const i of u.items){const n=t.find(t=>t.id===i.product.id);n&&(i.product=n)}}function f(t){for(const i of u.items){const n=t.items.find(t=>t.package_id===i.product.id);if(!n||n.quantity!==i.quantity)throw new Error("套餐选择已变化,请重新报价");const u=i.product.sku_id===n.sku_id;i.product={...i.product,name:n.name,sku_id:n.sku_id,sku_name:u?i.product.sku_name:null,liters:u?i.product.liters:null,buckets:n.buckets/n.quantity,price_cents:n.unit_price_cents,unit_price_cents:Math.round(n.amount_cents/n.buckets)}}}function m(){u.items=[]}export{s as a,a as b,u as c,e as d,f as e,m as f,c as i,r as q,d as r,o as t};

+ 1 - 0
server/public/water-mini/assets/format.DDNdx33k.js

@@ -0,0 +1 @@
+import{af as n,aj as e,a1 as i}from"./index-B8ag6Oin.js";function r(n,e=2){return null==n?"—":(n/100).toLocaleString("zh-CN",{minimumFractionDigits:e,maximumFractionDigits:e})}function t(n,e=""){return null==n?"—":`${n}${e}`}const o={pending:"待调度",assigned:"待出发",transit:"配送中",completed:"已完成",cancelled:"已取消",returning:"待退货",returned:"已退货",expired:"已过期",paid:"已支付",online:"在线",offline:"离线",unknown:"状态未知",enterprise_admin:"企业管理员",enterprise_member:"企业成员",driver:"配送员",agent:"代理商"};function a(n){return n?o[n]||n:"—"}function s(n){e({url:n})}function u(e){n({title:e,icon:"none",duration:2600})}function c(n,e){return new Promise(r=>i({title:n,content:e,success:n=>r(n.confirm),fail:()=>r(!1)}))}function m(n){const e=Number(n);if(!Number.isSafeInteger(e)||e<1)throw new Error("页面参数无效,请返回列表重新进入");return e}export{c,s as g,m as i,a as l,r as m,u as t,t as v};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2 - 0
server/public/water-mini/assets/index-B8ag6Oin.js


+ 1 - 0
server/public/water-mini/assets/location.CMKgQ9k-.js

@@ -0,0 +1 @@
+import{ae as e,af as n}from"./index-B8ag6Oin.js";import{g as t}from"./format.DDNdx33k.js";function o(){return"undefined"==typeof window||window.isSecureContext?new Promise((n,t)=>e({type:"gcj02",success:e=>n({latitude:e.latitude,longitude:e.longitude}),fail:e=>{const n=e,o=Number(n.code),r=(n.errMsg||"").toLowerCase();1===o||/permission|denied|auth deny|unauthorized/.test(r)?t(new Error("定位权限被拒绝,请在浏览器网站设置和系统设置中允许位置访问")):2===o||/unavailable/.test(r)?t(new Error("设备暂时无法确定位置,请开启系统定位服务并检查网络后重试")):3===o||/timeout/.test(r)?t(new Error("定位超时,请检查网络或移动到信号较好的位置后重试")):t(new Error("无法获取位置,请检查浏览器定位权限与系统定位服务后重试"))}})):Promise.reject(new Error("当前网页地址不支持定位,请使用 HTTPS,或在本机通过 127.0.0.1 打开"))}function r(e,o,r){if(null==e||null==o||""===e||""===o)return void n({title:"该地址尚未定位",icon:"none"});const i=Number(e),s=Number(o);!Number.isFinite(i)||!Number.isFinite(s)||Math.abs(i)>90||Math.abs(s)>180||t("/pages/common/map?latitude="+encodeURIComponent(String(i))+"&longitude="+encodeURIComponent(String(s))+"&address="+encodeURIComponent(r||"配送地址"))}export{o as l,r as o};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/login-B_g5LMYc.css


+ 1 - 0
server/public/water-mini/assets/pages-account-identities.cfGy7VoK.js

@@ -0,0 +1 @@
+import{d as a,o as s,s as t,b as e,e as l,w as o,f as r,g as u,u as n,t as d,m as i,N as c,p as f,v as m,q as _,O as p,r as g,I as y}from"./index-B8ag6Oin.js";import{u as j}from"./useResource.CaerzKS8.js";import{I as k}from"./IdentityGuard.CwYBrUeO.js";import{P as I}from"./PageState._en-b4Fw.js";import"./format.DDNdx33k.js";import"./_plugin-vue_export-helper.BCo6x5W8.js";const v=a({__name:"identities",setup(a){const{loading:v,error:w,load:x}=j(async()=>(await p(),t.active&&g({url:y()}),!0));function b(){c({data:t.userId})}return s(()=>{t.token&&x()}),(a,s)=>{const c=f,p=m,g=_;return e(),l(c,{class:"page"},{default:o(()=>[r(k,null,{default:o(()=>[r(c,{class:"section"},{default:o(()=>[r(c,{class:"title"},{default:o(()=>[u("账号服务状态")]),_:1}),r(p,{class:"text-button",onClick:n(x)},{default:o(()=>[u("刷新")]),_:1},8,["onClick"])]),_:1}),r(c,{class:"muted"},{default:o(()=>[u("账号的服务身份由管理员绑定,登录后自动进入对应页面。")]),_:1}),r(I,{loading:n(v),error:n(w),onRetry:n(x)},null,8,["loading","error","onRetry"]),n(v)||n(w)||n(t).identities.length?i("",!0):(e(),l(c,{key:0,class:"card"},{default:o(()=>[r(c,{class:"title"},{default:o(()=>[u("账号已建立,等待绑定身份")]),_:1}),r(c,{class:"notice"},{default:o(()=>[u("请将用户编号提供给管理员,绑定企业、配送员或代理商后,点击刷新。")]),_:1}),r(c,{class:"row"},{default:o(()=>[r(g,{class:"muted"},{default:o(()=>[u("用户编号:"+d(n(t).userId),1)]),_:1}),r(p,{class:"secondary button-small",onClick:b},{default:o(()=>[u("复制编号")]),_:1})]),_:1})]),_:1}))]),_:1})]),_:1})}}});export{v as default};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-account-login.D8eq748L.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-account-profile.KHPfpwMf.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-account-rewards.C0e8pTTg.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-addresses-edit.DIpnioyg.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-addresses-index.DrwswDXb.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-agent-commissions.DbC6Tt6D.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-agent-customers.Dw8qBJq2.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-agent-dashboard.Ce45M_5p.js


+ 1 - 0
server/public/water-mini/assets/pages-agent-orders.DlU35ja-.js

@@ -0,0 +1 @@
+import{d as a,C as e,V as s,o as t,s as r,T as l,b as o,e as d,w as u,f as n,g as i,t as m,h as c,i as p,u as _,F as f,m as g,p as v,v as y,x as j,y as k,q as x}from"./index-B8ag6Oin.js";import{u as b}from"./usePaged.Zh5X8qoD.js";import{m as h}from"./format.DDNdx33k.js";import{I as w}from"./IdentityGuard.CwYBrUeO.js";import{P as B}from"./PageState._en-b4Fw.js";import{B as C}from"./BottomNav.C8EbEKD4.js";import"./_plugin-vue_export-helper.BCo6x5W8.js";const P=a({__name:"orders",setup(a){const P=e(0),{items:I,loading:N,error:q,hasMore:z,load:A}=b(a=>j(k("agent")+"/orders",{page:a,...P.value?{enterprise_id:P.value}:{}}));return s(a=>{P.value=Number(null==a?void 0:a.enterprise_id)||0}),t(()=>{var a;"agent"===(null==(a=r.active)?void 0:a.role)&&A(!0)}),l(()=>A()),(a,e)=>{const s=v,t=x,r=y;return o(),d(s,{class:"page"},{default:u(()=>[n(w,{kind:"agent"},{default:u(()=>[n(s,{class:"notice"},{default:u(()=>[i(m(P.value?"当前客户的真实收款记录":"当前辖区客户的真实收款记录"),1)]),_:1}),(o(!0),c(f,null,p(_(I),a=>(o(),d(s,{key:a.id,class:"card"},{default:u(()=>[n(s,{class:"row"},{default:u(()=>[n(t,{class:"strong"},{default:u(()=>[i(m(a.package_name),1)]),_:2},1024),n(t,{class:"tag green"},{default:u(()=>[i("已收款")]),_:1})]),_:2},1024),n(s,{class:"muted",style:{"margin-top":"14rpx"}},{default:u(()=>[i(m(a.created_at),1)]),_:2},1024),n(s,{class:"divider"}),n(s,{class:"row"},{default:u(()=>[n(t,{class:"muted"},{default:u(()=>[i(m(a.buckets)+"桶 · 企业编号 "+m(a.enterprise_id),1)]),_:2},1024),n(t,{class:"amount"},{default:u(()=>[i("¥"+m(_(h)(a.amount_cents)),1)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128)),n(B,{loading:_(N),error:_(q),empty:!_(I).length,onRetry:e[0]||(e[0]=a=>_(A)(!0))},null,8,["loading","error","empty"]),_(z)&&!_(N)?(o(),d(r,{key:0,class:"text-button",onClick:e[1]||(e[1]=a=>_(A)())},{default:u(()=>[i("加载更多")]),_:1})):g("",!0)]),_:1}),n(C,{active:"/pages/agent/orders"})]),_:1})}}});export{P as default};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-common-map.CowYrrOr.js


+ 1 - 0
server/public/water-mini/assets/pages-common-web.CChBn1GC.js

@@ -0,0 +1 @@
+import{d as a,C as s,V as e,b as t,e as n,w as l,f as r,g as o,m as u,p as c,ak as d}from"./index-B8ag6Oin.js";const i=a({__name:"web",setup(a){const i=s(""),p=s(!1);return e(a=>{try{const s=decodeURIComponent((null==a?void 0:a.url)||"");if(!/^https:\/\/[^\s]+$/i.test(s))throw new Error("invalid");i.value=s}catch{p.value=!0}}),(a,s)=>{const e=c,v=d;return p.value?(t(),n(e,{key:0,class:"page"},{default:l(()=>[r(e,{class:"notice warning"},{default:l(()=>[o("该服务链接暂不可用,请联系平台。")]),_:1})]),_:1})):i.value?(t(),n(v,{key:1,src:i.value},null,8,["src"])):u("",!0)}}});export{i as default};

+ 1 - 0
server/public/water-mini/assets/pages-devices-detail.BFGdXIhc.js

@@ -0,0 +1 @@
+import{d as e,C as a,V as s,b as r,e as o,w as t,f as d,u as i,m as n,p as l,x as u,y as m}from"./index-B8ag6Oin.js";import{u as p}from"./useResource.CaerzKS8.js";import{g as f,i as c}from"./format.DDNdx33k.js";import{I as g}from"./IdentityGuard.CwYBrUeO.js";import{P as v}from"./PageState._en-b4Fw.js";import{D as _,a as j}from"./DevicePageHeader.BvIDJ-FC.js";import{_ as y}from"./_plugin-vue_export-helper.BCo6x5W8.js";const x=y(e({__name:"detail",setup(e){const y=a(0),{data:x,loading:I,error:P,load:R}=p(()=>u(m("enterprise")+"/devices/"+c(y.value)));return s(e=>{y.value=Number(null==e?void 0:e.id),R()}),(e,a)=>{const s=l;return r(),o(s,{class:"device-page"},{default:t(()=>[d(_,{onManage:a[0]||(a[0]=e=>i(f)("/pages/devices/index"))}),d(g,{kind:"enterprise"},{default:t(()=>[d(v,{loading:i(I),error:i(P),onRetry:i(R)},null,8,["loading","error","onRetry"]),!i(x)||i(I)||i(P)?n("",!0):(r(),o(j,{key:0,data:i(x)},null,8,["data"]))]),_:1})]),_:1})}}}),[["__scopeId","data-v-d397884e"]]);export{x as default};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-devices-index.pnN-j6iv.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-driver-dashboard.C7tGduXi.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-driver-device.WD62t6N_.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-driver-fulfill.T5spFN-0.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-driver-routes.C56E1maM.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-driver-task.CcySao9U.js


+ 1 - 0
server/public/water-mini/assets/pages-driver-tasks.OP0L5HJB.js

@@ -0,0 +1 @@
+import{d as a,C as s,o as e,s as t,T as r,a as o,b as l,e as i,w as d,f as n,h as u,i as m,F as p,u as c,g as v,m as _,p as f,v as g,n as y,t as k,x as j,y as x}from"./index-B8ag6Oin.js";import{u as C}from"./usePaged.Zh5X8qoD.js";import{I as h}from"./IdentityGuard.CwYBrUeO.js";import{P as I}from"./PageState._en-b4Fw.js";import{_ as B}from"./TaskCard.vue_vue_type_script_setup_true_lang.Bqs_NGxC.js";import{B as P}from"./BottomNav.C8EbEKD4.js";import{_ as b}from"./_plugin-vue_export-helper.BCo6x5W8.js";import"./format.DDNdx33k.js";const w=b(a({__name:"tasks",setup(a){const b=s("all"),w=[["all","全部"],["pending","待出发"],["transit","配送中"],["completed","已完成"],["exception","异常"]],{items:T,loading:z,error:A,hasMore:F,load:G}=C(a=>j(x("driver")+"/tasks",{page:a,status:b.value}));return e(()=>{var a;"driver"===(null==(a=t.active)?void 0:a.role)&&G(!0)}),r(()=>G()),o(()=>G(!0)),(a,s)=>{const e=f,t=g;return l(),i(e,{class:"page"},{default:d(()=>[n(h,{kind:"driver"},{default:d(()=>[n(e,{class:"tabs"},{default:d(()=>[(l(),u(p,null,m(w,a=>n(e,{key:a[0],class:y({active:b.value===a[0]}),onClick:s=>{b.value=a[0],c(G)(!0)}},{default:d(()=>[v(k(a[1]),1)]),_:2},1032,["class","onClick"])),64))]),_:1}),(l(!0),u(p,null,m(c(T),a=>(l(),i(B,{key:a.id,item:a},null,8,["item"]))),128)),n(I,{loading:c(z),error:c(A),empty:!c(T).length,"empty-text":"当前分类暂无任务",onRetry:s[0]||(s[0]=a=>c(G)(!0))},null,8,["loading","error","empty"]),c(F)&&!c(z)?(l(),i(t,{key:0,class:"driver-action driver-action--secondary load-more",onClick:s[1]||(s[1]=a=>c(G)())},{default:d(()=>[v(" 加载更多 ")]),_:1})):_("",!0)]),_:1}),n(P,{active:"/pages/driver/tasks"})]),_:1})}}}),[["__scopeId","data-v-1838c1de"]]);export{w as default};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-home-index.DgTCMZWA.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-orders-checkout.CA5Xwfqa.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-orders-index.BgjVvYkb.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-orders-tracking.DpR3Xhza.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-packages-cart.DnWDwS19.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-packages-detail.5MAfUSjI.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-packages-index.CvdaWGcY.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/pages-rights-index.DdpNSARC.js


+ 1 - 0
server/public/water-mini/assets/pages-rights-ledger.B4nJXNjN.js

@@ -0,0 +1 @@
+import{d as e,o as a,s,T as t,b as r,e as l,w as o,f as n,g as d,h as i,i as u,u as p,F as c,m,p as _,v as f,t as g,x as y,y as v,q as h}from"./index-B8ag6Oin.js";import{u as j}from"./usePaged.Zh5X8qoD.js";import{I as k}from"./IdentityGuard.CwYBrUeO.js";import{P as x}from"./PageState._en-b4Fw.js";import"./format.DDNdx33k.js";import"./_plugin-vue_export-helper.BCo6x5W8.js";const w=e({__name:"ledger",setup(e){const w={purchase:"购买入账",promotion_reward:"推广赠水权益",reserve:"配送冻结",cancel:"取消释放",complete:"完成配送",partial_receive:"部分签收",delivery_return:"配送退货"},{items:P,loading:b,error:q,hasMore:C,load:I}=j(e=>y(v("enterprise")+"/ledger",{page:e}));return a(()=>{var e;(null==(e=s.active)?void 0:e.role.startsWith("enterprise_"))&&I(!0)}),t(()=>I()),(e,a)=>{const s=_,t=h,y=f;return r(),l(s,{class:"page"},{default:o(()=>[n(k,{kind:"enterprise"},{default:o(()=>[n(s,{class:"notice"},{default:o(()=>[d("显示每次业务操作的桶数,并非全部代表权益扣减。")]),_:1}),(r(!0),i(c,null,u(p(P),e=>(r(),l(s,{key:e.id,class:"card"},{default:o(()=>[n(s,{class:"row"},{default:o(()=>[n(s,null,{default:o(()=>[n(s,{class:"strong"},{default:o(()=>[d(g(w[e.kind]||e.kind),1)]),_:2},1024),n(s,{class:"muted"},{default:o(()=>[d(g(e.created_at),1)]),_:2},1024)]),_:2},1024),n(t,{class:"amount"},{default:o(()=>[d(g(e.quantity)+"桶",1)]),_:2},1024)]),_:2},1024),n(s,{class:"muted",style:{"margin-top":"15rpx"}},{default:o(()=>[d(g(e.reference),1)]),_:2},1024)]),_:2},1024))),128)),n(x,{loading:p(b),error:p(q),empty:!p(P).length,onRetry:a[0]||(a[0]=e=>p(I)(!0))},null,8,["loading","error","empty"]),p(C)&&!p(b)?(r(),l(y,{key:0,class:"text-button",onClick:a[1]||(a[1]=e=>p(I)())},{default:o(()=>[d("加载更多")]),_:1})):m("",!0)]),_:1})]),_:1})}}});export{w as default};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
server/public/water-mini/assets/uni.9e4445bb.css


+ 1 - 0
server/public/water-mini/assets/usePaged.Zh5X8qoD.js

@@ -0,0 +1 @@
+import{ag as a,C as e,R as u,s as l,ah as s}from"./index-B8ag6Oin.js";function t(t){const r=a(null),v=a([]),o=e(!1),n=e(""),c=e(!1),i=e(0),m=e({});let f=0,h=0;return u(()=>l.epoch,()=>{h++,r.value=null,v.value=[],o.value=!1,n.value="",f=0,i.value=0,m.value={},c.value=!1},{flush:"sync"}),{data:r,items:v,loading:o,error:n,hasMore:c,total:i,summary:m,load:async function(a=!1){if(o.value&&!a)return;if(!a&&f>0&&!c.value)return;const e=a?++h:h,u=l.epoch,y=a?1:f+1;a&&(v.value=[],f=0,c.value=!1,i.value=0,m.value={}),o.value=!0,n.value="";try{const s=await t(y);if(e!==h||u!==l.epoch)return;r.value=s,v.value=a?s.items:[...v.value,...s.items],i.value=s.total,c.value=s.has_more,s.summary&&(m.value=s.summary),f=y}catch(p){e===h&&u===l.epoch&&(n.value=p instanceof Error?p.message:"加载失败")}finally{e===h&&(o.value=!1),s()}}}}export{t as u};

+ 1 - 0
server/public/water-mini/assets/useResource.CaerzKS8.js

@@ -0,0 +1 @@
+import{ag as a,C as e,R as l,s as n,ah as o}from"./index-B8ag6Oin.js";function s(s){const u=a(null),c=e(!1),t=e("");let r=0;return l(()=>n.epoch,()=>{r++,u.value=null,c.value=!1,t.value=""},{flush:"sync"}),{data:u,loading:c,error:t,load:async function(){const a=++r,e=n.epoch;c.value=!0,t.value="";try{const l=await s();a===r&&e===n.epoch&&(u.value=l)}catch(l){a===r&&e===n.epoch&&(u.value=null,t.value=l instanceof Error?l.message:"加载失败")}finally{a===r&&(c.value=!1),o()}}}}export{s as u};

+ 2 - 2
server/public/water-mini/index.html

@@ -1,12 +1,12 @@
 <!doctype html>
 <html lang="zh-CN">
   <head>
-    <link rel="stylesheet" href="/water-mini/assets/uni.19648d3d.css">
+    <link rel="stylesheet" href="/water-mini/assets/uni.9e4445bb.css">
 
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
     <title>云泉智配</title>
-    <script type="module" crossorigin src="/water-mini/assets/index-B8jJyCMw.js"></script>
+    <script type="module" crossorigin src="/water-mini/assets/index-B8ag6Oin.js"></script>
     <link rel="stylesheet" crossorigin href="/water-mini/assets/index-DY2jyvfz.css">
   </head>
   <body>

+ 2 - 2
water-mini/README.md

@@ -8,11 +8,11 @@ uni-app Vue 3 + TypeScript,微信小程序为主要交付端,同时提供 H5
 
 ## 测试手机号登录
 
-页面上的“手机验证码登录”同时支持测试账号与正式手机号。三个指定测试号直接输入固定验证码 `66666`,调用 `/auth/test-phone`,无需获取或发送短信;其余号码调用 `/auth/send-sms` 获取随机六位短信码,再通过 `/auth/phone-login` 登录。短信验证码两分钟有效,过期必须重新获取,重发后旧码作废。发送间隔60秒与验证码有效期120秒是两个独立规则。
+页面上的“手机验证码登录”同时支持测试账号与正式手机号。三个指定测试号仅输入手机号,调用 `/auth/test-phone`,无需验证码;其余号码调用 `/auth/send-sms` 获取随机六位短信码,再通过 `/auth/phone-login` 登录。短信验证码两分钟有效,过期必须重新获取,重发后旧码作废。发送间隔60秒与验证码有效期120秒是两个独立规则。
 
 手机号入口在 `capabilities.sms_login` 或 `capabilities.test_phone_login` 任一开启时显示,但各自独立控制对应登录方式。测试号只走测试接口,不会因为测试能力关闭而改走短信。获取短信无需先勾选协议,提交登录仍需同意协议。正式手机号沿用后台预绑定已有账号的规则。
 
-在后端 `.env` 设置 `MINI_TEST_PHONE_LOGIN=true`,执行 `php -d extension=mbstring scripts/seed_mini_test_phone.php --apply` 并重载后端。按用户要求,测试登录不限制 `APP_ENV` 或客户端 IP,开发者工具和真机均可使用;固定验证码均为 `66666`,不发送短信。每个测试账号只绑定一种身份,登录后直接进入对应页面:
+在后端 `.env` 设置 `MINI_TEST_PHONE_LOGIN=true`,执行 `php -d extension=mbstring scripts/seed_mini_test_phone.php --apply` 并重载后端。按用户要求,测试登录不限制 `APP_ENV` 或客户端 IP,开发者工具和真机均可使用;测试账号无需验证码,不发送短信。每个测试账号只绑定一种身份,登录后直接进入对应页面:
 
 | 角色 | 测试手机号 | 登录后页面 |
 | --- | --- | --- |

+ 14 - 9
water-mini/tests/login-agreement-dom.test.mjs

@@ -60,7 +60,7 @@ async function click(element) {
   await Promise.resolve();
 }
 
-async function fixture(t, code = '66666') {
+async function fixture(t, code = '', phone = '13012345678') {
   const posts = [],
     messages = [],
     accepted = [],
@@ -108,10 +108,14 @@ async function fixture(t, code = '66666') {
     root.remove();
   });
   await click(root.querySelector('.login-option'));
-  const inputs = root.querySelectorAll('.phone-login input');
-  for (const [index, value] of ['13012345678', code].entries()) {
-    inputs[index].value = value;
-    inputs[index].dispatchEvent(new window.Event('input', { bubbles: true }));
+  const phoneInput = root.querySelector('.phone-login input');
+  phoneInput.value = phone;
+  phoneInput.dispatchEvent(new window.Event('input', { bubbles: true }));
+  await vue.nextTick();
+  const codeInput = root.querySelector('.code-field input');
+  if (codeInput) {
+    codeInput.value = code;
+    codeInput.dispatchEvent(new window.Event('input', { bubbles: true }));
   }
   await vue.nextTick();
   const consent = () =>
@@ -130,7 +134,8 @@ test('clicking the agreement text updates the actual checkbox and permits login'
   await click(app.consent());
   assert.equal(app.checked(), true);
   await app.submit();
-  assert.deepEqual(app.posts, [{ phone: '13012345678', code: '66666' }]);
+  assert.equal(app.root.querySelector('.code-field'), null);
+  assert.deepEqual(app.posts, [{ phone: '13012345678', code: '' }]);
   assert.equal(app.accepted.length, 1);
 });
 
@@ -161,10 +166,10 @@ test('opening the privacy link never changes agreement selection', async (t) =>
   assert.equal(app.posts.length, 1);
 });
 
-test('an agreed test login with a six-digit code shows a code error instead of an agreement error', async (t) => {
-  const app = await fixture(t, '666666');
+test('an agreed real phone login still rejects an invalid SMS code', async (t) => {
+  const app = await fixture(t, '66666', '13800138000');
   await click(app.consent());
   await app.submit();
   assert.equal(app.posts.length, 0);
-  assert.equal(app.messages.at(-1), '测试账号请输入5位测试验证码 66666');
+  assert.equal(app.messages.at(-1), '请输入6位短信验证码');
 });

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio