From fa8d4cc38de890c82b0ccacfd42235d7b31c65b2 Mon Sep 17 00:00:00 2001 From: Daniel Kou Date: Fri, 5 Jun 2026 14:47:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84OSS/CDN=EF=BC=8C=E7=A7=81?= =?UTF-8?q?=E5=AF=86OSS=EF=BC=8C=E5=95=86=E5=AE=B6=E5=85=A5=E9=A9=BB,?= =?UTF-8?q?=E5=AE=A2=E6=9C=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v2Home.js | 1 + api/v2local.js | 2 + doc/首页Banner跳转现状梳理.md | 84 ++ package-lock.json | 839 +++++++++++++++++- packages/advertising/goodsDetail/index.vue | 22 +- packages/customerService/index/index.vue | 372 +++++++- packages/customerService/picker/index.vue | 165 ++++ packages/localLife/detail/index.css | 80 ++ packages/localLife/detail/index.vue | 65 +- packages/myOrders/orderDetails/index.vue | 10 +- packages/shopEnter/auditStatus/index.css | 173 +++- packages/shopEnter/auditStatus/index.vue | 253 +++--- packages/shopEnter/camera/index.css | 235 +++++ packages/shopEnter/camera/index.vue | 165 ++++ packages/shopEnter/confirm/index.css | 182 ++++ packages/shopEnter/confirm/index.vue | 209 +++++ packages/shopEnter/example/index.vue | 16 +- packages/shopEnter/index/index.css | 254 ++++++ packages/shopEnter/index/index.vue | 977 ++++++++++++++++----- pages.json | 23 +- pages/index/index.vue | 101 ++- project.config.json | 15 +- project.private.config.json | 19 +- utils/uploadOSS.js | 10 +- 24 files changed, 3771 insertions(+), 501 deletions(-) create mode 100644 doc/首页Banner跳转现状梳理.md create mode 100644 packages/customerService/picker/index.vue create mode 100644 packages/shopEnter/camera/index.css create mode 100644 packages/shopEnter/camera/index.vue create mode 100644 packages/shopEnter/confirm/index.css create mode 100644 packages/shopEnter/confirm/index.vue diff --git a/api/v2Home.js b/api/v2Home.js index 049a5e35..ebcf62ec 100644 --- a/api/v2Home.js +++ b/api/v2Home.js @@ -2,6 +2,7 @@ export const apiArr = { getCateList: "/api/v2/wechat/merchant-cate-crud/list", //商家分类列表 getMerchantList: "/api/v2/wechat/merchant-info-crud/page", //商家列表 getHomeBanner: "/api/v2/wechat/home-banner-region-crud/page", //获取首页banner及其广告 + getHomeBannerMulti: "/api/v2/wechat/home-banner-region-crud/multi", //按广告位批量获取首页广告(一次返回多个 ad_position) getButtonNum:"/api/v2/wechat/nav-display-crud/info",//获取首页button的行数 数量 getHomeButton:"/api/v2/wechat/home-button-region-crud/page", //获取首页button diff --git a/api/v2local.js b/api/v2local.js index ad94c779..926cbe9d 100644 --- a/api/v2local.js +++ b/api/v2local.js @@ -3,6 +3,7 @@ export const apiArr = { getMerchantList:"/api/v2/wechat/merchant-info-crud/page",//商家列表 createComment:"/api/v2/wechat/merchant-evaluation-crud/creat",//创建用户评价 getMerchantInfo:"/api/v2/wechat/merchant-info-crud/info",//获取商家信息详情 + getShopActivityList:"/api/v2/wechat/commodity/shop-activity/list",//好店详情页-店铺活动商品列表 getMerchantComment:"/api/v2/wechat/merchant-evaluation-crud/page",//获取商家评价 merChantCommentLike:"/api/v2/wechat/merchant-evaluation-like-crud/creat",//点赞 merChantCommentUnlike:"/api/v2/wechat/merchant-evaluation-like-crud/del",//取消点赞 @@ -26,4 +27,5 @@ export const apiArr = { createStore:"/api/v2/wechat/store-info-crud/creat",//门店信息创建 + ocrRecognize:"/api/v1/wechat/oss/ocr-recognize",//证件 OCR 自动识别 }; diff --git a/doc/首页Banner跳转现状梳理.md b/doc/首页Banner跳转现状梳理.md new file mode 100644 index 00000000..0e8bcb76 --- /dev/null +++ b/doc/首页Banner跳转现状梳理.md @@ -0,0 +1,84 @@ +# 首页 Banner / 广告位 跳转现状梳理 + +> 状态:现状分析(仅梳理,代码未改)。日期:2026-06-03 +> 范围:小程序 `pages/index/index.vue` 首页各广告位的点击跳转逻辑,对照后端配置。 + +--- + +## 一、后端是怎么配置跳转的 + +每条 banner/广告(表 `home_banner_region`)、金刚位(表 `home_button_region`)都有统一的跳转配置字段,核心是 **`promotion_type`(推广类型)**: + +| promotion_type | 含义 | 配套字段 | +|---|---|---| +| 1 | 无跳转 | — | +| 2 | 选择活动 | 关联 `advertisement_goods`(按 banner id) | +| 3 | 跳转本程序页面 | `link_url` | +| 4 | 跳转其他小程序 | `appid` + `link_url` | +| 5 | 选择商品 | `advertisement_goods[].goods_id` | + +- 后台创建/编辑接口(`api/admin/v2/crud_home_banner_region.go`)用 `promotion_type` + `required-if` 校验对应字段,例如 type=4 必填 appid、type=3/4 必填 link_url。 +- `home_button_region`(金刚位)字段相同,也有 `promotion_type` / `link_url` / `appid`。 +- type=2/5 的落地:`/packages/advertising/index/index?id=` 是“广告聚合落地页”,传 banner 自身 id 进去,页面内部拉该 banner 关联的 `advertisement_goods` 商品列表展示,并可进入 `goodsDetail`。 + +--- + +## 二、前端实际怎么跳的(问题所在) + +首页有 4 个不同的点击处理函数各管一片,**几乎都没读 `promotion_type`**: + +### 1. `headerServerClick`(金刚位 tabList、homeLeftList 用) +- 文件:`pages/index/index.vue`(搜 `headerServerClick(e)`) +- 只看 `link_url` 和 `appid`,**完全忽略 `promotion_type`**。 +- 逻辑:无 `link_url` → 弹“此功能暂未开通”;有 `appid` → 跳小程序;否则当本程序路径 `NavgateTo`。 +- **后果**:type=2(活动)、type=5(商品)的配置它不认 → 落到“没 link_url”分支 → 弹“暂未开通”。 + +### 2. `toAdvertisingView`(广告横幅 serverLeft、serverRight[0] 用) +- 文件:`pages/index/index.vue:357` 附近 +- **写死**跳 `/packages/advertising/index/index?id=xxx`,不看 `promotion_type`,一律进广告落地页。 + +### 3. `goToPurify`(serverRight 非首个用,模板 `index.vue:101`) +- 文件:`pages/index/index.vue:363` 附近 +- **彻底写死**:固定跳净水小程序 `appId=wx77b22c0a0018e580`,path/appId 全硬编码,传入的 `item` 没用到,与后台配置零关系。 +- 模板:`@tap="index === 0 ? toAdvertisingView(serverRightList) : goToPurify(item)"` —— serverRight 第一个跳广告页,其余全跳净水小程序。 + +### 4. `headerServerClick2`(中部 serverItem / homeRightList1,2 用) +- 文件:`pages/index/index.vue`(搜 `headerServerClick2(e)`) +- 不跳外链,只按 `title` 匹配商家分类做筛选,或固定跳本地生活页。**注意:这一处可能是“按分类筛选”的有意设计,不一定算 bug。** + +### 5. 顶部轮播 Banner(位置 1,模板 `index.vue:68`) +- 点击事件被**注释掉了**(``),顶部 banner 现在点击无反应。 + +--- + +## 三、根因 + +后台用统一的 `promotion_type` 模型配跳转,前端却是早期“按位置分别写死”的处理函数拼起来的:既没统一读 `promotion_type`,部分位置还硬编码了目标(广告页、净水小程序)。所以出现“很多跳转和后台配置不符”——不是数据错,是前端没按配置解析。 + +--- + +## 四、建议修法(未实施,待决策) + +做一个统一跳转函数 `handleAdJump(item)`,严格按 `promotion_type` 分发: + +``` +switch promotion_type: + 1: 不跳 + 2: NavgateTo('/packages/advertising/index/index?id=' + item.id) // 活动 + 3: link_url 跳本程序页面(兼容 shopEnter 特例 / H5 / APP webview) + 4: navigateToMiniProgram(appid, link_url) // 其他小程序 + 5: NavgateTo('/packages/advertising/index/index?id=' + item.id) // 商品(同活动,落地页内展示) + 其他: 弹“暂未开通” +``` + +然后把首页所有广告位的 `@click`/`@tap` 都换成 `handleAdJump(item)`: +- 顶部轮播 banner:取消注释,改 `handleAdJump` +- 金刚位 tabList、homeLeftList:`headerServerClick` → `handleAdJump` +- serverLeft、serverRight:`toAdvertisingView` / `goToPurify` → `handleAdJump` + +### 实施前需确认的点 +1. `headerServerClick2`(中部 serverItem 按 title 筛分类)是否要保留分类筛选语义?还是也改成按 `promotion_type` 跳? +2. 净水小程序跳转:是想**保留写死**,还是改由后台某条 banner 配 `type=4 + 该 appid` 来控制(更灵活,去掉硬编码)? +3. type=2/5 是否都统一进广告落地页 `/packages/advertising/index/index?id=banner.id`(当前分析结论是“是”)。 + +> 相关:`promotion_type` 字段定义见 `huichang-server/internal/model/entity/home_banner_region.go`、`home_button_region.go`;广告落地页 `uniapp-ZHSQ/packages/advertising/index/index.vue`。 diff --git a/package-lock.json b/package-lock.json index 9dd5db54..887f026e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "支付键盘、数字键盘、付款键盘、密码键盘", "version": "1.0.1", - "lockfileVersion": 3, + "lockfileVersion": 2, "requires": true, "packages": { "": { @@ -1168,5 +1168,842 @@ "node": ">=0.4" } } + }, + "dependencies": { + "@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" + }, + "@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" + }, + "@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "requires": { + "@babel/types": "^7.28.4" + } + }, + "@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "requires": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + }, + "@vue/compiler-core": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz", + "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==", + "requires": { + "@babel/parser": "^7.28.3", + "@vue/shared": "3.5.21", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "@vue/compiler-dom": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz", + "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==", + "requires": { + "@vue/compiler-core": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "@vue/compiler-sfc": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz", + "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==", + "requires": { + "@babel/parser": "^7.28.3", + "@vue/compiler-core": "3.5.21", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.18", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "@vue/compiler-ssr": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz", + "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==", + "requires": { + "@vue/compiler-dom": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "@vue/reactivity": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz", + "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==", + "requires": { + "@vue/shared": "3.5.21" + } + }, + "@vue/runtime-core": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz", + "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==", + "requires": { + "@vue/reactivity": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "@vue/runtime-dom": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz", + "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==", + "requires": { + "@vue/reactivity": "3.5.21", + "@vue/runtime-core": "3.5.21", + "@vue/shared": "3.5.21", + "csstype": "^3.1.3" + } + }, + "@vue/server-renderer": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz", + "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==", + "requires": { + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "@vue/shared": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz", + "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "callback-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/callback-stream/-/callback-stream-1.1.0.tgz", + "integrity": "sha512-sAZ9kODla+mGACBZ1IpTCAisKoGnv6PykW7fPk1LrM+mMepE18Yz0515yoVcrZy7dQsTUp3uZLQ/9Sx1RnLoHw==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "> 1.0.0 < 3.0.0" + } + }, + "commist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", + "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", + "requires": { + "leven": "^2.1.0", + "minimist": "^1.1.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "requires": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + } + }, + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "requires": { + "ms": "^2.1.3" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "requires": { + "once": "^1.4.0" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, + "es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "requires": { + "d": "^1.0.2", + "ext": "^1.7.0" + } + }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "requires": { + "type": "^2.7.2" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "help-me": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-1.1.0.tgz", + "integrity": "sha512-P/IZ8yOMne3SCTHbVY429NZ67B/2bVQlcYGZh2iPPbdLrEQ/qY5aGChn0YTDmt7Sb4IKRI51fypItav+lNl76w==", + "requires": { + "callback-stream": "^1.0.2", + "glob-stream": "^6.1.0", + "through2": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==" + }, + "magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "mqtt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-3.0.0.tgz", + "integrity": "sha512-0nKV6MAc1ibKZwaZQUTb3iIdT4NVpj541BsYrqrGBcQdQ7Jd0MnZD1/6/nj1UFdGTboK9ZEUXvkCu2nPCugHFA==", + "requires": { + "base64-js": "^1.3.0", + "commist": "^1.0.0", + "concat-stream": "^1.6.2", + "end-of-stream": "^1.4.1", + "es6-map": "^0.1.5", + "help-me": "^1.0.1", + "inherits": "^2.0.3", + "minimist": "^1.2.0", + "mqtt-packet": "^6.0.0", + "pump": "^3.0.0", + "readable-stream": "^2.3.6", + "reinterval": "^1.1.0", + "split2": "^3.1.0", + "websocket-stream": "^5.1.2", + "xtend": "^4.0.1" + } + }, + "mqtt-packet": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", + "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", + "requires": { + "bl": "^4.0.2", + "debug": "^4.1.1", + "process-nextick-args": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==" + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "requires": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==" + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "vue": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz", + "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==", + "requires": { + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "websocket-stream": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.5.2.tgz", + "integrity": "sha512-8z49MKIHbGk3C4HtuHWDtYX8mYej1wWabjthC/RupM9ngeukU4IWoM46dgth1UOS/T4/IqgEdCDJuMe2039OQQ==", + "requires": { + "duplexify": "^3.5.1", + "inherits": "^2.0.1", + "readable-stream": "^2.3.3", + "safe-buffer": "^5.1.2", + "ws": "^3.2.0", + "xtend": "^4.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } } } diff --git a/packages/advertising/goodsDetail/index.vue b/packages/advertising/goodsDetail/index.vue index e062a0ad..2b525672 100644 --- a/packages/advertising/goodsDetail/index.vue +++ b/packages/advertising/goodsDetail/index.vue @@ -582,8 +582,10 @@ export default { // 使用完整的商品数据对象,而不是itemObj this.currentGG = this.info.commodity_goods_info_list[this.currentGGIndex]; - // 将promotional_price赋值给sales_price - this.currentGG.sales_price = this.promotional_price; + // 将promotional_price赋值给sales_price(无活动价时保留商品自身价格,如客服分享场景) + if (this.promotional_price !== "" && this.promotional_price != null) { + this.currentGG.sales_price = this.promotional_price; + } // 设置相关属性 this.changeImg = this.currentGG.commodity_pic[0]; @@ -616,8 +618,10 @@ export default { // 切换规格 changeGG(item, index) { this.currentGG = item; - // 将promotional_price赋值给sales_price - this.currentGG.sales_price = this.promotional_price; + // 将promotional_price赋值给sales_price(无活动价时保留商品自身价格) + if (this.promotional_price !== "" && this.promotional_price != null) { + this.currentGG.sales_price = this.promotional_price; + } this.currentGGIndex = index; if (this.currentGG.cart_count) { this.currentNum = this.currentGG.cart_count.count; @@ -778,7 +782,15 @@ export default { } }, onLoad(options) { - this.itemObj = JSON.parse(decodeURIComponent(options.item)); + // 来自客服聊天卡片:优先从本地存储读完整数据(避免 URL 过长) + if (options && options.fromChat) { + let stashed + try { stashed = uni.getStorageSync('chatCardItem') } catch (e) { stashed = null } + uni.removeStorageSync('chatCardItem') + this.itemObj = stashed || JSON.parse(decodeURIComponent(options.item)) + } else { + this.itemObj = JSON.parse(decodeURIComponent(options.item)); + } const meun = menuButtonInfo(); this.top = meun.top; this.localHeight = meun.height; diff --git a/packages/customerService/index/index.vue b/packages/customerService/index/index.vue index ff67e77b..05346cfc 100644 --- a/packages/customerService/index/index.vue +++ b/packages/customerService/index/index.vue @@ -33,9 +33,44 @@ }" class="message-item"> - + + {{ message.content }} + + + + 图片加载中… + + + + + 视频加载中… + + + + + 商品 + + {{ message.card.name }} + ¥{{ message.card.price }} + 商品 + + + + + + 订单 + + 订单 {{ message.card.order_no }} + ¥{{ message.card.amount }} + 订单 · 共{{ message.card.count }}件 + + + {{ message.content }} @@ -46,18 +81,45 @@ + + + + + + + 🖼️ + 相册图片 + + + 📷 + 拍摄 + + + 🎬 + 视频 + + + 🛒 + 商品/购物车 + + + 📦 + 订单 + + @@ -592,4 +809,115 @@ export default { --header-height: 80px; /* 头部高度 */ --input-height: 80px; /* 输入区域高度 */ } + +/* 图片/视频消息 */ +.message-media { + max-width: 60%; +} +.chat-img { + width: 320rpx; + height: 320rpx; + border-radius: 12rpx; + background: #f0f0f0; +} +.chat-video { + width: 400rpx; + height: 300rpx; + border-radius: 12rpx; +} +.media-loading { + padding: 30rpx 40rpx; + background: #fff; + border-radius: 12rpx; + color: #999; + font-size: 24rpx; +} + +/* 商品/订单卡片 */ +.message-card { + display: flex; + width: 520rpx; + background: #fff; + border-radius: 14rpx; + overflow: hidden; + box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06); +} +.card-pic { + width: 180rpx; + height: 180rpx; + flex-shrink: 0; + background: #f5f5f5; +} +.card-pic--ph { + display: flex; + align-items: center; + justify-content: center; + color: #bbb; + font-size: 28rpx; +} +.card-info { + flex: 1; + padding: 18rpx 20rpx; + display: flex; + flex-direction: column; + justify-content: space-between; + min-width: 0; +} +.card-name { + font-size: 28rpx; + color: #222; + line-height: 38rpx; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.card-price { + font-size: 32rpx; + color: #FF370B; + font-weight: 600; +} +.card-tag { + align-self: flex-start; + font-size: 20rpx; + color: #999; + border: 1rpx solid #eee; + border-radius: 6rpx; + padding: 0 10rpx; +} + +/* "+" 按钮与更多面板 */ +.plus-btn { + display: flex; + align-items: center; + justify-content: center; + width: 60rpx; + height: 60rpx; +} +.more-panel { + display: flex; + flex-wrap: wrap; + padding: 24rpx 12rpx; + background: #f7f7f7; +} +.panel-item { + width: 20%; + display: flex; + flex-direction: column; + align-items: center; + gap: 8rpx; + font-size: 22rpx; + color: #666; + margin-bottom: 16rpx; +} +.panel-icon { + width: 96rpx; + height: 96rpx; + background: #fff; + border-radius: 16rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 44rpx; +} \ No newline at end of file diff --git a/packages/customerService/picker/index.vue b/packages/customerService/picker/index.vue new file mode 100644 index 00000000..c09b95b5 --- /dev/null +++ b/packages/customerService/picker/index.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/packages/localLife/detail/index.css b/packages/localLife/detail/index.css index be45a8b2..baa4629a 100644 --- a/packages/localLife/detail/index.css +++ b/packages/localLife/detail/index.css @@ -425,4 +425,84 @@ page { .coupon_item_button::after { border: none; +} + +/* ============ 店铺活动商品 ============ */ +.shop-activity { + padding: 24rpx; +} + +.shop-activity-title { + font-size: 32rpx; + font-weight: 600; + color: #222; + padding-left: 16rpx; + border-left: 6rpx solid #FF370B; + margin-bottom: 20rpx; +} + +.shop-activity-list { + display: flex; + flex-direction: column; + gap: 20rpx; +} + +.sa-goods { + display: flex; + align-items: center; + background: #fff; + border: 1rpx solid #f2f2f2; + border-radius: 12rpx; + padding: 16rpx; +} + +.sa-pic { + width: 160rpx; + height: 160rpx; + border-radius: 8rpx; + flex-shrink: 0; + background: #f5f5f5; +} + +.sa-info { + flex: 1; + margin-left: 20rpx; + display: flex; + flex-direction: column; + justify-content: center; + min-width: 0; +} + +.sa-name { + font-size: 28rpx; + color: #222; + line-height: 38rpx; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.sa-price-row { + display: flex; + align-items: baseline; + margin-top: 16rpx; + gap: 16rpx; +} + +.sa-price { + font-size: 34rpx; + font-weight: 600; + color: #FF370B; +} + +.sa-unit { + font-size: 22rpx; + font-weight: normal; +} + +.sa-origin { + font-size: 22rpx; + color: #999; + text-decoration: line-through; } \ No newline at end of file diff --git a/packages/localLife/detail/index.vue b/packages/localLife/detail/index.vue index 94ed6984..b0be3c58 100644 --- a/packages/localLife/detail/index.vue +++ b/packages/localLife/detail/index.vue @@ -59,6 +59,27 @@ + + + + 店铺活动 + + + + + + {{ sku.goods_name || item.commodity_name }} + + ¥{{ sku.group_buy_price }}/{{ sku.goods_unit }} + 单买价 ¥{{ sku.sales_price }} + + + + + + + @@ -181,7 +202,8 @@ export default { isDisabled: false, coupons: [], couponDetails: [], - showCouponPopup: false + showCouponPopup: false, + shopActivityList: [] // 店铺活动商品(团购 activity_type=2) }; }, onLoad(options) { @@ -213,6 +235,7 @@ export default { this.flag = false this.commentList = [] this.getCommentList() + this.getShopActivity() }); }, onShow() { @@ -229,6 +252,46 @@ export default { }, methods: { + // 店铺活动商品(团购 activity_type=2),小区来源与团购一致(绑定房产小区) + getShopActivity() { + const userId = uni.getStorageSync('userId') + if (!userId) return + const params = { + user_id: userId, + merchant_id: this.info.id, + community_id: uni.getStorageSync('changeCommData') ? uni.getStorageSync('changeCommData').id : '' + } + request(apiArr.getShopActivityList, "POST", params, {}, false).then(res => { + const list = (res.list || []).map(item => { + const group_buy_goods_list = (item.group_buy_goods_list || []).map(sku => ({ + ...sku, + commodity_pic: picUrl + sku.commodity_pic, + quantity: 0 + })) + return { + ...item, + commodity_pic: picUrl + item.commodity_pic, + group_buy_goods_list + } + }) + this.shopActivityList = list + }).catch(() => { + this.shopActivityList = [] + }) + }, + // 点击店铺活动商品 -> 复用团购详情页 + toShopActivityDetail(itemObj) { + let targetItem = itemObj + if (!targetItem.group_buy_activity_info && targetItem.group_buy_goods_list && targetItem.group_buy_goods_list.length > 0) { + targetItem = targetItem.group_buy_goods_list[0] + } + if (!targetItem.group_buy_activity_info) return + const item = { + ...targetItem, + groupById: targetItem.group_buy_activity_info.id + } + NavgateTo(`/packages/shop/groupPurchaseDetail/index?item=${JSON.stringify(item)}`) + }, getCouponList() { const params = { mch_id: uni.getStorageSync("merchantInfo").id, diff --git a/packages/myOrders/orderDetails/index.vue b/packages/myOrders/orderDetails/index.vue index 6b9aba3e..371904cc 100644 --- a/packages/myOrders/orderDetails/index.vue +++ b/packages/myOrders/orderDetails/index.vue @@ -170,7 +170,15 @@ export default { }; }, onLoad(options) { - const item = JSON.parse(options?.item); + let item + // 来自客服聊天卡片:完整订单数据经本地存储中转(避免 URL 过长被截断) + if (options && options.fromChat) { + try { item = uni.getStorageSync('chatCardItem') } catch (e) { item = null } + uni.removeStorageSync('chatCardItem') + } + if (!item) { + item = JSON.parse(options?.item); + } this.orderInfo = item; // 启动倒计时 item.order_status == "1" ? this.startCountdown() : ""; diff --git a/packages/shopEnter/auditStatus/index.css b/packages/shopEnter/auditStatus/index.css index 8b801b99..6eb09683 100644 --- a/packages/shopEnter/auditStatus/index.css +++ b/packages/shopEnter/auditStatus/index.css @@ -1,67 +1,148 @@ +/* ============================================================ + * 商家入驻 - 资料审核状态页 + * 审核中 #FF9F0A 通过 #34C759 失败 #FF3B30 主色 #FF370B + * ============================================================ */ +page { + background-color: #F6F7F9; + min-height: 100vh; +} + .container { - margin-top: 100rpx; - display: flex; - justify-content: center; + padding: 24rpx; + box-sizing: border-box; + padding-bottom: 200rpx; } -.auditStatus { - width: 100px; - height: 100px; - margin: 0 auto; +.audit-card { + background: #FFFFFF; + border-radius: 16rpx; + padding: 60rpx 40rpx 48rpx; + display: flex; + flex-direction: column; + align-items: center; } -.title { - font-size: 40rpx; - font-weight: bold; - margin: 10rpx 0; - text-align: center; +.audit-icon { + width: 120rpx; + height: 120rpx; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 28rpx; } -.content{ - font-size: 26rpx; - margin-top: 40rpx; - text-align: center; - color: #a9a9a9; +.audit-icon--ing { + background: #FFF4E0; } -.info{ - margin-top: 70rpx; - width: 500rpx; - background-color: #f6f6fa; - padding: 20rpx 30rpx; - border-radius: 20rpx; +.audit-icon--ok { + background: #E6F8EA; } -.info view{ - display: flex; - justify-content: space-between; - margin: 15rpx 0; +.audit-icon--fail { + background: #FDECEA; } -.info_text{ - color: #999999; +.audit-title { + font-size: 36rpx; + font-weight: 600; + color: #222; + margin-bottom: 16rpx; } -.info_text2{ - color: #faba5a; +.audit-desc { + font-size: 26rpx; + color: #999; + text-align: center; + line-height: 40rpx; + padding: 0 20rpx; + margin-bottom: 32rpx; } -.btn{ - margin-top: 50rpx; - border: none; - background-color: #ff4218; - color: #ffffff; - border-radius: 50rpx; +.audit-times { + width: 100%; + border-top: 1rpx solid #F2F2F2; + padding-top: 24rpx; } -.warning{ - color: #ff4218; - font-size: 27rpx; - margin: 50rpx 0; +.audit-time-row { + display: flex; + justify-content: center; + font-size: 26rpx; + color: #666; + line-height: 44rpx; } -.warning_title{ - font-size: 30rpx; - font-weight: bold; - margin-bottom: 20rpx; -} \ No newline at end of file +/* 驳回原因框 */ +.reject-box { + width: 100%; + background: #FFF7F4; + border: 1rpx solid #FFD9CD; + border-radius: 12rpx; + padding: 24rpx; + margin-bottom: 24rpx; +} + +.reject-title { + display: flex; + align-items: center; + gap: 10rpx; + font-size: 28rpx; + font-weight: 600; + color: #FF370B; + margin-bottom: 14rpx; +} + +.reject-text { + font-size: 26rpx; + color: #FF370B; + line-height: 42rpx; + white-space: pre-wrap; +} + +.reject-imgs { + margin-top: 18rpx; +} + +.reject-imgs-label { + font-size: 24rpx; + color: #999; + margin-bottom: 12rpx; +} + +.reject-thumbs { + display: flex; + flex-wrap: wrap; + gap: 12rpx; +} + +.reject-thumb { + width: 120rpx; + height: 120rpx; + border-radius: 8rpx; + border: 1rpx solid #EEE; +} + +/* 底部按钮 */ +.audit-footer { + position: fixed; + left: 0; + right: 0; + bottom: 0; + background: #FFFFFF; + padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); + box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.04); + z-index: 99; +} + +.btn-primary { + height: 88rpx; + background: linear-gradient(91deg, #FF7658 0%, #FF370B 100%); + border-radius: 44rpx; + color: #FFFFFF; + font-size: 30rpx; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/packages/shopEnter/auditStatus/index.vue b/packages/shopEnter/auditStatus/index.vue index bab1eeaa..38a5b4e0 100644 --- a/packages/shopEnter/auditStatus/index.vue +++ b/packages/shopEnter/auditStatus/index.vue @@ -1,128 +1,141 @@ + + \ No newline at end of file + diff --git a/packages/shopEnter/camera/index.css b/packages/shopEnter/camera/index.css new file mode 100644 index 00000000..c5000e57 --- /dev/null +++ b/packages/shopEnter/camera/index.css @@ -0,0 +1,235 @@ +/* ============================================================ + * 商家入驻 - 自定义相机(取景框拍证件) + * ============================================================ */ +page { + background: #000; +} + +.cam-page { + position: fixed; + inset: 0; + background: #000; + overflow: hidden; +} + +/* 顶部导航 */ +.cam-nav { + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 20; + display: flex; + align-items: center; + justify-content: space-between; + padding: 12rpx 24rpx; + height: 88rpx; +} + +.cam-nav-back { + width: 60rpx; + height: 60rpx; + display: flex; + align-items: center; +} + +.cam-nav-title { + color: #fff; + font-size: 32rpx; + font-weight: 500; +} + +.cam-nav-right { + width: 60rpx; +} + +/* 相机取景 */ +.cam-view { + width: 100%; + height: 100vh; +} + +/* 取景框遮罩 */ +.cam-overlay { + position: absolute; + inset: 0; + z-index: 10; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + pointer-events: none; +} + +.cam-frame { + position: relative; + border: 2rpx dashed rgba(255, 255, 255, 0.7); + border-radius: 16rpx; +} + +.frame-landscape { + width: 86vw; + height: 54vw; +} + +.frame-portrait { + width: 64vw; + height: 86vw; +} + +.cam-corner { + position: absolute; + width: 44rpx; + height: 44rpx; + border-color: #FF370B; + border-style: solid; + border-width: 0; +} + +.cam-corner.tl { + top: -2rpx; + left: -2rpx; + border-top-width: 6rpx; + border-left-width: 6rpx; + border-top-left-radius: 16rpx; +} + +.cam-corner.tr { + top: -2rpx; + right: -2rpx; + border-top-width: 6rpx; + border-right-width: 6rpx; + border-top-right-radius: 16rpx; +} + +.cam-corner.bl { + bottom: -2rpx; + left: -2rpx; + border-bottom-width: 6rpx; + border-left-width: 6rpx; + border-bottom-left-radius: 16rpx; +} + +.cam-corner.br { + bottom: -2rpx; + right: -2rpx; + border-bottom-width: 6rpx; + border-right-width: 6rpx; + border-bottom-right-radius: 16rpx; +} + +.cam-tip { + margin-top: 36rpx; + color: #fff; + font-size: 28rpx; + text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.6); +} + +/* 横版/竖版切换 */ +.cam-orient { + position: absolute; + bottom: 280rpx; + left: 0; + right: 0; + z-index: 20; + display: flex; + justify-content: center; + gap: 24rpx; +} + +.orient-item { + padding: 12rpx 40rpx; + border-radius: 40rpx; + background: rgba(255, 255, 255, 0.18); + color: rgba(255, 255, 255, 0.8); + font-size: 28rpx; +} + +.orient-item.active { + background: #FF370B; + color: #fff; +} + +/* 底部操作 */ +.cam-actions { + position: absolute; + bottom: 0; + left: 0; + right: 0; + z-index: 20; + height: 240rpx; + display: flex; + align-items: center; + justify-content: space-around; + padding-bottom: env(safe-area-inset-bottom); + background: rgba(0, 0, 0, 0.3); +} + +.cam-action-side { + width: 110rpx; + display: flex; + flex-direction: column; + align-items: center; + gap: 8rpx; + color: #fff; + font-size: 24rpx; +} + +.cam-action-placeholder { + opacity: 0; +} + +.cam-shutter { + width: 130rpx; + height: 130rpx; + border-radius: 50%; + background: #fff; + border: 8rpx solid rgba(255, 255, 255, 0.4); + box-sizing: border-box; +} + +.cam-shutter:active { + transform: scale(0.94); +} + +/* 预览态 */ +.cam-preview { + width: 100%; + height: 100vh; + background: #000; +} + +.cam-preview-actions { + position: absolute; + bottom: 0; + left: 0; + right: 0; + z-index: 20; + height: 200rpx; + display: flex; + align-items: center; + justify-content: center; + gap: 40rpx; + padding-bottom: env(safe-area-inset-bottom); + background: rgba(0, 0, 0, 0.4); +} + +.prev-btn { + width: 240rpx; + height: 88rpx; + border-radius: 44rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 30rpx; +} + +.prev-retake { + background: rgba(255, 255, 255, 0.2); + color: #fff; +} + +.prev-submit { + background: linear-gradient(91deg, #FF7658 0%, #FF370B 100%); + color: #fff; +} diff --git a/packages/shopEnter/camera/index.vue b/packages/shopEnter/camera/index.vue new file mode 100644 index 00000000..c770fc80 --- /dev/null +++ b/packages/shopEnter/camera/index.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/packages/shopEnter/confirm/index.css b/packages/shopEnter/confirm/index.css new file mode 100644 index 00000000..c6666bdd --- /dev/null +++ b/packages/shopEnter/confirm/index.css @@ -0,0 +1,182 @@ +/* ============================================================ + * 商家入驻 - 确认信息页(预览信息) + * 主色 #FF370B 背景 #F6F7F9 + * ============================================================ */ +page { + background-color: #F6F7F9; + min-height: 100vh; + padding-bottom: 200rpx; +} + +.container { + padding-bottom: 40rpx; + box-sizing: border-box; +} + +/* 顶部进度条(复用主页样式) */ +.step-bar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 24rpx 30rpx 28rpx; + background: linear-gradient(91deg, #FF7658 0%, #FF370B 100%); +} + +.step-pill { + flex: 1; + height: 60rpx; + margin: 0 8rpx; + border-radius: 30rpx; + background: rgba(255, 255, 255, 0.18); + display: flex; + align-items: center; + justify-content: center; + color: rgba(255, 255, 255, 0.65); + font-size: 26rpx; +} + +.step-pill.active { + background: #FFFFFF; + color: #FF370B; + font-weight: 600; +} + +.confirm-head { + font-size: 32rpx; + font-weight: 600; + color: #222; + padding: 28rpx 24rpx 8rpx; +} + +/* 分组卡片 */ +.cf-group { + background: #FFFFFF; + margin: 16rpx 24rpx 0; + border-radius: 16rpx; + padding: 8rpx 24rpx; +} + +.cf-group-title { + font-size: 28rpx; + font-weight: 600; + color: #222; + padding: 20rpx 0 12rpx; + border-bottom: 1rpx solid #F2F2F2; +} + +.cf-row { + display: flex; + align-items: flex-start; + justify-content: space-between; + padding: 22rpx 0; + border-bottom: 1rpx solid #F7F7F7; +} + +.cf-row:last-child { + border-bottom: none; +} + +.cf-k { + font-size: 26rpx; + color: #999; + flex-shrink: 0; + margin-right: 24rpx; +} + +.cf-v { + font-size: 26rpx; + color: #222; + text-align: right; + flex: 1; + word-break: break-all; +} + +/* 文件资料行 */ +.cf-file-row { + display: flex; + align-items: flex-start; + justify-content: space-between; + padding: 22rpx 0; + border-bottom: 1rpx solid #F7F7F7; +} + +.cf-file-row:last-child { + border-bottom: none; +} + +.cf-thumbs { + display: flex; + flex-wrap: wrap; + gap: 12rpx; + justify-content: flex-end; + flex: 1; + margin-left: 24rpx; +} + +.cf-thumb { + width: 120rpx; + height: 120rpx; + border-radius: 8rpx; + border: 1rpx solid #EEE; +} + +.cf-empty { + font-size: 24rpx; + color: #B7B7B7; +} + +/* 协议勾选 */ +.agreement { + display: flex; + align-items: center; + padding: 24rpx 24rpx 0; +} + +.agreement-text { + font-size: 24rpx; + color: #666; + margin-left: 8rpx; +} + +.agreement-link { + color: #FF370B; +} + +/* 底部按钮(吸底) */ +.bottom-bar { + position: fixed; + left: 0; + right: 0; + bottom: 0; + background: #FFFFFF; + padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); + display: flex; + gap: 16rpx; + box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.04); + z-index: 99; +} + +.btn-primary { + flex: 1; + height: 88rpx; + background: linear-gradient(91deg, #FF7658 0%, #FF370B 100%); + border-radius: 44rpx; + color: #FFFFFF; + font-size: 30rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.btn-secondary { + flex: 1; + height: 88rpx; + background: #FFFFFF; + border: 1rpx solid #FF370B; + border-radius: 44rpx; + color: #FF370B; + font-size: 30rpx; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/packages/shopEnter/confirm/index.vue b/packages/shopEnter/confirm/index.vue new file mode 100644 index 00000000..c10e7a1d --- /dev/null +++ b/packages/shopEnter/confirm/index.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/packages/shopEnter/example/index.vue b/packages/shopEnter/example/index.vue index 228ff667..1286a622 100644 --- a/packages/shopEnter/example/index.vue +++ b/packages/shopEnter/example/index.vue @@ -36,6 +36,19 @@ 4. 仅支持二代身份证 + + 行业资质示例 + + + + + 拍摄要求: + 1. 请上传与经营品类对应的资质(如食品经营许可证) + 2. 照片需清晰完整,四角完整可见 + 3. 不得有遮挡、涂改、反光 + 4. 资质需在有效期内 + + @@ -55,7 +68,8 @@ export default { // 设置导航栏标题 const titleMap = { license: '营业执照示例', - idcard: '身份证示例' + idcard: '身份证示例', + industry: '行业资质示例' } uni.setNavigationBarTitle({ title: titleMap[this.type] || '资质示例' diff --git a/packages/shopEnter/index/index.css b/packages/shopEnter/index/index.css index b62a3f5f..c09d2efb 100644 --- a/packages/shopEnter/index/index.css +++ b/packages/shopEnter/index/index.css @@ -418,3 +418,257 @@ page { font-size: 26rpx; color: #B7B7B7; } + +/* ============ Tab2 资质相关 ============ */ +.qual-thumb { + width: 100%; + height: 360rpx; + border-radius: 12rpx; + position: relative; + overflow: hidden; + border: 1rpx solid #EBEBEB; +} + +.qual-thumb-img { + width: 100%; + height: 100%; +} + +.qual-thumb-del { + position: absolute; + top: 8rpx; + right: 8rpx; + width: 44rpx; + height: 44rpx; + border-radius: 50%; + background: rgba(0, 0, 0, 0.5); + color: #fff; + font-size: 32rpx; + display: flex; + align-items: center; + justify-content: center; + line-height: 1; +} + +.id-card-row { + display: flex; + gap: 20rpx; + margin-top: 12rpx; +} + +.id-card-cell { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 12rpx; +} + +.id-card-cell .upload-add { + width: 100%; + height: 200rpx; +} + +.id-card-cell .qual-thumb { + width: 100%; + height: 200rpx; +} + +.id-card-cell-label { + font-size: 24rpx; + color: #999; +} + +.forever-toggle { + display: flex; + align-items: center; + gap: 10rpx; + margin-top: 12rpx; + padding-left: 4rpx; +} + +.forever-toggle-text { + font-size: 24rpx; + color: #666; +} + +/* ============ 有效期分段控件(永久有效 / 截止日期) ============ */ +.validity-seg { + display: flex; + gap: 16rpx; +} + +.validity-seg .seg-item { + flex: 1; + height: 72rpx; + border: 1rpx solid #EBEBEB; + border-radius: 8rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 26rpx; + color: #666; + background: #FFFFFF; +} + +.validity-seg .seg-item.active { + color: #FF370B; + border-color: #FF370B; + background: #FFF1ED; + font-weight: 600; +} + +/* ============ 结算页:银行账户信息分组标题 ============ */ +.section-title { + display: flex; + align-items: center; + font-size: 30rpx; + color: #222; + font-weight: 600; + padding: 28rpx 24rpx 4rpx; +} + +.section-title::before { + content: ''; + width: 6rpx; + height: 30rpx; + background: #FF370B; + border-radius: 3rpx; + margin-right: 12rpx; +} + +/* 结算页行内底部提示 */ +.row-tip { + font-size: 22rpx; + color: #86909C; + padding: 12rpx 24rpx 0; + line-height: 34rpx; +} + +/* 结算页可点击选择行右侧布局 */ +.row_con--select { + display: flex; + align-items: center; + justify-content: space-between; +} + +.row_con .row_value { + flex: 1; + font-size: 28rpx; + color: #222; +} + +.row_con .row_value.placeholder { + color: #B7B7B7; +} + +/* ============ 结算页 银行账户信息表单 ============ */ +.Msg { + background: #FFFFFF; + margin: 12rpx 24rpx 0; + border-radius: 16rpx; + padding: 0 24rpx; +} + +.Msg .row { + display: flex; + flex-direction: column; + padding: 24rpx 0; + border-bottom: 1rpx solid #F2F2F2; +} + +.Msg .row:last-child { + border-bottom: none; +} + +.Msg .row_label { + font-size: 26rpx; + color: #222; + margin-bottom: 14rpx; + display: flex; + align-items: center; +} + +.Msg .row_label .star { + color: #FF370B; + margin-right: 4rpx; +} + +.Msg .row_con { + height: 80rpx; + border: 1rpx solid #EBEBEB; + border-radius: 8rpx; + padding: 0 20rpx; + display: flex; + align-items: center; + background: #FFFFFF; +} + +.Msg .row_con input { + flex: 1; + font-size: 28rpx; + color: #222; + height: 80rpx; + line-height: 80rpx; +} + +.Msg .row_con input::placeholder { + color: #B7B7B7; +} + +/* 结算页底部按钮组 */ +.btn-group { + display: flex; + gap: 16rpx; + padding: 40rpx 24rpx; +} + +.btn-group .prevBtn { + flex: 1; + height: 88rpx; + background: #FFFFFF; + border: 1rpx solid #FF370B; + border-radius: 44rpx; + color: #FF370B; + font-size: 30rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.btn-group .nextBtn { + flex: 1; + height: 88rpx; + background: linear-gradient(91deg, #FF7658 0%, #FF370B 100%); + border-radius: 44rpx; + color: #FFFFFF; + font-size: 30rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.action-sheet { + width: 100%; + background: #F2F2F4; + padding-bottom: env(safe-area-inset-bottom); +} + +.action-item { + background: #FFFFFF; + padding: 32rpx 0; + text-align: center; + font-size: 32rpx; + color: #222; + border-bottom: 1rpx solid #F0F0F0; +} + +.action-item:active { + background: #F8F8F8; +} + +.action-cancel { + margin-top: 12rpx; + color: #999; + border-bottom: none; +} diff --git a/packages/shopEnter/index/index.vue b/packages/shopEnter/index/index.vue index d55a7905..49e7e3bc 100644 --- a/packages/shopEnter/index/index.vue +++ b/packages/shopEnter/index/index.vue @@ -63,16 +63,16 @@ - *联系人 + *负责人姓名 - + - *手机号 + *负责人手机号 - + @@ -119,139 +119,255 @@ - + - - - 统一社会信用代码* - - + + + + *营业执照 + 查看示例 + + + + + + 拍摄/上传 + + + + × - - 法人姓名* - - + + + *执照名称 + + - - 法人身份证号* - - + + *统一社会信用代码 + + + + + + *法人代表 + + + + + + *有效期至 + + 永久有效 + 截止日期 + + + + {{ license_valid_until || '请选择截止日期' }} + + - - - 营业执照* - - - - - 上传图片 - - - 查看示例 + + + + + *{{ enterType === 'enterprise' ? '法人身份证' : '身份证' }} + 查看示例 + + + + + + + 正面(人像面) + + + + × + + 正面(人像面) + + + + + + 反面(国徽面) + + + + × + + 反面(国徽面) - - {{ enterType === 'enterprise' ? '法人身份证正面' : '身份证正面' }}* - - - - - 上传图片 - - - 查看示例 + + + *身份证号 + + - - {{ enterType === 'enterprise' ? '法人身份证反面' : '身份证反面' }}* - - - - - 上传图片 - - + + *有效期至 + + 永久有效 + 截止日期 + + + + {{ id_valid_until || '请选择截止日期' }} + + - - 上一步 - 下一步 + + + + + *行业资质 + (选填) + 查看示例 + + + + + + 拍摄/上传 + + + + × + + + + + + *证书名称 + + + + + + + + *证书编号 + + + + + + + + *有效期至 + + + 永久有效 + 截止日期 + + + + {{ industry_valid_until || '请选择截止日期' }} + + + + + + + + + ! + + 资质要求 + · 请上传最新证件,有效期截止时间应大于15天 + · 请拍摄执照原件、扫描件或加盖公章的复印件,不可摄屏 + · 营业执照上经营场所地址需与门店信息地址一致 + + 银行账户信息 - - - - - - - - - 我已阅读并同意《商家入驻协议》 + + *{{ enterType === 'enterprise' ? '公司银行账号' : '银行卡号' }} + + + + + + *开户银行名称 + + + {{ bank_name || '请选择开户银行' }} + + + + + + *开户银行所在地 + + + {{ bankRegionLabel || '请选择开户银行所在地' }} + + + + + + *开户银行支行名称 + + + + + + *开户银行联行号 + + + + 需精确到支行;联行号为银行间清算编号,共12位数字 + 需精确到支行,例如:中国工商银行北京中关村支行 + 上一步 - 提交入驻 + 预览信息 + + + + + + + + 取消 + 选择开户银行 + 确定 + + + + {{ item }} + + @@ -292,6 +408,43 @@ + + + + + 取消 + 开户银行所在地 + 确定 + + + + + {{ item.ad_name }} + + + + + + {{ item.short_name }} + + + + + + {{ item.short_name }} + + + + + + + @@ -332,10 +485,27 @@ - + 下一步 + + 上一步 + 下一步 + + + + + + + + + 拍照 + 从相册选择 + 取消 + + @@ -384,9 +554,29 @@ export default { bank_name: "", bank_branch: "", account_name: "", + bank_union_no: "", // 开户银行联行号(12位,企业必填) store_name: "", address: "", + // 开户银行所在地(三级联动) + showBankRegion: false, + bankCity: [], + bankBuss: [], + bankTempProv: {}, + bankTempCity: {}, + bankTempBuss: {}, + bankConfirmProv: {}, + bankConfirmCity: {}, + bankConfirmBuss: {}, + // 开户银行名称下拉 + showBankNamePicker: false, + bankNameList: [ + '中国工商银行', '中国农业银行', '中国银行', '中国建设银行', + '交通银行', '中国邮政储蓄银行', '招商银行', '中信银行', + '中国光大银行', '华夏银行', '中国民生银行', '广发银行', + '平安银行', '兴业银行', '浦发银行', '北京银行', '上海银行', + ], + // 企业入驻额外字段 credit_code: "", legal_person: "", @@ -422,6 +612,39 @@ export default { { value: 2, label: '即将开业' }, { value: 3, label: '休息中' }, ], + + // === Tab2 资质字段 === + // 营业执照 + license_name: '', // 执照名称 + license_credit_code: '', // 统一社会信用代码 + license_legal_person: '', // 法人姓名 + license_valid_until: '', // 有效期(永久 / 具体日期) + license_is_forever: false, // 是否长期有效 + // 身份证(个体)/ 法人身份证(企业)—— 共用字段 + id_card_no: '', // 身份证号 + id_valid_until: '', // 身份证有效期 + id_is_forever: false, + // 行业资质(企业必填,个体选填) + industryList: [], // 显示用 [{ url }] + industryPath: [], // 提交用 path + industry_name: '', // 资质名称 + industry_cert_no: '', // 证书编号 + industry_valid_until: '', // 有效期 + industry_is_forever: false, + + // 当前打开的日期选择器目标字段名 + datePickerKey: '', + showDatePicker: false, + dateMin: new Date(2000, 0, 1).getTime(), + dateMax: new Date(2099, 11, 31).getTime(), + + // 上传图片:拍照/相册菜单 + showImageActionSheet: false, + pickTarget: '', // 'license' / 'idFront' / 'idBack' / 'industry' + + // 复选框样式 + checkBoxOn: 'width:32rpx;height:32rpx;border-radius:50%;background:#FF370B;display:flex;align-items:center;justify-content:center;', + checkBoxOff: 'width:32rpx;height:32rpx;border-radius:50%;border:2rpx solid #C8C8C8;background:#fff;', } }, computed: { @@ -436,6 +659,13 @@ export default { const opt = this.bizStatusList.find(o => o.value === this.bizStatus) return opt ? opt.label : '' }, + bankRegionLabel() { + const a = this.bankConfirmProv && this.bankConfirmProv.ad_name + const b = this.bankConfirmCity && this.bankConfirmCity.short_name + const c = this.bankConfirmBuss && this.bankConfirmBuss.short_name + if (!a) return '' + return [a, b, c].filter(Boolean).join('/') + }, }, methods: { // ===== 新版弹层交互 ===== @@ -497,6 +727,175 @@ export default { this.showBizStatus = false }, + // ===== 开户银行所在地三级联动 ===== + async openBankRegion() { + if (!this.pro || !this.pro.length) await this.getPro() + this.bankTempProv = this.bankConfirmProv && this.bankConfirmProv.ad_code ? this.bankConfirmProv : {} + this.bankTempCity = this.bankConfirmCity && this.bankConfirmCity.ad_code ? this.bankConfirmCity : {} + this.bankTempBuss = this.bankConfirmBuss && this.bankConfirmBuss.ad_code ? this.bankConfirmBuss : {} + if (this.bankTempProv.ad_code) { + const r = await request(MapApi.getArea, "POST", { parent_ad_code: this.bankTempProv.ad_code }, {}, false) + this.bankCity = r.rows + } + if (this.bankTempCity.ad_code) { + const r = await request(MapApi.getArea, "POST", { parent_ad_code: this.bankTempCity.ad_code }, {}, false) + this.bankBuss = r.rows + } + this.showBankRegion = true + }, + async tapBankProv(item) { + this.bankTempProv = item + this.bankTempCity = {} + this.bankTempBuss = {} + this.bankBuss = [] + const r = await request(MapApi.getArea, "POST", { parent_ad_code: item.ad_code }, {}, false) + this.bankCity = r.rows + }, + async tapBankCity(item) { + this.bankTempCity = item + this.bankTempBuss = {} + const r = await request(MapApi.getArea, "POST", { parent_ad_code: item.ad_code }, {}, false) + this.bankBuss = r.rows + }, + tapBankBuss(item) { + this.bankTempBuss = item + }, + confirmBankRegion() { + if (!this.bankTempProv.ad_code) { + uni.showToast({ title: '请选择省', icon: 'none' }); return + } + if (!this.bankTempCity.ad_code) { + uni.showToast({ title: '请选择市', icon: 'none' }); return + } + if (!this.bankTempBuss.ad_code) { + uni.showToast({ title: '请选择区', icon: 'none' }); return + } + this.bankConfirmProv = this.bankTempProv + this.bankConfirmCity = this.bankTempCity + this.bankConfirmBuss = this.bankTempBuss + this.showBankRegion = false + }, + selectBankName(name) { + this.bank_name = name + this.showBankNamePicker = false + }, + // 结算页 -> 预览/确认页 + goPreview() { + if (!this.validateTab3()) return + const itemObj = this.buildSubmitParams() + NavgateTo('/packages/shopEnter/confirm/index?itemObj=' + encodeURIComponent(JSON.stringify(itemObj))) + }, + + // ===== Tab2 资质相关 ===== + // 拍照/相册菜单 + pickQualImage(target) { + this.pickTarget = target + this.showImageActionSheet = true + }, + pickImage(source) { + this.showImageActionSheet = false + if (source === 'camera') { + // 打开自定义取景框相机页 + NavgateTo('/packages/shopEnter/camera/index?target=' + this.pickTarget) + return + } + uni.chooseImage({ + count: 1, + sizeType: ['compressed'], + sourceType: ['album'], + success: (res) => { + const filePath = res.tempFilePaths && res.tempFilePaths[0] + if (!filePath) return + this.uploadQualImage(filePath) + }, + }) + }, + uploadQualImage(filePath, target) { + const t = target || this.pickTarget + uni.showLoading({ title: '上传中', mask: true }) + upload(filePath, res => { + uni.hideLoading() + const path = res.data.path + if (t === 'license') { + this.imgList5 = [{ url: filePath }] + this.imgList6 = [path] + this.runOcr('business_license', path) + } else if (t === 'idFront') { + this.idCardFrontList = [{ url: filePath }] + this.idCardFrontPath = [path] + this.runOcr('id_card', path) + } else if (t === 'idBack') { + this.idCardBackList = [{ url: filePath }] + this.idCardBackPath = [path] + } else if (t === 'industry') { + this.industryList = [{ url: filePath }] + this.industryPath = [path] + } + }, 'merchant_private') + }, + // 调用后端 OCR,自动回填表单字段(未开通 OCR 时静默忽略) + runOcr(scene, objectKey) { + const cleanKey = (objectKey || '').replace(/^\/+/, '') + if (!cleanKey) return + uni.showLoading({ title: '识别中', mask: true }) + request(apiArr.ocrRecognize, 'POST', { scene, object_key: cleanKey }, {}, false).then(res => { + uni.hideLoading() + if (!res) return + if (scene === 'business_license') { + if (res.company_name) this.license_name = res.company_name + if (res.credit_code) this.license_credit_code = res.credit_code + if (res.legal_person) this.legal_person = res.legal_person + uni.showToast({ title: '已自动识别执照信息', icon: 'none' }) + } else if (scene === 'id_card') { + if (res.name) this.legal_person = this.legal_person || res.name + if (res.id_number) this.id_card_no = res.id_number + uni.showToast({ title: '已自动识别身份证信息', icon: 'none' }) + } + }).catch(() => { + // OCR 未开通或失败:静默,用户手动填写 + uni.hideLoading() + }) + }, + previewQualImage(url) { + if (!url) return + uni.previewImage({ urls: [url] }) + }, + deleteIndustry(e) { + this.industryList.splice(e.index, 1) + this.industryPath.splice(e.index, 1) + }, + + // 日期选择 + openDatePicker(key) { + this.datePickerKey = key + this.showDatePicker = true + }, + onDateConfirm(e) { + const ts = e.value + const d = new Date(ts) + const y = d.getFullYear() + const m = String(d.getMonth() + 1).padStart(2, '0') + const day = String(d.getDate()).padStart(2, '0') + this[this.datePickerKey] = `${y}-${m}-${day}` + this.showDatePicker = false + }, + toggleForever(key) { + this[key] = !this[key] + // 长期有效时清空具体日期 + if (this[key]) { + const dateKey = key.replace('_is_forever', '_valid_until') + this[dateKey] = '' + } + }, + // 有效期分段控件:永久有效 / 截止日期 + setValidity(key, isForever) { + this[key] = isForever + if (isForever) { + const dateKey = key.replace('_is_forever', '_valid_until') + this[dateKey] = '' + } + }, + switchTab(tab) { // 点击 Tab 切换时需要校验前面的 Tab if (tab > this.currentTab) { @@ -519,43 +918,64 @@ export default { validateTab1() { // 基本信息校验 if (!this.store_name) { uni.showToast({ title: '请输入门店名称', icon: 'none' }); return false; } - if (!this.confirmProv.ad_code) { uni.showToast({ title: '请选择所在省', icon: 'none' }); return false; } - if (!this.confirmCity.ad_code) { uni.showToast({ title: '请选择所在市', icon: 'none' }); return false; } - if (!this.confirmBusiness.ad_code) { uni.showToast({ title: '请选择所在区', icon: 'none' }); return false; } + if (!this.confirmProv.ad_code) { uni.showToast({ title: '请选择所在地区', icon: 'none' }); return false; } + if (!this.confirmCity.ad_code) { uni.showToast({ title: '请选择所在地区', icon: 'none' }); return false; } + if (!this.confirmBusiness.ad_code) { uni.showToast({ title: '请选择所在地区', icon: 'none' }); return false; } if (!this.address) { uni.showToast({ title: '请输入详细地址', icon: 'none' }); return false; } - if (!this.contact_name) { uni.showToast({ title: '请输入联系人姓名', icon: 'none' }); return false; } - if (!this.contact_phone) { uni.showToast({ title: '请输入联系人手机号', icon: 'none' }); return false; } - if (!isPhone(this.contact_phone)) { uni.showToast({ title: '联系人手机号格式不正确', icon: 'none' }); return false; } - if (!this.confirmClassify.id) { uni.showToast({ title: '请选择商家分类', icon: 'none' }); return false; } + if (!this.confirmClassify.id) { uni.showToast({ title: '请选择商家类目', icon: 'none' }); return false; } + if (!this.bizStatus) { uni.showToast({ title: '请选择营业状态', icon: 'none' }); return false; } + if (!this.contact_name) { uni.showToast({ title: '请输入负责人姓名', icon: 'none' }); return false; } + if (!this.contact_phone) { uni.showToast({ title: '请输入负责人手机号', icon: 'none' }); return false; } + if (!isPhone(this.contact_phone)) { uni.showToast({ title: '负责人手机号格式不正确', icon: 'none' }); return false; } + if (!this.imgList3.length) { uni.showToast({ title: '请上传店内环境照片', icon: 'none' }); return false; } + if (!this.imgList.length) { uni.showToast({ title: '请上传门头环境照片', icon: 'none' }); return false; } return true; }, validateTab2() { // 资质信息校验 - if (this.enterType === 'enterprise') { - if (!this.credit_code) { uni.showToast({ title: '请输入统一社会信用代码', icon: 'none' }); return false; } - if (!/^[0-9A-HJ-NPQRTUWXY]{18}$/.test(this.credit_code.toUpperCase())) { - uni.showToast({ title: '统一社会信用代码格式不正确(18位)', icon: 'none' }); - return false; - } - if (!this.legal_person) { uni.showToast({ title: '请输入法人姓名', icon: 'none' }); return false; } - if (!this.legal_id_card) { uni.showToast({ title: '请输入法人身份证号', icon: 'none' }); return false; } - if (!/(^\d{15}$)|(^\d{17}([0-9X])$)/.test(this.legal_id_card.toUpperCase())) { - uni.showToast({ title: '法人身份证号格式不正确', icon: 'none' }); - return false; - } - } + // 营业执照 if (!this.imgList6.length) { uni.showToast({ title: '请上传营业执照', icon: 'none' }); return false; } + if (!this.license_name) { uni.showToast({ title: '请输入执照名称', icon: 'none' }); return false; } + if (!this.license_credit_code) { uni.showToast({ title: '请输入统一社会信用代码', icon: 'none' }); return false; } + if (!/^[0-9A-HJ-NPQRTUWXY]{18}$/.test(this.license_credit_code.toUpperCase())) { + uni.showToast({ title: '统一社会信用代码格式不正确(18位)', icon: 'none' }); + return false; + } + if (!this.legal_person) { uni.showToast({ title: '请输入法人姓名', icon: 'none' }); return false; } + if (!this.license_is_forever && !this.license_valid_until) { + uni.showToast({ title: '请选择营业执照有效期', icon: 'none' }); return false; + } + // 身份证 if (!this.idCardFrontPath.length) { uni.showToast({ title: '请上传身份证正面照片', icon: 'none' }); return false; } if (!this.idCardBackPath.length) { uni.showToast({ title: '请上传身份证反面照片', icon: 'none' }); return false; } + if (!this.id_card_no) { uni.showToast({ title: '请输入身份证号', icon: 'none' }); return false; } + if (!/(^\d{15}$)|(^\d{17}([0-9X])$)/.test(this.id_card_no.toUpperCase())) { + uni.showToast({ title: '身份证号格式不正确', icon: 'none' }); + return false; + } + if (!this.id_is_forever && !this.id_valid_until) { + uni.showToast({ title: '请选择身份证有效期', icon: 'none' }); return false; + } + // 行业资质:企业必填;个体如果传了图就要求三个字段 + const industryRequired = this.enterType === 'enterprise' || this.industryList.length > 0 + if (industryRequired) { + if (!this.industryPath.length) { uni.showToast({ title: '请上传行业资质', icon: 'none' }); return false; } + if (!this.industry_name) { uni.showToast({ title: '请输入资质名称', icon: 'none' }); return false; } + if (!this.industry_cert_no) { uni.showToast({ title: '请输入证书编号', icon: 'none' }); return false; } + if (!this.industry_is_forever && !this.industry_valid_until) { + uni.showToast({ title: '请选择行业资质有效期', icon: 'none' }); return false; + } + } return true; }, validateTab3() { - // 结算信息校验(个人 / 企业都需要银行四要素) + // 结算信息校验(个人 / 企业都需要银行要素) if (!this.account_name) { - uni.showToast({ - title: this.enterType === 'enterprise' ? '请输入企业开户名称' : '请输入开户人姓名', - icon: 'none' - }); + uni.showToast({ title: '请输入银行开户名', icon: 'none' }); + return false; + } + if (this.account_name.length > 50) { + uni.showToast({ title: '银行开户名不得超过50个字符', icon: 'none' }); return false; } if (!this.bank_card) { @@ -565,12 +985,24 @@ export default { }); return false; } - if (!/^\d{15,20}$/.test(this.bank_card)) { - uni.showToast({ title: '银行账号格式不正确(15-20位数字)', icon: 'none' }); + if (!/^\d{8,30}$/.test(this.bank_card)) { + uni.showToast({ title: '银行账号格式不正确(8-30位数字)', icon: 'none' }); + return false; + } + if (!this.bank_name) { uni.showToast({ title: '请输入开户银行名称', icon: 'none' }); return false; } + if (!this.bankConfirmBuss.ad_code) { uni.showToast({ title: '请选择开户银行所在地', icon: 'none' }); return false; } + if (!this.bank_branch) { uni.showToast({ title: '请输入开户银行支行名称', icon: 'none' }); return false; } + // 企业(对公账户)必须填写联行号,12位数字 + if (this.enterType === 'enterprise') { + if (!this.bank_union_no) { uni.showToast({ title: '请输入开户银行联行号', icon: 'none' }); return false; } + if (!/^\d{12}$/.test(this.bank_union_no)) { + uni.showToast({ title: '开户银行联行号必须为12位数字', icon: 'none' }); + return false; + } + } else if (this.bank_union_no && !/^\d{12}$/.test(this.bank_union_no)) { + uni.showToast({ title: '开户银行联行号必须为12位数字', icon: 'none' }); return false; } - if (!this.bank_name) { uni.showToast({ title: '请输入开户银行', icon: 'none' }); return false; } - if (!this.bank_branch) { uni.showToast({ title: '请输入开户支行', icon: 'none' }); return false; } return true; }, showExample(type) { @@ -642,50 +1074,28 @@ export default { } }, - cancelBuss() { - this.show3 = false; - }, - clickBuss(e) { - this.show3 = false; - this.confirmBusiness = e.value[0] + // 根据 ad_code 回显开户银行所在地(独立于门店省市区) + parseBankAdCode(adCode) { + if (!adCode) return; + const provinceCode = adCode.toString().substring(0, 2) + '0000'; + const cityCode = adCode.toString().substring(0, 4) + '00'; + const districtCode = adCode.toString(); + const province = this.pro.find(item => item.ad_code == provinceCode); + if (!province) return; + this.bankConfirmProv = province; + request(MapApi.getArea, "POST", { parent_ad_code: provinceCode }, {}, false).then(res => { + this.bankCity = res.rows; + const city = this.bankCity.find(item => item.ad_code == cityCode); + if (!city) return; + this.bankConfirmCity = city; + request(MapApi.getArea, "POST", { parent_ad_code: cityCode }, {}, false).then(r2 => { + this.bankBuss = r2.rows; + const district = this.bankBuss.find(item => item.ad_code == districtCode); + if (district) this.bankConfirmBuss = district; + }); + }); }, - cancelCity() { - this.show2 = false; - }, - clickCity(e) { - this.show2 = false; - this.getBuss(e.value[0].ad_code) - this.confirmCity = e.value[0] - }, - - cancelPro() { - this.show = false; - }, - clickPro(e) { - this.show = false; - this.getCity(e.value[0].ad_code) - this.confirmProv = e.value[0] - }, - cancelClassify() { - this.show4 = false; - }, - clickClassify(e) { - this.show4 = false; - this.confirmClassify = e.value[0] - }, - chooseCity() { - this.show = true; - }, - chooseCity2() { - this.show2 = true; - }, - chooseCity3() { - this.show3 = true; - }, - chooseClassify() { - this.show4 = true; - }, afterReadImg(e) { e.file.forEach(item => { upload(item.url, res => { @@ -752,59 +1162,78 @@ export default { } this[listKey] = result }, - submit() { + // 汇总所有表单字段为提交参数 + 预览展示用的附加字段 + buildSubmitParams() { let that = this - if (!that.validateTab3()) return; - if (!that.agreeProtocol) { - uni.showToast({ title: '请先阅读并同意商家入驻协议', icon: 'none' }); - return; - } let interior_photo = that.imgList4.join(",") let facade_photo = that.imgList2.join(",") let license_photo = that.imgList6.join(",") let id_card_front = that.idCardFrontPath.join(",") let id_card_back = that.idCardBackPath.join(",") + let industry_photo = that.industryPath.join(",") - let params = { + return { enter_type: that.enterType === 'enterprise' ? 2 : 1, contact_name: that.contact_name, phone: that.contact_phone, - bank_card: that.bank_card, - bank_name: that.bank_name, - bank_branch: that.bank_branch, - account_name: that.account_name, merchant_name: that.store_name, address: that.address, ad_code: that.confirmBusiness.ad_code, + merchant_cate_id: that.confirmClassify.id, + business_status: that.bizStatus, facade_photo, interior_photo, + // 资质信息 —— 营业执照 license_photo, + license_name: that.license_name, + credit_code: that.license_credit_code, + legal_person: that.legal_person, + license_valid_until: that.license_is_forever ? '' : that.license_valid_until, + license_is_forever: that.license_is_forever ? 1 : 2, + // 资质信息 —— 法人/经营者身份证 id_card_front, id_card_back, - merchant_cate_id: that.confirmClassify.id, - } - - if (that.enterType === 'enterprise') { - params.credit_code = that.credit_code; - params.legal_person = that.legal_person; - params.legal_id_card = that.legal_id_card; - params.account_type = 2; - } else { - params.account_type = 1; + id_card_no: that.id_card_no, + legal_id_card: that.id_card_no, // 法人身份证号与证件号一致 + id_valid_until: that.id_is_forever ? '' : that.id_valid_until, + id_is_forever: that.id_is_forever ? 1 : 2, + // 资质信息 —— 行业资质 + industry_photo, + industry_name: that.industry_name, + industry_cert_no: that.industry_cert_no, + industry_valid_until: that.industry_is_forever ? '' : that.industry_valid_until, + industry_is_forever: that.industry_is_forever ? 1 : 2, + // 结算信息 + account_name: that.account_name, + bank_card: that.bank_card, + bank_name: that.bank_name, + bank_branch: that.bank_branch, + bank_area_code: that.bankConfirmBuss.ad_code, + bank_union_no: that.bank_union_no, + account_type: that.enterType === 'enterprise' ? 2 : 1, + // 以下为预览/回显展示用(后端忽略未知字段) + _region_label: that.regionLabel, + _cate_name: that.confirmClassify.cate_name || '', + _biz_status_label: that.bizStatusLabel, + _bank_region_label: that.bankRegionLabel, } + }, + submit() { + let that = this + if (!that.validateTab3()) return; + const params = that.buildSubmitParams() request(apiArr.createStore, "POST", params).then(res => { - // 提交成功后用最新表单 + 服务端返回拼一个 itemObj 给 auditStatus 页用 - const newItem = { - ...params, - id: res && res.id, + // 审核页仅需少量字段;用 reLaunch 清空页面栈,避免返回造成二次提交 + const auditItem = { status: 1, create_time: new Date().toLocaleString('sv-SE').replace('T', ' '), handle_time: '', - merchant_code: '', remark: '' } - NavgateTo("../auditStatus/index?itemObj=" + encodeURIComponent(JSON.stringify(newItem))) + uni.reLaunch({ + url: "/packages/shopEnter/auditStatus/index?itemObj=" + encodeURIComponent(JSON.stringify(auditItem)) + }) }).catch(res => { const msg = res && res.message ? res.message : '提交失败,请稍后重试' if (msg.includes("agent_nil")) { @@ -853,6 +1282,63 @@ export default { }) }, + // 编辑回显:把已有门店数据填充到表单 + fillEditData(item) { + this.itemObj = item + this.store_name = item.merchant_name || '' + this.address = item.address || '' + this.contact_name = item.contact_name || '' + this.contact_phone = item.phone || '' + this.confirmClassify = this.classify.find(c => c.id == item.merchant_cate_id) || '' + this.bank_card = item.bank_card || '' + this.bank_name = item.bank_name || '' + this.bank_branch = item.bank_branch || '' + this.account_name = item.account_name || '' + this.bank_union_no = item.bank_union_no || '' + // 资质字段回显 + this.license_name = item.license_name || '' + this.license_credit_code = item.credit_code || '' + this.legal_person = item.legal_person || '' + this.license_valid_until = item.license_valid_until || '' + this.license_is_forever = item.license_is_forever === 1 + this.id_card_no = item.id_card_no || item.legal_id_card || '' + this.id_valid_until = item.id_valid_until || '' + this.id_is_forever = item.id_is_forever === 1 + this.industry_name = item.industry_name || '' + this.industry_cert_no = item.industry_cert_no || '' + this.industry_valid_until = item.industry_valid_until || '' + this.industry_is_forever = item.industry_is_forever === 1 + + // 入驻类型回显 + if (item.enter_type === 2) { + this.enterType = 'enterprise' + } + // 营业状态回显 + if (item.business_status) { + this.bizStatus = item.business_status + } + + // 省市区 / 开户银行所在地回显 + if (item.ad_code) this.parseAdCode(item.ad_code) + if (item.bank_area_code) this.parseBankAdCode(item.bank_area_code) + + // 门头 / 店内:公开 bucket + this.imgList = item.facade_photo ? item.facade_photo.split(",").map(p => ({ url: this.picUrl + p })) : [] + this.imgList2 = item.facade_photo ? item.facade_photo.split(",") : [] + this.imgList3 = item.interior_photo ? item.interior_photo.split(",").map(p => ({ url: this.picUrl + p })) : [] + this.imgList4 = item.interior_photo ? item.interior_photo.split(",") : [] + + // 营业执照、身份证、行业资质 —— 私密 bucket,需要签名 URL 才能回显 + this.imgList6 = item.license_photo ? item.license_photo.split(",").filter(Boolean) : [] + this.idCardFrontPath = item.id_card_front ? item.id_card_front.split(",").filter(Boolean) : [] + this.idCardBackPath = item.id_card_back ? item.id_card_back.split(",").filter(Boolean) : [] + this.industryPath = item.industry_photo ? item.industry_photo.split(",").filter(Boolean) : [] + this.signPrivatePaths(this.imgList6, 'imgList5') + this.signPrivatePaths(this.idCardFrontPath, 'idCardFrontList') + this.signPrivatePaths(this.idCardBackPath, 'idCardBackList') + this.signPrivatePaths(this.industryPath, 'industryList') + }, + }, onLoad(options) { // 获取入驻类型 @@ -860,47 +1346,50 @@ export default { this.enterType = options.enterType; } + // 监听自定义相机页回传的拍摄结果 + this._onCapture = ({ target, filePath }) => { + if (!filePath) return + this.pickTarget = target + this.uploadQualImage(filePath, target) + } + uni.$on('shopEnter:capture', this._onCapture) + + // 读取编辑数据:优先本地存储中转(edit=1),兼容旧的 URL itemObj 传参 + let editData = null + if (options.edit) { + try { + editData = uni.getStorageSync('shopEnterEditData') || null + uni.removeStorageSync('shopEnterEditData') + } catch (e) { + console.error('读取编辑数据失败:', e) + } + } else if (options.itemObj) { + try { + editData = JSON.parse(decodeURIComponent(options.itemObj)) + } catch (e1) { + try { editData = JSON.parse(options.itemObj) } catch (e2) { + console.error('解析 itemObj 失败:', e2) + } + } + } + // 先执行数据获取方法 Promise.all([this.getPro(), this.getClassify()]).then(() => { // 数据获取完成后再进行赋值操作(编辑回显) - if (options.itemObj) { - this.itemObj = JSON.parse(options.itemObj) - this.store_name = this.itemObj.merchant_name - this.address = this.itemObj.address - this.contact_name = this.itemObj.contact_name - this.contact_phone = this.itemObj.phone - this.confirmClassify = this.classify.find(item => item.id == this.itemObj.merchant_cate_id) - this.bank_card = this.itemObj.bank_card - this.bank_name = this.itemObj.bank_name || '' - this.bank_branch = this.itemObj.bank_branch || '' - this.account_name = this.itemObj.account_name || '' - this.credit_code = this.itemObj.credit_code || '' - this.legal_person = this.itemObj.legal_person || '' - this.legal_id_card = this.itemObj.legal_id_card || '' - - // 入驻类型回显 - if (this.itemObj.enter_type === 2) { - this.enterType = 'enterprise'; + if (editData) { + try { + this.fillEditData(editData) + } catch (e) { + console.error('编辑回显失败:', e) } - - // 解析ad_code回显省市区 - if (this.itemObj.ad_code) { - this.parseAdCode(this.itemObj.ad_code); - } - this.imgList = this.itemObj.facade_photo ? this.itemObj.facade_photo.split(",").map(item => ({ url: this.picUrl + item })) : [] - this.imgList2 = this.itemObj.facade_photo ? this.itemObj.facade_photo.split(",") : [] - this.imgList3 = this.itemObj.interior_photo ? this.itemObj.interior_photo.split(",").map(item => ({ url: this.picUrl + item })) : [] - this.imgList4 = this.itemObj.interior_photo ? this.itemObj.interior_photo.split(",") : [] - - // 营业执照、身份证 —— 私密 bucket,需要签名 URL 才能回显 - this.imgList6 = this.itemObj.license_photo?.split(",").filter(Boolean) || [] - this.idCardFrontPath = this.itemObj.id_card_front ? this.itemObj.id_card_front.split(",").filter(Boolean) : [] - this.idCardBackPath = this.itemObj.id_card_back ? this.itemObj.id_card_back.split(",").filter(Boolean) : [] - this.signPrivatePaths(this.imgList6, 'imgList5') - this.signPrivatePaths(this.idCardFrontPath, 'idCardFrontList') - this.signPrivatePaths(this.idCardBackPath, 'idCardBackList') } }) + }, + onUnload() { + if (this._onCapture) { + uni.$off('shopEnter:capture', this._onCapture) + this._onCapture = null + } } } diff --git a/pages.json b/pages.json index 3b2648a8..4740f247 100644 --- a/pages.json +++ b/pages.json @@ -145,6 +145,13 @@ "navigationBarBackgroundColor": "#F9F9F9" } }, + { + "path": "picker/index", + "style": { + "navigationBarTitleText": "选择", + "navigationBarBackgroundColor": "#fff" + } + }, { "path": "chattingRecords/index", "style": { @@ -586,6 +593,20 @@ "navigationBarBackgroundColor": "#fff" } }, + { + "path": "confirm/index", + "style": { + "navigationBarTitleText": "商家入驻", + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path": "camera/index", + "style": { + "navigationBarTitleText": "拍摄证件", + "navigationStyle": "custom" + } + }, { "path": "sucess/index", "style": { @@ -597,7 +618,7 @@ { "path": "auditStatus/index", "style": { - "navigationBarTitleText": "审核状态", + "navigationBarTitleText": "资料审核", "navigationBarBackgroundColor": "#fff" } }, diff --git a/pages/index/index.vue b/pages/index/index.vue index 068c0e89..85de8781 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -489,6 +489,9 @@ export default { uni.setStorageSync('location', preciseLocation); uni.setStorageSync('ad_code', ad_info.adcode); // TODO: 这里需要强依赖 ad_code 去查询,必须保障代码先后执行顺序正确 + // 先一次性批量拉取首页各广告位(1-11),后续各 getHomeXxx 直接读缓存, + // 把原来十几次 banner-region 请求压成一次 + await this.prefetchBannerGroups(); const [bannerList, serverLeft, serverRightList, homeLeftList, homeRightList, bottomList, buttonList, categoryList] = await Promise.all([ this.getHomeBanner(),// 轮播图查询 @@ -677,18 +680,45 @@ export default { }, - async getHomeBanner() { + // 一次性拉取多个广告位,结果缓存到 this._bannerGroups,供各 getHomeXxx 读取, + // 把原来十几次 banner-region 请求压成一次。 + async prefetchBannerGroups(positions = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) { + try { + const res = await request(apiArr2.getHomeBannerMulti, "POST", { + ad_code: Number(uni.getStorageSync('ad_code')), + ad_positions: positions, + longitude: uni.getStorageSync('location').lng, + latitude: uni.getStorageSync('location').lat, + page_size: 50 + }, { silent: false }); + this._bannerGroups = (res && res.groups) ? res.groups : {}; + } catch (e) { + console.warn('批量拉取首页广告失败,回退逐个请求:', e); + this._bannerGroups = null; // 标记不可用,各方法回退单查 + } + }, + + // 读取某广告位的数据:优先用批量缓存,缓存缺失则回退单个 page 请求(保证方法可独立工作) + async getBannerRows(position) { + if (this._bannerGroups) { + const rows = this._bannerGroups[String(position)] || []; + return rows; + } const res = await request(apiArr2.getHomeBanner, "POST", { ad_code: uni.getStorageSync('ad_code'), - ad_position: 1, + ad_position: position, longitude: uni.getStorageSync('location').lng, latitude: uni.getStorageSync('location').lat, page_num: 1, - page_size: 10 + page_size: 50 }, { silent: false }); + return (res && res.rows) ? res.rows : []; + }, - if (res.rows && res.rows.length) { - let filterRes = this.filterShowList(res.rows, 1); + async getHomeBanner() { + const rows = await this.getBannerRows(1); + if (rows && rows.length) { + let filterRes = this.filterShowList(rows, 1); filterRes.forEach(item => { item.pic_src = picUrl + item.pic_src }) @@ -699,21 +729,14 @@ export default { }, async getServerLeft() { - const res = await request(apiArr2.getHomeBanner, "POST", { - ad_code: uni.getStorageSync('ad_code'), - ad_position: 2, - longitude: uni.getStorageSync('location').lng, - latitude: uni.getStorageSync('location').lat, - page_num: 1, - page_size: 10 - }, { silent: false }); - if (!res.rows || !res.rows.length) { + const rows = await this.getBannerRows(2); + if (!rows || !rows.length) { this.serverLeftList = [] } - if (res.rows && res.rows.length) { - this.serverLeftList = res.rows - let filterRes = this.filterShowList(res?.rows, 1); + if (rows && rows.length) { + this.serverLeftList = rows + let filterRes = this.filterShowList(rows, 1); filterRes.forEach(item => { item.pic_src = picUrl + item.pic_src }) @@ -727,19 +750,12 @@ export default { async getServerRight() { const rightList = [] for (let i = 3; i < 5; i++) { - const res = await request(apiArr2.getHomeBanner, "POST", { - ad_code: uni.getStorageSync('ad_code'), - ad_position: i, - longitude: uni.getStorageSync('location').lng, - latitude: uni.getStorageSync('location').lat, - page_num: 1, - page_size: 10 - }, { silent: false }); - if (!res.rows || !res.rows.length) { + const rows = await this.getBannerRows(i); + if (!rows || !rows.length) { this.serverRightList = [] } - if (res.rows && res.rows.length) { - let filterRes = this.filterShowList(res?.rows, 1); + if (rows && rows.length) { + let filterRes = this.filterShowList(rows, 1); filterRes.forEach(item => { item.pic_src = picUrl + item.pic_src }) @@ -750,16 +766,9 @@ export default { }, async getHomeMidLeft() { - const res = await request(apiArr2.getHomeBanner, "POST", { - ad_code: uni.getStorageSync('ad_code'), - ad_position: 5, - longitude: uni.getStorageSync('location').lng, - latitude: uni.getStorageSync('location').lat, - page_num: 1, - page_size: 10 - }, { silent: false }); - if (res.rows && res.rows.length) { - let filterRes = this.filterShowList(res?.rows, 1); + const rows = await this.getBannerRows(5); + if (rows && rows.length) { + let filterRes = this.filterShowList(rows, 1); filterRes.forEach(item => { item.pic_src = picUrl + item.pic_src }) @@ -772,19 +781,9 @@ export default { async getHomeMidRight() { const rightList = [] for (let i = 6; i < 12; i++) { - const res = await request(apiArr2.getHomeBanner, "POST", { - ad_code: uni.getStorageSync('ad_code'), - ad_position: i, - longitude: uni.getStorageSync('location').lng, - latitude: uni.getStorageSync('location').lat, - page_num: 1, - page_size: 10 - }, { silent: false }); - if (res.rows && res.rows.length) { - // let firstItem = res.rows[0]; - // firstItem.pic_src = picUrl + firstItem.pic_src; - // rightList.push(firstItem); - let filterRes = this.filterShowList(res?.rows, 1); + const rows = await this.getBannerRows(i); + if (rows && rows.length) { + let filterRes = this.filterShowList(rows, 1); filterRes.forEach(item => { item.pic_src = picUrl + item.pic_src }) diff --git a/project.config.json b/project.config.json index 0f04c309..b6f14a5e 100644 --- a/project.config.json +++ b/project.config.json @@ -1,7 +1,7 @@ { "appid": "wx1addb25675dd8e70", "compileType": "miniprogram", - "libVersion": "3.8.3", + "libVersion": "3.9.1", "packOptions": { "ignore": [], "include": [] @@ -19,7 +19,18 @@ "disablePlugins": [], "outputPath": "" }, - "condition": true + "condition": true, + "compileWorklet": false, + "uglifyFileName": false, + "uploadWithSourceMap": true, + "packNpmManually": false, + "minifyWXSS": true, + "minifyWXML": true, + "localPlugins": false, + "disableUseStrict": false, + "useCompilerPlugins": false, + "swc": false, + "disableSWC": true }, "condition": {}, "editorSetting": { diff --git a/project.private.config.json b/project.private.config.json index 39b9d096..a0a19c2f 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -2,7 +2,22 @@ "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", "projectname": "uniapp-ZHSQ", "setting": { - "compileHotReLoad": true + "compileHotReLoad": true, + "urlCheck": true, + "coverView": true, + "lazyloadPlaceholderEnable": false, + "skylineRenderEnable": false, + "preloadBackgroundData": false, + "autoAudits": false, + "useApiHook": true, + "showShadowRootInWxmlPanel": true, + "useStaticServer": false, + "useLanDebug": false, + "showES6CompileOption": false, + "checkInvalidKey": true, + "ignoreDevUnusedFiles": true, + "bigPackageSizeSupport": false }, - "libVersion": "3.9.1" + "libVersion": "3.16.0", + "condition": {} } \ No newline at end of file diff --git a/utils/uploadOSS.js b/utils/uploadOSS.js index d6abf9d3..41d33ae7 100644 --- a/utils/uploadOSS.js +++ b/utils/uploadOSS.js @@ -19,8 +19,10 @@ const inferExt = (filePath) => { return filePath.substring(idx + 1).toLowerCase(); }; -const fetchCredential = (scene, ext) => { +const fetchCredential = (scene, ext, bindId) => { return new Promise((resolve, reject) => { + const data = { scene, ext }; + if (bindId) data.bind_id = bindId; // 客服聊天场景:按会话分目录 uni.request({ url: RequsetUrl + "/api/v1/wechat/oss/credential", method: "POST", @@ -28,7 +30,7 @@ const fetchCredential = (scene, ext) => { Authorization: uni.getStorageSync("ctoken") || "", "Content-Type": "application/json", }, - data: { scene, ext }, + data, success: (res) => { if (res.statusCode !== 200) return reject(new Error("获取上传凭证失败:" + res.statusCode)); const body = res.data || {}; @@ -78,7 +80,7 @@ const postToOSS = (filePath, cred) => { * @param {boolean} [opts.showLoading=true] * @returns {Promise<{ objectKey: string, url: string }>} */ -export const uploadOSS = async ({ filePath, scene, ext, showLoading = true }) => { +export const uploadOSS = async ({ filePath, scene, ext, bindId, showLoading = true }) => { if (!filePath) throw new Error("filePath 不能为空"); if (!scene) throw new Error("scene 不能为空"); @@ -87,7 +89,7 @@ export const uploadOSS = async ({ filePath, scene, ext, showLoading = true }) => if (showLoading) uni.showLoading({ title: "上传中", mask: true }); try { - const cred = await fetchCredential(scene, finalExt); + const cred = await fetchCredential(scene, finalExt, bindId); await postToOSS(filePath, cred); return { objectKey: cred.object_key,