feat(commission): 支持计奖商品参与设置、独立分成与多规格规则,完善团队中心与微信快捷登录

这个提交包含在:
chen
2026-09-17 19:27:17 +08:00
父节点 3c7df9688b
当前提交 829e88cfa9
共有 54 个文件被更改,包括 3536 次插入 和 666 次删除

查看文件

@@ -1,5 +1,5 @@
{
"name": "Shopro",
"name": "恒链数通",
"appid": "__UNI__082C0BA",
"description": "Shopro是由SheepJS团队开发,使用Uniapp+Vue3技术驱动的在线商城系统,内含诸多功能与丰富的活动,期待您的使用和反馈。",
"versionName": "3.2.0",

465
uniapp/package-lock.json 自动生成的 普通文件
查看文件

@@ -0,0 +1,465 @@
{
"name": "shopro",
"version": "3.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "shopro",
"version": "3.1.0",
"license": "MIT",
"dependencies": {
"@hyoga/uni-socket.io": "^1.0.1",
"dayjs": "^1.11.9",
"lodash": "^4.17.21",
"luch-request": "^3.1.0",
"pinia": "2.1.4",
"pinia-plugin-persist-uni": "1.2.0",
"qs-canvas": "^1.0.11",
"weixin-js-sdk": "^1.6.0"
},
"devDependencies": {
"prettier": "^3.0.0",
"vconsole": "^3.15.1"
}
},
"node_modules/@babel/runtime": {
"version": "7.29.7",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz",
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@dcloudio/types": {
"version": "2.6.12",
"resolved": "https://registry.npmmirror.com/@dcloudio/types/-/types-2.6.12.tgz",
"integrity": "sha512-mrCMwcINy1IFjU9VUqLeWBkj404yWs5paLDttBcA+eqUjanuUQbBcTVPqlrGgkyzLXDcV2oDDZRSNxNpXi4kMQ==",
"license": "Apache-2.0"
},
"node_modules/@hyoga/uni-socket.io": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/@hyoga/uni-socket.io/-/uni-socket.io-1.0.1.tgz",
"integrity": "sha512-+a3PvweyFHx39IJfJWoO9wYsvv50XCIslJ23OiOs8/jMdCZud7c4uWoZF5gH2iskcX72JcDm1Gk5g5o8X7dxEg==",
"license": "MIT",
"dependencies": {
"socket.io-client": "^2.1.1"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.6.4",
"resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
"node_modules/after": {
"version": "0.8.2",
"resolved": "https://registry.npmmirror.com/after/-/after-0.8.2.tgz",
"integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==",
"license": "MIT"
},
"node_modules/arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmmirror.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
"license": "MIT"
},
"node_modules/backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==",
"license": "MIT"
},
"node_modules/base64-arraybuffer": {
"version": "0.1.4",
"resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
"integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/blob": {
"version": "0.0.5",
"resolved": "https://registry.npmmirror.com/blob/-/blob-0.0.5.tgz",
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
"license": "MIT"
},
"node_modules/component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw=="
},
"node_modules/component-emitter": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.1.tgz",
"integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmmirror.com/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA=="
},
"node_modules/copy-text-to-clipboard": {
"version": "3.2.2",
"resolved": "https://registry.npmmirror.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.2.tgz",
"integrity": "sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/core-js": {
"version": "3.50.0",
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.50.0.tgz",
"integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"engines": {
"node": "*"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/dayjs": {
"version": "1.11.23",
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.23.tgz",
"integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==",
"license": "MIT"
},
"node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/engine.io-client": {
"version": "3.5.6",
"resolved": "https://registry.npmmirror.com/engine.io-client/-/engine.io-client-3.5.6.tgz",
"integrity": "sha512-2fDMKiXSU7bGRDCWEw9cHEdRNfoU8cpP6lt+nwJhv72tSJpO7YBsqMqYZ63eVvwX3l9prPl2k/mxhfVhY+SDWg==",
"license": "MIT",
"dependencies": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"ws": "~7.5.10",
"xmlhttprequest-ssl": "~1.6.2",
"yeast": "0.1.2"
}
},
"node_modules/engine.io-parser": {
"version": "2.2.1",
"resolved": "https://registry.npmmirror.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
"license": "MIT",
"dependencies": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.4",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"node_modules/has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"license": "MIT",
"dependencies": {
"isarray": "2.0.1"
}
},
"node_modules/has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==",
"license": "MIT"
},
"node_modules/indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmmirror.com/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg=="
},
"node_modules/isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==",
"license": "MIT"
},
"node_modules/lodash": {
"version": "4.18.1",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT"
},
"node_modules/luch-request": {
"version": "3.1.1",
"resolved": "https://registry.npmmirror.com/luch-request/-/luch-request-3.1.1.tgz",
"integrity": "sha512-p7+mlcEtgRcd0OfXC4XZbyiwSr1XgCeqNT7LlVUjnk7InYl/8d5Rk7BUqAYNA2WRafI1wRIUQWRWZRpeUwWR0w==",
"license": "MIT",
"dependencies": {
"@dcloudio/types": "^2.0.16"
}
},
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/mutation-observer": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/mutation-observer/-/mutation-observer-1.0.3.tgz",
"integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==",
"dev": true
},
"node_modules/parseqs": {
"version": "0.0.6",
"resolved": "https://registry.npmmirror.com/parseqs/-/parseqs-0.0.6.tgz",
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==",
"license": "MIT"
},
"node_modules/parseuri": {
"version": "0.0.6",
"resolved": "https://registry.npmmirror.com/parseuri/-/parseuri-0.0.6.tgz",
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==",
"license": "MIT"
},
"node_modules/pinia": {
"version": "2.1.4",
"resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.1.4.tgz",
"integrity": "sha512-vYlnDu+Y/FXxv1ABo1vhjC+IbqvzUdiUC3sfDRrRyY2CQSrqqaa+iiHmqtARFxJVqWQMCJfXx1PBvFs9aJVLXQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/devtools-api": "^6.5.0",
"vue-demi": ">=0.14.5"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"@vue/composition-api": "^1.4.0",
"typescript": ">=4.4.4",
"vue": "^2.6.14 || ^3.3.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/pinia-plugin-persist-uni": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/pinia-plugin-persist-uni/-/pinia-plugin-persist-uni-1.2.0.tgz",
"integrity": "sha512-9ZLdeB+nfeu0WD7WEv19E1u2cWbnK/J8fDR5w56JPGoQtbU4Uy8VLKSvfHlbuVzGxBaE1DhG4/ulWVm3oAArpg==",
"dependencies": {
"vue-demi": "^0.12.1"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0",
"pinia": "^2.0.0",
"vue": "^2.0.0 || >=3.0.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/pinia-plugin-persist-uni/node_modules/vue-demi": {
"version": "0.12.5",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.12.5.tgz",
"integrity": "sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/prettier": {
"version": "3.9.7",
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.9.7.tgz",
"integrity": "sha512-T3mF5P7HFzZVLDQuCUNtJj6WK1pcpLMweMNUVwGb01bLNkH9AkKxtZvmInw8K6bnn2O3d6/5RHl6zSHiBAD0Og==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/qs-canvas": {
"version": "1.0.11",
"resolved": "https://registry.npmmirror.com/qs-canvas/-/qs-canvas-1.0.11.tgz",
"integrity": "sha512-WJwLwrAA1++ZqT6eR2F4Qa42yowybDUtQ2TDPtDOwhD1i4DzEOotug5N20cDkHat9l69ThOWoxV4qJbLKAjkNg==",
"license": "BSD 3-Clause"
},
"node_modules/socket.io-client": {
"version": "2.5.0",
"resolved": "https://registry.npmmirror.com/socket.io-client/-/socket.io-client-2.5.0.tgz",
"integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==",
"license": "MIT",
"dependencies": {
"backo2": "1.0.2",
"component-bind": "1.0.0",
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"engine.io-client": "~3.5.0",
"has-binary2": "~1.0.2",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
}
},
"node_modules/socket.io-parser": {
"version": "3.3.6",
"resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-3.3.6.tgz",
"integrity": "sha512-+VwteZF0qtYVkcO1nhKf6ZUVz5wq6Ya+Lx10y3Y81Sp5+iyGGY2GTcd81W36C/r1tjP+GhXjiXaLKlCMyE+yHQ==",
"license": "MIT",
"dependencies": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
}
},
"node_modules/to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmmirror.com/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A=="
},
"node_modules/vconsole": {
"version": "3.15.1",
"resolved": "https://registry.npmmirror.com/vconsole/-/vconsole-3.15.1.tgz",
"integrity": "sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.17.2",
"copy-text-to-clipboard": "^3.0.1",
"core-js": "^3.11.0",
"mutation-observer": "^1.0.3"
}
},
"node_modules/vue": {
"version": "2.6.14",
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.6.14.tgz",
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==",
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
"license": "MIT",
"peer": true
},
"node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/weixin-js-sdk": {
"version": "1.6.5",
"resolved": "https://registry.npmmirror.com/weixin-js-sdk/-/weixin-js-sdk-1.6.5.tgz",
"integrity": "sha512-Gph1WAWB2YN/lMOFB/ymb+hbU/wYazzJgu6PMMktCy9cSCeW5wA6Zwt0dpahJbJ+RJEwtTv2x9iIu0U4enuVSQ==",
"license": "MIT"
},
"node_modules/ws": {
"version": "7.5.13",
"resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.13.tgz",
"integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "1.6.3",
"resolved": "https://registry.npmmirror.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz",
"integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmmirror.com/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==",
"license": "MIT"
}
}
}

查看文件

@@ -1,5 +1,5 @@
<template>
<s-layout title="积分商城">
<s-layout title="兑换商城">
<!-- 资产看板:当前积分与可用兑换券 -->
<view class="asset-banner ss-m-20 ss-p-20">
<view class="ss-flex ss-row-between ss-col-center">
@@ -17,7 +17,7 @@
</button>
</view>
<view class="asset-tip ss-m-t-16">
💡 兑换商品时支持使用兑换券 1:1 抵扣现金部分
💡 兑换商品时支持使用可用兑换券 1:1 全额抵扣现金
</view>
</view>
@@ -34,7 +34,7 @@
<s-empty
v-if="state.pagination.total === 0"
icon="/static/goods-empty.png"
text="暂无积分商品"
text="暂无兑换商品"
></s-empty>
<uni-load-more
v-if="state.pagination.total > 0"

查看文件

@@ -12,6 +12,28 @@
</view>
<!-- 账户信息 -->
<account-info />
<!-- 团队作战快捷看板 -->
<view class="team-quick-card ss-flex ss-row-between ss-col-center" @tap="sheep.$router.go('/pages/commission/team')">
<view class="team-quick-left ss-flex ss-col-center">
<view class="icon-wrap ss-flex ss-row-center ss-col-center">
<uni-icons type="staff" size="24" color="#ff6000"></uni-icons>
</view>
<view class="team-quick-info ss-m-l-16">
<view class="team-title ss-flex ss-col-center">
<text class="title-bold">团队作战中心</text>
<text class="active-badge ss-m-l-10" v-if="userInfo?.active_30d !== false && agentInfo?.active_30d !== false">正常活跃</text>
<text class="warn-badge ss-m-l-10" v-else>奖励暂停</text>
</view>
<view class="team-sub ss-m-t-6">
直推 {{ agentInfo?.child_user_count_1 || 0 }} 人 · 团队共 {{ agentInfo?.child_user_count_all || 0 }} 人
</view>
</view>
</view>
<view class="team-quick-right ss-flex ss-col-center">
<text class="manage-text">去管理</text>
<uni-icons type="right" size="14" color="#ff6000"></uni-icons>
</view>
</view>
<!-- 菜单栏 -->
<commission-menu />
<!-- 分销记录 -->
@@ -103,4 +125,62 @@
color: #ffffff;
}
}
.team-quick-card {
width: 694rpx;
margin: 20rpx auto 0;
padding: 22rpx 28rpx;
box-sizing: border-box;
background: linear-gradient(135deg, #ffffff 0%, #fffbf0 100%);
border-radius: 16rpx;
border: 1rpx solid #ffe8c2;
box-shadow: 0 4rpx 16rpx rgba(247, 213, 152, 0.25);
position: relative;
z-index: 3;
.icon-wrap {
width: 72rpx;
height: 72rpx;
border-radius: 36rpx;
background: #fff0e6;
}
.team-quick-info {
.title-bold {
font-size: 28rpx;
font-weight: bold;
color: #692e04;
}
.active-badge {
font-size: 20rpx;
padding: 2rpx 10rpx;
border-radius: 12rpx;
background: #ecfdf5;
color: #059669;
font-weight: 500;
}
.warn-badge {
font-size: 20rpx;
padding: 2rpx 10rpx;
border-radius: 12rpx;
background: #fef2f2;
color: #dc2626;
font-weight: 500;
}
.team-sub {
font-size: 22rpx;
color: #a17545;
font-family: OPPOSANS;
}
}
.team-quick-right {
.manage-text {
font-size: 24rpx;
font-weight: 500;
color: #ff6000;
margin-right: 4rpx;
}
}
}
</style>

查看文件

@@ -12,6 +12,19 @@
</view>
</view>
<!-- 穿透查看成员明细提示条 -->
<view v-if="state.buyerId > 0" class="buyer-filter-bar ss-flex ss-row-between ss-col-center">
<view class="ss-flex ss-col-center">
<uni-icons type="person-filled" size="16" color="#ff6000"></uni-icons>
<text class="filter-tip-text ss-m-l-10">
正在筛选成员:<text class="buyer-highlight">【{{ state.buyerName || ('ID:' + state.buyerId) }}】</text>的贡献
</text>
</view>
<button class="ss-reset-button clear-filter-btn" @tap="onClearBuyerFilter">
查看全部
</button>
</view>
<su-sticky>
<su-tabs
:list="tabMaps"
@@ -139,6 +152,8 @@
loadStatus: '',
showDetail: false,
current: null,
buyerId: 0,
buyerName: '',
overview: {
month_income: '0.00',
skip_count: 0,
@@ -179,11 +194,15 @@
async function getLogList(page = 1, list_rows = 10) {
state.loadStatus = 'loading';
try {
const res = await sheep.$api.partner.rewards({
tab: tabMaps[state.currentTab]?.value || 'all',
const params = {
tab: tabMaps.value[state.currentTab]?.value || 'all',
page,
list_rows,
});
};
if (state.buyerId > 0) {
params.buyer_id = state.buyerId;
}
const res = await sheep.$api.partner.rewards(params);
if (res?.code === 1) {
const pageData = pickList(res.data);
state.pagination = {
@@ -220,7 +239,20 @@
state.showDetail = true;
}
onLoad(() => {
function onClearBuyerFilter() {
state.buyerId = 0;
state.buyerName = '';
state.pagination = { ...emptyPagination };
getLogList(1);
}
onLoad((options) => {
if (options?.buyer_id) {
state.buyerId = Number(options.buyer_id) || 0;
}
if (options?.buyer_name) {
state.buyerName = decodeURIComponent(options.buyer_name);
}
getOverview();
getLogList();
});
@@ -239,6 +271,29 @@
</script>
<style lang="scss" scoped>
.buyer-filter-bar {
margin: 16rpx 24rpx;
padding: 16rpx 24rpx;
background: #fff4e5;
border-radius: 12rpx;
border: 1rpx solid #ffd8a8;
.filter-tip-text {
font-size: 24rpx;
color: #a17545;
}
.buyer-highlight {
font-weight: bold;
color: #ff6000;
}
.clear-filter-btn {
font-size: 22rpx;
padding: 6rpx 18rpx;
border-radius: 20rpx;
background: #ff6000;
color: #ffffff;
}
}
.header-box {
background-color: $white;
padding: 30rpx;

查看文件

@@ -22,6 +22,25 @@
<text class="referrer-name">{{ userInfo.parent_user.nickname }}</text>
</view>
<!-- 专属邀请码与拓展卡片 -->
<view class="invite-action-card ss-flex ss-row-between ss-col-center">
<view class="invite-code-wrap ss-flex ss-col-center">
<text class="invite-label">专属邀请码:</text>
<text class="invite-code">HL{{ userInfo.id || '---' }}</text>
<button class="ss-reset-button copy-code-btn ss-m-l-10" @tap="onCopyInviteCode">复制</button>
</view>
<view class="invite-btn-group ss-flex ss-col-center">
<button class="ss-reset-button invite-btn-poster ss-flex ss-col-center" @tap="onOpenShareModal">
<uni-icons type="image" size="14" color="#ffffff"></uni-icons>
<text class="ss-m-l-6">邀请海报</text>
</button>
<button class="ss-reset-button invite-btn-link ss-m-l-12 ss-flex ss-col-center" @tap="onCopyShareLink">
<uni-icons type="link" size="14" color="#ff6000"></uni-icons>
<text class="ss-m-l-6">复制链接</text>
</button>
</view>
</view>
<!-- 团队核心数据总览卡片 -->
<view class="team-data-box ss-flex ss-col-center ss-row-between">
<!-- 团队总人数卡片 -->
@@ -85,6 +104,20 @@
</view>
</view>
<!-- 团队收益与业绩统计大盘 -->
<view class="team-wealth-box ss-flex ss-col-center ss-row-between">
<view class="wealth-card ss-flex-1 ss-m-r-16">
<view class="wealth-title">团队贡献总收益(元)</view>
<view class="wealth-num text-orange">¥{{ state.summary.team_total_reward || '0.00' }}</view>
<view class="wealth-sub">本月贡献: ¥{{ state.summary.team_month_reward || '0.00' }}</view>
</view>
<view class="wealth-card ss-flex-1">
<view class="wealth-title">团队自购总业绩(元)</view>
<view class="wealth-num text-gold">¥{{ state.summary.team_total_consume || '0.00' }}</view>
<view class="wealth-sub">团队累计订单: {{ state.summary.team_order_count || 0 }} 笔</view>
</view>
</view>
<!-- 30天自购保活健康度胶囊条 -->
<view class="health-bar ss-flex ss-row-between ss-col-center">
<view class="health-title">保活健康度:</view>
@@ -206,6 +239,10 @@
{{ item.team_level === 1 ? '一级直推' : '二级间推' }}
</text>
</view>
<view class="member-sub-info ss-flex ss-col-center ss-m-t-4" v-if="item.mobile_hide || item.id">
<text class="member-phone" v-if="item.mobile_hide">{{ item.mobile_hide }}</text>
<text class="member-id-tag ss-m-l-8">ID: {{ item.id }}</text>
</view>
<view class="member-meta-row ss-flex ss-col-center ss-m-t-8">
<!-- 身份徽章 -->
<view v-if="memberLevelName(item)" class="tag-box ss-flex ss-col-center">
@@ -310,13 +347,20 @@
<text class="ss-m-l-6">拨打</text>
</button>
<button
v-if="item.mobile_raw"
v-if="item.mobile_raw || item.mobile_hide"
class="ss-reset-button action-btn btn-copy ss-m-l-12"
@tap.stop="onCopyText(item.mobile_raw, '手机号已复制')"
@tap.stop="onCopyText(item.mobile_raw || item.mobile_hide, '手机号已复制')"
>
<uni-icons type="paperclip" size="14" color="#666666"></uni-icons>
<text class="ss-m-l-6">复制手机</text>
</button>
<button
class="ss-reset-button action-btn btn-reward ss-m-l-12"
@tap.stop="onJumpRewards(item.id, item.nickname)"
>
<uni-icons type="wallet" size="14" color="#ff6000"></uni-icons>
<text class="ss-m-l-6">收益</text>
</button>
<button
class="ss-reset-button action-btn btn-detail ss-m-l-12"
@tap.stop="onOpenMemberDetail(item)"
@@ -387,6 +431,8 @@
<view class="drawer-sub ss-flex ss-col-center ss-m-t-8">
<text class="user-id">ID: {{ state.currentMember.id }}</text>
<text class="dot-split">·</text>
<text class="user-phone">手机: {{ state.currentMember.mobile_hide || '未绑定' }}</text>
<text class="dot-split">·</text>
<text class="join-time">{{ formatTime(state.currentMember.createtime) }} 加入</text>
</view>
</view>
@@ -496,16 +542,16 @@
<text class="ss-m-l-8">呼叫成员</text>
</button>
<button
v-if="state.currentMember.mobile_raw"
v-if="state.currentMember.mobile_raw || state.currentMember.mobile_hide"
class="ss-reset-button drawer-btn drawer-btn-sub ss-flex-1 ss-m-r-16"
@tap="onCopyText(state.currentMember.mobile_raw, '手机号已复制')"
@tap="onCopyText(state.currentMember.mobile_raw || state.currentMember.mobile_hide, '手机号已复制')"
>
<uni-icons type="paperclip" size="16" color="#ff6000"></uni-icons>
<text class="ss-m-l-8">复制电话</text>
</button>
<button
class="ss-reset-button drawer-btn drawer-btn-outline ss-flex-1"
@tap="onJumpRewards(state.currentMember.id)"
@tap="onJumpRewards(state.currentMember.id, state.currentMember.nickname)"
>
<uni-icons type="list" size="16" color="#666666"></uni-icons>
<text class="ss-m-l-8">查收益流水</text>
@@ -577,6 +623,10 @@
expiring_count: 0,
inactive_count: 0,
partner_count: 0,
team_total_consume: '0.00',
team_total_reward: '0.00',
team_month_reward: '0.00',
team_order_count: 0,
},
pagination: {
data: [],
@@ -728,9 +778,32 @@
state.showDetail = true;
}
function onJumpRewards(buyerId) {
function onJumpRewards(buyerId, buyerName = '') {
state.showDetail = false;
sheep.$router.go(`/pages/commission/rewards?buyer_id=${buyerId}`);
const nameParam = buyerName ? `&buyer_name=${encodeURIComponent(buyerName)}` : '';
sheep.$router.go(`/pages/commission/rewards?buyer_id=${buyerId}${nameParam}`);
}
function onCopyInviteCode() {
if (!userInfo.value?.id) {
sheep.$helper.toast('请先登录');
return;
}
const code = `HL${userInfo.value.id}`;
sheep.$helper.copyText(code, '专属邀请码已复制');
}
function onCopyShareLink() {
if (!userInfo.value?.id) {
sheep.$helper.toast('请先登录');
return;
}
const shareQuery = sheep.$platform.share.buildSpmQuery({
page: '1',
query: '0',
});
const shareUrl = sheep.$platform.share.buildSpmPath(shareQuery);
sheep.$helper.copyText(shareUrl, '专属推广链接已复制');
}
function onOpenShareModal() {
@@ -825,6 +898,59 @@
}
}
// 专属邀请码卡片
.invite-action-card {
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
border-radius: 16rpx;
padding: 12rpx 20rpx;
margin-bottom: 20rpx;
.invite-code-wrap {
.invite-label {
font-size: 24rpx;
color: #ffffff;
font-weight: 500;
}
.invite-code {
font-size: 28rpx;
font-weight: bold;
color: #ffffff;
font-family: OPPOSANS;
letter-spacing: 1rpx;
}
.copy-code-btn {
font-size: 20rpx;
padding: 4rpx 14rpx;
border-radius: 16rpx;
background: #ffffff;
color: #ff6000;
font-weight: 500;
}
}
.invite-btn-group {
.invite-btn-poster {
height: 48rpx;
padding: 0 16rpx;
border-radius: 24rpx;
background: #ff6000;
color: #ffffff;
font-size: 22rpx;
font-weight: 500;
}
.invite-btn-link {
height: 48rpx;
padding: 0 16rpx;
border-radius: 24rpx;
background: #ffffff;
color: #ff6000;
font-size: 22rpx;
font-weight: 500;
}
}
}
// 团队信息总览
.team-data-box {
.data-card {
@@ -893,6 +1019,41 @@
color: #333333;
font-family: OPPOSANS;
}
// 团队收益与业绩看板
.team-wealth-box {
margin-top: 20rpx;
.wealth-card {
background: #ffffff;
border-radius: 20rpx;
padding: 18rpx 20rpx;
box-sizing: border-box;
.wealth-title {
font-size: 22rpx;
color: #999999;
line-height: 28rpx;
margin-bottom: 6rpx;
}
.wealth-num {
font-size: 32rpx;
font-weight: bold;
font-family: OPPOSANS;
line-height: 38rpx;
margin-bottom: 6rpx;
&.text-orange {
color: #ff6000;
}
&.text-gold {
color: #c48a3a;
}
}
.wealth-sub {
font-size: 20rpx;
color: #888888;
line-height: 24rpx;
}
}
}
@@ -1127,6 +1288,24 @@
}
}
.member-sub-info {
font-size: 20rpx;
color: #999999;
font-family: OPPOSANS;
.member-phone {
color: #666666;
font-size: 22rpx;
}
.member-id-tag {
background: #f3f4f6;
color: #9ca3af;
padding: 2rpx 8rpx;
border-radius: 6rpx;
font-size: 18rpx;
}
}
.member-meta-row {
gap: 8rpx;
}
@@ -1240,6 +1419,10 @@
background: #f3f4f6;
color: #4b5563;
}
&.btn-reward {
background: #fff7ed;
color: #ea580c;
}
&.btn-detail {
background: #ffffff;
color: #666666;

查看文件

@@ -33,13 +33,14 @@
<view v-if="goodsPrice.price > 0" class="price-text"> ¥{{ goodsPrice.price }} </view>
<text v-if="goodsPrice.price > 0 && goodsPrice.score > 0">+</text>
<image
v-if="goodsPrice.score > 0"
:src="sheep.$url.static('/assets/addons/shopro/uniapp/goods/score1.svg')"
class="score-img"
></image>
<view class="score-text ss-m-r-16">
<view v-if="goodsPrice.score > 0" class="score-text ss-m-r-16">
{{ goodsPrice.score }}
</view>
<view v-if="goodsPrice.price > 0" class="voucher-tip-tag">支持兑换券抵扣</view>
<view v-if="goodsPrice.price > 0" class="voucher-tip-tag">支持兑换券全额抵扣</view>
</view>
<view class="sales-text">
{{ formatExchange(state.goodsInfo.sales_show_type, state.goodsInfo.sales) }}

查看文件

@@ -5,7 +5,7 @@
navbar="custom"
tabbar="/pages/index/index"
:bgStyle="template.style?.background"
:navbarStyle="template.style?.navbar"
:navbarStyle="navbarStyle"
onShareAppMessage
:showFloatButton="true"
>
@@ -30,6 +30,43 @@
});
const template = computed(() => sheep.$store('app').template?.home);
// 代码直接接管首页顶部导航栏 Logo,不依赖后台装修配置
const navbarStyle = computed(() => {
const base = template.value?.style?.navbar || {};
return {
...base,
mode: 'normal',
type: 'color',
color: '#FFFFFF',
list: {
mp: [
{
width: 3,
height: 1,
top: 0,
left: 0,
type: 'image',
src: '/static/logo.png',
url: '/pages/index/index',
borderRadius: 0,
},
],
app: [
{
width: 4,
height: 1,
top: 0,
left: 2,
type: 'image',
src: '/static/logo.png',
url: '/pages/index/index',
borderRadius: 0,
},
],
},
};
});
onLoad((options) => {
// #ifdef MP
// 小程序识别二维码

查看文件

@@ -8,7 +8,7 @@
:num="state.goodsItem.goods_num"></s-goods-item>
</view>
<uni-forms ref="form" v-model="formData" :rules="rules" label-position="top">
<uni-forms ref="form" :modelValue="formData" :rules="rules" label-position="top">
<!-- 售后类型 -->
<view class="refund-item">
<view class="item-title ss-m-b-20">售后类型</view>
@@ -135,7 +135,7 @@ const state = reactive({
},
],
});
const formData = reactive({
let formData = reactive({
type: '',
reason: '',
mobile: '',

查看文件

@@ -100,7 +100,7 @@
>
<view class="item-title">兑换券</view>
<view class="ss-flex ss-col-center" @tap="openVoucher">
<text class="item-value text-red" v-if="state.orderPayload.voucher_fee > 0"
<text class="item-value text-red" v-if="Number(state.orderInfo.voucher_fee || state.orderPayload.voucher_fee) > 0"
>-¥{{ state.orderInfo.voucher_fee || state.orderPayload.voucher_fee }}</text
>
<text
@@ -197,7 +197,7 @@
<view class="footer-box border-top ss-flex ss-row-between ss-p-x-20 ss-col-center">
<view class="total-box-footer ss-flex ss-col-center">
<view class="total-num ss-font-30 text-red"> ¥{{ state.orderInfo.pay_fee }} </view>
<view v-if="state.orderPayload.order_type === 'score'" class="ss-flex">
<view v-if="state.orderPayload.order_type === 'score' && Number(state.orderInfo.score_amount) > 0" class="ss-flex">
<view class="total-num ss-font-30 text-red ss-m-l-4">+</view>
<image
:src="sheep.$url.static('/assets/addons/shopro/uniapp/goods/score1.svg')"
@@ -313,10 +313,22 @@
}
if (exchangeNow.value) {
const hasScore = Number(state.orderInfo.score_amount) > 0;
const voucherFee = Number(state.orderInfo.voucher_fee || state.orderPayload.voucher_fee || 0);
let confirmContent = '确定立即兑换此商品?';
if (hasScore && voucherFee > 0) {
confirmContent = `确定使用 ${voucherFee} 元兑换券与 ${state.orderInfo.score_amount} 积分立即兑换?`;
} else if (voucherFee > 0) {
confirmContent = `确定使用 ${voucherFee} 元兑换券立即兑换(现金实付 0 元)?`;
} else if (hasScore) {
confirmContent = `确定使用 ${state.orderInfo.score_amount} 积分立即兑换?`;
}
uni.showModal({
title: '提示',
content: '确定使用积分立即兑换?',
title: '兑换确认',
content: confirmContent,
cancelText: '再想想',
confirmText: '确定兑换',
success: async function (res) {
if (res.confirm) {
submitOrder();
@@ -359,6 +371,10 @@
state.orderInfo.goods_list.forEach((item) => {
state.totalNumber += item.goods_num;
});
// 积分/兑换商城订单:若后端自动计算了兑换券抵扣,同步至 orderPayload
if (state.orderPayload.order_type === 'score' && state.orderPayload.voucher_fee === undefined && data.voucher_fee !== undefined) {
state.orderPayload.voucher_fee = data.voucher_fee;
}
}
// 获取可用优惠券

查看文件

@@ -0,0 +1,138 @@
<!-- 微信小程序手机号一键快捷登录 - mpMobileLogin -->
<template>
<view class="mp-mobile-login-wrap">
<!-- 标题栏 -->
<view class="head-box ss-m-b-50">
<view class="ss-flex ss-m-b-16">
<view class="head-title head-title-animation">手机号快捷登录</view>
</view>
<view class="head-subtitle">授权微信手机号,享有一键快捷登录体验</view>
</view>
<!-- 微信手机号一键登录主按钮 -->
<view class="btn-box ss-m-b-40">
<button
class="ss-reset-button wechat-quick-btn ss-flex ss-row-center ss-col-center"
open-type="getPhoneNumber"
@getphonenumber="onGetPhoneNumber"
>
<text class="cicon-wechat ss-m-r-16 wechat-icon"></text>
<text class="btn-text">手机号一键快捷登录</text>
</button>
</view>
<!-- 备选切换登录方式 -->
<view class="switch-box ss-flex ss-row-center ss-col-center">
<view class="switch-item" @tap="showAuthModal('smsLogin')">验证码登录</view>
<view class="divider"></view>
<view class="switch-item" @tap="showAuthModal('accountLogin')">账号密码登录</view>
</view>
</view>
</template>
<script setup>
import sheep from '@/sheep';
import { showAuthModal, closeAuthModal } from '@/sheep/hooks/useModal';
const props = defineProps({
agreeStatus: {
type: Boolean,
default: false,
},
});
const emits = defineEmits(['onConfirm']);
async function onGetPhoneNumber(e) {
if (!props.agreeStatus) {
emits('onConfirm', true);
sheep.$helper.toast('请阅读并勾选协议');
return;
}
if (e.detail?.errMsg !== 'getPhoneNumber:ok') {
return;
}
uni.showLoading({
title: '登录中...',
mask: true,
});
try {
const result = await sheep.$platform.useProvider('wechat').mobileLogin(e.detail);
if (result) {
closeAuthModal();
await sheep.$store('user').loginAfter();
sheep.$helper.toast('登录成功');
} else {
sheep.$helper.toast('登录失败,请重试');
}
} catch (err) {
console.error('mobileLogin error', err);
sheep.$helper.toast('登录异常,请稍后重试');
} finally {
uni.hideLoading();
}
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
.mp-mobile-login-wrap {
padding-top: 10rpx;
}
.btn-box {
width: 100%;
margin-top: 50rpx;
}
.wechat-quick-btn {
width: 100%;
height: 88rpx;
background: #07c160;
border-radius: 44rpx;
color: #ffffff;
box-shadow: 0 8rpx 16rpx rgba(7, 193, 96, 0.25);
transition: all 0.2s;
&:active {
opacity: 0.9;
transform: scale(0.98);
}
.wechat-icon {
font-size: 40rpx;
line-height: 1;
}
.btn-text {
font-size: 32rpx;
font-weight: 500;
letter-spacing: 1rpx;
}
}
.switch-box {
margin-top: 36rpx;
font-size: 26rpx;
color: #888888;
.switch-item {
padding: 10rpx 20rpx;
font-size: 26rpx;
color: #666666;
&:active {
color: var(--ui-BG-Main);
}
}
.divider {
width: 2rpx;
height: 24rpx;
background-color: #dddddd;
}
}
</style>

查看文件

@@ -8,6 +8,13 @@
@click="closeAuthModal"
/> -->
<view class="login-wrap">
<!-- 0. 微信小程序手机号一键快捷登录 mpMobileLogin -->
<mp-mobile-login
v-if="authType === 'mpMobileLogin'"
:agreeStatus="state.protocol"
@onConfirm="onConfirm"
/>
<!-- 1. 账号密码登录 accountLogin -->
<account-login
v-if="authType === 'accountLogin'"
@@ -56,7 +63,7 @@
>立即注册</button
>
<view class="or-title">或</view>
<button class="ss-reset-button login-btn" @tap="thirdLogin('wechat')">快捷登录</button>
<button class="ss-reset-button login-btn" @tap="showAuthModal('mpMobileLogin')">快捷登录</button>
<view class="circle"></view>
</view>
@@ -99,7 +106,7 @@
</view>
<view
v-if="['accountLogin', 'smsLogin', 'smsRegister'].includes(authType)"
v-if="['accountLogin', 'smsLogin', 'smsRegister', 'mpMobileLogin'].includes(authType)"
class="agreement-box ss-flex ss-row-center"
:class="{ shake: currentProtocol }"
>
@@ -136,6 +143,7 @@
<script setup>
import { computed, reactive, ref } from 'vue';
import sheep from '@/sheep';
import mpMobileLogin from './components/mp-mobile-login.vue';
import accountLogin from './components/account-login.vue';
import smsLogin from './components/sms-login.vue';
import smsRegister from './components/sms-register.vue';

查看文件

@@ -13,7 +13,11 @@
class="menu-icon-wrap ss-flex ss-row-center ss-col-center"
@tap="sheep.$router.go(data.url)"
>
<image class="nav-image" :src="sheep.$url.cdn(data.src)" mode="aspectFit"></image>
<image
class="nav-image"
:src="data.src && data.src.startsWith('/static/') ? data.src : sheep.$url.cdn(data.src)"
mode="aspectFit"
></image>
</view>
<view class="ss-flex-1" v-if="data.type == 'search'" :style="[{ width: width }]">
<s-search-block
@@ -55,8 +59,11 @@
}
.menu-icon-wrap {
width: 100%;
height: 100%;
.nav-image {
height: 24px;
height: 30px;
max-width: 100%;
}
}
</style>

查看文件

@@ -29,15 +29,22 @@
<view class="ss-col-bottom">
<view
v-if="goodsFields.score_price?.show"
class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10 ss-flex"
class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10 ss-flex ss-col-center"
:style="[{ color: goodsFields.score_price.color }]"
>
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
<view v-if="Number(data.price?.[0] || data.price) > 0">
¥{{ data.price?.[0] || data.price }}
<text v-if="Number(data.score) > 0">+</text>
</view>
<image
v-if="Number(data.score) > 0"
:src="sheep.$url.static('/assets/addons/shopro/uniapp/goods/score1.svg')"
class="score-img"
></image>
{{ data.score }}
<text v-if="Number(data.score) > 0">{{ data.score }}</text>
<view v-if="Number(data.score) <= 0 && Number(data.price?.[0] || data.price) > 0" class="voucher-sub-tag ss-m-l-8">
兑换券
</view>
</view>
<view
@@ -88,15 +95,22 @@
<view class="ss-m-t-10">
<view
v-if="goodsFields.score_price?.show"
class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
class="lg-goods-price ss-m-r-12 ss-flex ss-col-center font-OPPOSANS"
:style="[{ color: goodsFields.score_price.color }]"
>
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
<view v-if="Number(data.price?.[0] || data.price) > 0">
¥{{ data.price?.[0] || data.price }}
<text v-if="Number(data.score) > 0">+</text>
</view>
<image
v-if="Number(data.score) > 0"
:src="sheep.$url.static('/assets/addons/shopro/uniapp/goods/score1.svg')"
class="score-img"
></image>
{{ data.score }}
<text v-if="Number(data.score) > 0">{{ data.score }}</text>
<view v-if="Number(data.score) <= 0 && Number(data.price?.[0] || data.price) > 0" class="voucher-sub-tag ss-m-l-8">
兑换券
</view>
</view>
<view
v-if="goodsFields.price?.show && data.original_price > 0"
@@ -146,13 +160,20 @@
</view>
</slot>
<view class="ss-flex ss-col-bottom ss-p-l-16 ss-p-r-16 font-OPPOSANS">
<view class="sl-goods-price ss-m-r-12 ss-flex">
<view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
<view class="sl-goods-price ss-m-r-12 ss-flex ss-col-center">
<view v-if="Number(data.price?.[0] || data.price) > 0">
¥{{ data.price?.[0] || data.price }}
<text v-if="Number(data.score) > 0">+</text>
</view>
<image
v-if="Number(data.score) > 0"
:src="sheep.$url.static('/assets/addons/shopro/uniapp/goods/score1.svg')"
class="score-img"
></image>
<view>{{ data.score ? data.score : '' }}</view>
<view v-if="Number(data.score) > 0">{{ data.score }}</view>
<view v-if="Number(data.score) <= 0 && Number(data.price?.[0] || data.price) > 0" class="voucher-sub-tag ss-m-l-8">
兑换券
</view>
</view>
<view
v-if="data.original_price > 0"
@@ -454,4 +475,13 @@
height: 36rpx;
margin: 0 4rpx;
}
.voucher-sub-tag {
font-size: 20rpx;
color: #ff3000;
background: rgba(255, 48, 0, 0.1);
border: 1rpx solid rgba(255, 48, 0, 0.25);
border-radius: 6rpx;
padding: 2rpx 8rpx;
line-height: normal;
}
</style>

查看文件

@@ -2,15 +2,12 @@
<template>
<view class="ss-user-info-wrap ss-p-t-50">
<view class="ss-flex ss-col-center ss-row-between ss-m-b-20">
<view class="left-box ss-flex ss-col-center ss-m-l-36">
<!-- 已登录状态 -->
<view v-if="isLogin" class="left-box ss-flex ss-col-center ss-m-l-36">
<view class="avatar-box ss-m-r-24">
<image
class="avatar-img"
:src="
isLogin
? sheep.$url.cdn(userInfo.avatar)
: sheep.$url.static('/assets/addons/shopro/uniapp/default_avatar.png')
"
:src="sheep.$url.cdn(userInfo.avatar)"
mode="aspectFill"
@tap="sheep.$router.go('/pages/user/info')"
></image>
@@ -20,7 +17,7 @@
<view class="nick-name ss-m-r-20">{{ userInfo?.nickname || nickname }}</view>
</view>
<view
v-if="isLogin && showIdentityBadges"
v-if="showIdentityBadges"
class="identity-row ss-flex ss-col-center ss-flex-wrap"
@tap="onBadgeTap"
>
@@ -32,6 +29,55 @@
</view>
</view>
</view>
<!-- 未登录状态:微信小程序原生手机号快捷登录按钮 -->
<!-- #ifdef MP-WEIXIN -->
<button
v-else
class="ss-reset-button left-box ss-flex ss-col-center ss-m-l-36 unlogin-btn"
open-type="getPhoneNumber"
@getphonenumber="onQuickLogin"
>
<view class="avatar-box ss-m-r-24">
<image
class="avatar-img"
:src="sheep.$url.static('/assets/addons/shopro/uniapp/default_avatar.png')"
mode="aspectFill"
></image>
</view>
<view class="user-meta">
<view class="nickname-box ss-flex ss-col-center">
<view class="nick-name ss-m-r-20">点击登录</view>
</view>
<view class="quick-login-badge ss-flex ss-col-center">
<text class="cicon-wechat ss-m-r-8"></text>
<text class="quick-badge-text">手机号快捷登录</text>
</view>
</view>
</button>
<!-- #endif -->
<!-- 未登录状态:其他平台普通点击呼出弹窗 -->
<!-- #ifndef MP-WEIXIN -->
<view
v-else
class="left-box ss-flex ss-col-center ss-m-l-36"
@tap="showAuthModal()"
>
<view class="avatar-box ss-m-r-24">
<image
class="avatar-img"
:src="sheep.$url.static('/assets/addons/shopro/uniapp/default_avatar.png')"
mode="aspectFill"
></image>
</view>
<view class="user-meta">
<view class="nickname-box ss-flex ss-col-center">
<view class="nick-name ss-m-r-20">{{ nickname }}</view>
</view>
</view>
</view>
<!-- #endif -->
<view class="right-box ss-m-r-52">
<button class="ss-reset-button" @tap="showShareModal">
<text class="sicon-qrcode"></text>
@@ -41,13 +87,24 @@
<view
class="bind-mobile-box ss-flex ss-row-between ss-col-center"
v-if="isLogin && !userInfo.verification?.mobile"
v-if="showBindMobile"
>
<view class="ss-flex">
<text class="cicon-mobile-o"></text>
<view class="mobile-title ss-m-l-20"> 点击绑定手机号确保账户安全 </view>
</view>
<!-- #ifdef MP-WEIXIN -->
<button
class="ss-reset-button bind-btn"
open-type="getPhoneNumber"
@getphonenumber="onBindPhoneNumber"
>
去绑定
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<button class="ss-reset-button bind-btn" @tap="onBind">去绑定</button>
<!-- #endif -->
</view>
</view>
</template>
@@ -158,10 +215,50 @@
hasPartner.value,
);
const hasBoundMobile = computed(() => {
return Boolean(userInfo.value?.mobile || userInfo.value?.verification?.mobile);
});
const showBindMobile = computed(() => {
// 1. 未登录不展示
if (!isLogin.value) return false;
// 2. 存在已绑定手机号不展示
if (hasBoundMobile.value) return false;
// 3. 微信小程序环境:默认手机号快捷登录体系,不展示此冗余横幅
// #ifdef MP-WEIXIN
return false;
// #endif
// 4. 其他环境:受平台设置“绑定手机号”开关控制
return Boolean(sheep.$store('app').platform?.bind_mobile);
});
function onBind() {
showAuthModal('changeMobile');
}
// 微信小程序一键快捷绑定手机号
async function onBindPhoneNumber(e) {
if (e.detail?.errMsg !== 'getPhoneNumber:ok') {
showAuthModal('changeMobile');
return;
}
uni.showLoading({ title: '绑定中...', mask: true });
try {
const result = await sheep.$platform.useProvider('wechat').bindUserPhoneNumber(e.detail);
if (result) {
await sheep.$store('user').getInfo();
sheep.$helper.toast('绑定成功');
} else {
showAuthModal('changeMobile');
}
} catch (err) {
console.error('onBindPhoneNumber error', err);
showAuthModal('changeMobile');
} finally {
uni.hideLoading();
}
}
function onBadgeTap() {
if (!isLogin.value) {
showAuthModal();
@@ -169,12 +266,71 @@
}
sheep.$router.go('/pages/commission/index');
}
// 微信小程序手机号一键快捷登录
async function onQuickLogin(e) {
if (e.detail?.errMsg !== 'getPhoneNumber:ok') {
showAuthModal();
return;
}
uni.showLoading({
title: '登录中...',
mask: true,
});
try {
const result = await sheep.$platform.useProvider('wechat').mobileLogin(e.detail);
if (result) {
await sheep.$store('user').loginAfter();
sheep.$helper.toast('登录成功');
} else {
sheep.$helper.toast('登录失败,请重试');
showAuthModal();
}
} catch (err) {
console.error('onQuickLogin error', err);
sheep.$helper.toast('登录异常,请稍后重试');
} finally {
uni.hideLoading();
}
}
</script>
<style lang="scss" scoped>
.ss-user-info-wrap {
box-sizing: border-box;
.unlogin-btn {
text-align: left;
background: transparent;
padding: 0;
line-height: normal;
}
.quick-login-badge {
display: inline-flex;
align-items: center;
margin-top: 8rpx;
padding: 4rpx 14rpx;
font-size: 20rpx;
line-height: 28rpx;
color: #07c160;
background: rgba(7, 193, 96, 0.1);
border-radius: 20rpx;
border: 1rpx solid rgba(7, 193, 96, 0.25);
.cicon-wechat {
font-size: 24rpx;
line-height: 1;
}
.quick-badge-text {
font-size: 20rpx;
font-weight: 500;
}
}
.avatar-box {
width: 100rpx;
height: 100rpx;

查看文件

@@ -6,13 +6,22 @@ import test from '@/sheep/helper/test.js';
import $api from '@/sheep/api';
// 打开授权弹框
export function showAuthModal(type = 'accountLogin') {
export function showAuthModal(type = '') {
const modal = $store('modal');
let targetType = type;
if (!targetType) {
// #ifdef MP-WEIXIN
targetType = 'mpMobileLogin';
// #endif
// #ifndef MP-WEIXIN
targetType = 'accountLogin';
// #endif
}
// closeAuthModal();
setTimeout(() => {
modal.$patch((state) => {
state.auth = type;
state.auth = targetType;
});
}, 200);

查看文件

@@ -50,20 +50,27 @@ const login = async () => {
// 微信小程序手机号授权登陆
const mobileLogin = async (e) => {
return new Promise(async (resolve, reject) => {
if (e.errMsg !== 'getPhoneNumber:ok') {
const detail = e?.detail || e || {};
if (detail.errMsg !== 'getPhoneNumber:ok') {
resolve(false);
return;
}
const { code } = await third.wechat.login(
let currentSessionId = uni.getStorageSync('sessionId');
if (!currentSessionId) {
await getSessionId(false);
currentSessionId = uni.getStorageSync('sessionId');
}
const res = await third.wechat.login(
{
platform: 'miniProgram',
payload: encodeURIComponent(
JSON.stringify({
sessionId: uni.getStorageSync('sessionId'),
code: e.code,
iv: e.iv,
encryptedData: e.encryptedData,
sessionId: currentSessionId,
code: detail.code,
iv: detail.iv,
encryptedData: detail.encryptedData,
}),
),
},
@@ -72,12 +79,35 @@ const mobileLogin = async (e) => {
},
);
if (code === 1) {
if (res?.code === 1) {
resolve(true);
return;
}
if (code === -1) {
getSessionId(false);
if (res?.code === -1) {
const got = await getSessionId(false);
if (got) {
const retryRes = await third.wechat.login(
{
platform: 'miniProgram',
payload: encodeURIComponent(
JSON.stringify({
sessionId: uni.getStorageSync('sessionId'),
code: e.code,
iv: e.iv,
encryptedData: e.encryptedData,
}),
),
},
{
shareInfo: uni.getStorageSync('shareLog') || {},
},
);
if (retryRes?.code === 1) {
resolve(true);
return;
}
}
}
resolve(false);
});
@@ -229,20 +259,57 @@ const checkUpdate = async (silence = true) => {
// 绑定用户手机号
const bindUserPhoneNumber = (e) => {
return new Promise(async (resolve, reject) => {
const { code } = await third.wechat.bindUserPhoneNumber({
const detail = e?.detail || e || {};
if (detail.errMsg && !detail.errMsg.includes('ok')) {
resolve(false);
return;
}
let sessionId = uni.getStorageSync('sessionId');
if (!sessionId) {
await getSessionId(false);
sessionId = uni.getStorageSync('sessionId');
}
const res = await third.wechat.bindUserPhoneNumber({
platform: 'miniProgram',
payload: encodeURIComponent(
JSON.stringify({
sessionId: uni.getStorageSync('sessionId'),
iv: e.iv,
encryptedData: e.encryptedData,
code: e.code,
sessionId: sessionId,
iv: detail.iv,
encryptedData: detail.encryptedData,
code: detail.code,
}),
),
});
if (code === 1) {
if (res?.code === 1) {
await sheep.$store('user').getInfo();
resolve(true);
return;
}
// sessionId 过期重试
if (res?.code === -1) {
await getSessionId(false);
const retryRes = await third.wechat.bindUserPhoneNumber({
platform: 'miniProgram',
payload: encodeURIComponent(
JSON.stringify({
sessionId: uni.getStorageSync('sessionId'),
iv: detail.iv,
encryptedData: detail.encryptedData,
code: detail.code,
}),
),
});
if (retryRes?.code === 1) {
await sheep.$store('user').getInfo();
resolve(true);
return;
}
}
resolve(false);
});
};
@@ -279,6 +346,7 @@ function subscribeMessage(event) {
export default {
load,
login,
mobileLogin,
bind,
unbind,
transfer,

查看文件

@@ -80,6 +80,9 @@ const user = defineStore({
if (!Array.isArray(merged.identities)) {
merged.identities = [];
}
if (merged.mobile) {
merged.verification = { ...(merged.verification || {}), mobile: 1 };
}
this.userInfo = merged;
return Promise.resolve(merged);
@@ -151,7 +154,7 @@ const user = defineStore({
// 登录后设置全局分享参数
$share.getShareInfo();
// 提醒绑定手机号
if (app().platform.bind_mobile && !this.userInfo.verification?.mobile) {
if (app().platform.bind_mobile && !this.userInfo?.mobile && !this.userInfo?.verification?.mobile) {
showAuthModal('changeMobile');
}

二进制
uniapp/static/logo.jpg 普通文件

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 77 KiB

二进制
uniapp/static/logo.png 普通文件

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 160 KiB

二进制
uniapp/static/logo_trans.png 普通文件

二进制文件未显示。

之后

宽度:  |  高度:  |  大小: 184 KiB