提交 34c0c2d2 编写于 作者: zhangzhiwei's avatar zhangzhiwei

杨昌富定制H5

上级 6bd9d8a3
module.exports = {
extends: ["alloy", "alloy/vue", "alloy/typescript", "prettier"],
plugins: ["prettier", "vue"],
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
ecmaVersion: 2020,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
env: {
// 你的环境变量(包含多个预定义的全局变量)
//
// "browser": true,
node: true,
// "mocha": true,
// "jest": true,
// "jquery": true
},
settings: {
"import/resolver": {
alias: {
map: [["@", "./src"]],
extensions: [".ts", ".js", ".jsx", ".json", ".vue"],
},
},
},
globals: {
// 你的全局变量(设置为 false 表示它不允许被重新赋值)
// "myGlobal": false
},
rules: {
// 自定义你的规则
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
"vue/component-tags-order": [
"error",
{
order: ["template", "script", "style"],
},
],
},
};
node_modules
.idea
{
"typescript.tsdk": "node_modules\\typescript\\lib",
"i18n-ally.localesPaths": [
"src/static/lang"
],
"i18n-ally.keystyle": "nested"
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/static/favicon.ico">
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js" type="text/javascript"></script>
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
window._wx = wx
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div class="noLandScape"><img src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/verticalScreen.gif"/></div>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
文件已添加
因为 它太大了无法显示 源差异 。您可以改为 查看blob
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev": "uni --mode pre",
"local:prod": "uni --mode prod",
"local:dev-log": "uni --mode pre-log",
"local:prod-log": "uni --mode prod-log",
"build": "uni build",
"lint:fix": "npx eslint --fix --ext src/**/*.{vue,less,css,scss}"
},
"uni-app": {
"scripts": {
"test": {
"title": "h5测试环境",
"env": {
"UNI_PLATFORM": "h5",
"APP_ENV": "H5-Test"
}
},
"pro": {
"title": "h5正式环境",
"env": {
"UNI_PLATFORM": "h5",
"APP_ENV": "H5-Pro"
}
}
}
},
"dependencies": {
"@dcloudio/uni-app": "^3.0.0-alpha-3031220220222002",
"@dcloudio/uni-components": "^3.0.0-alpha-3031220220222002",
"@dcloudio/uni-h5": "^3.0.0-alpha-3031220220222002",
"@types/md5": "^2.3.2",
"html2canvas": "^1.4.1",
"md5": "^2.3.0",
"pdfh5": "^1.4.2",
"qrcode": "^1.5.0",
"sass": "^1.49.9",
"vant": "^3.5.1",
"vconsole": "^3.14.6",
"vue": "^3.2.31",
"vue-i18n": "^9.1.9",
"vuex": "^4.0.2"
},
"devDependencies": {
"@dcloudio/types": "^2.5.17",
"@dcloudio/uni-automator": "^3.0.0-alpha-3031220220222002",
"@dcloudio/uni-cli-shared": "^3.0.0-alpha-3031220220222002",
"@dcloudio/vite-plugin-uni": "^3.0.0-alpha-3031220220222002",
"@intlify/vite-plugin-vue-i18n": "^3.3.1",
"@types/node": "^17.0.21",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"@vitejs/plugin-vue": "^2.0.0",
"autoprefixer": "^10.4.2",
"babel-eslint": "^10.1.0",
"eslint": "^8.11.0",
"eslint-config-alloy": "^4.5.1",
"eslint-plugin-vue": "^8.5.0",
"typescript": "^4.5.2",
"vite": "^2.8.4",
"vite-plugin-style-import": "^2.0.0",
"vue-eslint-parser": "^8.3.0"
}
}
export default {
base_url: "",
api_url: "/pre",
subdomain: "etaoh5-pre", // 子域名
};
//# sourceMappingURL=.env.pre.js.map
\ No newline at end of file
{"version":3,"file":".env.pre.js","sourceRoot":"","sources":[".env.pre.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,MAAM;IACf,SAAS,EAAE,YAAY,EAAE,MAAM;CACR,CAAC"}
\ No newline at end of file
export default {
base_url: "",
api_url: "/pre", // 相对路径-本地代理
subdomain: "etaoh5-pre", // 子域名
} as NodeJS.ProcessUniEnv;
export default {
base_url: "",
api_url: "/prod",
subdomain: "etaoh5", // 子域名
};
//# sourceMappingURL=.env.prod.js.map
\ No newline at end of file
{"version":3,"file":".env.prod.js","sourceRoot":"","sources":[".env.prod.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,OAAO;IAChB,SAAS,EAAE,QAAQ,EAAE,MAAM;CACJ,CAAC"}
\ No newline at end of file
export default {
base_url: "", // *.edstao.com 泛域名
api_url: "/prod", // 相对路径-本地代理
subdomain: "etaoh5", // 子域名
} as NodeJS.ProcessUniEnv;
import pre from "./.env.pre";
import prod from "./.env.prod";
import Vconsole from 'vconsole';
(function () {
try {
if (process.env.NODE_ENV) { // 打包后没有process
if (process.env.NODE_ENV.indexOf('-log') > -1) {
new Vconsole();
}
if (["pre", "pre-log"].includes(process.env.NODE_ENV)) {
process.uniEnv = pre;
}
else if (["prod", "prod-log"].includes(process.env.NODE_ENV)) {
process.uniEnv = prod;
}
}
}
catch { }
})();
//# sourceMappingURL=env.js.map
\ No newline at end of file
{"version":3,"file":"env.js","sourceRoot":"","sources":["env.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,YAAY,CAAC;AAC7B,OAAO,IAAI,MAAM,aAAa,CAAC;AAC/B,OAAO,QAAQ,MAAM,UAAU,CAAA;AAE/B,CAAC;IACC,IAAI;QACF,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,eAAe;YACzC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;gBAC7C,IAAI,QAAQ,EAAE,CAAC;aAChB;YACD,IAAI,CAAC,KAAK,EAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;gBACpD,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC;aACtB;iBAAM,IAAI,CAAC,MAAM,EAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;gBAC7D,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;aACvB;SACF;KACF;IAAC,MAAM,GAAE;AACZ,CAAC,CAAC,EAAE,CAAC"}
\ No newline at end of file
import pre from "./.env.pre";
import prod from "./.env.prod";
import Vconsole from 'vconsole'
(function () {
try {
if (process.env.NODE_ENV) { // 打包后没有process
if (process.env.NODE_ENV.indexOf('-log') > -1) {
new Vconsole();
}
if (["pre","pre-log"].includes(process.env.NODE_ENV)) {
process.uniEnv = pre;
} else if (["prod","prod-log"].includes(process.env.NODE_ENV)) {
process.uniEnv = prod;
}
}
} catch {}
})();
<script setup lang="ts">
import api from "./api";
import {onLaunch, onShow, onHide} from "@dcloudio/uni-app";
import {WXUtils} from "./utils/utils";
function getUrl(url) {
const q = {};
url.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => q[k] = v);
return q;
}
onLaunch((e) => {
let device = navigator.userAgent.toLowerCase();
window._wx.miniProgram.postMessage({ data:{}});
console.log(window.__wxjs_environment === 'miniprogram','window.__wxjs_environment === \'miniprogram\'');
if (!(window.__wxjs_environment === 'miniprogram')) {
if (!/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile|mobile/.test(device)) {
if (window.location.port === '3000') {
window.location.href = 'https://etaoh5-pre.edstao.com/pc/'
} else {
window.location.href = '/pc/'
}
}
}
uni.setStorageSync('isWxjs_environment', window.__wxjs_environment === 'miniprogram')
if (window.__wxjs_environment === 'miniprogram') {
let subdomain =getUrl(window.location.href)
if(subdomain.name){
uni.setStorageSync('subdomain',subdomain.name)
}
try {
uni.setStorageSync('uniEnv', process.uniEnv) // 打包后没有process
} catch {
}
} else {
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function () {
if (window.orientation === 180 || window.orientation === 0) {
window.location.reload()
}
;
}, false);
uni.setStorageSync('subdomain', window.location.href.replace(/(.*\/\/)|(\.edstao.*)/g, ''))
uni.setStorageSync('isWX', WXUtils.isWeiXin())
try {
uni.setStorageSync('uniEnv', process.uniEnv) // 打包后没有process
uni.setStorageSync('subdomain', process.uniEnv.subdomain) // 打包后没有process
} catch {
}
}
});
onShow(() => {
console.log("App Show");
});
onHide(() => {
console.log("App Hide");
});
</script>
<style lang="scss">
.host_tip {
color: #ff5500;
border: 1px solid #ff5500;
font-size: 12px;
margin-right: 2px;
font-weight: bold;
padding: 0 1px
}
.van-badge{
border: 1px!important;
}
.sign {
position: absolute;
right: 1.8vw;
top: 2vw;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
// #ifdef H5
uni-page-head {
display: none;
}
.noLandScape {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
justify-content: center;
text-align: center;
background: gray;
display: none;
img {
max-width: 100vw;
max-height: 100vh;
}
}
// @media screen and (orientation: portrait) and (max-width:1024px) {
// .noLandScape {
// z-index: 0;
// display: none;
// }
// }
// @media screen and (orientation: landscape) and (max-width:1024px) {
// .noLandScape {
// z-index: 99999;
// display: block;
// }
// }
// #endif
</style>
import request from "@/common/request";
export default {
indexModule() {
return request({
url: "/api/index/module",
});
},
getIndexEtaomall(data) {
return request({
url: "/api/index/getIndexEtaomall",
data,
});
},
storeCard(data) {
return request({
url: "/api/store/storeCard",
data,
});
},
};
//# sourceMappingURL=_index.js.map
\ No newline at end of file
{"version":3,"file":"_index.js","sourceRoot":"","sources":["_index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,eAAe;IACb,WAAW;QACT,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,mBAAmB;SACzB,CAAC,CAAC;IACL,CAAC;IACD,gBAAgB,CAAC,IAAS;QACxB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,6BAA6B;YAClC,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,SAAS,CAAC,IAAS;QACjB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,sBAAsB;YAC3B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
\ No newline at end of file
import request from "@/common/request";
export default {
indexModule() {
return request({
url: "/api/index/module",
});
},
getIndexEtaomall(data: any) {
return request({
url: "/api/index/getIndexEtaomall",
data,
});
},
storeCard(data: any) {
return request({
url: "/api/store/storeCard",
data,
});
},
};
import request from "@/common/request";
export default {
cartAdd(data) {
return request({
url: "/api/cart/add",
method: 'POST',
data,
});
},
cartList(data) {
return request({
url: "/api/cart/list",
data,
});
},
cartRemove(data) {
return request({
url: "/api/cart/remove",
method: 'POST',
data,
});
},
cartCount() {
return request({
url: "/api/cart/count",
});
},
cartCheck(data) {
return request({
url: "/api/cart/check",
method: 'POST',
data
});
},
cartSettle(data) {
return request({
url: "/api/cart/settle",
method: 'POST',
data
});
},
cartModify(data) {
return request({
url: "/api/cart/modify",
method: 'POST',
data
});
},
};
//# sourceMappingURL=cart.js.map
\ No newline at end of file
{"version":3,"file":"cart.js","sourceRoot":"","sources":["cart.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,eAAe;IACb,OAAO,CAAC,IAAS;QACf,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,eAAe;YACpB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,QAAQ,CAAC,IAAS;QAChB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,gBAAgB;YACrB,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,UAAU,CAAC,IAAS;QAClB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,kBAAkB;YACvB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,SAAS;QACP,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,iBAAiB;SACvB,CAAC,CAAC;IACL,CAAC;IACD,SAAS,CAAC,IAAS;QACjB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,iBAAiB;YACtB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,UAAU,CAAC,IAAS;QAClB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,kBAAkB;YACvB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,UAAU,CAAC,IAAS;QAClB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,kBAAkB;YACvB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
\ No newline at end of file
import request from "@/common/request";
export default {
cartAdd(data: any) {
return request({
url: "/api/cart/add",
method: 'POST',
data,
});
},
cartList(data: any) {
return request({
url: "/api/cart/list",
data,
});
},
cartRemove(data: any) {
return request({
url: "/api/cart/remove",
method: 'POST',
data,
});
},
cartCount() {
return request({
url: "/api/cart/count",
});
},
cartCheck(data: any) {
return request({
url: "/api/cart/check",
method: 'POST',
data
});
},
cartSettle(data: any) {
return request({
url: "/api/cart/settle",
method: 'POST',
data
});
},
cartModify(data: any) {
return request({
url: "/api/cart/modify",
method: 'POST',
data
});
},
};
import request from "@/common/request";
export default {
productFav(data) {
return request({
url: "/api/fav/product/fav",
method: 'POST',
data
});
},
productDel(data) {
return request({
url: "/api/fav/product/del",
method: 'POST',
data
});
},
brandFav(data) {
return request({
url: "/api/fav/brand/fav",
method: 'POST',
data
});
},
brandDel(data) {
return request({
url: "/api/fav/brand/del",
method: 'POST',
data
});
},
getJsApiTicket() {
return request({
url: "/api/wx/getJsApiTicket",
raw: true
});
},
getWechartConfig(data) {
return request({
url: "/php/getWxConfigTest.php",
method: 'POST',
data,
raw: true
});
},
// 不使用该方法,只用有没有优惠价来判断
isSJS(data) {
return request({
url: "/api/user/isSJS",
data,
});
},
upload(file) {
return request({
url: "/api/image/upload",
upLoadFile: true,
fileKey: 'image',
file
});
},
receiveArea() {
return request({
url: "/api/receive/area"
});
},
};
//# sourceMappingURL=common.js.map
\ No newline at end of file
{"version":3,"file":"common.js","sourceRoot":"","sources":["common.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,eAAe;IACb,UAAU,CAAC,IAAS;QAClB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,sBAAsB;YAC3B,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,UAAU,CAAC,IAAS;QAClB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,sBAAsB;YAC3B,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,QAAQ,CAAC,IAAS;QAChB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,oBAAoB;YACzB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,QAAQ,CAAC,IAAS;QAChB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,oBAAoB;YACzB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,cAAc;QACZ,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,wBAAwB;YAC7B,GAAG,EAAE,IAAI;SACV,CAAC,CAAC;IACL,CAAC;IACD,gBAAgB,CAAC,IAAS;QACxB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,0BAA0B;YAC/B,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,GAAG,EAAE,IAAI;SACV,CAAC,CAAC;IACL,CAAC;IACD,qBAAqB;IACrB,KAAK,CAAC,IAAS;QACb,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,iBAAiB;YACtB,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,IAAU;QACf,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,mBAAmB;YACxB,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE,OAAO;YAChB,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,WAAW;QACT,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,mBAAmB;SACzB,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
\ No newline at end of file
import request from "@/common/request";
export default {
productFav(data: any) {
return request({
url: "/api/fav/product/fav",
method: 'POST',
data
});
},
productDel(data: any) {
return request({
url: "/api/fav/product/del",
method: 'POST',
data
});
},
brandFav(data: any) {
return request({
url: "/api/fav/brand/fav",
method: 'POST',
data
});
},
brandDel(data: any) {
return request({
url: "/api/fav/brand/del",
method: 'POST',
data
});
},
getJsApiTicket() {
return request({
url: "/api/wx/getJsApiTicket",
raw: true
});
},
getWechartConfig(data: any) {
return request({
url: "/php/getWxConfigTest.php",
method: 'POST',
data,
raw: true
});
},
// 不使用该方法,只用有没有优惠价来判断
isSJS(data: any) {
return request({
url: "/api/user/isSJS",
data,
});
},
upload(file: File) {
return request({
url: "/api/image/upload",
upLoadFile: true,
fileKey: 'image', // 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容
file
});
},
receiveArea() {
return request({
url: "/api/receive/area"
});
},
};
{"version":3,"file":"good.js","sourceRoot":"","sources":["good.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,eAAe;IACb,UAAU,CAAC,KAAsB;QAC/B,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,eAAe,GAAG,KAAK;SAC7B,CAAC,CAAC;IACL,CAAC;IACD,SAAS,CAAC,IAAS;QACjB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,iBAAiB;YACtB,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,WAAW,CAAC,IAAS;QACnB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,mBAAmB;YACxB,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,aAAa;YAC3B,MAAM,EAAE;gBACN,cAAc,EAAE,gCAAgC;aACjD;YACD,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,gBAAgB,CAAC,IAAS;QACxB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,6BAA6B;YAClC,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,aAAa;YAC3B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,WAAW,CAAC,IAAS;QACnB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,mBAAmB;YACxB,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,aAAa;YAC3B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,QAAQ,CAAC,IAAS;QAChB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,qBAAqB;YAC1B,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,aAAa;YAC3B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,OAAO,CAAC,IAAS;QACf,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,oBAAoB;YACzB,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,aAAa;YAC3B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,WAAW,CAAC,IAAS;QACnB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,uBAAuB;YAC5B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
\ No newline at end of file
import request from "@/common/request";
export default {
getProduct(skuId: string | number, data: any) {
return request({
url: "/api/product/" + skuId,
data
});
},
brandInfo(data: any) {
return request({
url: "/api/brand/info",
data
});
},
wxSign(data: any) {
return request({
url: "/api/WeiXin/wxSign?skuId="+data.skuId+'&etaomallId='+data.etaomallId+'&url='+data.url,
method: 'POST',
});
},
imageDetail(data: any) {
return request({
url: "/api/image/detail",
method: 'POST',
responseType: 'arraybuffer',
header: {
'Content-Type': 'application/json;charset=utf-8'
},
data
});
},
pictureAndQrCode(data: any) {
return request({
url: "/api/image/pictureAndQrCode",
method: 'POST',
responseType: 'arraybuffer',
data
});
},
imageQrCode(data: any) {
return request({
url: "/api/image/qrCode",
method: 'POST',
responseType: 'arraybuffer',
data
});
},
skuImage(data: any) {
return request({
url: "/api/image/skuImage",
method: 'POST',
responseType: 'arraybuffer',
data
});
},
handTag(data: any) {
return request({
url: "/api/image/handTag",
method: 'POST',
responseType: 'arraybuffer',
data
});
},
traDeManage(data: any) {
return request({
url: "/api/user/traDeManage",
data
});
}
};
import request from "@/common/request";
export default {
productList(data) {
return request({
url: "/api/product/list",
data,
});
},
sortAndSearch(data) {
return request({
url: "/api/index/sortAndSearch",
data,
});
},
getBrandList(data) {
return request({
url: "/api/brand/index",
data,
});
},
getBrandOtherInfo(data) {
return request({
url: "/api/brand/otherInfo",
data,
});
},
brandFav(data) {
return request({
url: "/api/fav/brand/fav",
data,
});
},
brandDel(data) {
return request({
url: "/api/fav/brand/del",
data,
});
},
};
//# sourceMappingURL=goodList.js.map
\ No newline at end of file
{"version":3,"file":"goodList.js","sourceRoot":"","sources":["goodList.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,eAAe;IACX,WAAW,CAAC,IAAU;QAClB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,mBAAmB;YACxB,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,aAAa,CAAC,IAAU;QACpB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,0BAA0B;YAC/B,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,YAAY,CAAC,IAAU;QACnB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,kBAAkB;YACvB,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,iBAAiB,CAAC,IAAU;QACxB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,sBAAsB;YAC3B,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,QAAQ,CAAC,IAAU;QACf,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,oBAAoB;YACzB,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,QAAQ,CAAC,IAAU;QACf,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,oBAAoB;YACzB,IAAI;SACP,CAAC,CAAC;IACP,CAAC;CACJ,CAAC"}
\ No newline at end of file
import request from "@/common/request";
export default {
productList(data?: any) {
return request({
url: "/api/product/list",
data,
});
},
sortAndSearch(data?: any) {
return request({
url: "/api/index/sortAndSearch",
data,
});
},
getBrandList(data?: any) {
return request({
url: "/api/brand/index",
data,
});
},
getBrandOtherInfo(data?: any) {
return request({
url: "/api/brand/otherInfo",
data,
});
},
brandFav(data?: any) {
return request({
url: "/api/fav/brand/fav",
data,
});
},
brandDel(data?: any) {
return request({
url: "/api/fav/brand/del",
data,
});
},
};
import index from "./_index";
import goodList from "./goodList";
import login from "./login";
import good from "./good";
import my from "./my";
import cart from "./cart";
import common from "./common";
import order from "./order";
const api = {
...index,
...goodList,
...login,
...good,
...my,
...cart,
...common,
...order,
};
export default api;
//# sourceMappingURL=index.js.map
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,UAAU,CAAC;AAC7B,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,IAAI,MAAM,QAAQ,CAAC;AAC1B,OAAO,EAAE,MAAM,MAAM,CAAC;AACtB,OAAO,IAAI,MAAM,QAAQ,CAAC;AAC1B,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,KAAK,MAAM,SAAS,CAAC;AAE5B,MAAM,GAAG,GAAG;IACV,GAAG,KAAK;IACR,GAAG,QAAQ;IACX,GAAG,KAAK;IACR,GAAG,IAAI;IACP,GAAG,EAAE;IACL,GAAG,IAAI;IACP,GAAG,MAAM;IACP,GAAG,KAAK;CACX,CAAC;AAEF,eAAe,GAAG,CAAC"}
\ No newline at end of file
import index from "./_index";
import goodList from "./goodList";
import login from "./login";
import good from "./good";
import my from "./my";
import cart from "./cart";
import common from "./common";
import order from "./order";
const api = {
...index,
...goodList,
...login,
...good,
...my,
...cart,
...common,
...order,
};
export default api;
import request from "@/common/request";
export default {
authcode(data) {
return request({
url: "/api/account/authcode",
method: "POST",
data,
});
},
signup(data) {
return request({
url: "/api/account/signup",
method: "POST",
data,
noToast: true,
});
},
findPwd(data) {
return request({
url: "/api/account/findPwd",
method: "POST",
data,
noToast: true,
});
},
setPwd(data) {
return request({
url: "/api/account/setPwd",
method: "POST",
data,
});
},
login(data) {
return request({
url: "/api/account/login",
method: "POST",
data,
});
},
wxlogin(data) {
return request({
url: "/api/account/wxlogin",
method: "POST",
data,
});
},
logout(data) {
return request({
url: "/api/account/logout",
method: "POST",
data,
});
},
};
//# sourceMappingURL=login.js.map
\ No newline at end of file
{"version":3,"file":"login.js","sourceRoot":"","sources":["login.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,eAAe;IACb,QAAQ,CAAC,IAAS;QAChB,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,uBAAuB;YAC5B,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,IAAS;QACd,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,qBAAqB;YAC1B,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IACD,OAAO,CAAC,IAAS;QACf,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,sBAAsB;YAC3B,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,IAAS;QACd,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,qBAAqB;YAC1B,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,IAAS;QACb,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,oBAAoB;YACzB,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,IAAS;QACd,OAAO,OAAO,CAAC;YACb,GAAG,EAAE,qBAAqB;YAC1B,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
\ No newline at end of file
import request from "@/common/request";
export default {
authcode(data: any) {
return request({
url: "/api/account/authcode",
method: "POST",
data,
});
},
signup(data: any) {
return request({
url: "/api/account/signup",
method: "POST",
data,
noToast: true,
});
},
findPwd(data: any) {
return request({
url: "/api/account/findPwd",
method: "POST",
data,
noToast: true,
});
},
setPwd(data: any) {
return request({
url: "/api/account/setPwd",
method: "POST",
data,
});
},
login(data: any) {
return request({
url: "/api/account/login",
method: "POST",
data,
});
},
wxlogin(data: any) {
return request({
url: "/api/account/wxlogin",
method: "POST",
data,
});
},
logout(data: any) {
return request({
url: "/api/account/logout",
method: "POST",
data,
});
},
};
import request from "@/common/request";
export default {
accountInfo(data: any) {
return request({
url: "/api/account/info",
data,
});
},
setHeadImage(data: any) {
return request({
url: "/api/account/info/setHeadImage",
method: 'POST',
data,
});
},
bindName(data: any) {
return request({
url: "/api/account/info/bindName",
method: 'POST',
data,
});
},
bindEmail(data: any) {
return request({
url: "/api/account/info/bindEmail",
method: 'POST',
data,
});
},
setSex(data: any) {
return request({
url: "/api/account/info/setSex",
method: 'POST',
data,
});
},
alterPassword(data: any) {
return request({
url: "/api/account/info/alterPassword",
method: 'POST',
data,
});
},
logout() {
return request({
url: "/api/account/logout",
});
},
receiveList(data: any) {
return request({
url: "/api/receive/list",
data
});
},
receiveAdd(data: any) {
return request({
url: "/api/receive/add",
method: 'POST',
data,
});
},
receiveEdit(data: any) {
return request({
url: "/api/receive/edit",
method: 'POST',
data,
});
},
receiveDel(data: any) {
return request({
url: "/api/receive/del",
data
});
},
favProductList(data: any) {
return request({
url: "/api/fav/product/list",
data
});
},
favBrandList(data: any) {
return request({
url: "/api/fav/brand/list",
data
});
},
getOrderCount() {
return request({
url: "/api/order/getOrderCount"
});
},
};
import request from "@/common/request";
export default {
getCanUse(data) {
return request({
url: "/api/index/canUse",
data
});
},
getOrderDetail(data) {
return request({
url: "/api/order/detail/" + data,
});
},
afterSaleImg() {
return request({
url: "/api/order/afterSaleImg/"
});
},
getOrderList(data) {
return request({
url: "/api/order/list",
method: 'POST',
data
});
},
settleInfo(data) {
return request({
url: "/api/order/settleInfo",
method: 'POST',
data
});
},
orderAdd(data) {
return request({
url: "/api/order/add",
method: 'POST',
data
});
},
orderPay(data) {
return request({
url: "/api/order/pay",
method: 'POST',
data
});
},
remindDeliverGoods(data) {
return request({
url: "/api/order/remindDeliverGoods",
data,
noToast: true
});
},
confirmReceipt(data) {
return request({
url: `/api/order/confirmReceipt/${data.orderId}?domain=${data.domain}`,
});
},
orderCancel(id) {
return request({
url: "/api/order/cancel/" + id,
});
},
platfromlist() {
return request({
url: "/api/channel/platfromlist",
});
},
batchAdd(data) {
return request({
url: "/api/cart/batchAdd",
method: 'POST',
data
});
},
};
//# sourceMappingURL=order.js.map
\ No newline at end of file
{"version":3,"file":"order.js","sourceRoot":"","sources":["order.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAEvC,eAAe;IACX,cAAc,CAAC,IAAS;QACpB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,oBAAoB,GAAG,IAAI;SACnC,CAAC,CAAC;IACP,CAAC;IACD,YAAY;QACR,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,0BAA0B;SAClC,CAAC,CAAC;IACP,CAAC;IACD,YAAY,CAAC,IAAS;QAClB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,iBAAiB;YACtB,MAAM,EAAE,MAAM;YACd,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,UAAU,CAAC,IAAS;QAChB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,uBAAuB;YAC5B,MAAM,EAAE,MAAM;YACd,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,QAAQ,CAAC,IAAS;QACd,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,gBAAgB;YACrB,MAAM,EAAE,MAAM;YACd,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,QAAQ,CAAC,IAAS;QACd,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,gBAAgB;YACrB,MAAM,EAAE,MAAM;YACd,IAAI;SACP,CAAC,CAAC;IACP,CAAC;IACD,kBAAkB,CAAC,IAAS;QACxB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,+BAA+B;YACpC,IAAI;YACJ,OAAO,EAAE,IAAI;SAChB,CAAC,CAAC;IACP,CAAC;IACD,cAAc,CAAC,IAAS;QACpB,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,6BAA6B,IAAI,CAAC,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE;SACzE,CAAC,CAAC;IACP,CAAC;IACD,WAAW,CAAC,EAAO;QACf,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,oBAAoB,GAAG,EAAE;SACjC,CAAC,CAAC;IACP,CAAC;IACD,YAAY;QACR,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,2BAA2B;SACnC,CAAC,CAAC;IACP,CAAC;IACD,QAAQ,CAAC,IAAS;QACd,OAAO,OAAO,CAAC;YACX,GAAG,EAAE,oBAAoB;YACzB,MAAM,EAAE,MAAM;YACd,IAAI;SACP,CAAC,CAAC;IACP,CAAC;CACJ,CAAC"}
\ No newline at end of file
import request from "@/common/request";
export default {
getCanUse(data: any) {
return request({
url: "/api/index/canUse",
data
});
},
getOrderDetail(data: any) {
return request({
url: "/api/order/detail/" + data,
});
},
afterSaleImg() {
return request({
url: "/api/order/afterSaleImg/"
});
},
getOrderList(data: any) {
return request({
url: "/api/order/list",
method: 'POST',
data
});
},
settleInfo(data: any) {
return request({
url: "/api/order/settleInfo",
method: 'POST',
data
});
},
orderAdd(data: any) {
return request({
url: "/api/order/add",
method: 'POST',
data
});
},
orderPay(data: any) {
return request({
url: "/api/order/pay",
method: 'POST',
data
});
},
remindDeliverGoods(data: any) {
return request({
url: "/api/order/remindDeliverGoods",
data,
noToast: true
});
},
confirmReceipt(data: any) {
return request({
url: `/api/order/confirmReceipt/${data.orderId}?domain=${data.domain}`,
});
},
orderCancel(id: any) {
return request({
url: "/api/order/cancel/" + id,
});
},
platfromlist() {
return request({
url: "/api/channel/platfromlist",
});
},
batchAdd(data: any) {
return request({
url: "/api/cart/batchAdd",
method: 'POST',
data
});
},
};
import { Toast } from "vant";
import { PageUtils } from "@/utils/utils";
const request = (options) => {
Toast.loading({
message: '加载中...',
forbidClick: true,
duration: 200
});
return new Promise((resolve, reject) => {
const { token } = uni.getStorageSync("user") || {};
const header = {
...(options.noToken ? undefined : { Authorization: token }),
...options.header,
};
const url = (options.baseUrl || uni.getStorageSync("uniEnv")?.api_url || "") + options.url;
if (options.upLoadFile) {
uni.uploadFile({
url: url,
file: options.file,
name: options.fileKey,
success: (res) => {
const { code, data, message } = JSON.parse(res.data);
// 当前使用这个的只有/api/image/upload,但是这个不用鉴权,不会出现401状态
if (res.statusCode == 401) {
// @ts-ignore
const redirect = encodeURIComponent(PageUtils.getCurPage().$page.fullPath);
uni.reLaunch({ url: "/pages/login/login?redirect=" + redirect });
Toast(message);
reject(message);
}
if (code == 200) {
resolve(data);
}
else {
Toast(message);
reject(message);
}
},
fail: (err) => {
reject(err);
},
});
}
else {
uni.request({
method: options.method,
header,
responseType: options.responseType,
url,
data: options.data,
success: (res) => {
const { code, data, message } = res.data;
if (res.statusCode == 401) {
// @ts-ignore
const redirect = encodeURIComponent(PageUtils.getCurPage().$page.fullPath);
uni.reLaunch({ url: "/pages/login/login?redirect=" + redirect });
Toast(message);
reject(message);
}
if (options.raw) {
resolve(res.data);
}
else if (options.responseType) {
resolve(res.data);
}
else if (code == 200) {
resolve(data);
}
else {
Toast(message);
reject(message);
}
},
fail: (err) => {
reject(err);
},
});
}
});
};
export default request;
//# sourceMappingURL=request.js.map
//# sourceMappingURL=request.js.map
\ No newline at end of file
{"version":3,"file":"request.js","sourceRoot":"","sources":["request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,EAAE;IACxB,KAAK,CAAC,OAAO,CAAC;QACV,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,GAAG;KAChB,CAAC,CAAC;IACH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG;YACX,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;YAC3D,GAAG,OAAO,CAAC,MAAM;SACpB,CAAC;QACF,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;QAC3F,IAAI,OAAO,CAAC,UAAU,EAAE;YACpB,GAAG,CAAC,UAAU,CAAC;gBACX,GAAG,EAAE,GAAG;gBACR,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,OAAO;gBACrB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;oBACb,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACrD,gDAAgD;oBAChD,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE;wBACvB,aAAa;wBACb,MAAM,QAAQ,GAAG,kBAAkB,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC3E,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,8BAA8B,GAAG,QAAQ,EAAE,CAAC,CAAC;wBACjE,KAAK,CAAC,OAAO,CAAC,CAAC;wBACf,MAAM,CAAC,OAAO,CAAC,CAAC;qBACnB;oBACD,IAAI,IAAI,IAAI,GAAG,EAAE;wBACb,OAAO,CAAC,IAAI,CAAC,CAAC;qBACjB;yBACI;wBACD,KAAK,CAAC,OAAO,CAAC,CAAC;wBACf,MAAM,CAAC,OAAO,CAAC,CAAC;qBACnB;gBACL,CAAC;gBACD,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;oBACV,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,CAAC;aACJ,CAAC,CAAC;SACN;aACI;YACD,GAAG,CAAC,OAAO,CAAC;gBACR,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,MAAM;gBACN,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,GAAG;gBACH,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;oBACb,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;oBACzC,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE;wBACvB,aAAa;wBACb,MAAM,QAAQ,GAAG,kBAAkB,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC3E,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,8BAA8B,GAAG,QAAQ,EAAE,CAAC,CAAC;wBACjE,KAAK,CAAC,OAAO,CAAC,CAAC;wBACf,MAAM,CAAC,OAAO,CAAC,CAAC;qBACnB;oBACD,IAAI,OAAO,CAAC,GAAG,EAAE;wBACb,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;qBACrB;yBACI,IAAI,OAAO,CAAC,YAAY,EAAE;wBAC3B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;qBACrB;yBACI,IAAI,IAAI,IAAI,GAAG,EAAE;wBAClB,OAAO,CAAC,IAAI,CAAC,CAAC;qBACjB;yBACI;wBACD,KAAK,CAAC,OAAO,CAAC,CAAC;wBACf,MAAM,CAAC,OAAO,CAAC,CAAC;qBACnB;gBACL,CAAC;gBACD,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;oBACV,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,CAAC;aACJ,CAAC,CAAC;SACN;IACL,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AACF,eAAe,OAAO,CAAC;AACvB,mCAAmC"}
\ No newline at end of file
import { Toast } from "vant";
import { PageUtils } from "@/utils/utils";
const request = (options) => {
Toast.loading({
message: '加载中...',
forbidClick: true,
duration: 200
});
return new Promise((resolve, reject) => {
const { token } = uni.getStorageSync("user") || {};
const header = {
...(options.noToken ? undefined : { Authorization: token }),
...options.header,
};
const url = (options.baseUrl || uni.getStorageSync("uniEnv")?.api_url || "") + options.url;
if (options.upLoadFile) {
uni.uploadFile({
url: url,
file: options.file,
name: options.fileKey,
success: (res) => {
const { code, data, message } = JSON.parse(res.data);
// 当前使用这个的只有/api/image/upload,但是这个不用鉴权,不会出现401状态
if (res.statusCode == 401) {
// @ts-ignore
const redirect = encodeURIComponent(PageUtils.getCurPage().$page.fullPath);
uni.reLaunch({ url: "/pages/login/login?redirect=" + redirect });
Toast(message);
reject(message);
}
if (code == 200) {
resolve(data);
}
else {
Toast(message);
reject(message);
}
},
fail: (err) => {
reject(err);
},
});
}
else {
uni.request({
method: options.method,
header,
responseType: options.responseType,
url,
data: options.data,
success: (res) => {
const { code, data, message } = res.data;
if (res.statusCode == 401) {
// @ts-ignore
const redirect = encodeURIComponent(PageUtils.getCurPage().$page.fullPath);
uni.reLaunch({ url: "/pages/login/login?redirect=" + redirect });
Toast(message);
reject(message);
}
if (options.raw) {
resolve(res.data);
}
else if (options.responseType) {
resolve(res.data);
}
else if (code == 200) {
resolve(data);
}
else {
Toast(message);
reject(message);
}
},
fail: (err) => {
reject(err);
},
});
}
});
};
export default request;
//# sourceMappingURL=request.js.map
\ No newline at end of file
<template>
<van-tabbar v-model="props.current" @change="tabChange" z-index="9999">
<van-tabbar-item v-for="item in list" :badge="item.badge || ''" :badge-props="{ color: '#FE521F' }">
<span>{{ item.text }}</span>
<template #icon="props">
<img v-if="item.selectedIconPath && item.iconPath"
:src="props.active ? item.selectedIconPath : item.iconPath" />
<van-icon v-else :name="item.icon" />
</template>
</van-tabbar-item>
</van-tabbar>
</template>
<script setup lang="ts">
interface TabbarItem {
text?: string;
badge?: number; // 红点数
icon?: string; // vant-icon-class
iconPath?: string; // 优先 > icon
selectedIconPath?: string; // 优先 > icon
}
interface Props {
list: Array<TabbarItem>;
current?: number;
}
const props = withDefaults(defineProps<Props>(), {
list: undefined,
current: 0,
});
const emit = defineEmits(["tabChange"]);
function tabChange(index: number) {
uni.setNavigationBarTitle({
title: props.list[index].text || "",
});
emit("tabChange", index);
}
</script>
<style lang="scss" scoped>
</style>
<template>
<van-overlay class="popup_banner" :show="show">
<van-icon class="popup_close" name="close" @tap="onClose"/>
<van-swipe class="popup_swipe" lazy-render :autoplay="3000" indicator-color="white" @tap.stop>
<van-swipe-item v-for="item in list">
<img class="popup_image" :src="item.iconpath" @tap="goto(item.josnContent)"/>
</van-swipe-item>
</van-swipe>
</van-overlay>
</template>
<script setup lang="ts">
interface Props {
show: boolean;
list: Array<any>;
}
const props = withDefaults(defineProps<Props>(), {
show: false,
list: () => []
});
const emit = defineEmits(["update:show"]);
function onClose() {
emit("update:show", false);
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
</script>
<style lang="scss" scoped>
.popup_banner {
z-index: 100;
vertical-align: middle;
}
.popup_image {
max-width: 80vw;
height: calc(100vh - 240px);
object-fit: contain;
}
.popup_swipe {
margin: 120px 0;
}
.popup_close {
position: absolute;
right: 37px;
top: 80px;
font-size: 40px;
color: #fff;
z-index: 8;
}
</style>
<template>
<view class="fix_rb" :style="{ bottom }">
<van-image v-if="showNav" width="48px" class="btn mg-b-px-10" src="/static/img/rb_nav.png" @tap="onNavOpen" />
<br />
<van-image width="48px" class="btn toTop" :class="{ 'show': state.showToTop }"
src="/static/img/rb_top.png" @tap="gotoTop" />
</view>
<van-overlay style="z-index: 7" :show="state.nav.show" @tap="state.nav.show = false">
<view class="fix_rb bg-white ra-20 pd-h-px-20 pd-v-px-5 mg-r-px-10-m" v-show="state.nav.show">
<template v-for="(item, index) in state.nav.list">
<view class="inline-block text-center pd-px-5" style="width: 45px" @tap="goto(item.url)">
<van-icon size="24" :name="item.icon" />
<view class="text-ss">{{ item.name }}</view>
</view>
<br v-if="index % 3 == 2" />
</template>
</view>
</van-overlay>
</template>
<script setup lang="ts">
import { onMounted, reactive } from 'vue';
import { onPageScroll } from '@dcloudio/uni-app'
interface Props {
showNav?: boolean;
bottom?: string;
}
const props = withDefaults(defineProps<Props>(), {
showNav: false,
bottom: '75px'
});
const state = reactive({
showToTop: false,
nav: {
show: false,
list: [
{ name: '首页', icon: 'wap-home-o', url: '/' },
{ name: '分类', icon: 'apps-o', url: '/?index=1' },
{ name: '搜索', icon: 'search', url: '/pages/topSearch/index' },
{ name: '购物车', icon: 'shopping-cart-o', url: '/?index=2' },
{ name: '我的', icon: 'manager-o', url: '/?index=3' },
{ name: '收藏夹', icon: 'like-o', url: '/pages/my/fav' },
]
}
})
function gotoTop() {
uni.pageScrollTo({
scrollTop: 0
});
}
onPageScroll(e => {
state.showToTop = e.scrollTop > 100
})
function onNavOpen() {
state.nav.show = true
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
</script>
<style lang="scss" scoped>
.fix_rb {
position: fixed;
right: 12px;
z-index: 6;
transition: all ease-in-out .2s;
bottom: 75px;
.toTop {
opacity: 0;
&.show {
opacity: 1;
}
}
}
</style>
/// <reference types="vite/client" />
declare module "*.vue" {
import { DefineComponent } from "vue";
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>;
export default component;
}
// 环境
declare module 'process' {
global {
namespace NodeJS {
interface ProcessUniEnv {
base_url: string;
api_url: string;
subdomain: string;
}
interface Process {
uniEnv: NodeJS.ProcessUniEnv;
}
}
}
}
interface Window {
_wx: {
config: (config: unknown) => void;
error: (config: unknown) => any;
ready: (config: unknown) => void;
updateAppMessageShareData: (config: unknown) => void;
updateTimelineShareData: (config: unknown) => void;
};
_sha1: Function;
}
// import './utils/checkDevice';
import { createSSRApp } from "vue";
import App from "./App.vue";
import Vant from "vant";
import { Lazyload, ImagePreview } from 'vant';
import "vant/lib/index.css";
import "./static/style/global.scss";
import "./.env/env";
window['global'] = window;
export function createApp() {
const app = createSSRApp(App);
app.use(Vant).use(Lazyload).use(ImagePreview);
return {
app,
};
}
//# sourceMappingURL=main.js.map
\ No newline at end of file
{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,GAAG,MAAM,WAAW,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,oBAAoB,CAAC;AAC5B,OAAO,4BAA4B,CAAC;AACpC,OAAO,YAAY,CAAC;AACnB,MAAc,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;AACnC,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC9C,OAAO;QACL,GAAG;KACJ,CAAC;AACJ,CAAC"}
\ No newline at end of file
// import './utils/checkDevice'
import { createSSRApp } from "vue";
import App from "./App.vue";
import Vant from "vant";
import { Lazyload, ImagePreview } from 'vant';
import "vant/lib/index.css";
import "./static/style/global.scss";
import "./.env/env";
(window as any)['global'] = window;
export function createApp() {
const app = createSSRApp(App);
app.use(Vant).use(Lazyload).use(ImagePreview);
return {
app,
};
}
{
"name": "",
"appid": "",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
"uniStatistics": {
"enable": false
},
"h5" : {
"router" : {
"mode":"hash"
}
},
"vueVersion": "3"
}
{
"pages": [
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "E淘商城"
}
}, {
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录"
}
}, {
"path": "pages/login/register",
"style": {
"navigationBarTitleText": "注册"
}
}, {
"path": "pages/login/forget",
"style": {
"navigationBarTitleText": "找回密码"
}
}, {
"path": "pages/login/policy",
"style": {
"navigationBarTitleText": "隐私政策"
}
}, {
"path": "pages/login/service",
"style": {
"navigationBarTitleText": "服务协议"
}
}, {
"path": "pages/classify/index",
"style": {
"navigationBarTitleText": "筛选分类"
}
}, {
"path": "pages/good/detail",
"style": {
"navigationBarTitleText": "商品详情"
}
}, {
"path": "pages/good/share",
"style": {
"navigationBarTitleText": "分享详情"
}
},{
"path": "pages/good/contact",
"style": {
"navigationBarTitleText": "服务运营商"
}
},{
"path": "pages/good/issue",
"style": {
"navigationBarTitleText": "服务条款"
}
}, {
"path": "pages/good/download",
"style": {
"navigationBarTitleText": "图片下载"
}
}, {
"path": "pages/good/size",
"style": {
"navigationBarTitleText": "尺寸"
}
},
{
"path": "pages/topSearch/index",
"style": {
"navigationBarTitleText": "E淘商城-搜索"
}
},
{
"path": "pages/goodList/index",
"style": {
"navigationBarTitleText": "E淘商城-列表页"
}
},
{
"path": "pages/index/storeCard",
"style": {
"navigationBarTitleText": "店铺名片列表"
}
},
{
"path": "pages/good/brandShop",
"style": {
"navigationBarTitleText": "店铺"
}
},
{
"path": "pages/order/orderList",
"style": {
"navigationBarTitleText": "我的订单"
}
},
{
"path": "pages/order/orderDetails",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{
"path": "pages/order/paySuccess",
"style": {
"navigationBarTitleText": "支付成功"
}
},
{
"path": "pages/order/beforeconfirm",
"style": {
"navigationBarTitleText": "确认订单"
}
},
{
"path": "pages/my/detail",
"style": {
"navigationBarTitleText": "个人信息"
}
},
{
"path": "pages/my/address",
"style": {
"navigationBarTitleText": "收货地址" // 不要这个,用于判断组件/页面调用
}
},
{
"path": "pages/order/afterSales",
"style": {
"navigationBarTitleText": "申请售后"
}
},
{
"path": "pages/order/customerService",
"style": {
"navigationBarTitleText": "客服介入"
}
},
{
"path": "pages/my/fav",
"style": {
"navigationBarTitleText": "我的收藏"
}
},
{
"path": "pages/my/certificate",
"style": {
"navigationBarTitleText": "证件信息"
}
},
{
"path": "pages/my/technicalSupport",
"style": {
"navigationBarTitleText": "E淘提供技术支持"
}
},
{
"path": "pages/my/pdfh5",
"style": {
"navigationBarTitleText": "营业执照"
}
}
],
"subPackages": [
{
"root": "pagesSub",
"pages": [
{
"path": "index",
"style": {
"navigationBarTitleText": "首页"
}
}
]
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
}
}
view
<template>
<view class="pd-b-px-95">
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<text class="top-center">{{ '购物车' + (state.cart.num ? `(${state.cart.num})` : '') }}</text>
<text class="top_right" :class="[state.cart.edit ? 'text-orange' : 'text-gray']" @tap="onCartEdit">
{{ state.cart.edit ? '完成' : '编辑' }}
</text>
</view>
</van-sticky>
<van-pull-refresh v-model="state.refresh" @refresh="cartList()">
<view v-if="state.cart.list.length > 0">
<view style="min-height: calc(100vh - 180px)" v-if="state.switch.newView">
<van-cell-group inset class="mg-v-40" v-for="(bItem, index) in state.cart.list">
<van-cell v-if="state.switch.brand" value-class="flex" :border="false">
<van-checkbox icon-size="17px" v-model="bItem.all" @tap="() => { onCheck(bItem); onItemAll(index) }" />
<view class="pd-l-20 text-s" @tap="goto(``)">
{{ bItem.brand.name }}
<van-icon name="arrow" />
</view>
</van-cell>
<van-divider v-if="state.switch.brand" class="mg-v-0" />
<van-checkbox-group icon-size="17px" v-model="bItem.select"
:ref="(el: any) => { if (el) items[index] = el }">
<van-swipe-cell v-for="gItem in bItem.list">
<van-cell>
<view class="flex">
<!-- 编辑时,放开选择 -->
<van-checkbox :name="gItem" @tap="onCheck(bItem, gItem)"
:disabled="!state.cart.edit && isUnselectable(gItem)" />
<van-image class="pd-l-20" height="156rpx" width="156rpx" fit="cover" :src="gItem.mainImg"
@tap="onGood(gItem)" loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="156rpx" />
<view class="pd-l-20">
<view class="ellipsis text-s" style="width: calc(100vw - 360rpx);">{{ gItem.title }}</view>
<view class="justify-between justify-middle mg-b-10 pd-h-15 bg-gray text-ss"
style="border-radius: 5rpx;height: 23px" @tap="onChangeGood(bItem, gItem)">
<view class="ellipsis" style="width: calc(100vw - 410rpx);">{{ gItem.info }}</view>
<van-icon v-if="state.switch.changeGood" name="arrow-down" />
</view>
<view class="flex justify-middle">
<van-image width="30px" height="16px" :src="gItem.zoneIcon" />
<text v-if="state.switch.delivery" class="text-ss text-yellow pd-l-50">
交货期:{{ gItem.deliveryTimeStr }}
</text>
<text v-if="state.switch.stock" class="text-ss text-yellow pd-l-50">
库存:{{ gItem.stock }}
</text>
</view>
</view>
</view>
<view class="flex">
<view class="text-center mg-l-50 mg-r-20" style="width: 160rpx">
<text class="text-red text-ss scale-85 scale-t" v-if="!gItem.saleable">商品已下架</text>
<text class="text-red text-ss scale-85 scale-rt" v-else-if="gItem.moq > gItem.stock">暂时无货</text>
<text class="text-red text-ss scale-85 scale-rt" v-else-if="!gItem.isBrandAgent">商家未代理该品牌</text>
</view>
<view style="width: calc(100vw - 360rpx);">
<template v-if="gItem.salePrice !== null">
<view class="text-gray text-ss scale-85 scale-lt mg-t-5-m">零售价:¥{{ gItem.productPrice }}</view>
<view class="justify-between justify-middle mg-t-10-m">
<view class="text-darkGray text-bold text-ss">优惠价:¥{{ gItem.salePrice }}</view>
<van-stepper :disabled="isUnselectable(gItem)" v-model="gItem.productQty" theme="round"
button-size="15px" :before-change="(num) => beforeCartModify(num, gItem)" :min="gItem.moq"
:max="gItem.stock" @focus="onStepperFocus(gItem)" />
</view>
</template>
<template v-else>
<view class="justify-between justify-middle mg-t-10-m">
<view class="text-darkGray text-bold text-ss">零售价:¥{{ gItem.productPrice }}</view>
<van-stepper :disabled="isUnselectable(gItem)" v-model="gItem.productQty" theme="round"
button-size="15px" :before-change="(num) => beforeCartModify(num, gItem)" :min="gItem.moq"
:max="gItem.stock" @focus="onStepperFocus(gItem)" />
</view>
</template>
</view>
</view>
<view v-if="state.switch.cartRemark"
class="justify-middle justify-middle mg-l-80 mg-t-20 mg-b-5 pd-l-20 pd-r-10 bg-gray"
style="border-radius: 5rpx;height: 28px;width: calc(100vw - 235rpx);">
<view class="text-ss text-darkGray">商品备注</view>
<view class="text-ss pd-h-15 ellipsis" style="width: calc(100vw - 370rpx);"
@tap="onChangeRemark(gItem)">
<text class="text-black ellipsis" v-if="gItem.remark">{{ gItem.remark }}</text>
<text class="text-gray ellipsis" v-else>选填,请先和商家协商一致</text>
</view>
</view>
</van-cell>
<template #right>
<van-button class="swipe_btn" square type="primary" @tap="onCollect([gItem])">移入<br />收藏夹</van-button>
<van-button class="swipe_btn" type="danger" text="删除" @tap="onDelete([gItem])" />
</template>
</van-swipe-cell>
</van-checkbox-group>
</van-cell-group>
</view>
<view style="min-height: calc(100vh - 180px)" v-else>
<van-cell-group class="mg-v-px-10" v-for="(bItem, index) in state.cart.list">
<van-divider v-if="state.switch.brand" class="mg-v-0" />
<van-checkbox-group icon-size="17px" v-model="bItem.select"
:ref="(el: any) => { if (el) items[index] = el }">
<van-swipe-cell v-for="gItem in bItem.list">
<van-cell :border="false">
<view class="flex">
<van-checkbox :name="gItem" @tap="onCheck(bItem, gItem)"
:disabled="!state.cart.edit && (isUnselectable(gItem))" />
<view class="justify-middle" style="position:relative" @tap="onGood(gItem)">
<van-image class="pd-l-px-10" height="110px" width="110px" fit="cover" :src="gItem.mainImg"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="110px" />
<!--购物车活动角标-->
<div class="sign" v-if="gItem.subScriptImgUrl">
<img :src="gItem.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{gItem.discount}}</div>
</div>
<span v-for="(item,index) in gItem.leftDownIcons" :key="index" :style="{left:index*35+'px'}" style="position:absolute;bottom:0;">
<van-image width="32px" height="16px"
:src="item" />
</span>
</view>
<view class="pd-l-px-10" @tap="onGood(gItem)">
<view class="text-m ellipsis line_over2" style="width: calc(100vw - 180px)">{{
gItem.title
}}</view>
<view class="justify-between justify-middle text-m" style="height: 23px">
<view style="width: calc(100vw - 180px);">规格:{{ gItem.info }}</view>
</view>
<template v-if="gItem.salePrice">
<view class="text-gray text-m mg-t-5-m" v-if="gItem.actPrice">零售价:¥{{ gItem.productPrice }}</view>
<view class="text-gray text-m mg-t-5-m line-through" v-else>零售价:¥{{ gItem.productPrice }}</view>
<view class="text-gray line-through" v-if="gItem.actPrice">优惠价:¥{{ gItem.salePrice }}</view>
<view class="text-orange text-m mg-t-5-m" v-else>优惠价:¥{{ gItem.salePrice }}</view>
<view v-if="gItem.actPrice" class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ gItem.actPrice }}</text>
</view>
</template>
<template v-else>
<view v-if="gItem.actPrice">
<view class="text-gray text-ss line-through">零售价¥{{ gItem.productPrice }}</view>
<view class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ gItem.actPrice }}</text>
</view>
</view>
<text v-else class="text-orange text-m mg-t-5-m" >零售价¥{{ gItem.productPrice }}</text>
</template>
</view>
</view>
</van-cell>
<van-divider class="mg-v-0" />
<van-cell>
<view class="justify-between">
<view>
<text class="text-red text-l" v-if="!gItem.saleable">商品已下架</text>
<text class="text-red text-l" v-else-if="gItem.moq > gItem.stock">暂时无货</text>
<text class="text-red text-l" v-else-if="!gItem.isBrandAgent">商家未代理该品牌</text>
<text class="text-l" v-else>商品可售</text>
</view>
<van-stepper :disabled="isUnselectable(gItem)" v-model="gItem.productQty" button-size="25px"
input-width="60px" :before-change="(num) => beforeCartModify(num, gItem)" :min="gItem.moq"
:max="gItem.stock" @focus="onStepperFocus(gItem)" />
</view>
<view v-if="state.switch.cartRemark"
class="justify-middle justify-middle mg-l-80 mg-t-20 mg-b-5 pd-l-20 pd-r-10 bg-gray"
style="border-radius: 5rpx;height: 28px;width: calc(100vw - 235rpx);">
<view class="text-ss text-darkGray">商品备注</view>
<view class="text-ss pd-h-15 ellipsis" style="width: calc(100vw - 370rpx);"
@tap="onChangeRemark(gItem)">
<text class="text-black ellipsis" v-if="gItem.remark">{{ gItem.remark }}</text>
<text class="text-gray ellipsis" v-else>选填,请先和商家协商一致</text>
</view>
</view>
</van-cell>
<view class="text-red text-ss pd-h-10 pd-v-15" style="background: #fffaf7">
工厂库存:{{ gItem.stock }}
</view>
<template #right>
<van-button class="swipe_btn" square type="primary" @tap="onCollect([gItem])">移入<br />收藏夹</van-button>
<van-button class="swipe_btn" type="danger" text="删除" @tap="onDelete([gItem])" />
</template>
</van-swipe-cell>
</van-checkbox-group>
</van-cell-group>
</view>
</view>
<view v-else class="justify-center" style="min-height: calc(100vh - 180px)">
<van-empty description="购物车竟然是空的" />
<van-button class="text-l" color="linear-gradient(315deg, #FE521F 0%, #FE7902 100%)" round block
style="width: 240rpx" @tap="goto('/')">
去逛逛
</van-button>
</view>
</van-pull-refresh>
<van-action-bar v-if="state.cart.list.length > 0"
class="mg-b-px-50 pd-l-30 pd-r-20 custom-width justify-between sh-t">
<van-checkbox class="text-m" icon-size="17px" v-model="state.all" @tap="onItemAll()">全选</van-checkbox>
<view class="justify-between justify-middle">
<template v-if="state.cart.edit">
<van-action-bar-button style="width: 180rpx;" type="danger" text="删除"
@tap="ask('是否删除选中商品', onDelete, selected)" />
<van-action-bar-button style="width: 180rpx;" type="warning" text="移入收藏夹"
@tap="ask('是否收藏选中商品', onCollect, selected)" />
</template>
<template v-else>
<view class="text-right text-black pd-r-20">
<view class="text-m">合计:<text class="text-orange"></text><text class="text-orange text-xl text-bold">{{ state.sum }}</text></view>
<view v-if="state.switch.discount" class="text-s">已优惠:<text class="text-l text-bold">0.00</text></view>
</view>
<van-action-bar-button style="width: 220rpx;" color="#ff6600" type="primary" :text="`去结算(${selected.length})`"
@tap="onCartCheck(selected)" />
</template>
</view>
</van-action-bar>
<van-dialog v-model:show="state.remark.show" show-cancel-button @confirm="onSetRemark">
<van-field v-model="state.remark.value" rows="3" autosize type="textarea" placeholder="选填,请先和商家协商一致" />
</van-dialog>
<van-form @submit="onNumChange" class="round">
<van-dialog class="withBg pd-b-px-70" v-model:show="state.num.show" theme="round-button" width="264px">
<template #title>
<view class="pd-h-px-20">
<view class="mg-t-px-10-m text-bold">设置商品数量</view>
<!-- 起订量固定为1就不提示了 -->
<view class="text-gray text-s" style="min-height: 20px;">库存:{{ state.num.gItem.stock }}</view>
</view>
</template>
<view class="pd-h-px-20 pd-v-px-10">
<van-field v-model="state.num.value" ref="numField" :class="{ 'field-focus': state.focus == 'num' }"
type="digit" placeholder="请输入商品数量" @focus="onFocus('num')" @blur="onFocus('')" clearable autocomplete="off"
clear-trigger="always" />
</view>
<template #footer>
<van-action-bar class="pd-h-px-15 pd-b-px-15">
<van-action-bar-button type="warning" text="取消" @tap="state.num.show = false" />
<van-action-bar-button type="danger" text="保存" native-type="submit" />
</van-action-bar>
</template>
</van-dialog>
</van-form>
</view>
</template>
<script setup lang="ts">
import api from '@/api';
import { Toast } from "vant";
import { computed, nextTick, onBeforeMount, reactive, ref } from 'vue';
import { Dialog } from "vant";
import { PageUtils } from '@/utils/utils';
const state = reactive({
cart: {
num: 0,
edit: false,
list: [] as any,
},
all: false,
remark: {
show: false,
gItem: {} as any,
value: ''
},
num: {
show: false,
value: '',
gItem: {} as any
},
focus: '',
loading: false,
loadingSon: {
num: false
},
refresh: false,
sum: 0,
switch: {
changeGood: false, // 变更规格
cartRemark: false, // 购物车备注
delivery: false, // 交货期
brand: false, // 品牌
discount: false, // 优惠价
// ----旧----
stock: true, // 库存
// ----新UI----
newView: false
},
})
const items: any = ref([])
const numField: any = ref()
const selected = computed(() => {
if (!state.cart.list) return []
let _list: any = []
state.cart.list.forEach((item: any) => _list.push(...item.select))
if (!state.cart.edit) {
nextTick(() => {
onSettle(selected.value)
})
}
return _list
})
const emit = defineEmits(["setCartCount"]);
onBeforeMount(() => {
const { token } = uni.getStorageSync("user") || {};
if (token) {
cartList()
} else {
if(window.__wxjs_environment === 'miniprogram'){
window._wx.miniProgram.redirectTo({ url: "/pages/login/login" })
}else {
Dialog.confirm({
message: '您尚未登录,请前往登录',
title: "提示",
cancelButtonText: '返回首页'
}).then(() => {
uni.reLaunch({
url: '/pages/login/login'
})
}).catch(() => {
uni.reLaunch({
url: '/'
})
});
}
}
})
function onCartEdit() {
// 从编辑状态返回时,去除不可选商品
if (state.cart.edit) {
state.cart.list.forEach((bItem: any) => {
const select: any = []
bItem.select.forEach((gItem: any) => {
if (!isUnselectable(gItem)) select.push(gItem)
})
bItem.select = select
})
}
state.cart.edit = !state.cart.edit
onCheck()
}
function isUnselectable(gItem: any) {
return !gItem.saleable || gItem.moq > gItem.stock || !gItem.isBrandAgent
}
/**
*
* 有{index}单个品牌的选择按钮-需要勾选那“一个品牌”的“全部商品”
* 有{}全选按钮-需要设置“全部品牌”、“全部商品”
* */
function onItemAll(index?: number) {
if (state.cart.edit) {
nextTick(() => {
if (index != undefined) {
const bItem = state.cart.list[index]
bItem.select = bItem.all ? bItem.list : []
} else {
state.cart.list.forEach((bItem: any) => {
bItem.select = state.all ? bItem.list : []
bItem.all = state.all
})
}
})
} else {
nextTick(() => {
if (index != undefined) {
const bItem = state.cart.list[index]
if (bItem.all) {
// 选择能选上的
const select: any = []
bItem.list.forEach((gItem: any) => {
if (!isUnselectable(gItem)) select.push(gItem)
})
bItem.select = select
} else {
bItem.select = []
}
} else {
if (state.all) {
state.cart.list.forEach((bItem: any) => {
bItem.all = true
// 选择能选上的
const select: any = []
bItem.list.forEach((gItem: any) => {
if (!isUnselectable(gItem)) select.push(gItem)
})
bItem.select = select
})
} else {
state.cart.list.forEach((bItem: any) => {
bItem.all = false
bItem.select = []
})
}
}
})
}
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function onChangeRemark(gItem: any) {
state.remark.value = gItem.remark
state.remark.gItem = gItem
state.remark.show = true
}
function onSetRemark() {
state.remark.gItem.remark = state.remark.value
state.remark.gItem = undefined
state.remark.show = true
}
function beforeCartModify(num: number, gItem: any): any {
if (state.loading) return
state.loading = true
return new Promise((resolve, reject) => {
api.cartModify({
cartId: gItem.cartId,
link: uni.getStorageSync('subdomain'),
productQty: num
})
.then(() => {
state.loading = false
if (selected.value.find((item: any) => item.cartId == gItem.cartId)) {
onSettle(selected.value)
}
resolve(true)
})
.catch(() => {
state.loading = false
reject(false)
})
});
}
function onCartCheck(list: Array<any>) {
// 暂时屏蔽功能
// const isWxjs_environment = uni.getStorageSync("isWxjs_environment") || false;
// if(isWxjs_environment){
// Toast.loading({
// message: '正在优化订单,暂时无法支付!',
// forbidClick: true,
// });
// return
// }
if (state.loading) return
if (list.length == 0) {
Toast('请选择商品')
return
}
state.loading = true
api.cartCheck({
cartIds: list.map((item: any) => item.cartId),
link: uni.getStorageSync('subdomain')
})
.then(() => {
let carts = []
list.forEach(item => {
carts.push({ cartId: item.cartId, count: item.productQty, skuId: item.skuId })
})
state.loading = false
uni.navigateTo({
url: '/pages/order/beforeconfirm?list=' + encodeURIComponent(JSON.stringify(carts)),
})
})
.catch(() => {
state.loading = false
})
}
function onSettle(list: Array<any>) {
if (state.loading) return
if (list.length == 0) {
state.sum = 0
return
}
state.loading = true
api.cartSettle({
cartIds: list.map((item: any) => item.cartId),
link: uni.getStorageSync('subdomain')
})
.then((data: any) => {
state.sum = data.settlePrice
state.loading = false
})
.catch(() => {
state.loading = false
})
}
function onDelete(list: Array<any>) {
if (state.loading) return
state.loading = true
api.cartRemove(list.map((item: any) => item.cartId))
.then(() => {
state.loading = false
cartList()
})
.catch(() => {
state.loading = false
})
}
function onCollect(list: Array<any>) {
if (state.loading) return
state.loading = true
api.productFav({
link: uni.getStorageSync('subdomain'),
skuIds: list.map((item: any) => item.skuId)
}).then((data: any) => {
state.loading = false
onDelete(list)
}).catch(() => {
state.loading = false
})
}
/**
* ---这个函数只计算checkBox的勾选状态---
* 有{bItem,gItem(变更勾选状态)}单个商品选择-(会影响那一个商品对应“一个品牌”、“全选”勾选状态>所以重新计算)
* 有{bItem(变更勾选状态)}单个品牌选择-(会影响“全选”勾选状态>所以重新计算)
* 有{}-编辑状态变更时-(重新计算“全部品牌”、“全选”勾选状态)
* */
function onCheck(bItem?: any, gItem?: any) {
if (state.cart.edit) {
nextTick(() => {
let all = true
// gItem单个商品选择选择时,重新计算bItem单个品牌勾选
if (gItem && bItem) {
if (bItem.select.length != bItem.list.length) {
bItem.all = false
} else {
bItem.all = true
}
} else if (!gItem && !bItem) {
state.cart.list.forEach((bItem: any) => {
// 是否单个品牌全选
if (bItem.select.length == bItem.list.length) {
bItem.all = true
} else {
bItem.all = false
}
})
}
// 重新计算全选按钮
all = !state.cart.list.find((_bItem: any) => {
return !_bItem.all
})
state.all = all
})
} else {
nextTick(() => {
let all = true
if (gItem && bItem) {
// gItem单个商品选择选择时,重新计算bItem单个品牌勾选
if (bItem.select.length != bItem.selectableNum) {
bItem.all = false
} else if (bItem.selectableNum == 0) {
bItem.all = false // 无意义,因为非编辑状态,它一直为false
} else {
bItem.all = true
}
} else if (!gItem && !bItem) {
state.cart.list.forEach((bItem: any) => {
// 是否单个品牌全选
if (bItem.select.length == bItem.selectableNum) {
bItem.all = true
} else {
bItem.all = false
}
})
}
// 重新计算全选按钮
all = !state.cart.list.find((_bItem: any) => {
// 因为selectableNum=0的品牌一直为false,跳过这些品牌
return _bItem.selectableNum != 0 && !_bItem.all
})
state.all = all
})
}
}
function onChangeGood(bItem: any, gItem: any) {
if (!state.switch.changeGood) false
console.log('ljong:onChangeGood', bItem, gItem)
}
function cartList() {
if (state.loading) return
state.loading = true
api.cartList({ link: uni.getStorageSync('subdomain') })
.then((data: any) => {
state.all = false
// 这个结构是为了之后准备的
state.cart.num = data.total
emit("setCartCount", state.cart.num)
state.cart.list = data.goods.map((item: any, index: number) => {
return {
all: false,
select: [],
selectableNum: (!item.saleable || 1 > item.stock || !item.isBrandAgent) ? 0 : 1, // 运算出可选数量
brand: {
name: '新版本-品牌名',
id: item.brandId
},
list: [{
leftDownIcons:item.leftDownIcons,
subScriptImgUrl:item.subScriptImgUrl,
discount:item.discount,
actPrice:item.actPrice,
cartId: item.cartId,
skuId: item.skuId,
title: item.title,
info: item.size,
mainImg: item.mainImg,
zoneIcon: item.zoneIcon,
deliveryTimeStr: '', // 新版本-备注
salePrice: item.salePrice,
stock: item.stock,
productPrice: item.productPrice,
productQty: item.productQty,
remark: '', // 新版本-备注
moq: 1, // B端没有限制
spuId: item.spuId,
saleable: item.saleable,
isBrandAgent: item.isBrandAgent
}]
}
})
}).finally(() => {
state.loading = false
state.refresh = false
})
}
function onGood(gItem: any) {
if (!gItem.saleable) {
Toast('商品已下架');
} else if (gItem.moq > gItem.stock) {
Toast('暂时无货');
} else if (!gItem.isBrandAgent) {
Toast('商家未代理该品牌');
} else {
goto(`/pages/good/detail?skuId=${gItem.skuId}&spuId=${gItem.spuId}`)
}
}
function ask(message: string, fn: Function, ...arg: any) {
if (selected.value.length == 0) {
Toast('请勾选商品')
return
}
Dialog.confirm({
message,
title: "提示"
}).then(() => {
fn(...arg)
})
}
function onStepperFocus(gItem: any) {
state.num.gItem = gItem
state.num.show = true
setTimeout(() => {
numField.value && numField.value.focus()
state.num.value = gItem.productQty
})
}
function onFocus(focus: string) {
state.focus = focus
}
function goBack() {
PageUtils.goBack()
}
function onNumChange() {
if (state.num.value === '' || state.num.value === undefined || state.num.value === null) {
Toast('请输入商品数量')
} else if (state.num.gItem.moq > state.num.value) {
Toast('不能小于起订量' + state.num.gItem.moq)
} else if (state.num.gItem.stock < state.num.value) {
Toast('不能大于库存' + state.num.gItem.stock)
} else {
if (state.loadingSon.num) return
state.loadingSon.num = true
const orignNum = state.num.gItem.productQty
state.num.gItem.productQty = state.num.value
beforeCartModify(Number(state.num.value), state.num.gItem).then(() => {
state.num.show = false
}).catch(() => {
// 改回去
state.num.gItem.productQty = orignNum
}).finally(() => {
state.loadingSon.num = false
})
}
}
</script>
<style lang="scss" scoped>
.sign {
position: absolute;
right: 1.8vw;
top: 0;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
.swipe_btn {
height: 100%;
width: 100rpx;
padding: 0;
font-size: 26rpx;
}
.top_right {
position: absolute;
right: 10px;
}
</style>
<style scoped>
.box {
padding: 0.225rem;
margin: 0.425rem 0;
box-shadow: 0.0625rem 0.3125rem 0.3125rem #ffffff;
text-align: center;
background: #f1f5f8;
border: 1px solid #d6d8d9;
/*解决iOS滚动条卡住的问题*/
-webkit-overflow-scrolling: touch;
}
.right_side {
position: fixed;
width: 0.55rem;
height: 100%;
right: 0;
top: 2.6rem;
z-index: 999;
}
.right_side .letter_slider {
position: absolute;
width: 1.8rem;
overflow: hidden;
right: 0;
top: 0;
background: #ffffff;
height: 87%;
overflow-y: auto;
z-index: 999;
}
.right_side .letter_slider_li {
height: 2rem;
line-height: 2rem;
text-align: center;
font-size: 1rem;
color: #858585;
}
.radio {
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid #dcdcdc;
padding-left: 1rem;
}
.radio:first-child {
padding-top: 1rem;
}
.radio:last-child {
margin-bottom: 0;
}
.last_box:last-child {
padding-bottom: 2.6rem;
}
</style>
<template>
<view style="background: #f1f5f8;height: 100vh">
<div v-show="!showHome">
<van-sticky>
<van-nav-bar
title="组合筛选"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
</van-sticky>
<div v-if="index==0">
<!--<h4 style="color: #539fe7;padding: 10px">#{{item.name}}</h4>-->
<!--<div style="background: #ffffff;">-->
<!--<van-row style="padding: 30rpx 0;margin: 0 1rem">-->
<!--<van-col span="7" class="box" v-for="son in item.menus"-->
<!--@click="choiceType(son)" style="margin-right: 10px">-->
<!--{{son.name}}-->
<!--</van-col>-->
<!--</van-row>-->
<!--</div>-->
<div v-for="item in list">
<div v-for="son in item.menus">
<p style="color: #539fe7;padding: 10px">#{{son.name}}</p>
<div style="background: #ffffff;">
<van-row style="margin-left: 12px">
<van-col style="margin-right: 5px" span="7" class="box" v-for="sun in son.menus" @click="choiceType(sun)">
<span style="margin-top: 5px;font-size: 14px;text-align: center">
{{sun.name}}</span>
</van-col>
</van-row>
</div>
</div>
</div>
</div>
<div v-else-if="index==5">
<van-radio-group v-for="item in list.letter" v-model="params.brandId">
<div :id="item" style="margin-top: -50px;padding-top: 50px;background: #ffff">
<van-divider><span style="color: #2b2b2b;font-size: 34rpx;font-weight: bold">{{item}}</span>
</van-divider>
<div style="background: #ffffff" class="last_box">
<van-radio :name="son.id" v-for="son in list.menu[item]" class="radio"
@click="chaneRadio(son.name)">
<img v-if="son.img"
v-lazy="son.img"
style="vertical-align: middle;margin: 0 10px"
width="55"
height="37"
:src="son.img"
/>
{{son.name}}
</van-radio>
</div>
</div>
<div class="right_side">
<div class="letter_slider">
<ul v-for="item in brankList">
<li class="letter_slider_li" @click="changeLi(item)">{{item}}</li>
</ul>
</div>
</div>
</van-radio-group>
</div>
<div v-else>
<div>
<h4 style="color: #539fe7;padding: 10px">#{{changeName(index.toString())}}</h4>
<div style="background: #ffffff;">
<van-row style="padding: 30rpx 0;margin: 0 1rem">
<van-col v-for="item in list" span="7" class="box"
@click="choiceType(index!=4?item.name:item)"
style="margin-right: 10px">
<span v-if="index!=4">{{item.name}}</span>
<span v-else>{{changeZq(item.name)}}</span>
</van-col>
</van-row>
</div>
</div>
</div>
</div>
<van-sticky>
<van-tabs v-model:active="active" color="#ff6600" line-width="206rpx"
title-active-color="#ff6600" v-show="showHome">
<van-tab title="分类检索">
<Combination />
</van-tab>
<van-tab title="组合筛选">
<div>
<van-cell :title="item.name" @click="getTypeList(index)" is-link :value="item.text"
v-for="(item,index) in typeList" />
<div style="margin: 10rpx 10rpx;padding-top: 50rpx">
<van-button color="#ff6600" size="large" @click="save">确认</van-button>
</div>
<div style="margin: 10rpx 10rpx">
<van-button size="large" @click="clearParams">清空</van-button>
</div>
</div>
</van-tab>
</van-tabs>
</van-sticky>
</view>
<tabbar :current="tabIndex" :list="listS" @tab-change="changeIndex" />
</template>
<script lang="ts">
import {Toast} from 'vant';
import api from "@/api";
import Combination from './model/combination.vue';
import {reactive, toRefs, onMounted, onRenderTriggered, watch} from 'vue';
import tabbar from "@/components/layout/tabbar.vue";
// 接口规范
interface thatProps {
showHome: Boolean,
active: Number,
}
export default {
//打印出上个页面传递的参数。
onLoad(option) {
if (option.good == 1) {
this.active = 1
}
},
components: {
Combination,tabbar
},
setup() {
const that: thatProps = reactive({
listS: [
{
text: "首页",
icon: "wap-home",
},
{
text: "分类",
icon: "bars",
},
{
text: "购物车",
icon: "shopping-cart",
badge: 0
},
{
text: "我的",
icon: "manager",
},
],
tabIndex:1,
dataList: {},
brankList: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
params: {
minSalePrice: '',
maxSalePrice: '',
material: '',
styleName: '',
space: '',
color: '',
zone: '',
brandId: '',
menuId: '',
},
showHome: true,
typeList: [
{
name: '类型',
text: ''
},
{name: '风格'},
{name: '材质'},
{name: '价格'},
{name: '权益'}, {name: '品牌'}, {name: '空间'}, {name: '色温'}],
list: [{name: '热门标签', list: ['吊灯1', '吊灯2', '吊灯3', '吊灯4', '吊灯5', '吊灯6', '吊灯', '吊灯', '吊灯']}],
active: 0,
index: 0,
changeIndex(index){
that.tabIndex = index
uni.navigateTo({
url: `/pages/index?index=${index}`,
});
},
chaneRadio(e) {
console.log(e);
that.typeList[that.index].text = e
that.showHome = true
},
clearParams() {
that.params = {
minSalePrice: '',
maxSalePrice: '',
material: '',
styleName: '',
space: '',
color: '',
zone: '',
search: ''
}
that.typeList.forEach(item => {
item.text = ''
})
},
changeZq: (name) => {
switch (name) {
case 'TTT':
return '淘淘淘专区'
case 'VIP':
return 'PLUS'
case 'XIAN_LIANG':
return '限量专区'
case 'XIAO_E':
return '小E专区'
case 'YAN_XUAN':
return '严选专区'
case 'YOU_XUAN':
return '优选专区'
case 'XIN_P':
return '新品专区'
case 'AUTONOM_HD':
return '活动专区'
}
},
changeName: (index) => {
switch (index) {
case '1':
return '风格'
case '2':
return '材质'
case '3':
return '价格'
case '4':
return '权益'
case '5':
return '品牌'
case '6':
return '空间'
case '7':
return '色温'
}
},
changeLi: (e) => {
let topH1 = document.getElementById(e)
topH1.scrollIntoView({
behavior: 'smooth',
})
},
// 非空校验
isEmpty(a) {
if (a === "") return true; //检验空字符串
if (a === "null") return true; //检验字符串类型的null
if (a === "undefined") return true; //检验字符串类型的 undefined
if (!a && a !== 0 && a !== "") return true; //检验 undefined 和 null
if (Array.prototype.isPrototypeOf(a) && a.length === 0) return true; //检验空数组
if (Object.prototype.isPrototypeOf(a) && Object.keys(a).length === 0) return true; //检验空对象
return false;
},
//组合筛选拼接url
dealUrlFormData(url, data) {
let params = []
Object.keys(data).forEach((key) => {
if (!that.isEmpty(data[key])) {
params.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
}
})
return url + '?' + params.join("&");
},
save: () => {
localStorage.setItem('isClassify', true)
uni.navigateTo({
url: that.dealUrlFormData('/pages/goodList/index', that.params),
});
},
choiceType: (type) => {
if (that.index == 0) {
that.params.menuId = type.id
that.typeList[that.index].text = type.name
that.showHome = true
return
}
if (that.index == 3) {
let minSalePrice = ''
let maxSalePrice = ''
if (type.indexOf('元以下') > -1) {
maxSalePrice = type.replace('元以下', '')
} else if (type.indexOf('以上') > -1) {
minSalePrice = type.replace('以上', '')
} else {
let str = type.replace('元', '')
minSalePrice = str.split('-')[0]
maxSalePrice = str.split('-')[1]
}
that.params['minSalePrice'] = minSalePrice
that.params['maxSalePrice'] = maxSalePrice
that.typeList[that.index].text = type
that.showHome = true
return
}
if (that.index == 4) {
that.params.zone = type.id
that.typeList[that.index].text = that.changeZq(type.name)
that.showHome = true
return
}
if (that.index == 1) that.params.styleName = type
if (that.index == 2) that.params.material = type
if (that.index == 5) that.params.brandId = type
if (that.index == 6) that.params.space = type
if (that.index == 7) that.params.color = type
that.typeList[that.index].text = type
that.showHome = true
},
getTypeList: (index) => {
that.showHome = false
that.index = index
switch (index) {
case 0:
return that.list = that.dataList.type
case 1:
return that.list = that.dataList.style
case 2:
return that.list = that.dataList.material
case 3:
return that.list = that.dataList.price
case 4:
that.list = []
for (let k in that.dataList.zone) {
that.dataList.zone[k].resource[0].id = that.dataList.zone[k].id
that.dataList.zone[k].resource[0].name = k
that.dataList.zone[k].resource[0].iconpath = 'https://img.edsmall.com/ewy/resource/image/61dc6af3-c2a4-4d5b-870b-d146430175b3.png'
that.list.push(that.dataList.zone[k].resource[0])
}
break;
case 5:
Toast.loading({
duration:300,
message: '加载中...',
forbidClick: true,
loadingType: 'spinner',
});
setTimeout(() => {
return that.list = that.dataList.brand
}, 200)
case 6:
return that.list = that.dataList.room
case 7:
return that.list = that.dataList.color
}
},
onClickLeft: () => {
that.showHome = true
},
getBanner: () => {
api.sortAndSearch({link: uni.getStorageSync("subdomain") }).then((res: any) => {
that.dataList = res
that.list = res.type
})
}
})
// watch
watch([() => that.index], (newValue, oldValue) => {
// console.log(newValue);
// console.log(oldValue);
})
onMounted(() => {
that.getBanner()
})
// watch
onRenderTriggered((event) => {
})
const refState = toRefs(that)
return {
...refState
}
}
}
</script>
<template>
<div class="container" style="background: #ffffff">
<div class="main">
<van-sidebar class="sidebar" v-model="categoryIndex" @change="onChange">
<van-sidebar-item v-for="(item,index) in categoryList" :key="index" :title="item.name" />
</van-sidebar>
<div class="right-content" >
<div v-for="item in list" style="margin:26rpx 10rpx" v-if="categoryIndex==0">
<van-divider><span
style="color: #2b2b2b;font-size: 34rpx;font-weight: bold">{{item.name}}</span>
</van-divider>
<div v-for="son in item.menus">
<p style="margin: 10px 0;font-size: 24rpx;font-weight: bold">{{son.name}}</p>
<van-grid :border="false" :column-num="3">
<van-grid-item v-for="sun in son.menus" @click="toGoodList(sun.id)">
<div>
<van-image :src="sun.icon" width="15vw" height="15vw"/>
<p style="margin-top: 5px;font-size: 12px;text-align: center">
{{sun.name}}</p>
</div>
</van-grid-item>
</van-grid>
</div>
</div>
<div v-if="categoryIndex!=0&&categoryIndex!=5">
<van-grid :border="true" :column-num="3">
<van-grid-item v-for="item in list">
<div @click="toGoodList(categoryIndex!=4?item.name:item.id)" style="text-align: center">
<van-image :src="categoryIndex==4?item.iconpath:item.img" />
<p style="margin-top: 5px;font-size: 12px;text-align: center;margin-bottom: 10px">
<span v-if="categoryIndex!=4">{{item.name}}</span>
<span v-else>{{changeName(item.name)}}</span>
</p>
</div>
</van-grid-item>
</van-grid>
</div>
<div v-if="categoryIndex==5">
<div v-for="item in list.letter" style="padding-right: 1rem">
<van-divider><span :id="item"
style="color: #2b2b2b;font-size: 34rpx;font-weight: bold">{{item}}</span>
</van-divider>
<van-grid :border="false" :column-num="3">
<van-grid-item v-for="son in list.menu[item]" @click="toGoodList(son.id)">
<div>
<van-image v-if="son.img" :src="son.img" width="15vw" height="15vw"
/>
<p style="margin-top: 5px;font-size: 12px;text-align: center">
{{son.name}}</p>
</div>
</van-grid-item>
</van-grid>
</div>
</div>
<div class="right_side" v-if="categoryIndex==5&&list.letter">
<div class="letter_slider">
<ul v-for="item in list.letter">
<li class="letter_slider_li" @click="changeLi(item)">{{item}}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Toast } from 'vant';
import api from "@/api";
import {reactive, toRefs, onMounted,getCurrentInstance} from 'vue';
export default {
setup() {
const that = reactive({
categoryList: [{name: "类型", type: 'menuId'}, {name: "风格", type: 'styleName'}, {
name: "材质",
type: 'material'
}, {name: "价格", type: 'money'}, {name: "权益", type: 'zone'}, {name: "品牌", type: 'brandId'}, {
name: "空间",
type: 'space'
}, {name: "色温", type: 'color'}],
list: [],
categoryIndex: 0,
dataList: {},
toGoodList: (search) => {
uni.navigateTo({
url: `/pages/goodList/index?${that.categoryList[that.categoryIndex].type}=${search}`,
});
},
changeLi: (e) => {
let topH1 = document.getElementById(e)
topH1.scrollIntoView({
behavior: 'smooth',
})
},
changeName: (name) => {
switch (name) {
case 'TTT':
return '淘淘淘专区'
break;
case 'VIP':
return 'PLUS'
break;
case 'XIAN_LIANG':
return '限量专区'
break;
case 'XIAO_E':
return '小E专区'
break;
case 'YAN_XUAN':
return '严选专区'
break;
case 'YOU_XUAN':
return '优选专区'
break;
case 'XIN_P':
return '新品专区'
break;
case 'AUTONOM_HD':
return '活动专区'
}
},
getBanner: () => {
api.sortAndSearch({link: uni.getStorageSync("subdomain") }).then((res: any) => {
that.dataList = res
that.list = res.type
})
},
onChange: (e) => {
switch (e) {
case 0:
that.list = []
setTimeout(() => {
that.list = that.dataList.type
}, 0)
return
break;
case 1:
return that.list = that.dataList.style
break;
case 2:
return that.list = that.dataList.material
break;
case 3:
return that.list = that.dataList.price
break;
case 4:
that.list = []
for (let k in that.dataList.zone) {
that.dataList.zone[k].resource[0].id = that.dataList.zone[k].id
that.dataList.zone[k].resource[0].name = k
that.list.push(that.dataList.zone[k].resource[0])
}
break;
case 5:
Toast.loading({
duration:300,
message: '加载中...',
forbidClick: true,
loadingType: 'spinner',
});
setTimeout(()=>{
return that.list = that.dataList.brand
},200)
break;
case 6:
return that.list = that.dataList.room
break;
case 7:
return that.list = that.dataList.color
break;
}
}
});
onMounted(() => {
that.getBanner()
let search = getCurrentInstance().$pageInstance.attrs.act
if(search){
that.categoryIndex = search
that.onChange(Number(that.categoryIndex))
}
})
const refState = toRefs(that)
return {
...refState
}
}
}
</script>
<style scoped>
.container{
-webkit-overflow-scrolling: touch;
}
.right_side {
position: fixed;
width: 0.45rem;
height: 100%;
right: 0;
top: 2.6rem;
z-index: 999;
}
.right_side .letter_slider {
position: absolute;
width: 1.6rem;
overflow: hidden;
right: 0;
top: 0;
height: 87%;
overflow-y: auto;
z-index: 9999;
}
.right_side .letter_slider_li {
height: 2rem;
line-height: 2rem;
text-align: center;
font-size: .9rem;
color: #858585;
}
.right-content {
flex: 1;
height: 88vh;
overflow-x: scroll;
padding-bottom: 10px;
}
.sidebar {
height: 88vh;
overflow-x: scroll;
-webkit-overflow-scrolling: touch;
}
.main {
display: flex;
}
</style>
\ No newline at end of file
<template>
<view class="text-center pd-b-px-55">
<van-sticky>
<van-nav-bar
title="店铺"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
<div class="shop_body">
<div style="display: flex;padding: 1.3rem">
<img style="width: 6rem;height: 3.6rem;border-radius: 3rem"
:src="state.brandInfo.imgPath" alt="">
<div class="shop_title">
<p>{{state.brandInfo.brandName}}</p>
<p style="font-size: 12px">粉丝:{{state.brandInfo.favCount}}</p>
</div>
</div>
<div class="about">
<span v-if="!state.brandInfo.isFav" @click="brandFav">+关注</span>
<span v-else @click="brandDel">已关注</span>
</div>
</div>
<van-tabs v-model:active="state.active" color="#ff6600" line-width="206rpx"
title-active-color="#ff6600" @click-tab="changeTab">
<van-tab title="全部商品">
</van-tab>
<van-tab title="新品">
</van-tab>
</van-tabs>
</van-sticky>
<div style="margin-top: .2rem"></div>
<van-list :loading="state.good.loading" :finished="state.good.finished" finished-text="没有更多了" offset="10"
@load="onGoodLoad">
<van-grid :center="false" :column-num="1">
<van-grid-item class="text-left" v-for="(item, index) in state.good.list" :key="index"
@click="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${item.spuId}`)">
<van-row>
<van-col span="7" style="position: relative">
<van-image class="self_center" width="200rpx" height="200rpx" lazy-load
:src="item.mainImg" />
<!--店铺活动角标-->
<div class="sign" v-if="item.subScriptImgUrl">
<img :src="item.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{item.discount}}</div>
</div>
<view style="position: absolute;left: 0;bottom: 0">
<van-image v-if="item.zoneIcon" width="60rpx" lazy-load :src="item.zoneIcon" />
<van-image v-if="item.isVideoIcon" class="pd-l-5" width="32rpx" height="32rpx" src="/static/img/play.png" />
</view>
</van-col>
<van-col span="16" offset="1">
<p class="text-s ellipsis line_over2 pd-t-10" style="height: 32px;margin-bottom:6px">
{{ item.title }}
</p>
<div style="line-height: 1.2rem" v-if="item.salePrice !== null">
<p class="text-ss">{{ item.size }}</p>
<p class="text-gray text-ss"></p>
<div v-if="item.actPrice">
<div >
<p class="text-gray text-ss " style="float: right;margin-right: 20px">
零售价¥
<text class="text-bold text-l">{{ item.productPrice }}</text>
</p>
<div class="text-gray text-ss line-through" >
优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</div>
</div>
</div>
<div v-if="!item.actPrice">
<p class="text-gray text-ss line-through">零售价¥{{ item.productPrice
}} </p>
<p class="text-orange text-ss" >
优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</p>
</div>
<p class="text-orange text-ss" v-if="item.actPrice">
活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</p>
</div>
<div style="line-height: 1.2rem" v-else>
<p class="text-ss">{{ item.size }}</p>
<p class="text-gray text-ss"></p>
<p class="text-gray text-ss line-through"
style="font-size: 15px;margin-top: 5px" v-if="item.actPrice">
零售价¥
<text class="text-bold text-l">{{ item.productPrice }}</text>
</p>
<p class="text-orange text-ss"
style="color: #ff8b3e;font-size: 15px;margin-top: 5px" v-else>
零售价¥
<text class="text-bold text-l">{{ item.productPrice }}</text>
</p>
<p class="text-orange text-ss"
style="color: #ff8b3e;font-size: 15px;margin-top: 5px" v-if="item.actPrice">
活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</p>
</div>
</van-col>
</van-row>
</van-grid-item>
</van-grid>
</van-list>
<view v-if="state.good.fail" class="text-ss text-gray pd-50" @click="failReset">请求失败,点击重试
<van-icon name="replay" />
</view>
<view class="fix_rb">
<van-image width="40px" class="btn toTop" :class="{ 'show': state.showToTop }"
src="/static/img/rb_top.png"
@tap="gotoTop" />
</view>
</view>
</template>
<script setup lang="ts">
import api from "@/api";
import {onMounted, reactive, getCurrentInstance} from 'vue';
import {onPageScroll} from '@dcloudio/uni-app'
const state = reactive({
showToTop: false,
brandInfo: {},
skuId: '',
params: {},
active: 0,
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any
}
})
onMounted(() => {
state.params.brandId = getCurrentInstance().ctx.$page.options.brandId || ''
getBrandOtherInfo()
});
function gotoTop() {
uni.pageScrollTo({
scrollTop: 0
});
}
onPageScroll(e => {
state.showToTop = e.scrollTop > 100
})
function brandDel() {
api.brandDel({
brandIds: [state.params.brandId],
}).then(res => {
getBrandOtherInfo()
})
}
function brandFav() {
api.brandFav({
brandId: state.params.brandId,
link: uni.getStorageSync('subdomain'),
}).then(res => {
getBrandOtherInfo()
})
}
function onClickLeft() {
history.back()
}
function goto(url: any) {
url && uni.navigateTo({url})
}
function changeTab(e) {
state.good.list = []
state.good.page = 0
if (e.name == 0) {
state.params['sortType'] = 0
}
if (e.name == 1) {
state.params['sortType'] = 1
}
onGoodLoad()
}
function getBrandOtherInfo() {
api.getBrandOtherInfo({
brandId: state.params.brandId
}).then(res => {
state.brandInfo = res
})
}
function onGoodLoad() {
if (state.good.loading || state.good.fail) return
state.good.loading = true
++state.good.page
api.getBrandList({
...state.params,
pageSize: 20,
pageNum: state.good.page,
link: uni.getStorageSync('subdomain'),
}).then((data: any) => {
if (!data||!data.hasNextPage){
state.good.finished = true
}
state.good.list.push(...data.list)
})
.catch(() => {
state.good.fail = true
})
.finally(() => {
state.good.loading = false
})
}
function failReset() {
state.good.page -= 1
state.good.finished = false
state.good.fail = false
onGoodLoad()
}
</script>
<style lang="scss" scoped>
.fix_rb {
position: fixed;
bottom: 75px;
right: 12px;
z-index: 6;
transition: all ease-in-out .2s;
.toTop {
opacity: 0;
&.show {
opacity: 1;
}
}
}
.shop_body {
background: url("/static/img/brandShop_bg.png") no-repeat center 0px;
background-position: center 0px;
background-size: cover;
height: 6rem;
/*background: linear-gradient(to right, #ff744b, #f9a281);*/
position: relative;
.shop_title {
text-align: left;
line-height: 1.6rem;
margin-left: 1rem;
margin-top: .1rem;
color: #ffffff;
font-weight: 500;
}
}
.about {
border-radius: 20px;
border: 1px solid #ff6800;
padding: 8px 20px;
position: absolute;
top: 36%;
right: 5%;
background: #fc6820;
font-size: 12px;
color: #ffffff;
}
:root {
--van-sidebar-selected-border-height: 30px;
}
.search_bar {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100vw;
z-index: 5;
}
.banner_top {
height: 43.5vw;
}
.banner_afterTop,
.banner_afterTap {
height: 20vw;
}
.block_title {
margin: 40 rpx auto 25 rpx auto;
width: 60vw;
}
</style>
<template>
<view>
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view class="top-center">{{ state.title }}</view>
<view class="top-right" @tap="goto('/pages/good/issue')">
<view class="text-m">服务条款</view>
</view>
</view>
</van-sticky>
<view>
<view class="justify-middle pd-h-25 mg-t-20 mg-h-20 mail_box" s>
<van-image class="mail_bg" fit="cover" src="/static/img/brand_bg.png"/>
<view class="mail_info justify-middle" style="margin-top: 10px;margin-bottom: 10px">
<view class="mail_logo">
<van-image fit="cover" width="120rpx" height="120rpx" round
:src="state.mail.logoUrl" />
</view>
<view class="mg-l-30 text-white text-xl">{{ state.mail.crocsAddress }}</view>
</view>
</view>
<van-cell-group inset class="mail_detail mg-h-20">
<van-cell class="pd-t-30" :title="state.mail.contactPhone" icon="phone-o">
<template #value>
<a v-if="state.mail.contactPhone" class="justify-end justify-middle"
:href="'tel:' + state.mail.contactPhone">
<view class="call_button btn" style="border-radius: 10rpx;padding: 0rpx 15rpx;border: 1rpx solid #FE521F">一键拨打</view>
</a>
</template>
</van-cell>
<van-cell class="pd-b-30" :title="state.mail.companyAddress" icon="location-o" />
<van-cell class="pd-b-30" value="查看" is-link @click="state.value='',state.showImg=true">
<template #title>
<img src="../../static/img/ico1.png" alt="" style="width: 18px;vertical-align: sub">
证照信息
</template>
</van-cell>
</van-cell-group>
</view>
<van-cell-group class="mg-h-0 mg-t-25" inset>
<van-cell :border="false">
<template #title>
<view class="text-l">客服列表</view>
</template>
</van-cell>
<van-divider class="mg-v-0" />
<div style="position: relative">
<van-cell v-for="item in state.service" class="justify-middle">
<template #title>
<view class="flex">
<van-image class="pd-r-20" fit="cover" width="24px" height="24px" round
src="/static/img/contactor.png" />
<view>
<view class="text-l">{{ item.serviceName }}</view>
<view class="text-s">
<view v-if="item.serviceMobile" class="justify-middle">
电话:{{ item.serviceMobile }}
<a :href="'tel:' + item.serviceMobile"
class="justify-middle pd-l-20">
<view class="call_button btn" style="border-radius: 10rpx;padding: 0rpx 15rpx;border: 1rpx solid #FE521F">一键拨打</view>
</a>
</view>
<view v-if="item.serviceWechat">微信:{{ item.serviceWechat }}</view>
<view v-if="item.qq">QQ&nbsp;&nbsp;{{ item.qq }}</view>
</view>
</view>
</view>
</template>
<template #right-icon>
<van-image v-if="item.wechatQRUrl" fit="cover" height="120rpx" width="120rpx"
class="qrcode"
:src="item.wechatQRUrl"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="120rpx" @tap="onImagePreview(item.wechatQRUrl)" />
</template>
</van-cell>
<view v-if="state.service.length == 0" class="justify-center" style="height:400px">
<van-image width="160px" class="mail_bg" fit="cover" src="/static/img/no_contact.png" />
<view class="text-m text-darkGray pd-50">暂无任何客服信息喔~</view>
<div style="text-align: center;width: 100%;margin-top: 30px">
<p><img style="width: 20px;height: 20px;vertical-align: sub;margin-right: 10px" src="../../static/favicon.ico" alt=""><span style="color: #666666">E淘提供技术支持</span></p>
<p @click="gotoU" style="margin-top: 20px"><span style="color: #666666">资质与规则</span></p>
</div>
</view>
<div v-if="state.service.length >0" style="text-align: center;width: 100%;margin: 30px auto">
<p><img style="width: 20px;height: 20px;vertical-align: sub;margin-right: 10px" src="../../static/favicon.ico" alt=""><span style="color: #666666">E淘提供技术支持</span></p>
<p @click="gotoU" style="margin-top: 20px"><span style="color: #666666">资质与规则</span></p>
</div>
</div>
</van-cell-group>
<van-dialog :show="state.showImg" title="请输入验证码查看证照信息" show-cancel-button @confirm="confirm"
@cancel="state.showImg=false">
<div style="text-align: center">
<div class="ValidCode disabled-select"
style="background: #fafafa;margin: 15px auto;width: 200px;height: 34px">
<span v-for="(item, index) in state.codeList" :key="index" :style="getStyle(item)">{{item.code}}</span>
</div>
<p style="font-size: 14px;color: #666666;margin: 10px auto" @click="refreshCode">看不清?点击图片刷新</p>
<van-field v-model="state.value" placeholder="请输入验证码"
style="width: 70%;border-bottom: 2px solid #fe9576;margin: 0 auto" />
</div>
</van-dialog>
<to-top />
</view>
</template>
<script setup lang="ts">
import api from '@/api';
import {onBeforeMount, reactive,} from 'vue';
import toTop from '@/components/tool/toTop.vue';
import {PageUtils} from '@/utils/utils';
import {ImagePreview, Toast } from 'vant';
import {onPageScroll} from '@dcloudio/uni-app'
onPageScroll(e => {
}) // uniapp的Bug,这句话不要去掉,否则to-top不生效
const state = reactive({
value: '',
codeList: [],
showImg: false,
title: PageUtils.getTitle(),
service: [] as any,
mail: {} as any
})
onBeforeMount(() => {
traDeManage()
createdCode()
})
function gotoU() {
uni.redirectTo({
url: "/pages/my/technicalSupport?name=contact",
});
}
function confirm() {
let str = ''
if(state.codeList.length>0){
state.codeList.forEach(item=>{
str+=item.code
})
}
if(str.toLowerCase()==state.value.toLowerCase()){
uni.navigateTo({
url: "/pages/my/certificate",
});
}else {
Toast.fail('请输入正确的验证码');
}
}
function refreshCode() {
createdCode()
}
function createdCode() {
const len = 4
const codeList = []
const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789'
const charsLen = chars.length
// 生成
for (let i = 0; i < len; i++) {
const rgb = [Math.round(Math.random() * 220), Math.round(Math.random() * 240), Math.round(Math.random() * 200)]
codeList.push({
code: chars.charAt(Math.floor(Math.random() * charsLen)),
color: `rgb(${rgb})`,
fontSize: `2${[Math.floor(Math.random() * 10)]}px`,
padding: `${[Math.floor(Math.random() * 10)]}px`,
transform: `rotate(${Math.floor(Math.random() * 90) - Math.floor(Math.random() * 90)}deg)`
})
}
// 指向
state.codeList = codeList
}
function getStyle(data) {
return `color: ${data.color}; font-size: ${data.fontSize}; padding: ${data.padding}; transform: ${data.transform}`
}
function traDeManage() {
api.traDeManage({domain: uni.getStorageSync('subdomain')})
.then((data: any) => {
state.service = data.serviceList
state.mail = data.brandMessage
})
}
function onImagePreview(url: string) {
ImagePreview({images: [url], closeable: true})
}
function goBack() {
uni.navigateTo({
url: "/pages/index",
});
}
function goto(url: any) {
url && uni.navigateTo({url})
}
</script>
<style lang="scss" scoped>
/*.ValidCode {*/
/*display: flex;*/
/*justify-content: center;*/
/*align-items: center;*/
/*cursor: pointer;*/
/*span {*/
/*display: inline-block;*/
/*}*/
/*}*/
.mail_box {
position: relative;
height: 185 rpx;
width: 100%;
.mail_bg {
position: absolute;
left: 0;
top: 0;
right: 0;
width: calc(100vw - 40rpx);
height: 260 rpx;
}
.mail_info {
z-index: 1;
.mail_logo {
width: 118 rpx;
height: 118 rpx;
border: 4 rpx solid #fff;
position: relative;
border-radius: 50%;
&::before {
content: "";
position: absolute;
border-radius: 50%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(180deg, #ffe5cd 0%, #ffb399 100%);
}
}
}
.mail_detail {
width: 100%;
}
}
.call_button {
border-radius: 10 rpx;
padding: 0 rpx 15 rpx;
border: 1 rpx solid #FE521F;
color: #FE521F;
font-size: 12px;
line-height: 20px;
}
.qrcode {
border: 1 rpx solid #DDDDDD;
border-radius: 10 rpx;
padding: 10 rpx;
}
</style>
<template>
<view class="pd-b-px-55">
<van-sticky>
<view class="top-bar top_bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<van-tabs class="top_tab" v-model:active="state.tab.active" @click-tab="scrollTo" animated>
<van-tab v-for="item in state.tab.list" :title="item.name" />
</van-tabs>
<van-icon v-if="!isAPP" class="top-right" name="share-o" @tap="tapchange" />
</view>
</van-sticky>
<van-swipe lazy-render id="good" class="banner_top"
:class="{ 'video': video, 'video_black': video && state.banner.activeTop == 0 }" ref="topBanner"
@change="onTopBannerChange">
<van-swipe-item v-if="video">
<video style="height: 100%;width: 100vw;" objet-fit="contain" :poster="skuData?.mainImg || ''"
:src="video"
controls :enable-progress-gesture="false" />
</van-swipe-item>
<van-swipe-item v-if="skuData?.mainImg" @tap="onImagePreview(skuData.mainImg)" class="good_img">
<van-image height="100%" width="100vw" fit="contain"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="100vw"
:src="skuData.mainImg" />
<!--详情页活动角标-->
<div class="sign" v-if="skuData.subScriptImgUrl">
<img :src="skuData.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{skuData.discount}}</div>
</div>
<van-image v-if="zoneIcon[0]" class="zone_icon" style="left: 10rpx" width="60rpx" :src="zoneIcon[0]" />
<van-image v-if="zoneIcon[1]" class="zone_icon" style="left: 80rpx" width="60rpx"
:src="zoneIcon[1]" />
<!--<span v-if="skuData.coTip==1" class="zone_icon host_tip" style="left: 90rpx;">热销</span>-->
</van-swipe-item>
<template v-if="video" #indicator="{ active, total }">
<view class="justify-center">
<view class="flex">
<view class="indicator" :class="{ 'active': active == 0 }"
@tap="onIndicatorClick(0)">
<van-icon name="play" />
视频
</view>
<view class="indicator" :class="{ 'active': active == 1 }"
@tap="onIndicatorClick(1)">图片
</view>
</view>
</view>
</template>
</van-swipe>
<van-skeleton class="bg-white pd-v-20" title :row="2" :loading="!state.inited">
<template v-if="state.switch.newView">
<template v-if="skuData">
<view class="bg-white pd-20">
<template v-if="skuData.salePrice !== null">
<view class="text-orange text-ss">优惠价¥
<text class="text-bold text-xl">{{ skuData.salePrice }}</text>
</view>
<view class="text-gray text-ss">零售价¥{{ skuData.productPrice }}</view>
</template>
<template v-else>
<view class="text-orange text-ss">零售价¥
<text class="text-bold text-xl">{{ skuData.productPrice }}</text>
</view>
</template>
<view class="flex justify-middle">
<van-image v-if="zoneIcon" class="pd-v-10" width="60rpx" :src="zoneIcon[0]" />
<text v-if="state.switch.stock" class="text-ss text-yellow pd-l-50">
库存:{{ skuData.stock }}
</text>
<text v-if="state.switch.delivery" class="text-ss text-yellow pd-l-50">
交货期:{{ Enum.get("delivery", state.data.deliveryTime) }}
</text>
</view>
<view class="text-l text-bold text-black">{{ skuData.title }}</view>
</view>
<van-cell-group class="mg-v-25" inset>
<van-cell v-if="state.switch.changeGood" is-link>
<template #title>
<text class="text-gray">已选</text>
<text class="text-black pd-l-20">{{ skuData.model || "未选择" }}</text>
</template>
<template #right-icon>
<van-icon class="justify-middle" name="ellipsis" />
</template>
</van-cell>
<van-cell v-if="state.switch.size" is-link
@tap="goto(state.skuId ? `/pages/good/size?skuId=` + state.skuId : undefined)">
<template #title>
<text class="text-gray">规格</text>
<text class="text-black pd-l-20">
{{
`W${skuData.specWidth}*H${skuData.specHeight}*D${skuData.specLength}`
}}
</text>
</template>
<template #right-icon>
<van-icon class="justify-middle" name="ellipsis" />
</template>
</van-cell>
<van-cell :is-link="!!state.skuId" @tap="onSkuInfo">
<template #title>
<view class="justify-middle">
<view class="text-gray">参数</view>
<view class="text-black pd-l-20 ellipsis block"
style="width: 510rpx">{{ skuInfo }}
</view>
</view>
</template>
<template #right-icon>
<van-icon class="justify-middle" name="ellipsis" />
</template>
</van-cell>
</van-cell-group>
</template>
<van-cell-group v-if="state.brand" class="mg-v-25" inset>
<van-cell is-link>
<template #title>
<view class="justify-middle">
<van-image class="pd-r-15" width="100rpx" round fit="contain"
:src="state.brand.brandLogo" />
<view>
<view class="justify-middle text-m text-bold text-black">
<van-image class="pd-r-10" width="14px" height="15px"
v-if="state.data.etaoProductVip"
src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/vip_icon.png?time=1" />
{{ state.brand.brandName }}
</view>
<view class="text-gray text-ss pd-t-10">在售商品{{
state.brand.productCount }}
</view>
</view>
</view>
</template>
<template #right-icon>
<view class="justify-middle text-orange text-ss">
进入品牌
<van-icon name="arrow" />
</view>
</template>
</van-cell>
<!-- 这个是旧版本的规格选择 -->
<van-cell v-if="state.data.skuJson && state.data.skuJson.length > 1">
<template #title>
<view class="flex scrollx_container">
<template v-for="item in state.data.skuJson">
<view v-if="item.skuId != state.skuId" class="text-center pd-r-40"
@tap="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${state.data.spuId}`)">
<van-image height="18vw" width="18vw" fit="cover" lazy-load
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="18vw"
:src="item.mainImg" />
<view class="text-orange text-ss mg-l-10-m mg-t-10-m">
{{ item.salePrice !== null ? item.salePrice :
item.productPrice }}
</view>
</view>
</template>
</view>
</template>
</van-cell>
</van-cell-group>
</template>
<template v-else-if="skuData">
<view class="bg-white pd-px-10">
<view class="text-l text-black">{{ skuData.title }}</view>
<view class="flex" v-if="skuData.salePrice">
<view>
<view class="text-blue">生产周期:{{ Enum.get("delivery", state.data.deliveryTime)
}}
</view>
<view class="text-gray line-through" v-if="skuData.actPrice">优惠价:¥{{
skuData.salePrice }}
</view>
<view class="text-orange" v-else>优惠价:¥{{ skuData.salePrice }}</view>
<view class="text-orange" v-if="skuData.actPrice">活动价:¥{{ skuData.actPrice
}}
</view>
</view>
<view class="pd-l-30">
<view class="pd-l-30">工厂库存:{{ skuData.stock }}</view>
<view class="pd-l-30 text-gray " v-if="skuData.actPrice">零售价:¥{{
skuData.productPrice }}
</view>
<view class="pd-l-30 text-gray line-through" v-else>零售价:¥{{
skuData.productPrice }}
</view>
</view>
</view>
<view class="flex" v-else>
<view>
<view>生产周期:{{ Enum.get("delivery", state.data.deliveryTime) }}</view>
<view v-if="skuData.actPrice">
<view class="text-gray line-through">零售价:¥{{ skuData.productPrice }}
</view>
<view class="text-orange">活动价:¥{{ skuData.actPrice }}</view>
</view>
<view v-else>
<view class="text-orange">零售价:¥{{ skuData.productPrice }}</view>
</view>
</view>
<view class="pd-l-30">
<view class="pd-l-30">工厂库存:{{ state.data.stock }}</view>
</view>
</view>
</view>
<van-cell-group v-if="state.brand" class="mg-v-px-10">
<van-cell>
<template #title>
<view class="justify-middle">
<van-image class="br" width="100px" height="70px" fit="cover"
:src="state.brand.brandLogo"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="70px" />
<view class="pd-l-20">
<view class="justify-middle text-m text-bold text-black">
<van-image class="pd-r-10" width="14px" height="15px"
fit="contain" v-if="state.data.etaoProductVip"
src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/vip_icon.png?time=1" />
{{ state.brand.brandName }}
</view>
<view class="text-gray text-ss">商品数:{{ state.brand.productCount
}}
</view>
<view class="flex">
<van-button plain class="detail_btn" size="mini"
@tap="goBrand(state.brand.brandId)">查看品牌
</van-button>
<van-button plain class="detail_btn" size="mini"
:type="state.brand.isFav ? 'primary' : 'default'"
style="margin-left: 20rpx"
@tap="check(onCollectBrand)">
{{ state.brand.isFav ? "已收藏品牌" : "收藏品牌" }}
</van-button>
</view>
</view>
</view>
</template>
</van-cell>
</van-cell-group>
<van-collapse class="no-padding mg-b-25" v-model="state.collapse.openList">
<van-collapse-item name="1">
<template #title>
<view class="good_anchor">产品参数</view>
</template>
<van-cell-group>
<van-cell v-if="skuData.lightSourceCount || skuData.lightSourceCount == 0">
<template #title>
<text class="inline-block skuInfo_label">光源:</text>
<text class="text-gray">{{ skuData.lightSourceCount }}</text>
</template>
</van-cell>
<van-cell v-for="item in sizeList" is-link
@tap="goto(state.skuId ? `/pages/good/size?skuId=` + state.skuId : undefined)">
<template #title>
<text class="inline-block skuInfo_label">{{ item.name }}(mm)
</text>
<text class="text-gray">{{ item.value }}</text>
</template>
<template #right-icon>
<van-icon class="justify-middle" name="ellipsis" />
</template>
</van-cell>
<template v-for="item in state.data.labelJson">
<van-cell v-if="item.labelParams.length > 0">
<template #title>
<view class="flex">
<view class="skuInfo_label">{{ item.name }}</view>
<view class="skuInfo_info text-gray">
{{ item.labelParams.map((label: any) =>
label.name).join(",") }}
</view>
</view>
</template>
</van-cell>
</template>
</van-cell-group>
</van-collapse-item>
</van-collapse>
</template>
<view id="detail">
<van-divider v-if="state.switch.newView" :style="{ borderColor: '#8c8c8c', padding: '0 30vw' }">
商品详情
</van-divider>
<view v-else class="good_anchor">产品详情</view>
</view>
<!-- 下面的图片不能用lazy,计算不出高度 -->
<van-image v-for="item in detailImgs"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="100vw" width="100vw" :src="item" />
<van-image v-if="skuData.salePrice" icon-size="100vw" width="100vw"
src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/price_tip0.png" />
<van-image v-else icon-size="100vw" width="100vw"
src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/price_tip1.png" />
<template v-if="!state.switch.newView">
<view id="otherSku" class="good_anchor">同系列推荐</view>
<van-list v-if="state.data.skuJson" class="mg-t-15" :finished="true" finished-text="已经到底了哦~">
<van-grid :center="false" :column-num="2" :gutter="7">
<template v-for="item in state.data.skuJson">
<van-grid-item v-if="item.skuId != state.skuId" class="text-left"
@tap="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${state.data.spuId}`)">
<van-image class="self_center" width="30vw" height="30vw" lazy-load
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="30vw"
:src="item.mainImg" />
<view class="mg-t-30-m">
<van-image v-if="zoneIcon" width="60rpx" height="32rpx"
:src="zoneIcon[0]" />
<van-image v-if="item.isVideoIcon" class="mg-l-5" width="32rpx"
height="32rpx"
src="/static/img/play.png" />
</view>
<text class="text-s ellipsis line_over2 pd-t-10"
style="width: 320rpx;height: 32px;margin-bottom:6px">
{{ item.title }}
</text>
<text class="text-ss"
v-if="item.specHeight || item.specLength || item.specWidth">
{{ `W(宽):${item.specWidth} H(高):${item.specHeight}
D(深):${item.specLength}` }}
</text>
<text class="text-gray text-ss"></text>
<template v-if="item.salePrice !== null">
<view class="text-gray text-ss line-through">零售价¥{{
item.productPrice }}
</view>
<view class="text-orange text-ss">优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</view>
</template>
<template v-else>
<view class="text-orange text-ss">零售价¥
<text class="text-bold text-l">{{ item.productPrice }}
</text>
</view>
</template>
</van-grid-item>
</template>
</van-grid>
</van-list>
</template>
</van-skeleton>
<van-action-bar class="sh-t">
<van-action-bar-icon v-if="state.skuId" icon="down" text="下载"
@tap="goto(`/pages/good/download?skuId=` + state.skuId)" />
<van-action-bar-icon v-if="state.brand" icon="chat-o" text="客服" @tap="goto(`/pages/good/contact`)" />
<van-action-bar-icon :color="state.data.isFav ? '#f60' : ''"
:icon="state.data.isFav ? 'like' : 'like-o'"
:text="state.data.isFav ? '已收藏' : '收藏'" @tap="check(onCollect)" />
<van-action-bar-icon icon="cart-o" text="购物车" @tap="goto('/?index=2')" :badge="state.badge || ''" />
<van-action-bar-button :disabled="!skuData" type="warning" text="加入购物车" @tap="check(cartAdd)" />
</van-action-bar>
<van-popup v-model:show="state.popup.skuInfo.show" round position="bottom" teleport="#app" closeable>
<view class="text-bold text-center pd-v-30">产品参数</view>
<van-cell-group>
<van-cell v-if="skuData.lightSourceCount || skuData.lightSourceCount == 0">
<template #title>
<text class="inline-block skuInfo_label">光源:</text>
<text class="text-gray">{{ skuData.lightSourceCount }}</text>
</template>
</van-cell>
<template v-for="item in state.data.labelJson">
<van-cell v-if="item.labelParams.length > 0">
<template #title>
<view class="flex">
<view class="skuInfo_label">{{ item.name }}</view>
<view class="skuInfo_info text-gray">
{{ item.labelParams.map((label: any) => label.name).join(",") }}
</view>
</view>
</template>
</van-cell>
</template>
</van-cell-group>
</van-popup>
<to-top :showNav="true" />
<van-overlay v-if="state.wx.isWX" :show="state.share.show" @tap="state.share.show = false"
style="z-index: 7">
<van-image class="pd-40" style="float: right" width="120px" src="/static/img/share_tip.png" />
</van-overlay>
<van-share-sheet v-else v-model:show="state.share.show" title="立即分享" :options="state.share.options"
@select="onShareSelect" />
<van-popup v-model:show="state.share.showQRCode">
<view class="bg-white text-center pd-40" style="width: 300px">
<view class="text-bold">{{ skuData.title }}</view>
<van-image class="pd-v-20" width="250px" height="250px" :src="state.share.qrcode"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="250px" />
<view class="text-left mg-l-px-10">
1.打开微信,点击扫一扫即可分享到朋友圈<br />
2.长按进行保存<br />
3.截屏保存该页面进行分享<br />
</view>
</view>
</van-popup>
</view>
</template>
<script setup lang="ts">
import {Enum, PageUtils, WXUtils} from '@/utils/utils'
import {computed, nextTick, onBeforeMount, reactive, ref, onUnmounted,onMounted} from 'vue';
import {onPageScroll, onShow, onHide} from '@dcloudio/uni-app'
import {SwipeInstance, Toast} from 'vant';
import toTop from '@/components/tool/toTop.vue';
import api from '@/api';
import {ImagePreview} from 'vant';
import {Dialog} from "vant";
// @ts-ignore
import QRCode from 'qrcode'
const state = reactive({
skuId: '',
spuId: '',
tab: {
active: 0,
list: [
{name: '商品', target: '#good', top: 0},
{name: '详情', target: '#detail', top: 0},
{name: '推荐', target: '#otherSku', top: 0},
]
},
banner: {
activeTop: 0
},
data: {} as any,
brand: undefined as any,
popup: {
skuInfo: {
show: false
}
},
loading: {
cartAdd: false,
productFav: false,
brandFav: false,
qrcode: false
},
collapse: {
openList: ['1']
},
share: {
show: false,
options: [{name: '微信', icon: 'wechat'}],
showQRCode: false,
qrcode: ''
},
wx: {
isWX: false,
inited: false
},
badge: 0,
switch: {
changeGood: false, // 修改规格
// ----旧----
stock: true, // 库存
delivery: true, // 交货期
size: true, // 规格
// ----新UI----
newView: false,
},
test: false, // jssdk-debug
inited: false
})
const topBanner = ref<SwipeInstance>();
const video = computed(() => {
return state.data?.imgsJson?.video
})
const zoneIcon = computed(() => {
if (!state.data?.dailyIcons || state.data.dailyIcons.length == 0) return ''
return state.data?.dailyIcons
})
const detailImgs = computed(() => {
if (!state.data?.imgsJson?.detailImgs) return []
return state.data?.imgsJson?.detailImgs.split(',')
})
const skuData = computed(() => {
if (!state.data?.skuJson) return ''
const item = state.data.skuJson.find((item: any) => item.skuId == state.skuId)
return item
})
const sizeList = computed(() => {
if (!skuData.value) return []
return [
{name: '宽', value: skuData.value.specWidth},
{name: '高', value: skuData.value.specHeight},
{name: '深', value: skuData.value.specLength},
]
})
const skuInfo = computed(() => {
let info = ''
if (skuData.value) {
const {lightSourceCount}: any = skuData.value
if (lightSourceCount || lightSourceCount === 0) info += '光源:' + lightSourceCount + ';'
}
if (state.data.labelJson) {
state.data.labelJson.forEach((item: any) => {
if (item.labelParams.length > 0) {
info += item.name + ':'
info += item.labelParams.map((label: any) => label.name).join(',')
info += ';'
}
})
}
return info
})
onBeforeMount(() => {
let subdomain = getUrl(window.location.href)
if (subdomain.name) {
uni.setStorageSync('subdomain', subdomain.name)
}
const query: any = PageUtils.getCurQuery()
state.skuId = query.skuId
state.spuId = query.spuId
state.test = (query.test == 88888888)
if (!state.skuId) {
uni.navigateTo({
url: '/pages/index'
})
return
}
getProduct()
getIndexEtaomall()
// initWX()
})
onShow(() => {
const {token} = uni.getStorageSync("user") || {};
if (token) {
cartCount()
}
console.log();
if (state.skuId) {
getProduct()
}
})
const isAPP = ref(false)
onMounted(() => {
window._wx.miniProgram.getEnv((res) => {
if (res.miniprogram) {
isAPP.value=true
} else {
isAPP.value=false
}
});
});
onUnmounted(() => {
window._wx.miniProgram.postMessage({data: {}});
})
onHide(() => {
window._wx.miniProgram.postMessage({data: {}});
});
onPageScroll(e => {
let active = 0
state.tab.list.forEach((item, index) => {
if (item.top < e.scrollTop + 50) active = index
})
state.tab.active = active
})
function scrollTo(e: any) {
uni.pageScrollTo({
scrollTop: state.tab.list[e.name].top,
complete: function () {
setTimeout(() => {
state.tab.active = e.name
}, 600)
}
});
}
function onTopBannerChange(acitve: number) {
state.banner.activeTop = acitve
}
function onIndicatorClick(active: number) {
topBanner.value?.swipeTo(active)
}
function getProduct() {
api.getProduct(state.skuId, {domain: uni.getStorageSync('subdomain')}).then((data: any) => {
console.log(data);
state.data = data
if (data) {
window._wx.miniProgram.postMessage({data: {imgUrl: data.skuJson[0].mainImg, proName: data.labelTitle}});
}
brandInfo()
})
}
function brandInfo() {
api.brandInfo({brandId: state.data.brandId}).then((data: any) => {
state.brand = data
state.inited = true
getAnchor()
})
}
function goto(url: any) {
url && uni.navigateTo({url})
}
function onSkuInfo() {
state.popup.skuInfo.show = true
}
function onImagePreview(url: string) {
ImagePreview({images: [url], closeable: true})
}
function cartAdd() {
if (state.loading.cartAdd) return
state.loading.cartAdd = true
api.cartAdd({
skuId: state.skuId,
link: uni.getStorageSync('subdomain'),
productQty: 1, // B端去除起订量限制 skuData.value.moq
}).then(() => {
cartCount(true)
}).finally(() => {
state.loading.cartAdd = false
})
}
function onCollect() {
if (!state.skuId) return
if (state.data.isFav) {
Dialog.confirm({
message: '确认取消收藏',
title: "提示",
cancelButtonText: '取消'
}).then(() => {
productDel(state.skuId)
});
} else productFav(state.skuId)
}
function onCollectBrand() {
if (state.brand.isFav) {
Dialog.confirm({
message: '确认取消收藏品牌',
title: "提示",
cancelButtonText: '取消'
}).then(() => {
brandDel(state.brand.brandId)
});
} else brandFav(state.brand.brandId)
}
function productFav(id: string) {
if (state.loading.productFav) return
state.loading.productFav = true
api.productFav({
link: uni.getStorageSync('subdomain'),
skuIds: [id]
}).then((data: any) => {
state.data.isFav = true
}).finally(() => {
state.loading.productFav = false
})
}
function productDel(id: string) {
if (state.loading.productFav) return
state.loading.productFav = true
api.productDel({
skuIds: [id]
}).then((data: any) => {
state.data.isFav = false
}).finally(() => {
state.loading.productFav = false
})
}
function brandFav(id: string) {
if (state.loading.brandFav) return
state.loading.brandFav = true
api.brandFav({
link: uni.getStorageSync('subdomain'),
brandId: id
}).then((data: any) => {
state.brand.isFav = true
}).finally(() => {
state.loading.brandFav = false
})
}
function brandDel(id: string) {
if (state.loading.brandFav) return
state.loading.brandFav = true
api.brandDel({
brandIds: [id]
}).then((data: any) => {
state.brand.isFav = false
}).finally(() => {
state.loading.brandFav = false
})
}
function goBrand(id: string) {
uni.navigateTo({
url: `/pages/good/brandShop?brandId=${id}`,
})
}
function goBack() {
PageUtils.goBack()
}
function onShare() {
state.share.show = true
}
function getAnchor() {
setTimeout(() => {
state.tab.list.forEach(item => {
uni.createSelectorQuery().select(item.target).boundingClientRect(data => {
item.top = data?.top || 0
}).exec();
})
getAnchorCircle(10)
}, 200)
}
// 获取高度直到,不变为止
// -很奇葩对吧,我不知道其他方法。
// -因为滚动的时候,也要跟着动态变,所以必须预先知道高度。
//(如果监听滚动事件?可以,但是触发次数肯定比我多)
// (如果监听容器高度?可以,ResizeObserver新特性,兼容性不行)
function getAnchorCircle(heart: number) {
if (heart == 0) return
setTimeout(() => {
var firstTop = 0;
var rendering = true
state.tab.list.forEach((item: any, index: number) => {
uni.createSelectorQuery().select(item.target).boundingClientRect(data => {
if (index == 0) {
firstTop = data?.top || 0
return
}
const calcTop = (data?.top || 0) - firstTop
if (index == state.tab.list.length - 1 && calcTop == item.top) {
rendering = false
}
item.top = (data?.top || 0) - firstTop
}).exec();
})
if (rendering) {
getAnchorCircle(10)
} else {
getAnchorCircle(heart - 1)
}
}, 500)
}
function check(fn: Function) {
const {token} = uni.getStorageSync("user") || {};
if (token) {
fn()
} else {
Dialog.confirm({
message: '您尚未登录,请前往登录',
title: "提示",
cancelButtonText: '取消'
}).then(() => {
uni.reLaunch({
url: '/pages/login/login'
})
});
}
}
function initWX() {
// @ts-ignore
const url = window.location.href;
const wx = window._wx;
const wxConfig = {
debug: false, // 上生产,时设置成false
appId: "wx6165c6cc754deeba",
timestamp: '1690942632',
nonceStr: '06904d46-440a-4e61-926b-b589bd9d1232',
signature: 'dfc7b27e6b656e412b78b827a35633beeeb0cfef',
jsApiList: ["updateAppMessageShareData"],
};
wx.config(wxConfig);
wx.ready(function () {
wx.updateAppMessageShareData({
title: '商品详情', // 分享标题
desc: '默认秒i书', // 分享描述
link: url, // 分享链接
imgUrl: 'https://img.edsmall.com/ROOT/ETao/gl/busiImage/feaa15f0-5066-47c7-8508-429fa5b80965.png', // 分享图标
success: function (res) {
// console.log("分享成功返回的信息为:", res);;
}
})
});
wx.error(function (data: any) {
});
// if (uni.getStorageSync('isWX')) {
// state.wx.isWX = true
// WXUtils.initWXConfig(state.test).then((data: any) => {
// // 失败了也无所谓,就只是没分享信息而已
// state.wx.inited = true
// const wx = window._wx
// const mail = uni.getStorageSync('mail') || {}
// const shareConfig = {
// title: 'E淘商城-' + mail.mallName,
// desc: skuData.value?.title,
// link: url,
// imgUrl: skuData.value?.mainImg
// }
// wx.updateAppMessageShareData(shareConfig)
// wx.updateTimelineShareData(shareConfig)
// })
// }
}
let temEtaomallId = null
function getIndexEtaomall() {
api.getIndexEtaomall({ domain: uni.getStorageSync("subdomain") }).then((data: any) => {
temEtaomallId= data.etaomallId
})
}
function tapchange() {
let ua = navigator.userAgent.toLowerCase(); //判断是否是微信浏览器
let isWeixin = ua.indexOf("micromessenger") != -1; //判断是否
if (isWeixin) {
window._wx.miniProgram.getEnv((res) => {
if (res.miniprogram) {
onShare()
} else {
let link = uni.getStorageSync('subdomain')
console.log(temEtaomallId,'temEtaomallIdtemEtaomallIdtemEtaomallId');
uni.navigateTo({
url: `/pages/good/share?etaomallId=${temEtaomallId}&link=${link}&title=${skuData.value.title}&skuId=${skuData.value.skuId}&brandName=${state.brand.brandName}&mainImg=${skuData.value.mainImg}`,
})
}
});
} else {
onShare()
}
}
function onShareSelect(option: any) {
if (option.name == '微信') {
drawQR()
}
}
function getUrl(url) {
const q = {};
url.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => q[k] = v);
return q;
}
function drawQR() {
if (state.share.qrcode) {
state.share.showQRCode = true
return
}
if (state.loading.qrcode) return
state.loading.qrcode = true
let temurl = null
if (window.__wxjs_environment === 'miniprogram') {
let a = window.location.href
let huizui = a.substring(a.lastIndexOf("#"))
temurl = `https://${uni.getStorageSync('subdomain')}.edstao.com/${huizui}`
} else {
temurl = window.location.href
}
QRCode.toDataURL(temurl, {
width: 250,
height: 250,
margin: 1
} as QRCode.QRCodeToDataURLOptions).then((url: any) => {
state.share.qrcode = url
state.share.showQRCode = true
}).finally(() => {
state.loading.qrcode = false
})
}
function cartCount(afterAdd?: boolean) {
api.cartCount().then((data: any) => {
state.badge = data
afterAdd && Toast.success('加入购物车')
})
}
</script>
<style lang="scss" scoped>
.sign {
position: absolute;
right: 1.8vw;
top: 2vw;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
.top_bar {
margin-bottom: 3 rpx;
.top_tab {
width: 50vw;
}
}
.banner_top {
height: 60vw;
position: relative;
text-align: center;
&.video {
padding-bottom: 60 rpx;
}
&.video_black {
background: #000;
}
.indicator {
transition: all ease-in-out .2s;
padding: 8 rpx 20 rpx;
border-radius: 30 rpx;
margin: 10 rpx;
font-size: 20 rpx;
color: #333333;
background: #aaaaaa80;
min-width: 70 rpx;
&.active {
background: var(--orange);
color: #fff;
}
}
}
.scrollx_container {
overflow-x: scroll;
width: 85vw;
&::-webkit-scrollbar {
display: none;
}
}
.skuInfo_label {
width: 220 rpx;
}
.skuInfo_info {
width: 480 rpx;
}
.good_anchor {
background: #fff;
color: #333333;
font-size: 18px;
padding: 15 rpx 30 rpx;
border-left: 3px solid #FE521F;
}
.good_img {
position: relative;
.zone_icon {
position: absolute;
left: 20 rpx;
bottom: 20 rpx;
}
}
.detail_btn {
font-size: 14px;
padding: 10px;
height: 25px;
}
</style>
<template>
<view class="text-center">
<van-sticky>
<view class="sh mg-b-40">
<view class="top-bar justify-center bg-white">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view class="top-center">{{ state.title }}</view>
</view>
<van-tabs class="top_tab" v-model:active="state.tab.active" @change="onTab" scrollspy>
<van-tab v-for="(item, index) in state.tab.list" :name="item.name">
<template #title>
<view :style="index==1?'width:78px':''">{{item.title}}</view>
</template>
</van-tab>
</van-tabs>
</view>
</van-sticky>
<view style="height: 140vw">
<template v-for="(item, index) in state.tab.list">
<van-image v-if="state.tab.active == item.name && item.url" lazy-load
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="81vw" height="126vw"
width="81vw" :src="item.url" />
</template>
</view>
<view class="text-gray pd-20">{{ '>>长按上方图片保存<<' }}</view>
</view>
</template>
<script setup lang="ts">
import api from '@/api'
import { computed, onBeforeMount, reactive } from 'vue';
import { PageUtils } from '@/utils/utils';
const state = reactive({
title: PageUtils.getTitle(),
tab: {
active: 'detail',
list: [
{ title: '详情', name: 'detail', url: "" },
{ title: '图+二维码', name: 'pictureAndQrCode', url: "" },
{ title: '二维码', name: 'qrCode', url: "" },
{ title: '无底高清', name: 'skuImage', url: "" },
{ title: '吊牌', name: 'handTag', url: "" }
]
},
skuId: '',
data: {} as any,
brand: {} as any,
otherInfo: {
color: '',
material: ''
}
})
const skuData = computed(() => {
if (!state.data?.skuJson) return ''
const item = state.data.skuJson.find((item: any) => item.skuId == state.skuId)
return item
})
onBeforeMount(() => {
const query: any = PageUtils.getCurQuery()
state.skuId = query.skuId
if (!state.skuId) {
uni.navigateTo({
url: '/pages/index'
})
return
}
getProduct()
})
function getProduct() {
api.getProduct(state.skuId, { domain: uni.getStorageSync('subdomain') }).then((data: any) => {
state.data = data
const colorItem = state.data.labelJson.find((item: any) => item.labelNum == '10011')
const materialItem = state.data.labelJson.find((item: any) => item.labelNum == '10010')
if (colorItem) state.otherInfo.color = colorItem.labelParams.map((item: any) => item.name).join(',')
if (materialItem) state.otherInfo.material = materialItem.labelParams.map((item: any) => item.name).join(',')
brandInfo()
})
}
function brandInfo() {
api.brandInfo({ brandId: state.data.brandId }).then((data: any) => {
state.brand = data
const item = state.tab.list.find((item: any) => item.name == state.tab.active)
onTab(item ? item.name : state.tab.list[0].name)
})
}
function getBase64(data: any) {
const blob = new Blob([data], { type: "image/jpg" })
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject(error)
});
}
function imageDetail() {
console.log(state.otherInfo,'state.otherInfo');
const item = state.tab.list.find((item: any) => item.name == 'detail')
if (!item || item.url) return
api.imageDetail({
brandLogo: state.brand.brandLogo,
skuImage: skuData.value.mainImg,
model: skuData.value.model,
productPrice: skuData.value.productPrice,
salePrice: skuData.value.salePrice,
skuId: state.skuId,
domain: uni.getStorageSync("subdomain"),
specify: `W${skuData.value.specWidth}*H${skuData.value.specHeight}*D${skuData.value.specLength}`,
color: state.otherInfo.color,
lights: skuData.value.lightSourceCount || '',
material: state.otherInfo.material,
isSJS: skuData.value.salePrice !== null ? 1 : 0,
}).then((data: any) => {
getBase64(data).then((base64: any) => {
item.url = base64
})
})
}
function pictureAndQrCode() {
const item = state.tab.list.find((item: any) => item.name == 'pictureAndQrCode')
if (!item || item.url) return
api.pictureAndQrCode({
brandLogo: state.brand.brandLogo,
skuImage: skuData.value.mainImg,
model: skuData.value.model,
skuId: state.skuId,
domain: uni.getStorageSync("subdomain")
}).then((data: any) => {
getBase64(data).then((base64: any) => {
item.url = base64
})
})
}
function qrCode() {
const item = state.tab.list.find((item: any) => item.name == 'qrCode')
if (!item || item.url) return
api.imageQrCode({
brandLogo: state.brand.brandLogo,
model: skuData.value.model,
skuId: state.skuId,
domain: uni.getStorageSync("subdomain"),
}).then((data: any) => {
getBase64(data).then((base64: any) => {
item.url = base64
})
})
}
function skuImage() {
const item = state.tab.list.find((item: any) => item.name == 'skuImage')
if (!item || item.url) return
api.skuImage({
brandLogo: state.brand.brandLogo,
skuImage: skuData.value.mainImg,
model: skuData.value.model,
productPrice: skuData.value.productPrice,
salePrice: skuData.value.salePrice,
skuId: state.skuId,
domain: uni.getStorageSync("subdomain"),
specify: `W${skuData.value.specWidth}*H${skuData.value.specHeight}*D${skuData.value.specLength}`,
color: state.otherInfo.color,
lights: skuData.value.lightSourceCount || '',
material: state.otherInfo.material,
isSJS: skuData.value.salePrice !== null ? 1 : 0,
}).then((data: any) => {
getBase64(data).then((base64: any) => {
item.url = base64
})
})
}
function handTag() {
const item = state.tab.list.find((item: any) => item.name == 'handTag')
if (!item || item.url) return
api.handTag({
brandLogo: state.brand.brandLogo,
skuImage: skuData.value.mainImg,
model: skuData.value.model,
productPrice: skuData.value.productPrice,
skuId: state.skuId,
domain: uni.getStorageSync("subdomain"),
specify: `W${skuData.value.specWidth}*H${skuData.value.specHeight}*D${skuData.value.specLength}`,
classify: state.data.classify,
brandName: state.brand.brandName,
material: state.otherInfo.material
}).then((data: any) => {
getBase64(data).then((base64: any) => {
item.url = base64
})
})
}
function onTab(name: string) {
if (!skuData.value) return
if (name == 'detail') {
imageDetail()
} else if (name == 'pictureAndQrCode') {
pictureAndQrCode()
} else if (name == 'qrCode') {
qrCode()
} else if (name == 'skuImage') {
skuImage()
} else if (name == 'handTag') {
handTag()
}
}
function goBack() {
PageUtils.goBack()
}
</script>
<style lang="scss" scoped>
.top_tab {
width: 100vw;
}
</style>
<template>
<view>
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view class="top-center">{{ state.title }}</view>
</view>
</van-sticky>
<van-image width="100%" src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/issue.png" />
<to-top />
</view>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import toTop from '@/components/tool/toTop.vue';
import { PageUtils } from '@/utils/utils';
import { onPageScroll } from '@dcloudio/uni-app'
onPageScroll(e => { }) // uniapp的Bug,这句话不要去掉,否则to-top不生效
const state = reactive({
title: PageUtils.getTitle(),
})
function goBack() {
PageUtils.goBack()
}
</script>
<style lang="scss" scoped>
.mail_box {
position: relative;
height: 185rpx;
width: 100%;
}
</style>
<template>
<div style="background: #ffffff;height: 100vh;line-height: 50px">
<van-sticky>
<view class="top-bar top_bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goback" />
<p>分享详情</p>
</view>
</van-sticky>
<div style="padding: 20px">
<p>标题:E淘商城- {{userData.brandName}}</p>
<p>商品描述:{{userData.title}}</p>
<p>商品图片:<img style="width: 120px;vertical-align: top" :src="userData.mainImg" alt=""></p>
</div>
</div>
</template>
<script>
import api from "@/api";
export default {
name: "technicalSupport",
data() {
return {
userData:{},
url:'',
};
},
onLoad: function (option) { //option为object类型,会序列化上个页面传递的参数
window.location.href = `https://redirectwx.edstao.com/#/pages/good/share?etaomallId=${option.etaomallId}&link=${option.link}&title=${option.title}&skuId=${option.skuId}&brandName=${option.brandName}&mainImg=${option.mainImg}`
},
mounted(){
this.getUrl()
this.wxSign()
},
beforeDestroy(){
window.location.href = `https://${this.userData.link}.edstao.com/#/pages/good/detail?skuId=${this.userData.skuId}`
},
methods: {
goback() {
window.location.href = `https://${this.userData.link}.edstao.com/#/pages/good/detail?skuId=${this.userData.skuId}`
},
getUrl() {
let url = decodeURIComponent(window.location.href);
const q = {};
url.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => q[k] = v);
console.log(q,'qqqqqqqqqq');
this.userData = q;
},
wxSign() {
let that = this
api.wxSign({
skuId: this.userData.skuId,
etaomallId: this.userData.etaomallId,
url: window.location.href,
}).then((data) => {
that.url = data.redirecturl
that.initWX(data);
});
},
initWX(data) {
let that = this
const wx = window._wx;
const wxConfig = {
debug: false, // 上生产,时设置成false
appId: data.appid,
timestamp: data.timestamp,
nonceStr: data.nonceStr,
signature: data.signature,
jsApiList: ["updateAppMessageShareData"],
};
console.log(wxConfig);
wx.config(wxConfig);
wx.ready(function () {
wx.updateAppMessageShareData({
title: 'E淘商城-'+ that.userData.brandName, // 分享标题
desc: that.userData.title, // 分享描述
link: data.redirecturl, // 分享链接
imgUrl: that.userData.mainImg, // 分享图标
success: function (res) {
// console.log("分享成功返回的信息为:", res);;
},
});
});
wx.error(function (data) {
});
},
},
};
</script>
<style scoped>
</style>
<template>
<view class="text-center">
<van-sticky>
<view class="justify-center bg-white sh mg-b-40">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<van-tabs class="top_tab" v-model:active="state.tab.active" animated>
<van-tab v-for="item in state.tab.list" :title="item.name" />
</van-tabs>
</view>
</van-sticky>
<view class="whd_card">
<template v-for="(item, index) in state.tab.list">
<van-image v-show="state.tab.active == index"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="90vw" width="90vw" :src="item.url" />
</template>
<van-image loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="90vw" width="90vw"
src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/whd_detail.png" />
</view>
</view>
</template>
<script setup lang="ts">
import { onBeforeMount, reactive } from 'vue';
import { PageUtils } from '@/utils/utils';
const state = reactive({
tab: {
active: 0,
list: [
{ name: 'W', url: "https://img.edsmall.com/ROOT/ETao/fenxiao/h5/whd1.jpg" },
{ name: 'H', url: "https://img.edsmall.com/ROOT/ETao/fenxiao/h5/whd2.jpg" },
{ name: 'D', url: "https://img.edsmall.com/ROOT/ETao/fenxiao/h5/whd2.jpg" }
]
},
skuId: undefined,
})
onBeforeMount(() => {
const query: any = PageUtils.getCurQuery()
state.skuId = query.skuId
if (!state.skuId) {
uni.navigateTo({
url: '/pages/index'
})
return
}
})
function goBack() {
PageUtils.goBack()
}
</script>
<style lang="scss" scoped>
.top_tab {
width: 60vw;
}
.whd_card {
border-top: 5px solid var(--orange);
width: 90vw;
margin: 0 5vw;
box-shadow: 6rpx 10rpx 10rpx #aaaaaa80;
}
</style>
<template>
<view class="text-center pd-b-px-55">
<van-sticky>
<div style="display: flex;align-items:center;background: #ffffff">
<van-icon size="1.5rem" name="arrow-left" style="color: #757575;" @click="goBack" />
<van-search v-model="state.keyword" style="flex: 1" placeholder="请输入搜索关键词" @click.stop="topSearch" />
<img v-if="state.showStyle" src="../../static/img/icon_search1.jpg" alt="" @click="changeIcon"
style="width: 1.8rem;height: 1.6rem;margin-right: 3px">
<img v-if="!state.showStyle" src="../../static/img/icon_search2.jpg" alt="" @click="changeIcon"
style="width: 1.8rem;height: 1.6rem;margin-right: 3px">
</div>
<van-tabs v-model:active="state.active" color="#ff6600" line-width="206rpx"
title-active-color="#ff6600" @click-tab="changeTab">
<van-tab title="默认">
</van-tab>
<van-tab>
<template #title>
价格 <van-icon v-if="state.params.sort!==undefined" :class="state.params.sort==0?'down_price':'up_price'" name="play" />
</template>
</van-tab>
<van-tab title="筛选">
</van-tab>
</van-tabs>
</van-sticky>
<div style="margin-top: .2rem"></div>
<van-list :loading="state.good.loading" :finished="state.good.finished" finished-text="没有更多了"
@load="onGoodLoad">
<van-grid :center="false" :column-num="2" :gutter="3" v-if="state.showStyle">
<van-grid-item style="border-radius: 4px" class="text-left" v-for="(item, index) in state.good.list" :key="item.skuId"
@click="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${item.spuId}`)">
<van-image class="self_center" width="30vw" height="30vw" lazy-load :src="item.mainImg" />
<view :class="[item.zoneIcon||item.isVideoIcon||item.coTip==1?'mg-t-30-m':'']">
<!--活动角标-->
<div class="sign" v-if="item.subScriptImgUrl">
<img :src="item.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{item.discount}}</div>
</div>
<span v-if="item.coTip==1" style="color: #ff5500;border: 1px solid #ff5500;font-size: 12px;margin-right: 2px;font-weight: bold;padding: 1px">热销</span>
<span v-if="item.leftDownIcons&&item.leftDownIcons.length>0">
<span v-for="item1 in item.leftDownIcons " style="margin-right: 3px" >
<van-image width="60rpx" height="32rpx" :src="item1" />
</span>
</span>
<van-image v-if="item.isVideoIcon" class="mg-l-5" width="32rpx" height="32rpx" src="/static/img/play.png" />
</view>
<text class="text-s ellipsis line_over2 pd-t-10" style="width: 315rpx;margin-bottom:6px;">
{{ item.title }}
</text>
<text class="text-ss">{{ item.size }}</text>
<text class="text-gray text-ss"></text>
<!--未开启设计师模式-->
<div v-if="item.salePrice">
<view v-if="!item.actPrice" class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</view>
<view v-if="item.actPrice">
<view class="text-gray text-ss">零售价¥{{ item.productPrice }}</view>
<view class="text-gray text-ss line-through">优惠价¥{{ item.salePrice }}</view>
<view class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</view>
</view>
<view v-else class="text-orange text-ss">优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</view>
</div>
<div v-else class="text-orange" style="font-size: 13px;margin-top: 3px">
<view v-if="item.actPrice">
<view class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</view>
<view class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</view>
</view>
<text v-else class="text-bold text-ss" >零售价¥{{ item.productPrice }}</text>
</div>
</van-grid-item>
</van-grid>
<van-grid :center="false" :column-num="1" :gutter="7" v-else>
<van-grid-item class="text-left" v-for="(item, index) in state.good.list" :key="index"
@click="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${item.spuId}`)">
<van-row>
<van-col span="7" style="position: relative">
<van-image class="self_center" width="6rem" height="6rem" lazy-load
:src="item.mainImg" />
<!--活动角标-->
<div class="sign" style="top: 0" v-if="item.subScriptImgUrl">
<img :src="item.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{item.discount}}</div>
</div>
<view style="position: absolute;left: 0;bottom: 0">
<span v-if="item.coTip==1" style="color: #ff5500;border: 1px solid #ff5500;font-size: 12px;margin-right: 2px;font-weight: bold;padding: 1px">热销</span>
<van-image v-if="item.zoneIcon" width="60rpx" lazy-load :src="item.zoneIcon" />
<van-image v-if="item.isVideoIcon" class="pd-l-5" width="32rpx" height="32rpx" src="/static/img/play.png" />
</view>
</van-col>
<van-col span="16" offset="1">
<p class="text-s ellipsis line_over2 pd-t-10" >
{{ item.title }}
</p>
<div style="line-height: 1.2rem">
<p class="text-ss">{{ item.size }}</p>
<p class="text-gray text-ss"></p>
<div v-if="item.salePrice">
<view v-if="item.actPrice">
<p class="text-gray text-ss">零售价¥{{ item.productPrice }}</p>
<p class="text-gray text-ss line-through">优惠价¥{{ item.salePrice }}</p>
<p class="text-orange text-ss">
<img @click.stop="check(item)" src="../../static/img/car_search.png"
style="float: right;width: 1.8rem;margin-top: -5px" alt="">
活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</p>
</view>
<view v-else>
<p class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</p>
<p class="text-orange text-ss">
<img @click.stop="check(item)" src="../../static/img/car_search.png"
style="float: right;width: 1.8rem;margin-top: -5px" alt="">
优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</p>
</view>
</div>
<div v-else>
<view v-if="item.actPrice">
<view class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</view>
<p class="text-orange text-ss text-bold" style="font-size: 14px;margin-top: 6px" >
活动价¥{{ item.actPrice }}
<img @click.stop="check(item)" src="../../static/img/car_search.png"
style="float: right;width: 1.8rem;margin-top: -5px" alt="">
</p>
</view>
<p class="text-orange text-ss text-bold" style="font-size: 14px;margin-top: 6px" v-else>
零售价¥{{ item.productPrice }}
<img @click.stop="check(item)" src="../../static/img/car_search.png"
style="float: right;width: 1.8rem;margin-top: -5px" alt="">
</p>
</div>
</div>
</van-col>
</van-row>
</van-grid-item>
</van-grid>
</van-list>
<view v-if="state.good.fail" class="text-ss text-gray pd-50" @click="failReset">请求失败,点击重试
<van-icon name="replay" />
</view>
<to-top :showNav="true"/>
</view>
</template>
<script setup lang="ts">
import { Dialog } from "vant";
import {Toast} from 'vant';
import api from "@/api";
import {onMounted, reactive, getCurrentInstance} from 'vue';
import toTop from '@/components/tool/toTop.vue';
import { onPageScroll } from '@dcloudio/uni-app'
import { PageUtils } from '@/utils/utils'
onPageScroll(e => { }) // uniapp的Bug,这句话不要去掉,否则to-top不生效
const state = reactive({
skuId: '',
spuId: '',
params: {},
sortType:0,
showStyle: true,
active: 0,
keyword: "",
loading: {
cartAdd: false,
productFav: false,
brandFav: false,
share: false
},
banner: {
top: [] as any,
afterTop: [] as any,
afterTap: [] as any
},
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any
}
})
onMounted(() => {
state.showStyle = uni.getStorageSync('searchCard') === ''? true:uni.getStorageSync('searchCard')
let search = getCurrentInstance().ctx.$page.options || ''
if (search) {
// 价格搜索
if (search['money']) {
let minSalePrice = ''
let maxSalePrice = ''
let money = search['money']
if (money.indexOf('元以下') > -1) {
maxSalePrice = money.replace('元以下', '')
} else if (money.indexOf('以上') > -1) {
minSalePrice = money.replace('以上', '')
} else {
let str = money.replace('元', '')
minSalePrice = str.split('-')[0]
maxSalePrice = str.split('-')[1]
}
state.params['minSalePrice'] = minSalePrice
state.params['maxSalePrice'] = maxSalePrice
return
}
if (search['search']) {
state.keyword = decodeURIComponent(search['search'])
}
if (search['actId']) {
state.params['actId'] = search['actId']
state.keyword=''
}
let key = Object.keys(search)
state.params[key] = search[key]
}
state.params = search
// console.log(getUrl(window.location.href));
});
function goto(url: any) {
url && uni.navigateTo({url})
}
function cartAdd(data) {
if (state.loading.cartAdd) return
state.loading.cartAdd = true
api.cartAdd({
skuId: data.skuId,
link: uni.getStorageSync('subdomain'),
productQty: 1, // B端去除起订量限制 skuData.value.moq
}).then(() => {
Toast.success('加入购物车')
}).finally(() => {
state.loading.cartAdd = false
})
}
function check(item) {
const { token } = uni.getStorageSync("user") || {};
if (token) {
cartAdd(item)
} else {
Dialog.confirm({
message: '您尚未登录,请前往登录',
title: "提示",
cancelButtonText: '取消'
}).then(() => {
uni.navigateTo({
url: '/pages/login/login'
})
});
}
}
function changeTab(e) {
state.good.list = []
state.good.page = 0
if (e.name == 0) {
state.sortType=0
delete state.params['sort']
}
if (e.name == 1) {
state.sortType=3
state.params['sort'] == 1 ? state.params['sort'] = 0 : state.params['sort'] = 1
}
onGoodLoad()
if (e.name == 2) {
if(localStorage.getItem('isClassify')){
history.back()
}else {
uni.navigateTo({
url:'/pages/classify/index?good=1'
});
}
localStorage.removeItem('isClassify');
}
}
function changeIcon() {
state.showStyle = !state.showStyle
uni.setStorageSync('searchCard', state.showStyle)
}
function topSearch() {
uni.navigateTo({
url: "/pages/topSearch/index",
});
}
function getUrl(url) {
const q = {};
url.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => q[k] = v);
return q;
}
function onGoodLoad() {
// 获取link参数
// url.indexOf('localhost') == -1 ? link :
// let url = window.location.href
// let link = url.substring((url.indexOf("/") + 2), url.indexOf("."))
if (state.good.loading || state.good.fail) return
state.good.loading = true
++state.good.page
api.productList({
sortType: state.sortType,
...state.params,
pageNum: state.good.page,
pageSize: 20,
link:uni.getStorageSync("subdomain")?uni.getStorageSync("subdomain"):'alisa'
}).then((data: any) => {
if (!data||!data.hasNextPage){
state.good.finished = true
}
state.good.list.push(...data.list)
})
.catch(() => {
state.good.fail = true
})
.finally(() => {
state.good.loading = false
})
}
function failReset() {
state.good.page -= 1
state.good.finished = false
state.good.fail = false
onGoodLoad()
}
function goBack() {
PageUtils.goBack()
}
</script>
<style lang="scss" scoped>
.sign {
position: absolute;
right: 1.8vw;
top: 2vw;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
:root {
--van-sidebar-selected-border-height: 30px;
}
.search_bar {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100vw;
z-index: 5;
}
.banner_top {
height: 43.5vw;
}
.banner_afterTop,
.banner_afterTap {
height: 20vw;
}
.block_title {
margin: 40 rpx auto 25 rpx auto;
width: 60vw;
}
.down_price {
transition: all ease-in-out .2s;
transform: rotate(90deg);
}
.up_price {
transition: all ease-in-out .2s;
transform: rotate(-90deg);
}
</style>
<template>
<index v-if="state.tabIndex === 0" />
<classify v-if="state.tabIndex === 1" />
<cart v-if="state.tabIndex === 2" @setCartCount="setCartCount" />
<my v-if="state.tabIndex === 3" />
<tabbar :current="state.tabIndex" :list="state.list" @tab-change="(index) => state.tabIndex = index" />
</template>
<script setup lang="ts">
import api from "@/api";
import { onBeforeMount, reactive } from "vue";
import index from "./index/index.vue";
import classify from "./classify/index.vue";
import cart from "./cart/cart.vue";
import my from "./my/index.vue";
import tabbar from "@/components/layout/tabbar.vue";
import { PageUtils } from '@/utils/utils'
import { onPageScroll, onShow } from '@dcloudio/uni-app'
onPageScroll(e => { }) // uniapp的Bug,这句话不要去掉,否则to-top不生效
const state = reactive({
tabIndex: 0,
list: [
{
text: "首页",
icon: "wap-home",
},
{
text: "分类",
icon: "bars",
},
{
text: "购物车",
icon: "shopping-cart",
badge: 0
},
{
text: "我的",
icon: "manager",
},
],
});
onShow(() => {
const { token } = uni.getStorageSync("user") || {};
if (token) {
api.cartCount().then((data: any) => {
const item = state.list.find((item: any) => item.text == '购物车')
if (item) item.badge = data
})
}
})
onBeforeMount(() => {
const query: any = PageUtils.getCurQuery()
if (query.index) state.tabIndex = Number(query.index)
});
function setCartCount(num: number) {
const item = state.list.find((item: any) => item.text == '购物车')
if (item) item.badge = num
}
</script>
<style lang="scss" scoped>
</style>
<template>
<view class="text-center pd-b-px-55">
<img @click="gotoU" src="../../static/right_rule.png" style="position: fixed;right: 0;top: 70%;z-index: 99" alt="">
<van-sticky>
<view class="search_bar sh">
<van-search input-align="center" placeholder="搜索E淘商城商品" shape="round" v-model="state.keyword"
@focus="goSearch" >
<!--<template v-slot:right-icon>-->
<!--<van-icon name="photograph" @click="searchImg" size="1.2rem" />-->
<!--</template>-->
</van-search>
</view>
</van-sticky>
<van-swipe v-if="state.banner.indexCarouselBig.length > 0" lazy-render class="banner_top" :autoplay="3000"
indicator-color="white">
<van-swipe-item v-for="item in state.banner.indexCarouselBig">
<van-image :src="item.iconpath" @tap="goto(item.josnContent)" />
</van-swipe-item>
</van-swipe>
<van-swipe v-if="state.banner.indexCarouselSmall.length > 0" lazy-render class="banner_afterTop" vertical
:autoplay="3000" :show-indicators="false">
<van-swipe-item v-for="item in state.banner.indexCarouselSmall">
<van-image :src="item.iconpath" @tap="goto(item.josnContent)" />
</van-swipe-item>
</van-swipe>
<van-cell-group>
<van-cell is-link class="justify-middle" @tap="goto('/pages/index/storeCard')">
<template #title>
<view class="justify-middle">
<van-image fit="cover" height="70rpx" round @click.stop="goMe"
:src="state.mall.headImg || 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/mall_default.png'"
width="70rpx" />
<text class="pd-l-15 text-bold text-m" @click.stop="goMe">{{ state.mall.mallName }}</text>
</view>
</template>
<template #right-icon>
<view class="flex col text-center">
<van-icon class="text-orange text-xl" name="shop" />
<text class="text-gray text-ss block">店铺名片</text>
</view>
</template>
</van-cell>
</van-cell-group>
<!--活动入口 v-if="item.contentNumber=='493002004'"x新品-->
<div v-if="state.act_bg">
<div style="position: relative">
<img :src="state.act_bg" alt="" style="width: 98.5vw">
<div style="position: absolute;top: 33.2vw;">
<!--<div v-for="item in state.actList" style="display: inline-block">-->
<!--<img @click="goToAct(item.josnContent)" :src="item.iconpath"-->
<!--style="margin-left: .8vw;margin-bottom: .6vw;margin-right: .8vw;width: 42vw">-->
<!--</div>-->
<div style="display: flex">
<div>
<img @click="goToAct(state.actHotSell.josnContent)"
:src="state.actHotSell.iconpath"
style="padding-left: 7.5vw ;margin-bottom: .6vw;width: 42vw">
</div>
<div>
<img @click="goToAct(state.actEight.josnContent)" :src="state.actEight.iconpath"
style="margin-bottom: .6vw;width: 42vw;padding-right: 5.5vw">
<img @click="goToAct(state.actLittleE.josnContent)"
:src="state.actLittleE.iconpath"
style="margin-bottom: .6vw;width: 42vw;padding-right: 5.5vw">
</div>
</div>
</div>
</div>
</div>
<van-tabs class="pd-b-10" v-model:active="state.tab.active" animated swipeable>
<van-tab v-for="tItem in state.tab.tabList" :title="tItem.title">
<van-grid class="small-padding" :column-num="4">
<van-grid-item v-for="item in tItem.list" :key="item.id"
@click="changeTab(state.tab.active == 0 ? item.id : item.name)">
<van-image width="14vw" height="14vw" :src="item.icon || item.img" lazy-load
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="18vw" />
<text class="text-ss text-darkGray">{{ item.name }}</text>
</van-grid-item>
</van-grid>
</van-tab>
</van-tabs>
<van-swipe v-if="state.banner.middleBanner.length > 0" lazy-render class="banner_afterTap" vertical :autoplay="3000"
:show-indicators="false">
<van-swipe-item v-for="item in state.banner.middleBanner">
<van-image :src="item.iconpath" @tap="goto(item.josnContent)" />
</van-swipe-item>
</van-swipe>
<template v-if="state.banner.areaBanner.length > 0&&false">
<van-image class="block_title" src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/area_title.png" />
<view>
<view v-if="state.banner.areaBanner.length == 6">
<van-row gutter="8" class="pd-h-px-10">
<van-col span="12">
<van-image width="100%" radius="20rpx" :src="state.banner.areaBanner[0].iconpath"
@tap="changeTab(state.banner.areaBanner[0].josnContent, 'zq')" />
</van-col>
<van-col span="12" class="flex col justify-between">
<van-image width="100%" radius="20rpx" :src="state.banner.areaBanner[1].iconpath"
@tap="changeTab(state.banner.areaBanner[1].josnContent, 'zq')" />
<van-image width="100%" radius="20rpx" :src="state.banner.areaBanner[2].iconpath"
@tap="changeTab(state.banner.areaBanner[2].josnContent, 'zq')" />
</van-col>
</van-row>
<van-row gutter="8" class="pd-h-px-10 pd-t-px-10">
<van-col span="12" class="flex col justify-between">
<van-image width="100%" radius="20rpx" :src="state.banner.areaBanner[3].iconpath"
@tap="changeTab(state.banner.areaBanner[3].josnContent, 'zq',state.banner.areaBanner[3].ifCanEnter)" />
<van-image width="100%" radius="20rpx" :src="state.banner.areaBanner[4].iconpath"
@tap="changeTab(state.banner.areaBanner[4].josnContent, 'zq',)" />
</van-col>
<van-col span="12">
<van-image width="100%" radius="20rpx" :src="state.banner.areaBanner[5].iconpath"
@tap="changeTab(state.banner.areaBanner[5].josnContent, 'zq',state.banner.areaBanner[5].ifCanEnter)" />
</van-col>
</van-row>
</view>
</view>
</template>
<van-image class="block_title" src="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/recommend_title.png" />
<van-list v-if="state.inited" :loading="state.good.loading" :finished="state.good.finished" finished-text="没有更多了"
offset="10" @load="onGoodLoad">
<van-grid :center="false" :column-num="2" :gutter="3">
<van-grid-item class="text-left" v-for="item in state.good.list" style="border-radius: 4px"
@tap="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${item.spuId}`)">
<van-image class="self_center" width="30vw" height="30vw" lazy-load :src="item.mainImg"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="30vw" />
<!--活动角标-->
<div class="sign" v-if="item.subScriptImgUrl">
<van-image :src="item.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{item.discount}}</div>
</div>
<view :class="[item.zoneIcon||item.isVideoIcon||item.coTip==1?'mg-t-30-m':'']">
<span v-if="item.coTip==1" class="host_tip" style="position: relative;z-index: 9999">热销</span>
<span v-if="item.leftDownIcons&&item.leftDownIcons.length>0">
<span v-for="item1 in item.leftDownIcons" style="margin-right: 3px">
<van-image width="60rpx" height="32rpx" :src="item1" />
</span>
</span>
<van-image v-if="item.isVideoIcon" class="mg-l-5" width="32rpx" height="32rpx"
src="/static/img/play.png" />
</view>
<text class="text-s ellipsis line_over2 pd-t-10" style="width: 320rpx;height: 32px;margin-bottom:6px">
{{ item.title }}
</text>
<text class="text-ss">{{ item.size }}</text>
<text class="text-gray text-ss"></text>
<!--未开启设计师模式-->
<div v-if="item.salePrice">
<view v-if="!item.actPrice" class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</view>
<view v-if="item.actPrice">
<view class="text-gray text-ss">零售价¥{{ item.productPrice }}</view>
<view class="text-gray text-ss line-through">优惠价¥{{ item.salePrice }}</view>
<view class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</view>
</view>
<view v-else class="text-orange text-ss">优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</view>
</div>
<div v-else class="text-orange" style="font-size: 13px;margin-top: 3px">
<view v-if="item.actPrice">
<view class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</view>
<view class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</view>
</view>
<text v-else class="text-bold text-ss" >零售价¥{{ item.productPrice }}</text>
</div>
</van-grid-item>
</van-grid>
</van-list>
<view v-if="state.good.fail" class="text-ss text-gray pd-50" @tap="failReset">请求失败,点击重试
<van-icon name="replay" />
</view>
<to-top />
<popup-banner v-model:show.sync="state.banner.showPopup" :list="state.banner.popupCarousel" />
<van-overlay z-index="99999" :show="state.showCertificates" >
<van-image lazy-load :src="state.showCertificatesImg" style="width: 90%;margin: 50vw auto" />
<!--<van-button @click="state.showCertificates=false" size="small" type="primary" style="padding: 16px 20px;background: #ff6800;margin-top: -50px">知道了</van-button>-->
<!--<div class="wrapper1" @click.stop>-->
<!--<div class="block1" >-->
<!--<p style="margin: 18px auto;text-align: center">温馨提醒</p>-->
<!--<div style="line-height: 1.4rem">-->
<!--很抱歉,根据《电子商务法》相关法律法规之规定,因商家未能公示相关证照信息,-->
<!--暂时无法正常向您提供商城相关服务,请商家根据指引尽快补充证照信息,-->
<!--给您带来的不便,敬请见谅。-->
<!--</div>-->
<!--<div style="text-align: center;margin-top: 4vw;margin-bottom: 4vw">-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
</van-overlay>
<van-popup v-model:show="state.show" position="bottom" :style="{ height: '100%' }" >
<van-sticky>
<view class="search_bar sh" style="z-index: 99999999999">
识别到一下商品
</view>
</van-sticky>
<div style="margin: 20px auto">
<van-list v-if="state.inited" :loading="state.good.loading" :finished="state.good.finished" finished-text="没有更多了"
offset="10" @load="onGoodLoad">
<van-grid :center="false" :column-num="2" :gutter="7">
<van-grid-item class="text-left" v-for="item in state.good.list" style="border-radius: 4px"
@tap="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${item.spuId}`)">
<van-image class="self_center" width="30vw" height="30vw" lazy-load :src="item.mainImg"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="30vw" />
<!--活动角标-->
<div class="sign" v-if="item.subScriptImgUrl">
<van-image :src="item.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{item.discount}}</div>
</div>
<view :class="[item.zoneIcon||item.isVideoIcon||item.coTip==1?'mg-t-30-m':'']">
<span v-if="item.coTip==1" class="host_tip" style="position: relative;z-index: 9999">热销</span>
<span v-if="item.leftDownIcons&&item.leftDownIcons.length>0">
<span v-for="item1 in item.leftDownIcons" style="margin-right: 3px">
<van-image width="60rpx" height="32rpx" :src="item1" />
</span>
</span>
<van-image v-if="item.isVideoIcon" class="mg-l-5" width="32rpx" height="32rpx"
src="/static/img/play.png" />
</view>
<text class="text-s ellipsis line_over2 pd-t-10" style="width: 320rpx;height: 32px;margin-bottom:6px">
{{ item.title }}
</text>
<text class="text-ss">{{ item.size }}</text>
<text class="text-gray text-ss"></text>
<!--未开启设计师模式-->
<div v-if="item.salePrice">
<view v-if="!item.actPrice" class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</view>
<view v-if="item.actPrice">
<view class="text-gray text-ss">零售价¥{{ item.productPrice }}</view>
<view class="text-gray text-ss line-through">优惠价¥{{ item.salePrice }}</view>
<view class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</view>
</view>
<view v-else class="text-orange text-ss">优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</view>
</div>
<div v-else class="text-orange" style="font-size: 13px;margin-top: 3px">
<view v-if="item.actPrice">
<view class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</view>
<view class="text-orange text-ss">活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</view>
</view>
<text v-else class="text-bold text-ss" >零售价¥{{ item.productPrice }}</text>
</div>
</van-grid-item>
</van-grid>
</van-list>
</div>
</van-popup>
</view>
</template>
<script setup lang="ts">
import api from "@/api";
import { Toast } from 'vant';
import { onBeforeMount, onMounted, reactive,ref} from 'vue';
import toTop from '@/components/tool/toTop.vue';
import popupBanner from '@/components/tool/popupBanner.vue';
const state = reactive({
show:false,
actHotSell:null,
actEight:null,
actLittleE:null,
showCertificatesImg:'',
showCertificates:false,
keyword: "",
actList:[],
act_bg:'',
banner: {
areaBanner: [] as any,
indexCarouselBig: [] as any,
indexCarouselSmall: [] as any,
middleBanner: [] as any,
popupCarousel: [] as any,
showPopup: false,
},
tab: {
active: 0,
tabList: [
{ title: '类型', list: [] },
{ title: '空间', list: [] },
{ title: '风格', list: [] },
] as any
},
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any
},
mall: {} as any,
inited: false
})
onBeforeMount(() => {
getBanner()
getIndexEtaomall()
canUse()
})
const isAPP = ref(false)
onMounted(() => {
window._wx.miniProgram.getEnv((res) => {
if (res.miniprogram) {
isAPP.value=true
} else {
isAPP.value=false
}
});
setTimeout(() => {
state.inited = true
}, 1000)
});
function searchImg() {
const { token } = uni.getStorageSync("user") || {};
uni.chooseImage({
count: 1, //默认3
sizeType: ['original','compressed'],
success: function(res) {
let formData1 = {
image:res.tempFiles[0],
link:'alisa1',
pageNum:1,
pageSize:20
}
return new Promise((resolve, reject) => {
uni.uploadFile({
header: {
"Authorization": token
},
url: '/pre/api/image/search',
timeout: 1000*6,
filePath:'',
formData: formData1,
success: (res) => {
console.log(res);
},
complete: () => {
},
fail: (res) => {
}
})
})
}
});
}
function gotoU() {
uni.redirectTo({
url: "/pages/my/technicalSupport?name=index",
});
}
function goToAct(id) {
uni.navigateTo({
url: `/pages/goodList/index?actId=${id}`,
});
}
function setBgColor (bgColor) {
return {
background: 'url(' + bgColor + ') no-repeat 0 0',
'background-position':'center',
'background-sizing':'100% 100%',
'position':'relative'
}
}
function H() {
let url = 'https://etaoact.edstao.com/etaoappv3/?userId=1'
const weburl = encodeURIComponent(url+ '/weixin/QRCode&&name=alisa1'+ '&from=wx');
window._wx.miniProgram.redirectTo({url:`/pages/index?weburl=${weburl}`})
}
function goMe() {
uni.navigateTo({
url: "/pages/good/contact",
});
}
function goSearch() {
uni.navigateTo({
url: "/pages/topSearch/index",
});
}
function getBanner() {
api.indexModule().then((data: any) => {
if (!data) return
const { indexBanners, indexClassify } = data
state.banner = indexBanners
if (Object.keys(data.actBanner).length>0) {
let imgData = data.actBanner
state.act_bg = imgData.actBackground[0].iconpath
if (imgData.actHotSell.length > 0) {
state.actHotSell = imgData.actHotSell[0]
}
if (imgData.actEight.length > 0) {
state.actEight = imgData.actEight[0]
}
if (imgData.actLittleE.length > 0) {
state.actLittleE = imgData.actLittleE[0]
}
}
state.tab.tabList[0].list = [
...indexClassify.type.slice(0, 7),
{ img: 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/more.png', name: '更多' }
]
state.tab.tabList[1].list = [
...indexClassify.room.slice(0, 7),
{ img: 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/more.png', name: '更多' }
]
state.tab.tabList[2].list = [
...indexClassify.style.slice(0, 7),
{ img: 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/more.png', name: '更多' }
]
if (state.banner.popupCarousel.length > 0) state.banner.showPopup = true
})
}
function getIndexEtaomall() {
api.getIndexEtaomall({ domain: uni.getStorageSync("subdomain") }).then((data: any) => {
state.mall = data
uni.setStorageSync('mail', state.mall)
})
}
function canUse() {
api.getCanUse({ domain: uni.getStorageSync("subdomain") }).then((data: any) => {
if(data){
state.showCertificates=true
state.showCertificatesImg=data
}
})
}
function onGoodLoad() {
if (state.good.loading || state.good.fail) return
state.good.loading = true
state.good.page += 1
api.productList({ pageNum: state.good.page, sortType: 0, pageSize: 20, link: uni.getStorageSync("subdomain") }).then((data: any) => {
if (!data) return
if (!data||!data.hasNextPage){
state.good.finished = true
}
state.good.list.push(...data.list)
})
.catch(() => {
state.good.fail = true
})
.finally(() => {
state.good.loading = false
})
}
function failReset() {
state.good.page -= 1
state.good.finished = false
state.good.fail = false
onGoodLoad()
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function changeTab(name: any, ZQ?: any,num?:any) {
if (num==0) {
Toast('正在筹备中,敬请期待!');
return
}
if (ZQ == 'zq') {
uni.navigateTo({
url: `/pages/goodList/index?zone=${name}`,
});
return
}
if (!name || name == '更多') {
let act = 0
if (state.tab.active == 1) act = 6
if (state.tab.active == 2) act = 1
uni.navigateTo({
url: `/pages/classify/index?act=${act}`,
});
return
}
let type = null
if (state.tab.active == 0) {
type = 'menuId'
} else if (state.tab.active == 1) {
type = 'space'
} else if (state.tab.active == 2) {
type = 'styleName'
}
uni.navigateTo({
url: `/pages/goodList/index?${type}=${name}`,
});
}
</script>
<style lang="scss" scoped>
.sign {
position: absolute;
right: 1.8vw;
top: 2vw;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
.wrapper1 {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.block1 {
text-align: left;
padding: 0 10px;
border-radius: 10px;
width: 85%;
background-color: #fff;
}
.search_bar {
width: 100vw;
}
.banner_top {
height: 43.5vw;
}
.banner_afterTop,
.banner_afterTap {
height: 20vw;
}
.block_title {
margin: 40rpx auto 25rpx auto;
width: 60vw;
}
</style>
<template>
<view class="bg-max bg-gray">
<van-sticky>
<view class="justify-center bg-white sh pd-px-20 mg-b-20">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view class="top-center">{{ state.title }}</view>
</view>
</van-sticky>
<van-grid :column-num="2" :gutter="5" class="bg-gray pd-b-px-60">
<van-grid-item v-for="(item, index) in state.list" @tap="onCard(index)">
<view class="text-center bg-white mg-v-px-10-m">
<van-image :src="item.path" width="322rpx" height="543rpx"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="322rpx" />
<view>{{ item.name }}</view>
</view>
<!-- 这个部分是卡片的实体部分,我置底了 -->
<view class="card" :id="'card' + index" v-if="item.showed">
<canvas style="width: 720px;height: 1214px;" :id="'cardbg' + index" :canvas-id="'cardbg' + index" />
<view class="info flex">
<view>
<van-image width="160px" height="160px" :src="state.qrcode"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="160px" />
<view class="tip">扫码获取更多活动信息</view>
</view>
<view class="detail">
<view class="flex" v-for="item in state.infoList">
<view class="name">{{ item.name }}</view>
<view class="value">{{ item.value }}</view>
</view>
</view>
</view>
</view>
</van-grid-item>
</van-grid>
<view class="fixed-bottom text-center bg-white pd-30 br-t" style="z-index: 1">点击查高清图</view>
<van-image-preview v-model:show="state.preview.show" :start-position="state.preview.index" closeable
:images="state.list.map((item: any) => item.showPath)" @change="onCardShow" :showIndex="false"/>
<!-- 因为生成卡片会卡,所以加载完一张之后,再让用户操作 -->
<van-overlay :show="state.preview.loading" style="z-index: 2003"/>
</view>
</template>
<script setup lang="ts">
import api from '@/api';
import { onBeforeMount, reactive } from 'vue';
import { PageUtils } from '@/utils/utils';
// @ts-ignore
import QRCode from 'qrcode'
import html2Canvas from "html2canvas"
const state = reactive({
title: PageUtils.getTitle(),
data: {} as any,
list: [] as any,
infoList: [] as any,
qrcode: '',
preview: {
index: 0,
show: false,
loading: false
}
})
onBeforeMount(() => {
storeCard()
})
function storeCard() {
api.storeCard({
link: uni.getStorageSync('subdomain')
}).then((data: any) => {
state.data = data
state.list = data.cards
state.infoList = [
{ name: '商城名称:', value: state.data.mallName },
{ name: '商城网址:', value: state.data.mallLink + '.edstao.com' },
{ name: '联系电话:', value: state.data.mallContact },
{ name: '门店地址:', value: state.data.storeAddress },
]
})
}
// 再画卡片
function drawBg(index: number) {
const item = state.list[index]
uni.downloadFile({
url: item.path + '?timestamp=' + new Date().getTime(),
success: (res) => {
if (res.statusCode === 200) {
const ctx = uni.createCanvasContext('cardbg' + index)
ctx.drawImage(res.tempFilePath, 0, 0, 720, 1214)
ctx.draw()
// 等待1s画完卡片
setTimeout(() => {
const cardDom = document.getElementById("card" + index)
if (!cardDom) return
html2Canvas(cardDom, { useCORS: false }).then(canvas => {
// 生成实际blob-url
item.showPath = canvas.toDataURL("image/png")
})
}, 500);
}
},
fail: () => {
item.showed = false
},
complete: () => {
setTimeout(() => {
state.preview.loading = false
}, 1000)
},
})
}
// 先画二维码
function drawQR(index: number) {
const item = state.list[index]
if (item.showed || state.preview.loading) return
state.preview.loading = true
item.showed = true
if (state.qrcode) {
drawBg(index)
} else {
if(window.__wxjs_environment === 'miniprogram'&&state.data.appletCode){
var appresultText=state.data.appletCode
convertImgToBase64(appresultText, function(base64Img){
state.qrcode = base64Img
});
drawBg(index)
}else {
QRCode.toDataURL('https://'+state.data.mallLink + '.edstao.com', {
width: 160,
height: 160,
margin: 1
} as QRCode.QRCodeToDataURLOptions).then((url: any) => {
state.qrcode = url
drawBg(index)
}).catch(() => {
state.preview.loading = false
})
}
}
}
function convertImgToBase64(url, callback, outputFormat){
var canvas = document.createElement('CANVAS'),
ctx = canvas.getContext('2d'),
img = new Image;
img.crossOrigin = 'Anonymous';
img.onload = function(){
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img,0,0);
var dataURL = canvas.toDataURL(outputFormat || 'image/png');
callback.call(this, dataURL);
canvas = null;
};
img.src = url;
}
function onCard(index: number) {
state.preview.index = index
state.preview.show = true
drawQR(index)
}
function onCardShow(index: number) {
state.preview.index = index
drawQR(index)
}
function goBack() {
PageUtils.goBack()
}
</script>
<style lang="scss" scoped>
.card {
position: absolute;
width: 720px;
height: 1214px;
bottom: 0;
right: 0;
z-index: -1;
.info {
position: absolute;
top: 920px;
padding: 20px;
.tip {
font-size: 16px;
white-space: nowrap;
overflow: visible;
}
.detail {
font-size: 24px;
padding-left: 20px;
.name {
width: 140px;
}
.value {
width: 360px;
}
}
}
}
</style>
<template>
<view class="bg-white bg-max">
<view class="pd-40">
<view class="text-xxl pd-b-20 mg-l-10-m">
<van-icon name="arrow-left" @tap="goBack" />
</view>
<view v-show="state.step == 0">
<view class="text-xxl text-bold text-black pd-b-20">
{{ state.switch.reset ? '短信找回' : '找回密码' }}
</view>
<van-form class="transparent" @submit="onCheckCode">
<van-field :class="{ 'field-focus': state.focus == 'phone' }" ref="phoneField" v-model="state.params.phone"
placeholder="请输入手机号" type="digit" @focus="onFocus('phone')" @blur="onFocus('')" name="phone"
:clearable="!state.switch.reset" :disabled="state.switch.reset" clear-trigger="always">
<template #left-icon>
<van-icon class-prefix="icon" name="shoujihao" />
</template>
<template #right-icon v-if="!state.switch.reset">
<van-icon v-if="validPhone" color="#39b54a" name="checked" />
<van-icon v-else-if="state.params.phone.length == 11" color="#e54d42" name="clear" />
<van-icon v-else-if="state.params.phone.length > 0" color="#e54d42" name="warning" />
</template>
</van-field>
<van-field :class="{ 'field-focus': state.focus == 'robot' }" v-model="state.params.robot" ref="robotField"
autocomplete="off" placeholder="请输入图形校验码" @focus="onFocus('robot')" @blur="onFocus('')" clearable
clear-trigger="always">
<template #left-icon>
<van-icon class-prefix="icon" name="yanzhengma" />
</template>
<template #right-icon>
<van-image v-if="validPhone" height="75rpx" class="mg-v-25-m" @tap="onRobotCode"
:src="state.apiUrl + `/api/account/checkcode?type=2&phone=${state.params.phone}&t=${state.timestamp}`" />
</template>
</van-field>
<van-field :class="{ 'field-focus': state.focus == 'code' }" v-model="state.params.code" autocomplete="off"
placeholder="请输入手机验证码" type="digit" @focus="onFocus('code')" @blur="onFocus('')" clearable
clear-trigger="always" enterkeyhint="done">
<template #left-icon>
<van-icon name="envelop-o" />
</template>
<template #right-icon>
<van-button :disabled="!sendCodeOn" plain :color="sendCodeOn ? '#FE521F' : '#cccccc'" class="mg-l-20"
size="small" @tap="onSendCode" :loading="state.loading.sendCode">
{{ countDownStr > 0 ? `${countDownStr}s后重新发送` : '获取验证码' }}
</van-button>
</template>
</van-field>
<div class="pd-v-50">
<van-button :disabled="!checkCodeOn" native-type="submit" :loading="state.loading.checkCode" class="text-l"
:color="checkCodeOn ? 'linear-gradient(315deg, #FE521F 0%, #FE7902 100%)' : '#cccccc'" round block>
下一步
</van-button>
</div>
</van-form>
</view>
<view v-show="state.step == 1">
<view class="text-xxl text-bold text-black pd-b-20">重置密码</view>
<view class="text-ss pd-t-5 pd-b-30">
请输入正确格式(只可包含数字,英文和下划线),且长度为6-16位之间
</view>
<van-form class="transparent" @submit="onSetPwd">
<van-field :class="{ 'field-focus': state.focus == 'pwd' }" ref="pwdField" v-model="state.params.pwd"
autocomplete="off" clear-trigger="always" clearable placeholder="请输入新密码"
:type="state.showPwd ? 'text' : 'password'" @focus="onFocus('pwd')" @blur="onFocus('')">
<template #left-icon>
<van-icon class-prefix="icon" name="mima" />
</template>
<template #right-icon>
<van-icon class="mg-l-30" class-prefix="icon" @tap="onShowPwd"
:name="state.showPwd ? 'xianshimima' : 'yincangmima'" />
</template>
</van-field>
<van-field :class="{ 'field-focus': state.focus == 'rePwd' }" v-model="state.params.rePwd" autocomplete="off"
clear-trigger="always" clearable placeholder="请再次输入" :type="state.showRePwd ? 'text' : 'password'"
@focus="onFocus('rePwd')" @blur="onFocus('')">
<template #left-icon>
<van-icon class-prefix="icon" name="mima" />
</template>
<template #right-icon>
<view class="flex">
<template v-if="state.params.rePwd">
<van-icon v-if="validReRwd" color="#39b54a" name="checked" />
<van-icon v-else color="#e54d42" name="clear" />
</template>
<van-icon class="mg-l-30" class-prefix="icon" @tap="onShowRePwd"
:name="state.showRePwd ? 'xianshimima' : 'yincangmima'" />
</view>
</template>
</van-field>
<div class="pd-v-50">
<van-button :disabled="!setPwdOn" native-type="submit" :loading="state.loading.setPwd" type="primary" block
class="text-l" :color="setPwdOn ? 'linear-gradient(315deg, #FE521F 0%, #FE7902 100%)' : '#cccccc'" round>
下一步
</van-button>
</div>
</van-form>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { computed, reactive, onBeforeMount, onMounted, ref } from 'vue';
import { Toast } from 'vant';
import { useCountDown } from '@vant/use';
import md5 from 'md5';
import api from '@/api'
import { Dialog } from "vant";
import { PageUtils } from '@/utils/utils';
const state = reactive({
params: {
phone: '',
robot: '',
code: '',
pwd: '',
rePwd: '',
authCode: ''
},
timestamp: 0,
focus: '',
step: 0,
showKeyboard: false,
loading: {
sendCode: false,
checkCode: false,
setPwd: false
},
switch: {
reset: false
},
showPwd: false,
showRePwd: false,
apiUrl: uni.getStorageSync("uniEnv")?.api_url || ""
})
const phoneField: any = ref()
const robotField: any = ref()
const pwdField: any = ref()
const countDown = useCountDown({
time: 60 * 1000
});
const countDownStr = computed(() => {
return countDown.current.value.seconds
})
const validPhone = computed(() => {
state.timestamp = new Date().getTime()
return state.params.phone.length == 11 && /^1[3456789]\d{9}$/.test(state.params.phone)
})
const sendCodeOn = computed(() => {
return !!(countDownStr.value == 0 && state.params.phone.length == 11 && /^1[3456789]\d{9}$/.test(state.params.phone) && !state.loading.sendCode)
})
const checkCodeOn = computed(() => {
return !!(state.params.phone && state.params.robot && state.params.code)
})
const setPwdOn = computed(() => {
return !!(state.params.pwd == state.params.rePwd && state.params.pwd && state.params.rePwd)
})
const validReRwd = computed(() => {
return state.params.pwd == state.params.rePwd
})
onBeforeMount(() => {
const query: any = PageUtils.getCurQuery()
if (query.phone) state.params.phone = query.phone
if (query.reset) {
state.switch.reset = true
if (!state.params.phone) {
Dialog.alert({
title: '非法访问',
message: '请正常操作访问#3',
confirmButtonText: '返回首页'
}).then(() => {
uni.reLaunch({
url: '/'
})
})
return
}
}
})
onMounted(() => {
// 可能开发人员会直接,step = 1,所以我额外加了个判断
setTimeout(() => {
if (state.step == 0) {
if (state.params.phone) {
robotField.value && robotField.value.focus()
} else {
phoneField.value && phoneField.value.focus()
}
} else if (state.step == 1) {
pwdField.value && pwdField.value.focus()
}
})
})
function onFocus(focus: string) {
state.focus = focus
}
function onRobotCode() {
Toast.loading({
message: '加载中',
forbidClick: true,
});
state.timestamp = new Date().getTime()
}
function onSendCode() {
if (!state.params.robot) {
Toast('验证码不可为空')
return
}
if (state.loading.sendCode || !sendCodeOn) return
state.loading.sendCode = true
Toast.loading({
message: '加载中',
forbidClick: true,
});
api.authcode({
mobilePhone: state.params.phone,
checkCode: state.params.robot,
authType: 2
}).then((data: any) => {
state.params.code = ''
countDown.reset();
countDown.start();
}).finally(() => {
state.loading.sendCode = false
})
}
function onCheckCode() {
if (state.loading.checkCode) return
state.loading.checkCode = true
api.findPwd({
mobilePhone: state.params.phone,
checkCode: state.params.robot,
authCode: state.params.code
}).then((data: any) => {
state.params.authCode = data
state.step = 1
setTimeout(() => {
pwdField.value && pwdField.value.focus()
})
}).catch((data: any) => {
if (data === '账号不存在,请先注册') {
if (state.switch.reset) {
Dialog.alert({
title: '数据异常',
message: '当前用户手机不存在,请联系开发人员#01',
confirmButtonText: '返回首页'
}).then(() => {
uni.reLaunch({
url: '/'
})
})
} else {
Dialog.confirm({
message: '账号不存在,请先注册',
title: "提示",
cancelButtonText: '前往注册'
}).catch(() => {
// 减少用户二次填写
uni.navigateTo({
url: '/pages/login/register?phone=' + state.params.phone
})
});
}
}
}).finally(() => {
state.loading.checkCode = false
})
}
function onSetPwd() {
if (!/^[0-9a-zA-Z_]{6,16}$/.test(state.params.pwd)) {
Dialog.alert({
title: '提示',
message: '请输入正确格式(只可包含数字,英文和下划线),且长度为6-16位之间',
})
return
}
if (state.loading.setPwd) return
state.loading.setPwd = true
api.setPwd({
mobilePhone: state.params.phone,
newPwd: state.params.pwd,
confirmPwd: state.params.rePwd,
authCode: state.params.authCode
}).then(() => {
Toast.success('设置成功');
goBack()
}).finally(() => {
state.loading.setPwd = false
})
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function onShowPwd() {
state.showPwd = !state.showPwd
}
function onShowRePwd() {
state.showRePwd = !state.showRePwd
}
function goBack() {
if (state.switch.reset) {
PageUtils.goBack()
} else {
goto('/pages/login/login')
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<view class="login-bg">
<img @click="gotoU" src="../../static/right_rule.png" style="position: fixed;right: 0;top: 70%;z-index: 99" alt="">
<view class="pd-40">
<view class="text-xxl pd-b-20 mg-l-10-m">
<van-icon name="arrow-left" @tap="goto('/')" />
</view>
<van-image width="214rpx" src="/static/img/logo.png" />
<view class="text-xxl text-bold pd-v-45">你好,欢迎使用E淘商城。</view>
<van-form class="transparent" @submit="onSubmit">
<van-field :class="{ 'field-focus': state.focus == 'phone' }" v-model="state.params.phone" placeholder="请输入手机号"
type="digit" clearable @focus="onFocus('phone')" @blur="onFocus('')" clear-trigger="always" name="phone" autocomplete="on">
<template #left-icon>
<van-icon class-prefix="icon" name="shoujihao" />
</template>
</van-field>
<van-field :class="{ 'field-focus': state.focus == 'pwd' }" v-model="state.params.pwd" clearable
autocomplete="off" clear-trigger="always" placeholder="请输入密码" :type="state.showPwd ? 'text' : 'password'"
@focus="onFocus('pwd')" @blur="onFocus('')">
<template #left-icon>
<van-icon class-prefix="icon" name="mima" />
</template>
<template #right-icon>
<van-icon class="mg-l-30" class-prefix="icon" :name="state.showPwd ? 'xianshimima' : 'yincangmima'"
@tap="onShowPwd" />
</template>
</van-field>
<view class="justify-between pd-t-40 text-ss text-darkGray">
<view class="">
还没有账号? 立即
<text class="text-orange" @tap="goto('/pages/login/register')">注册</text>
</view>
<view class="" @tap="goto('/pages/login/forget?phone=' + state.params.phone)">忘记密码?</view>
</view>
<div class="pd-v-50">
<van-button :disabled="!loginOn" native-type="submit" class="text-l" :loading="state.loading.login"
:color="loginOn ? 'linear-gradient(315deg, #FE521F 0%, #FE7902 100%)' : '#cccccc'" round block>
登录
</van-button>
</div>
<view class="justify-between text-ss">
<van-checkbox class="" icon-size="17px" v-model="state.read">
<view class=" text-darkGray">
阅读并同意
<text class="text-orange" @tap="goto('/pages/login/policy')">《隐私协议》</text>
<text class="text-orange" @tap="goto('/pages/login/service')">《服务协议》</text>
</view>
</van-checkbox>
<van-checkbox v-if="state.switch.store" class="scale-9 scale-rt" icon-size="17px" v-model="state.store">
<text class=" text-darkGray">记住密码</text>
</van-checkbox>
</view>
</van-form>
<div v-if="state.hideshow" style="text-align: center;position: absolute;bottom: 10px;width: 100%;left: 0;" @click="gotoU">
<img style="width: 20px;height: 20px;vertical-align: sub;margin-right: 10px" src="../../static/favicon.ico" alt=""><span style="color: #666666">E淘提供技术支持</span>
</div>
</view>
</view>
</template>
<script setup lang="ts">
import api from '@/api';
import { computed, onBeforeMount, onMounted, reactive,watch } from 'vue';
import md5 from 'md5';
import { PageUtils } from '@/utils/utils'
import { Toast } from 'vant'
const state = reactive({
docmHeight: document.documentElement.clientHeight, //默认屏幕高度
showHeight: document.documentElement.clientHeight, //实时屏幕高度
hideshow:true, //显示或者隐藏footer
params: {
phone: '',
pwd: '',
},
showPwd: false,
focus: '',
read: false,
store: false,
loading: {
login: false,
},
redirect: undefined,
switch: {
store: false,
}
})
const loginOn = computed(() => {
return !!(state.params.phone && state.params.pwd)
})
watch([() => state.showHeight], (newValue, oldValue) => {
if (state.docmHeight > state.showHeight) {
state.hideshow = false
} else {
state.hideshow = true
}
})
onBeforeMount(() => {
window.onresize = ()=>{
return(()=>{
state.showHeight = document.body.clientHeight;
})()
}
const query: any = PageUtils.getCurQuery()
state.redirect = query.redirect
uni.removeStorageSync('user');
const storage: any = uni.getStorageSync('login') || {};
state.store = storage.store || false
state.params.phone = storage.phone || ''
state.params.pwd = storage.pwd || ''
})
// 因为登录页不一定是直接登录,所以不自动弹起
function onSubmit() {
if (!state.read) {
Toast('请阅读并同意协议')
return
}
if (state.loading.login) return
state.loading.login = true
api.login({
mobilePhone: state.params.phone,
password: state.params.pwd
}).then((data: any) => {
uni.setStorageSync('login', {
store: state.store,
phone: state.store ? state.params.phone : '',
pwd: state.store ? state.params.pwd : '',
})
uni.setStorageSync('user', data)
uni.reLaunch({ url: state.redirect || '/' })
}).finally(() => {
state.loading.login = false
})
}
function gotoU() {
uni.redirectTo({
url: "/pages/my/technicalSupport?name=login",
});
}
function onFocus(focus: string) {
state.focus = focus
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function onShowPwd() {
state.showPwd = !state.showPwd
}
</script>
<style lang="scss" scoped>
.login-bg {
background: url('@/static/img/login_bg.png') no-repeat;
background-size: 100% auto;
background-color: #ffffff;
height: 100vh;
}
</style>
<template>
<web-view src="https://img.edsmall.com/ROOT/ETao/resource/policy.html" />
</template>
\ No newline at end of file
<template>
<view class="bg-white bg-max">
<view class="pd-40">
<view class="text-xxl pd-b-20 mg-l-10-m">
<van-icon name="arrow-left" @tap="goto('/pages/login/login')" />
</view>
<view v-show="state.step == 0">
<view class="text-xxl text-bold text-black pd-b-20">注册</view>
<van-form class="transparent" @submit="onCheckCode">
<van-field :class="{ 'field-focus': state.focus == 'phone' }" ref="phoneField" v-model="state.params.phone"
name="phone" placeholder="请输入手机号" type="digit" @focus="onFocus('phone')" @blur="onFocus('')" clearable
clear-trigger="always">
<template #left-icon>
<van-icon class-prefix="icon" name="shoujihao" />
</template>
<template #right-icon>
<van-icon v-if="validPhone" color="#39b54a" name="checked" />
<van-icon v-else-if="state.params.phone.length == 11" color="#e54d42" name="clear" />
<van-icon v-else-if="state.params.phone.length > 0" color="#e54d42" name="warning" />
</template>
</van-field>
<van-field :class="{ 'field-focus': state.focus == 'robot' }" ref="robotField" v-model="state.params.robot"
autocomplete="off" placeholder="请输入图形校验码" @focus="onFocus('robot')" @blur="() => { onFocus(''); }" clearable
clear-trigger="always">
<template #left-icon>
<van-icon class-prefix="icon" name="yanzhengma" />
</template>
<template #right-icon>
<van-image v-if="validPhone" height="75rpx" class="mg-v-25-m mg-l-20" @tap="onRobotCode"
:src="state.apiUrl + `/api/account/checkcode?type=1&phone=${state.params.phone}&t=${state.timestamp}`" />
</template>
</van-field>
<van-field :class="{ 'field-focus': state.focus == 'code' }" v-model="state.params.code" autocomplete="off"
placeholder="请输入手机验证码" type="digit" @focus="onFocus('code')" @blur="onFocus('')" clearable
clear-trigger="always">
<template #left-icon>
<van-icon name="envelop-o" />
</template>
<template #right-icon>
<van-button :disabled="!sendCodeOn" plain :color="sendCodeOn ? '#FE521F' : '#cccccc'" class="mg-l-20"
size="small" @tap="onSendCode" :loading="state.loading.sendCode">
{{ countDownStr > 0 ? `${countDownStr}s后重新发送` : '获取验证码' }}
</van-button>
</template>
</van-field>
<div class="pd-v-50">
<van-button :disabled="!checkCodeOn" native-type="submit" :loading="state.loading.checkCode" class="text-l"
:color="checkCodeOn ? 'linear-gradient(315deg, #FE521F 0%, #FE7902 100%)' : '#cccccc'" round block>
下一步
</van-button>
</div>
</van-form>
</view>
<view v-show="state.step == 1">
<view class="text-xxl text-bold text-black pd-b-20">设置密码</view>
<view class="text-ss pd-t-5 pd-b-30">
请输入正确格式(只可包含数字,英文和下划线),且长度为6-16位之间
</view>
<van-form class="transparent" @submit="onSetPwd">
<van-field :class="{ 'field-focus': state.focus == 'pwd' }" ref="pwdField" v-model="state.params.pwd"
autocomplete="off" clear-trigger="always" clearable placeholder="请输入新密码"
:type="state.showPwd ? 'text' : 'password'" @focus="onFocus('pwd')" @blur="onFocus('')">
<template #left-icon>
<van-icon class-prefix="icon" name="mima" />
</template>
<template #right-icon>
<van-icon class="mg-l-30" class-prefix="icon" @tap="onShowPwd"
:name="state.showPwd ? 'xianshimima' : 'yincangmima'" />
</template>
</van-field>
<van-field :class="{ 'field-focus': state.focus == 'rePwd' }" v-model="state.params.rePwd" autocomplete="off"
clear-trigger="always" clearable placeholder="请再次输入" :type="state.showRePwd ? 'text' : 'password'"
@focus="onFocus('rePwd')" @blur="onFocus('')">
<template #left-icon>
<van-icon class-prefix="icon" name="mima" />
</template>
<template #right-icon>
<view class="flex">
<template v-if="state.params.rePwd">
<van-icon v-if="validReRwd" color="#39b54a" name="checked" />
<van-icon v-else color="#e54d42" name="clear" />
</template>
<van-icon class="mg-l-30" class-prefix="icon" @tap="onShowRePwd"
:name="state.showRePwd ? 'xianshimima' : 'yincangmima'" />
</view>
</template>
</van-field>
<div class="pd-v-50">
<van-button :disabled="!setPwdOn" native-type="submit" :loading="state.loading.setPwd" class="text-l"
:color="setPwdOn ? 'linear-gradient(315deg, #FE521F 0%, #FE7902 100%)' : '#cccccc'" round block>
下一步
</van-button>
</div>
</van-form>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { computed, reactive, ref, onMounted, onBeforeMount } from 'vue';
import { Toast } from 'vant';
import { useCountDown } from '@vant/use';
import md5 from 'md5';
import api from '@/api'
import { Dialog } from "vant";
import { PageUtils } from '@/utils/utils'
const state = reactive({
params: {
phone: '',
robot: '',
code: '',
pwd: '',
rePwd: '',
authCode: ''
},
timestamp: 0,
focus: '',
step: 0,
showKeyboard: false,
loading: {
sendCode: false,
checkCode: false,
setPwd: false
},
showPwd: false,
showRePwd: false,
apiUrl: uni.getStorageSync("uniEnv")?.api_url || ""
})
const phoneField: any = ref()
const robotField: any = ref()
const pwdField: any = ref()
const countDown = useCountDown({
time: 60 * 1000
});
const countDownStr = computed(() => {
return countDown.current.value.seconds
})
const validPhone = computed(() => {
state.timestamp = new Date().getTime()
return state.params.phone.length == 11 && /^1[3456789]\d{9}$/.test(state.params.phone)
})
const sendCodeOn = computed(() => {
return !!(countDownStr.value == 0 && state.params.phone.length == 11 && /^1[3456789]\d{9}$/.test(state.params.phone) && !state.loading.sendCode)
})
const checkCodeOn = computed(() => {
return !!(state.params.phone && state.params.robot && state.params.code)
})
const setPwdOn = computed(() => {
return !!(state.params.pwd == state.params.rePwd && state.params.pwd && state.params.rePwd)
})
const validReRwd = computed(() => {
return state.params.pwd == state.params.rePwd
})
onBeforeMount(() => {
const query: any = PageUtils.getCurQuery()
// 从忘记密码那边过来,可能会带上phone参数
if (query.phone) state.params.phone = query.phone
})
onMounted(() => {
// 可能开发人员会直接,step = 1,所以我额外加了个判断
setTimeout(() => {
if (state.step == 0) {
if (state.params.phone) {
robotField.value && robotField.value.focus()
} else {
phoneField.value && phoneField.value.focus()
}
} else if (state.step == 1) {
pwdField.value && pwdField.value.focus()
}
})
})
function onFocus(focus: string) {
state.focus = focus
}
function onRobotCode() {
Toast.loading({
message: '加载中',
forbidClick: true,
});
state.timestamp = new Date().getTime()
}
function onSendCode() {
if (!state.params.robot) {
Toast('验证码不可为空')
return
}
if (state.loading.sendCode || !sendCodeOn) return
state.loading.sendCode = true
Toast.loading({
message: '加载中',
forbidClick: true,
});
api.authcode({
mobilePhone: state.params.phone,
checkCode: state.params.robot,
authType: 1
}).then((data: any) => {
state.params.code = ''
countDown.reset();
countDown.start();
}).finally(() => {
state.loading.sendCode = false
})
}
function onCheckCode() {
if (state.loading.checkCode) return
state.loading.checkCode = true
api.signup({
mobilePhone: state.params.phone,
checkCode: state.params.robot,
authCode: state.params.code
}).then((data: any) => {
state.params.authCode = data
state.step = 1
setTimeout(() => {
pwdField.value && pwdField.value.focus()
})
}).catch((data: any) => {
if (data === '该手机号已经被注册了') {
Dialog.confirm({
message: '该手机号已经被注册了',
title: "提示",
cancelButtonText: '返回登录页'
}).catch(() => {
uni.navigateTo({
url: '/pages/login/login'
})
});
}
}).finally(() => {
state.loading.checkCode = false
})
}
function onSetPwd() {
if (!/^[0-9a-zA-Z_]{6,16}$/.test(state.params.pwd)) {
Dialog.alert({
title: '提示',
message: '请输入正确格式(只可包含数字,英文和下划线),且长度为6-16位之间',
})
return
}
if (state.loading.setPwd) return
state.loading.setPwd = true
api.setPwd({
mobilePhone: state.params.phone,
newPwd: state.params.pwd,
confirmPwd: state.params.rePwd,
authCode: state.params.authCode
}).then(() => {
Toast.success('注册成功');
uni.reLaunch({
url: '/pages/login/login'
})
}).finally(() => {
state.loading.setPwd = false
})
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function onShowPwd() {
state.showPwd = !state.showPwd
}
function onShowRePwd() {
state.showRePwd = !state.showRePwd
}
</script>
<style lang="scss" scoped>
</style>
<template>
<web-view src="https://img.edsmall.com/ROOT/ETao/resource/service.html" />
</template>
\ No newline at end of file
// 这个既是组件,也是页面
<template>
<view>
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view class="top-center">{{ state.title }}</view>
<view class="top-right">
<view class="text-m" @tap="onAdd">新增地址</view>
</view>
</view>
</van-sticky>
<van-list :loading="state.loading" :finished="state.finished" finished-text="" offset="10" @load="receiveList">
<van-pull-refresh v-model="state.refresh" @refresh="onReflesh">
<van-radio-group v-if="state.list.length > 0" v-model="state.selected" style="min-height: calc(100vh - 100px)">
<van-cell-group v-for="item in state.list">
<van-cell class="pd-l-0">
<template #title>
<view class="flex" style="width: 80vw">
<view class="justify-center" style="width: 40px">
<van-radio v-if="state.switch.isComponent" icon-size="17px" :name="item.addrId"
@tap="onAddressChange(item)" />
</view>
<view>
<view class="text-gray justify-middle">
<van-tag class="mg-r-10" type="primary" v-if="item.isDefault == 1">默认</van-tag>
{{ item.region }}
</view>
<view class="text-bold text-l">{{ item.detailAddress }}</view>
<view class="text-darkGray">
<text class="pd-r-20">{{ item.receiverName }}</text>
<text>{{ item.phone }}</text>
</view>
</view>
</view>
</template>
<template #right-icon>
<view class="justify-middle text-darkGray text-xl">
<van-icon class="pd-r-40" name="delete-o" @tap="receiveDel(item.addrId)" />
<van-icon name="edit" @tap="onEdit(item)" />
</view>
</template>
</van-cell>
</van-cell-group>
</van-radio-group>
<view v-else class="justify-center" style="min-height: calc(100vh - 180px)">
<van-empty description="您当前还没有收货地址" />
<van-button class="text-l" color="linear-gradient(315deg, #FE521F 0%, #FE7902 100%)" round block
style="width: 240rpx" @tap="onAdd">
新增地址
</van-button>
</view>
</van-pull-refresh>
</van-list>
<view v-if="state.fail && state.list > 0" class="text-ss text-gray pd-50 text-center" @tap="failReset">请求失败,点击重试
<van-icon name="replay" />
</view>
<to-top />
<!-- 因为只有这里用到,就不抽组件了 -->
<van-popup v-model:show="state.edit.show" position="right" class="bg-gray"
:style="{ width: '100%', height: '100%' }">
<van-sticky>
<view class="top-bar justify-center bg-white sh mg-b-20">
<van-icon class="top-left" name="arrow-left" @tap="state.edit.show = false" />
<view class="top-center">{{ state.edit.params.addrId ? '修改地址' : '新增地址' }}</view>
</view>
</van-sticky>
<van-form>
<van-cell-group class="pd-h-5 mg-b-15">
<van-field ref="nameField" v-model="state.edit.params.receiverName" maxlength="100" label="收货人" name="name"
placeholder="收货人姓名" />
<van-field v-model="state.edit.params.phone" type="digit" label="手机号码" name="phone" placeholder="手机号码"
clear-trigger="always" clearable>
<template #right-icon>
<van-icon v-if="validPhone" color="#39b54a" name="checked" />
<van-icon v-else-if="state.edit.params.phone.length == 11" color="#e54d42" name="clear" />
<van-icon v-else-if="state.edit.params.phone.length > 0" color="#e54d42" name="warning" />
</template>
</van-field>
<van-field v-model="state.edit.params.region" right-icon="arrow" placeholder="所在省市区" @tap="onAddress"
disabled>
<template #label>
<view class="text-darkGray">所在地区</view>
</template>
</van-field>
<van-field v-model="state.edit.params.detailAddress" maxlength="255" label="详细地址" name="address"
placeholder="街道门牌等详细信息" enterkeyhint="done" />
</van-cell-group>
<van-cell-group class="pd-h-5 mg-b-15">
<van-cell center title="设置为默认地址">
<template #right-icon>
<van-switch v-model="state.edit.params.isDefault" size="18" :active-value="1" :inactive-value="0" />
</template>
</van-cell>
</van-cell-group>
<div class="pd-50">
<!-- 因为最后一个是switch,所以我不想native-type="submit" -->
<van-button :disabled="!checkSaveOn" @tap="onSave" :loading="state.loading" class="text-l"
:color="checkSaveOn ? 'linear-gradient(315deg, #FE521F 0%, #FE7902 100%)' : '#cccccc'" round block>
保存
</van-button>
</div>
</van-form>
<van-popup v-model:show="state.popup.region.show" round position="bottom">
<van-picker title="所在地区" :columns="state.popup.region.options" :columns-field-names="state.popup.region.struct"
@confirm="onRegionChange" @cancel="state.popup.region.show = false" />
</van-popup>
</van-popup>
</view>
</template>
<script setup lang="ts">
import api from '@/api'
import { computed, onBeforeMount, reactive, ref } from 'vue';
import toTop from '@/components/tool/toTop.vue';
import { PageUtils } from '@/utils/utils';
import { Dialog, Toast } from 'vant';
interface Props {
addrId?: string;
}
const props = withDefaults(defineProps<Props>(), {
addrId: '',
});
const state = reactive({
title: PageUtils.getTitle(),
list: [] as any,
selected: '',
edit: {
show: false,
params: {
addrId: undefined,
receiverName: '',
phone: '',
regionNo: '',
region: '',
detailAddress: '',
isDefault: 0
}
},
refresh: false,
loading: false,
fail: false,
finished: false,
loadingSon: {
edit: false
},
receive: {
page: 0
},
popup: {
region: {
show: false,
options: [] as any,
struct: { text: 'name', values: 'id', children: 'arealist' }
}
},
switch: {
isComponent: false
}
})
const nameField: any = ref()
const emit = defineEmits(["change", "cancel"]);
const validPhone = computed(() => {
return state.edit.params.phone.length == 11 && /^1[3456789]\d{9}$/.test(state.edit.params.phone)
})
const checkSaveOn = computed(() => {
return validPhone.value && state.edit.params.receiverName && state.edit.params.region && state.edit.params.detailAddress
})
onBeforeMount(() => {
if (PageUtils.getTitle(true) != '收货地址') {
state.switch.isComponent = true
}
receiveArea()
receiveList()
})
function receiveList() {
if (state.loading || state.fail) return
state.loading = true
state.receive.page += 1
api.receiveList({ pageNum: state.receive.page }).then((data: any) => {
if (!data||!data.hasNextPage){
state.finished = true
}
state.list.push(...data.list)
})
.catch(() => {
state.fail = true
}).finally(() => {
state.refresh = false
state.loading = false
})
}
function onAddressChange(item: any) {
emit("change", item);
}
function goBack() {
if (state.switch.isComponent) {
emit("cancel");
} else {
PageUtils.goBack()
}
}
function onAdd() {
state.edit.params = {
addrId: undefined,
receiverName: '',
phone: '',
regionNo: '',
region: '',
detailAddress: '',
isDefault: 0
}
state.edit.show = true
// 只有新增地址时才自动弹起,因为编辑不一定重头全改
setTimeout(() => {
nameField.value && nameField.value.focus()
})
}
function onAddress() {
state.popup.region.show = true
}
function onRegionChange(list: any) {
state.edit.params.regionNo = list.map((item: any) => item.id).join(',')
state.edit.params.region = list.map((item: any) => item.name).join(' ')
state.popup.region.show = false
}
function receiveArea() {
api.receiveArea().then((data: any) => {
leavesAddProp(data, 'arealist')
state.popup.region.options = data
})
}
// vant-Bug-picker最后一层也需要"children"
function leavesAddProp(list: Array<any>, name: string) {
list.forEach((item: any) => {
if (item[name]) {
leavesAddProp(item[name], name)
} else {
item[name] = null
}
})
}
function onSave() {
if (state.loadingSon.edit) return
state.loadingSon.edit = true
if (state.edit.params.addrId) {
api.receiveEdit(state.edit.params).then(() => {
Toast.success('修改成功')
state.edit.show = false
onReflesh()
}).finally(() => {
state.loadingSon.edit = false
})
} else {
api.receiveAdd(state.edit.params).then(() => {
Toast.success('新增成功')
state.edit.show = false
onReflesh()
}).finally(() => {
state.loadingSon.edit = false
})
}
}
function receiveDel(addrId: string) {
Dialog.confirm({
message: '是否删除该地址',
title: "提示",
}).then(() => {
if (state.loading) return
state.loading = true
api.receiveDel({ addrId }).then(() => {
state.loading = false
onReflesh()
}).catch(() => {
state.loading = false
})
});
}
function onEdit(item: any) {
state.edit.params = {
addrId: item.addrId,
receiverName: item.receiverName,
phone: item.phone,
regionNo: item.regionNo,
region: item.region,
detailAddress: item.detailAddress,
isDefault: item.isDefault
}
state.edit.show = true
}
function onReflesh() {
state.list = []
state.receive.page = 0
state.finished = false
receiveList()
}
function failReset() {
state.receive.page -= 1
state.fail = false
receiveList()
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div>
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view>
<view class="text-m" style="font-size: 16px">证照信息</view>
</view>
</view>
</van-sticky>
<div style="text-align: center;margin-top: 150px">
<img v-if="mail.licensePath" style="width:60vw;height: 60vw;" :src="mail.licensePath" alt="加载失败">
<img v-else style="width:60vw;height: 60vw;" src="../../static/img/certificates_none.png" alt="加载失败">
<p v-if="!mail.licensePath" style="color: #666666 ">暂无任相关信息~</p>
</div>
<div style="text-align: center;position: absolute;bottom: 10px;width: 100%">
<img @click="gotoU" style="width: 20px;height: 20px;vertical-align: sub;margin-right: 10px" src="../../static/favicon.ico" alt=""><span style="color: #666666">E淘提供技术支持</span>
<p @click="gotoU" style="margin-top: 10px"><span style="color: #666666">资质与规则</span></p>
</div>
</div>
</template>
<script>
export default {
name: "certificate",
data(){
return{
mail:{},
}
},
methods: {
goBack() {
uni.redirectTo({
url: "/pages/good/contact",
});
},
gotoU(){
uni.redirectTo({
url: "/pages/my/technicalSupport?name=contact",
});
},
},
mounted(){
this.mail = uni.getStorageSync('mail')||{}
},
};
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<view class="pd-b-px-55">
<van-sticky>
<view class="top-bar justify-center bg-white sh mg-b-20">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view class="top-center">{{ state.title }}</view>
</view>
</van-sticky>
<van-cell-group class="pd-h-5 mg-b-15">
<van-cell class="pd-t-px-10 pd-b-px-0" :border="false">
<template #title>
<van-uploader class="round" v-model="state.headList" preview-size="60" :max-size="1024 * 1024 * 10"
:after-read="upload" max-count="1">
<template #default v-if="state.data.userHeadImage">
<van-image fit="cover" width="60px" height="60px" round :src="state.data.userHeadImage" />
</template>
</van-uploader>
</template>
</van-cell>
<van-cell is-link @tap="onEdit('真实姓名', 'userName', state.data.userName, 10)">
<template #title>
<text class="text-black">真实姓名</text>
</template>
<template #right-icon>
<view class="text-darkGray">
<view class="cell_value">{{ state.data.userName }}</view>
<van-icon name="arrow" class="pd-l-10" />
</view>
</template>
</van-cell>
<van-cell is-link @tap="onSex">
<template #title>
<text class="text-black">性别</text>
</template>
<template #right-icon>
<view class="text-darkGray">{{ Enum.get('userSex', state.data.userSex) }}
<van-icon name="arrow" class="pd-l-10" />
</view>
</template>
</van-cell>
</van-cell-group>
<van-cell-group class="pd-h-5">
<van-cell>
<template #title>
<text class="text-black">手机</text>
</template>
<template #right-icon>
<view class="text-darkGray">{{ state.data.userPhone }}</view>
</template>
</van-cell>
<van-cell is-link @tap="onEdit('邮箱', 'userEmail', state.data.userEmail, '25')">
<template #title>
<text class="text-black">邮箱</text>
</template>
<template #right-icon>
<view class="text-darkGray">
<view class="cell_value">{{ state.data.userEmail || '未绑定' }}</view>
<van-icon name="arrow" class="pd-l-10" />
</view>
</template>
</van-cell>
<van-cell is-link @tap="onChangePwd">
<template #title>
<text class="text-black">修改密码</text>
</template>
<template #right-icon>
<view class="text-darkGray">
<van-icon name="arrow" class="pd-l-10" />
</view>
</template>
</van-cell>
</van-cell-group>
<div class="pd-50">
<van-button class="text-l" :loading="state.loading.logout" @tap="logout"
color="linear-gradient(315deg, #FE521F 0%, #FE7902 100%)" round block>
退出登录
</van-button>
<div style="text-align: center;position: absolute;bottom: 10px;width: 100%;left: 0" @click="gotoU">
<img style="width: 20px;height: 20px;vertical-align: sub;margin-right: 10px" src="../../static/favicon.ico" alt=""><span style="color: #666666">E淘提供技术支持</span>
</div>
</div>
<!-- 通用改单个数据的dialog -->
<van-form @submit="onEditChange" class="round">
<van-dialog class="withBg pd-b-px-70" v-model:show="state.dialog.edit.show" theme="round-button" width="264px">
<template #title>
<view class="pd-h-px-20">
<view class="mg-t-px-10-m text-bold">{{ '设置' + state.dialog.edit.title }}</view>
<view class="text-gray text-s" style="min-height: 20px;"></view>
</view>
</template>
<view class="pd-h-px-20 pd-v-px-10">
<van-field ref="editField" v-model="state.dialog.edit.value" :class="{ 'field-focus': state.focus == 'edit' }"
:placeholder="'请输入' + state.dialog.edit.title" @focus="onFocus('edit')" @blur="onFocus('')" clearable
clear-trigger="always" :maxlength="state.dialog.edit.len" enterkeyhint="done" autocomplete="off" />
</view>
<template #footer>
<van-action-bar class="pd-h-px-15 pd-b-px-15">
<van-action-bar-button type="warning" text="取消" @tap="state.dialog.edit.show = false" />
<van-action-bar-button type="danger" text="保存" native-type="submit" />
</van-action-bar>
</template>
</van-dialog>
</van-form>
<van-form @submit="alterPassword" class="round">
<van-dialog class="withBg pd-b-px-70" v-model:show="state.dialog.pwd.show" theme="round-button" width="320px">
<template #title>
<view class="pd-h-px-20">
<view class="mg-t-px-10-m text-bold">修改密码</view>
<view class="text-gray text-s" style="min-height: 20px;">
忘记当前密码?
<text class="text-orange" @tap="onForget">短信找回</text>
</view>
</view>
</template>
<view class="pd-h-px-20 pd-v-px-10">
<van-field v-model="state.dialog.pwd.originPwd" class="mg-b-30" autocomplete="off" ref="pwdField"
:class="{ 'field-focus': state.focus == 'originPwd' }" placeholder="请输入当前密码" @focus="onFocus('originPwd')"
@blur="onFocus('')" :type="state.dialog.pwd.showOriginPwd ? 'text' : 'password'" clearable
clear-trigger="always">
<template #right-icon>
<view class="flex">
<van-icon class="mg-l-5" class-prefix="icon"
@tap="state.dialog.pwd.showOriginPwd = !state.dialog.pwd.showOriginPwd"
:name="state.dialog.pwd.showOriginPwd ? 'xianshimima' : 'yincangmima'" />
</view>
</template>
</van-field>
<van-field v-model="state.dialog.pwd.pwd" class="mg-b-30" :class="{ 'field-focus': state.focus == 'pwd' }"
placeholder="请确认新密码" @focus="onFocus('pwd')" @blur="onFocus('')" autocomplete="off"
:type="state.dialog.pwd.showPwd ? 'text' : 'password'" clearable clear-trigger="always">
<template #right-icon>
<view class="flex">
<van-icon class="mg-l-5" class-prefix="icon" @tap="state.dialog.pwd.showPwd = !state.dialog.pwd.showPwd"
:name="state.dialog.pwd.showPwd ? 'xianshimima' : 'yincangmima'" />
</view>
</template>
</van-field>
<van-field v-model="state.dialog.pwd.rePwd" :class="{ 'field-focus': state.focus == 'rePwd' }"
placeholder="请再次输入新密码" @focus="onFocus('rePwd')" @blur="onFocus('')" autocomplete="off"
:type="state.dialog.pwd.showRePwd ? 'text' : 'password'" clearable clear-trigger="always">
<template #right-icon>
<view class="flex">
<template v-if="state.dialog.pwd.rePwd">
<van-icon v-if="validReRwd" color="#39b54a" name="checked" />
<van-icon v-else color="#e54d42" name="clear" />
</template>
<van-icon class="mg-l-20" class-prefix="icon"
@tap="state.dialog.pwd.showRePwd = !state.dialog.pwd.showRePwd"
:name="state.dialog.pwd.showRePwd ? 'xianshimima' : 'yincangmima'" />
</view>
</template>
</van-field>
</view>
<template #footer>
<van-action-bar class="pd-h-px-15 pd-b-px-15">
<van-action-bar-button type="warning" text="取消" @tap="state.dialog.pwd.show = false" />
<van-action-bar-button type="danger" text="修改" native-type="submit" />
</van-action-bar>
</template>
</van-dialog>
</van-form>
<van-popup v-model:show="state.popup.sex.show" round position="bottom">
<van-picker title="性别" :columns="final.sexOptions" :default-index="state.popup.sex.default"
@confirm="onSexChange" />
</van-popup>
</view>
</template>
<script setup lang="ts">
import { computed, onBeforeMount, reactive, ref } from "vue";
import { Dialog, Toast } from 'vant';
import api from "@/api";
import { Enum, PageUtils } from '@/utils/utils';
import md5 from 'md5';
const state = reactive({
title: PageUtils.getTitle(),
phone: '',
data: {} as any,
headList: [] as any,
dialog: {
edit: {
show: false,
title: '',
name: '',
value: '',
len: ''
},
pwd: {
show: false,
originPwd: '',
pwd: '',
rePwd: '',
showOriginPwd: false,
showPwd: false,
showRePwd: false
},
},
popup: {
sex: {
show: false,
default: 0
}
},
focus: '',
loading: {
edit: false,
sex: false,
pwd: false,
logout: false
}
});
const final = {
sexOptions: [
{ text: '男', values: '1', children: null },
{ text: '女', values: '0', children: null }
]
}
const editField: any = ref()
const pwdField: any = ref()
const validReRwd = computed(() => {
return state.dialog.pwd.pwd == state.dialog.pwd.rePwd
})
onBeforeMount(() => {
const user: any = uni.getStorageSync('user') || { account: undefined }
if (user.token) {
state.phone = user.account
if (!state.phone) {
Dialog.alert({
title: '数据异常',
message: '当前用户缺少手机信息,请联系开发人员#021',
confirmButtonText: '返回首页'
}).then(() => {
uni.reLaunch({
url: '/'
})
})
return
}
accountInfo()
} else {
Dialog.confirm({
message: '您尚未登录,请前往登录',
title: "提示",
cancelButtonText: '返回首页'
}).then(() => {
uni.reLaunch({
url: '/pages/login/login'
})
}).catch(() => {
uni.reLaunch({
url: '/'
})
});
}
})
function gotoU() {
uni.redirectTo({
url: "/pages/my/technicalSupport?name=detail",
});
}
function goBack() {
PageUtils.goBack()
}
function accountInfo() {
api.accountInfo({ phone: state.phone }).then((data: any) => {
state.data = data
})
}
function onEdit(title: string, name: string, value: any, len?: any) {
state.dialog.edit.title = title
state.dialog.edit.name = name
state.dialog.edit.len = len || ''
state.dialog.edit.show = true
setTimeout(() => {
editField.value && editField.value.focus()
state.dialog.edit.value = value
})
}
function onFocus(focus: string) {
state.focus = focus
}
function onSex() {
const index = final.sexOptions.findIndex((item: any) => item.values == state.data.userSex)
state.popup.sex.default = index || 0
state.popup.sex.show = true
}
function onSexChange(list: Array<any>) {
if (state.loading.sex) return
state.loading.sex = true
api.setSex({
mobilePhone: state.phone,
sex: list[0].values
}).then(() => {
state.popup.sex.show = false
state.data.userSex = list[0].values
Toast.success('保存成功')
}).finally(() => {
state.loading.sex = false
})
}
function onEditChange() {
if (state.loading.edit) return
state.loading.edit = true
if (state.dialog.edit.name == 'userName') {
if (state.dialog.edit.value == '') {
Toast('请输入真实姓名')
state.loading.edit = false
return
}
api.bindName({
mobilePhone: state.phone,
name: state.dialog.edit.value
}).then(() => {
state.dialog.edit.show = false
state.data.userName = state.dialog.edit.value
Toast.success('保存成功')
}).finally(() => {
state.loading.edit = false
})
} else if (state.dialog.edit.name == 'userEmail') {
if (!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(state.dialog.edit.value)) {
Toast('请正确输入邮箱')
state.loading.edit = false
return
}
api.bindEmail({
mobilePhone: state.phone,
email: state.dialog.edit.value
}).then(() => {
state.dialog.edit.show = false
state.data.userEmail = state.dialog.edit.value
Toast.success('保存成功')
}).finally(() => {
state.loading.edit = false
})
} else {
console.error('请开发人员补充onEditChange中的逻辑')
state.loading.edit = false
}
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function upload(e: any) {
e.status = 'uploading'
e.message = '上传中...'
api.upload(e.file).then((data: any) => {
api.setHeadImage({
mobilePhone: state.phone,
headImage: data
}).then(() => {
// #1: 与下面注释#2一同使用
state.data.userHeadImage = data
e.status = 'done'
}).catch(() => {
Toast('修改头像失败')
})
}).catch(() => {
Toast('上传头像失败')
}).finally(() => {
// #2你删掉下面这句话就能知道,为什么我要加
state.headList = []
})
}
function onChangePwd() {
state.dialog.pwd = {
show: true,
originPwd: '',
pwd: '',
rePwd: '',
showOriginPwd: false,
showPwd: false,
showRePwd: false
}
setTimeout(() => {
pwdField.value && pwdField.value.focus()
})
}
function alterPassword() {
if (!/^[0-9a-zA-Z_]{6,16}$/.test(state.dialog.pwd.pwd)) {
Dialog.alert({
title: '提示',
message: '请输入正确格式(只可包含数字,英文和下划线),且长度为6-16位之间',
})
return
}
if (state.loading.pwd) return
state.loading.edit = true
api.alterPassword({
mobilePhone: state.phone,
password: state.dialog.pwd.originPwd,
newPwd: state.dialog.pwd.pwd,
confirmPwd: state.dialog.pwd.rePwd,
}).then(() => {
state.dialog.pwd.show = false
Toast.success('修改密码成功')
}).finally(() => {
state.loading.pwd = false
})
}
function onForget() {
state.dialog.pwd.show = false
goto(`/pages/login/forget?phone=${state.phone}&reset=1`)
}
function logout() {
api.logout().finally(() => {
uni.reLaunch({
url: '/pages/login/login'
})
})
}
</script>
<style lang="scss" scoped>
.top_tab {
width: 100vw;
}
.cell_value {
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
overflow: hidden;
max-width: 70vw;
height: 20px;
}
</style>
<template>
<view class="fav_box">
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack" />
<view class="top-center">
<van-tabs class="top_tab" v-model:active="state.tab.active">
<van-tab v-for="item in state.tab.list" :title="item.title" :name="item.name" />
</van-tabs>
</view>
<view class="top-right" @tap="onEdit">
<view class="text-m" :class="[state.edit ? 'text-orange' : 'text-gray']">{{ state.edit ? '完成' : '编辑' }}</view>
</view>
</view>
</van-sticky>
<view v-show="state.tab.active == 'product'">
<van-pull-refresh v-model="state.product.refresh" @refresh="favProductList()">
<view v-if="state.product.list.length > 0">
<van-checkbox-group class="pd-b-px-50" v-model="state.product.selected"
style="min-height: calc(100vh - 180px)">
<template v-for="gItem in state.product.list">
<view class="text-blue pd-v-10 pd-h-25" v-if="gItem.splitTitle">
{{ gItem.splitTitle }}
</view>
<van-swipe-cell v-else>
<van-cell class="pd-l-0">
<view class="flex">
<view class="justify-center" style="width: 40px" v-if="state.edit">
<van-checkbox icon-size="17px" :name="gItem" @tap="onProductCheck()" />
</view>
<view v-else style="margin-left: 28rpx"/>
<view class="justify-middle" style="position:relative" @tap="onProduct(gItem)">
<van-image height="88px" width="88px" fit="cover" :src="gItem.imgPath"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="88px" />
<!--商品收藏活动角标-->
<div class="sign" v-if="gItem.subScriptImgUrl">
<img :src="gItem.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{gItem.discount}}</div>
</div>
<span v-for="(item,index) in gItem.leftDownIcons" :key="index" :style="{left:index*35+'px'}" style="position:absolute;bottom:0;">
<van-image width="32px" height="16px"
:src="item" />
</span>
</view>
<view class="pd-l-20" @tap="onProduct(gItem)">
<view class="text-m ellipsis line_over2 pd-b-25" style="width: calc(100vw - 340rpx);min-height: 36px">
{{ gItem.title }}
</view>
<view class="justify-between justify-middle text-s">
<text style="width: calc(100vw - 340rpx);">规格:{{ gItem.size }}</text>
</view>
<template v-if="gItem.salePrice">
<div v-if="gItem.actPrice">
<text class="text-gray text-s mg-t-5-m pd-r-10 line-through">优惠价:¥{{ gItem.salePrice }}</text>
<text class="text-gray text-s mg-t-5-m ">零售价:¥{{ gItem.productPrice }}</text>
</div>
<div v-else>
<text class="text-orange text-s mg-t-5-m pd-r-10">优惠价:¥{{ gItem.salePrice }}</text>
<text class="text-gray text-s mg-t-5-m line-through">零售价:¥{{ gItem.productPrice }}</text>
</div>
</template>
<template v-else>
<text class="text-gray text-s mg-t-5-m line-through" v-if="gItem.actPrice" >零售价:¥{{ gItem.productPrice }}</text>
<text class="text-orange text-s mg-t-5-m" v-if="!gItem.actPrice" >零售价:¥{{ gItem.productPrice }}</text>
</template>
<p v-if="gItem.actPrice" class="text-orange text-s mg-t-5-m text-bold" style="margin-top: .1rem">活动价:¥{{ gItem.actPrice }}</p>
</view>
</view>
<template #right-icon>
<view class="justify-middle">
<img @tap="cartAdd(gItem.skuId)" wi src="/static/img/car_search.png" style="width: 1.8rem">
</view>
</template>
</van-cell>
<template #right>
<van-button class="swipe_btn" type="danger" text="删除" @tap="productDel([gItem])" />
</template>
</van-swipe-cell>
</template>
</van-checkbox-group>
</view>
<view v-else class="justify-center" style="min-height: calc(100vh - 180px)">
<van-empty description="您还没有收藏商品" />
<van-button class="text-l" color="linear-gradient(315deg, #FE521F 0%, #FE7902 100%)" round block
style="width: 240rpx" @tap="goto('/')">
去逛逛
</van-button>
</view>
</van-pull-refresh>
<van-action-bar v-if="state.product.list.length > 0 && state.edit"
class="pd-l-30 custom-width justify-between pd-r-20 sh-t">
<van-checkbox class="text-m" icon-size="17px" v-model="state.product.all" @tap="onProductAll()">全选
</van-checkbox>
<van-action-bar-button style="width: 240rpx;" type="danger" text="取消收藏"
@tap="askSelected('商品', productDel, state.product.selected)" />
</van-action-bar>
</view>
<view v-show="state.tab.active == 'brand'">
<van-pull-refresh v-model="state.brand.refresh" @refresh="favBrandList()">
<view v-if="state.brand.list.length > 0">
<van-checkbox-group class="pd-b-px-50" v-model="state.brand.selected" style="min-height: calc(100vh - 180px)">
<template v-for="bItem in state.brand.list">
<van-swipe-cell>
<van-cell class="pd-l-0">
<view class="flex">
<view class="justify-center" style="width: 40px" v-if="state.edit">
<van-checkbox icon-size="17px" :name="bItem" @tap="onBrandCheck()" />
</view>
<view v-else style="margin-left: 28rpx"/>
<view class="justify-middle" style="position:relative" @tap="onBrand(bItem)">
<van-image height="88px" width="88px" fit="cover" :src="bItem.imgPath"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png" icon-size="88px" />
</view>
<view class="pd-l-20" @tap="onBrand(bItem)">
<view class="text-m ellipsis line_over2 pd-v-20" style="width: calc(100vw - 160px);min-height: 36px">
{{ bItem.name }}
</view>
<text class="text-gray text-s mg-t-5-m">商品数量:{{ bItem.sales }}</text>
</view>
</view>
</van-cell>
<template #right>
<van-button class="swipe_btn" type="danger" text="删除" @tap="brandDel([bItem])" />
</template>
</van-swipe-cell>
</template>
</van-checkbox-group>
</view>
<view v-else class="justify-center" style="min-height: calc(100vh - 180px)">
<van-empty description="您还没有收藏品牌" />
<van-button class="text-l" color="linear-gradient(315deg, #FE521F 0%, #FE7902 100%)" round block
style="width: 240rpx" @tap="goto('/')">
去逛逛
</van-button>
</view>
</van-pull-refresh>
<van-action-bar v-if="state.brand.list.length > 0 && state.edit"
class="pd-l-30 custom-width justify-between pd-r-20 sh-t">
<van-checkbox class="text-s" icon-size="17px" v-model="state.brand.all" @tap="onBrandAll()">全选
</van-checkbox>
<van-action-bar-button style="width: 240rpx;" type="danger" text="取消收藏"
@tap="askSelected('品牌', brandDel, state.brand.selected)" />
</van-action-bar>
</view>
</view>
</template>
<script setup lang="ts">
import api from '@/api'
import { nextTick, onBeforeMount, reactive } from 'vue';
import { PageUtils } from '@/utils/utils';
import { Dialog, Toast } from 'vant'
const state = reactive({
aa:['https://img.edsmall.com/ewy/resource/image/5e41e82b-6d58-4090-8de7-ec726f144acc.png','https://img.edsmall.com/ewy/resource/image/5e41e82b-6d58-4090-8de7-ec726f144acc.png'],
tab: {
active: 'product',
list: [
{ title: '商品', name: 'product' },
{ title: '店铺', name: 'brand' }
]
},
product: {
all: false,
selected: [] as any,
loading: false,
list: [] as any,
orignList: [] as any,
refresh: false
},
brand: {
all: false,
selected: [] as any,
loading: false,
list: [] as any,
refresh: false
},
edit: false,
})
onBeforeMount(() => {
favProductList()
favBrandList()
})
function goBack() {
PageUtils.goBack()
}
function favProductList() {
let weekAgo: any = new Date().getTime() - (7 * 24 * 60 * 60 * 1000)
if (state.product.loading) return
state.product.loading = true
api.favProductList({ link: uni.getStorageSync('subdomain') }).then((data: any) => {
const list = []
if (data.length > 0) {
list.push({ splitTitle: '#最近1周' })
}
data.forEach((item: any) => {
if (weekAgo && weekAgo > item.addDate) {
list.push({ splitTitle: '#1周之后' })
weekAgo = undefined
list.push(item)
} else {
list.push(item)
}
})
state.product.all = false
state.product.selected = []
state.product.orignList = data
state.product.list = list
}).finally(() => {
state.product.refresh = false
state.product.loading = false
})
}
function favBrandList() {
if (state.brand.loading) return
state.brand.loading = true
api.favBrandList({ link: uni.getStorageSync('subdomain') }).then((data: any) => {
state.brand.all = false
state.brand.selected = []
state.brand.list = data
}).finally(() => {
state.brand.refresh = false
state.brand.loading = false
})
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function onProduct(gItem: any) {
if (!gItem.saleable) {
Toast('商品已下架');
} else if (gItem.moq > gItem.stock) {
Toast('暂时无货');
} else if (!gItem.isBrandAgent) {
Toast('商家未代理该品牌');
} else {
goto(`/pages/good/detail?skuId=${gItem.skuId}&spuId=${gItem.spuId}`)
}
}
function productDel(list: Array<any>) {
const skuIds = list.map((item: any) => item.skuId)
if (state.product.loading) return
state.product.loading = true
api.productDel({ skuIds }).then((data: any) => {
state.product.loading = false
favProductList()
}).catch(() => {
state.product.loading = false
})
}
function brandDel(list: Array<any>) {
const brandIds = list.map((item: any) => item.brandId)
if (state.brand.loading) return
state.brand.loading = true
api.brandDel({ brandIds }).then((data: any) => {
state.brand.loading = false
favBrandList()
}).catch(() => {
state.brand.loading = false
})
}
function onEdit() {
state.edit = !state.edit
}
function askSelected(targetName: string, fn: Function, selected: any) {
if (selected.length == 0) {
Toast('请勾选' + targetName)
return
}
Dialog.confirm({
message: '是否取消收藏选中' + targetName,
title: "提示"
}).then(() => {
fn(selected)
})
}
function onProductAll() {
if (state.product.all) {
state.product.selected = [...state.product.orignList]
} else {
state.product.selected = []
}
}
function onBrandAll() {
if (state.brand.all) {
state.brand.selected = [...state.brand.list]
} else {
state.brand.selected = []
}
}
function cartAdd(skuId: string) {
if (state.product.loading) return
state.product.loading = true
api.cartAdd({
skuId: skuId,
link: uni.getStorageSync('subdomain'),
productQty: 1, // B端去除起订量限制 skuData.value.moq
}).then(() => {
Toast.success('加入购物车')
}).finally(() => {
state.product.loading = false
})
}
function onProductCheck() {
nextTick(() => {
if (state.product.selected.length == state.product.orignList.length) {
state.product.all = true
} else {
state.product.all = false
}
})
}
function onBrand(bItem: any) {
if (!bItem.isBrandAgent) {
Toast('商家未代理该品牌');
} else {
goto(`/pages/good/brandShop?brandId=${bItem.brandId}`)
}
}
function onBrandCheck() {
nextTick(() => {
if (state.brand.selected.length == state.brand.list.length) {
state.brand.all = true
} else {
state.brand.all = false
}
})
}
</script>
<style lang="scss" scoped>
.top_tab {
width: 50vw;
}
.fav_box {
.van-cell {
line-height: 18px !important;
}
}
.swipe_btn {
height: 100%;
width: 100rpx;
padding: 0;
font-size: 26rpx;
}
</style>
<template>
<view class="pd-b-px-55">
<view class="top_box">
<view class="user_box justify-between justify-middle pd-l-50 pd-r-30 pd-v-45">
<view class="justify-middle">
<view class="user_head">
<van-image fit="cover" width="80rpx" height="80rpx"
@tap="onImagePreview(state.user.userHeadImage||'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/mall_default.png')" round
:src="state.user.userHeadImage||'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/mall_default.png'" />
</view>
<view class="mg-l-30 text-white text-xl">{{ state.user.userPhone }}</view>
</view>
<view class="user_edit btn" @tap="goto('/pages/my/detail')">账户管理
<van-icon name="edit" />
</view>
</view>
<van-cell-group inset class="mg-b-40">
<van-cell :border="false">
<template #title>
<view class="flex wrap justify-between">
<view v-for="item in state.actionList" class="text-center btn pd-h-25 pd-v-20"
@tap="goto(item.url)">
<van-badge :content="item.badge>0?item.badge:''">
<van-image width="32px" height="32px" :src="item.icon" />
</van-badge>
<view class="text-s">{{ item.name }}</view>
</view>
</view>
</template>
</van-cell>
<van-divider class="mg-v-0" />
<van-cell :border="false">
<template #title>
<view class="justify-between text-center">
<view class="long_action_btn justify-center btn" @tap="goto('/pages/my/fav')">
<view class="justify-middle">
<van-image class="pd-r-px-10" width="20px" height="20px"
src="/static/img/fav.png" />
我的收藏
</view>
</view>
<view class="v-divider" />
<view class="long_action_btn justify-center btn"
@tap="goto('/pages/my/address')">
<view class="justify-middle">
<van-image class="pd-r-px-10" width="20px" height="20px"
src="/static/img/address.png" />
收货地址
</view>
</view>
</view>
</template>
</van-cell>
</van-cell-group>
</view>
<van-sticky v-if="state.good.list.length > 0">
<van-cell-group class="sh" style="border-radius: 8px 8px 0 0">
<van-cell style="border-radius: 8px 8px 0 0">
<template #title>
<view class="justify-middle">
<text class="text-l">为您推荐</text>
<view class="v-divider mg-h-px-10" />
<text class="text-ss text-gray">大牌任你选</text>
</view>
</template>
<template #right-icon>
<view class="justify-middle text-daryGray text-s btn"
@tap="goto('/pages/goodList/index')">
查看更多
<van-icon name="arrow" />
</view>
</template>
</van-cell>
</van-cell-group>
</van-sticky>
<van-list :loading="state.good.loading">
<van-grid :center="false" :column-num="2">
<van-grid-item class="text-left" v-for="item in state.good.list" style="border-radius: 4px"
@tap="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${item.spuId}`)">
<van-image class="self_center" width="30vw" height="30vw" lazy-load :src="item.mainImg"
loading-icon="https://img.edsmall.com/ROOT/ETao/fenxiao/h5/default.png"
icon-size="30vw" />
<!--为你推荐活动角标-->
<div class="sign" v-if="item.subScriptImgUrl">
<img :src="item.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{item.discount}}</div>
</div>
<view :class="[item.zoneIcon||item.isVideoIcon?'mg-t-30-m':'']">
<van-image v-for="item in item.leftDownIcons" style="margin-right: 4rpx" width="60rpx" height="32rpx" :src="item" />
<van-image v-if="item.isVideoIcon" class="mg-l-5" width="32rpx" height="32rpx"
src="/static/img/play.png" />
</view>
<text class="text-s ellipsis line_over2 pd-t-10"
style="width: 320rpx;height: 32px;margin-bottom:6px">
{{ item.title }}
</text>
<text class="text-gray text-ss"></text>
<div style="line-height: 1.2rem" v-if="item.salePrice !== null">
<p class="text-ss">{{ item.size }}</p>
<p class="text-gray text-ss"></p>
<div v-if="item.actPrice">
<div >
<p class="text-gray text-ss " style="float: right;margin-right: 20px">
零售价¥
<text class="text-bold text-l">{{ item.productPrice }}</text>
</p>
<div class="text-gray text-ss line-through" >
优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</div>
</div>
</div>
<div v-if="!item.actPrice">
<p class="text-gray text-ss line-through">零售价¥{{ item.productPrice
}} </p>
<p class="text-orange text-ss" >
优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</p>
</div>
<p class="text-orange text-ss" v-if="item.actPrice">
活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</p>
</div>
<div style="line-height: 1.2rem" v-else>
<p class="text-ss">{{ item.size }}</p>
<p class="text-gray text-ss"></p>
<p class="text-gray text-ss line-through" v-if="item.actPrice">
零售价¥
<text class="text-bold text-l">{{ item.productPrice }}</text>
</p>
<p class="text-orange text-ss"
v-else>
零售价¥
<text class="text-bold text-l">{{ item.productPrice }}</text>
</p>
<p class="text-orange text-ss"
style="color: #ff8b3e;font-size: 15px;margin-top: 5px" v-if="item.actPrice">
活动价¥
<text class="text-bold text-l">{{ item.actPrice }}</text>
</p>
</div>
</van-grid-item>
</van-grid>
</van-list>
<to-top />
</view>
</template>
<script setup lang="ts">
import toTop from '@/components/tool/toTop.vue';
import {onBeforeMount, reactive} from "vue";
import {Dialog, ImagePreview} from 'vant';
import api from "@/api";
import {onShow} from "@dcloudio/uni-app";
const state = reactive({
user: {} as any,
phone: '',
// 建议以后走运营中心,我想走
actionList: [
{
name: '待付款',
url: '/pages/order/orderList?index=1',
icon: 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/order_wait_pay.png',
badge: ''
},
{
name: '待发货',
url: '/pages/order/orderList?index=2',
icon: 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/order_wait_deliver.png',
badge: ''
},
{
name: '待收货',
url: '/pages/order/orderList?index=3',
icon: 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/order_wait_receive.png',
badge: ''
},
{
name: '我的订单',
url: '/pages/order/orderList?index=0',
icon: 'https://img.edsmall.com/ROOT/ETao/fenxiao/h5/order_all.png',
badge: ''
},
],
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any
},
});
onShow(() => {
if (state.phone) {
accountInfo()
getOrderCount()
}
})
function getUrl(url) {
const q = {};
url.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => q[k] = v);
return q;
}
onBeforeMount(() => {
console.log(window.location.href,'window.location.href');
let href =getUrl(window.location.href).mobilePhone? true:false
console.log(href,'href');
// 判断小程序是否登录成功
if(href){
api.wxlogin({
mobilePhone:getUrl(window.location.href).mobilePhone,
}).then((data: any) => {
uni.setStorageSync('user', data)
uni.setStorageSync('login', {
store: false,
phone:getUrl(window.location.href).mobilePhone,
pwd: '',
})
state.phone = data.account
accountInfo()
getOrderCount()
onGoodLoad()
})
}else {
const user: any = uni.getStorageSync('user') || {account: undefined}
if (user.token) {
state.phone = user.account
if (!state.phone) {
Dialog.alert({
title: '数据异常',
message: '当前用户缺少手机信息,请联系开发人员#021',
confirmButtonText: '返回首页'
}).then(() => {
uni.reLaunch({
url: '/'
})
})
return
}
accountInfo()
getOrderCount()
onGoodLoad()
} else {
const isWxjs_environment = uni.getStorageSync("isWxjs_environment") || false;
if (isWxjs_environment) {
window._wx.miniProgram.redirectTo({url: "/pages/login/login"})
} else {
Dialog.confirm({
message: '您尚未登录,请前往登录',
title: "提示",
cancelButtonText: '返回首页'
}).then(() => {
uni.reLaunch({
url: '/pages/login/login'
})
}).catch(() => {
uni.reLaunch({
url: '/'
})
});
}
}
}
})
function accountInfo() {
api.accountInfo({phone: state.phone}).then((data: any) => {
state.user = data
})
}
function getOrderCount() {
api.getOrderCount().then((data: any) => {
state.actionList[0].badge = data.waitForPay
state.actionList[1].badge = data.waitForDelivery
state.actionList[2].badge = data.waitForReceive
})
}
function goto(url: any) {
url && uni.navigateTo({url})
}
function onGoodLoad() {
if (state.good.loading || state.good.fail) return
state.good.loading = true
state.good.page += 1
api.productList({sortType: 0, pageSize: 20, link: uni.getStorageSync("subdomain")}).then((data: any) => {
if (!data) return
if (!data || !data.hasNextPage) {
state.good.finished = true
}
state.good.list.push(...data.list)
})
.catch(() => {
state.good.fail = true
})
.finally(() => {
state.good.loading = false
})
}
function onImagePreview(url: string) {
ImagePreview({images: [url], closeable: true})
}
</script>
<style lang="scss" scoped>
.top_box {
background: url('@/static/img/my_bg.png') no-repeat;
background-size: 100% auto;
.user_box {
.user_head {
width: 78 rpx;
height: 78 rpx;
border: 2 rpx solid #fff;
position: relative;
border-radius: 50%;
&::before {
content: "";
position: absolute;
border-radius: 50%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(180deg, #ffe5cd 0%, #ffb399 100%);
}
}
.user_edit {
color: #fff;
background: rgba(255, 255, 255, 0.1000);
border-radius: 50px;
border: 1px solid rgba(255, 255, 255, 0.2400);
padding: 6px 12px;
font-size: 12px;
}
}
.long_action_btn {
width: 48%;
}
}
.v-divider {
width: 0.5px;
height: 20px;
background: #DDDDDD;
}
</style>
<template>
<div class="pdfBox">
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack()" />
<view>
<view class="text-m" style="font-size: 16px;color: #333333">{{title}}</view>
</view>
</view>
</van-sticky>
<div id="previewPdf"></div>
</div>
</template>
<script>
import pdfh5 from 'pdfh5';
import 'pdfh5/css/pdfh5.css'
export default {
name: 'pdfh5',
data () {
return {
pdfh5: null,
title:'E淘商城平台交易指引'
}
},
mounted(){
let url = null
if(this.$route.query.type==1){
this.title='营业执照'
url= 'https://edspicserver.oss-cn-hangzhou.aliyuncs.com/ROOT/ETao/resource/business_license.pdf'
}else if(this.$route.query.type==2) {
url='https://img.edsmall.com/ROOT/ETao/resource/trading_guidelines.pdf'
this.title='E淘商城平台交易指引'
}else {
url='https://img.edsmall.com/ROOT/ETao/resource/ThePeoplesRepublicofChina.pdf'
this.title='增值电信业务经营许可证'
}
this.openPdf(url)
},
methods: {
goBack(){
uni.redirectTo({
url:'/pages/my/technicalSupport?name=contact',
});
},
openPdf(url){ //url:PDF文件地址
this.pdfh5 = new pdfh5('#previewPdf', {
pdfurl:url
});
}
}
}
</script>
<style lang="scss" scoped>
.pdfBox {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #000;
overflow: hidden;
z-index: 99;
}
</style>
<template>
<div>
<van-sticky>
<view class="top-bar justify-center bg-white sh">
<van-icon class="top-left" name="arrow-left" @tap="goBack(url)" />
<view>
<view class="text-m" style="font-size: 16px;color: #333333">资质与规则</view>
</view>
</view>
</van-sticky>
<!--<img src="../../static/img/weizhi.png" style="width: 100%" alt="">-->
<div style="margin: 10px 10px">
<p style="color: #666666;">*若无法预览,请复制链接后在浏览器打开</p>
<van-divider :style="{borderColor: '#DDDDDD'}"/>
<h2 style="margin: 10px auto">E淘商城平台交易指引</h2>
<p><a style="color: #1A79FF" @click="goPDF(2)">https://img.edsmall.com/ROOT/ETao/resource/trading_guidelines.pdf</a></p>
<h2 style="margin: 10px auto;margin-top: 30px">营业执照</h2>
<p><a style="color: #1A79FF" @click="goPDF(1)">https://edspicserver.oss-cn-hangzhou.aliyuncs.com/ROOT/ETao/resource/business_license.pdf</a></p>
<h2 style="margin: 10px auto;margin-top: 30px">增值电信业务经营许可证</h2>
<p><a style="color: #1A79FF" @click="goPDF(3)">https://img.edsmall.com/ROOT/ETao/resource/ThePeoplesRepublicofChina.pdf</a></p>
</div>
</div>
</template>
<script>
export default {
name: "technicalSupport",
data(){
return{
url:''
}
},
onLoad: function (option) { //option为object类型,会序列化上个页面传递的参数
this.url=option.name
},
methods:{
goPDF(num){
uni.redirectTo({
url:'/pages/my/pdfh5?type='+num,
});
},
goBack(name) {
let url = ''
if(name=='login'){
url='/pages/login/login'
}else if(name=='contact'){
url='/pages/good/contact'
}else if(name=='detail'){
url='/pages/my/detail'
}else if(name=='index'){
url='/'
}
uni.redirectTo({
url:url,
});
},
}
};
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<view class="text-center pd-b-px-55">
<van-sticky>
<van-nav-bar
title="申请售后"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
</van-sticky>
<van-image style="width: 100%" :src="that.userInfo.imgUrl" />
<p style="font-size: 14px;text-align: center;color: #bfbfbf;margin-top: 20px">E淘·用心为您服务</p>
<van-row style="background: #ffffff;position: fixed;bottom: 0;width: 100%">
<van-col span="12" style="border-right: 1px solid #f9f9f9;text-align: center;padding: 16px" @click="goto('/pages/good/contact')">
<van-icon name="phone-circle-o" size="20px" style="color: #fe7e58;margin-right: 6px" />
联系商家
</van-col>
<van-col span="12" style="text-align: center;padding: 16px" @click="goto('/pages/order/customerService')">
<van-icon name="service-o" size="20px" style="color: #fe7e58;margin-right: 6px" />
平台介入
</van-col>
</van-row>
</view>
</template>
<script setup lang="ts">
import api from "@/api";
import {reactive,onMounted} from 'vue';
const that = reactive({
userInfo:{}
})
onMounted(() => {
afterSaleImg()
})
function afterSaleImg() {
api.afterSaleImg().then((res: any) => {
that.userInfo=res
})
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function onClickLeft() {
history.back()
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<van-sticky>
<van-nav-bar
title="确认订单"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
</van-sticky>
<div class="border_address"></div>
<van-row style="background: #ffffff;" @click="gotoAddress">
<van-col span="3">
<img style="width: 1.4rem;margin-left: .5rem;margin-top: 45%" src="../../static/img/sub_address.png"
alt="">
</van-col>
<van-col span="18">
<div style="text-align: left;margin: 1rem auto">
<p>收货人:{{that.addressObj.receiverName}} {{that.addressObj.phone}}</p>
<p>收货地址:{{that.addressObj.region}} {{that.addressObj.detailAddress}}</p>
</div>
</van-col>
</van-row>
<div class="border_address"></div>
<div style="background: #ffffff;font-size: 13px;text-align: left;padding: .8rem;margin-top: 1rem">
<h3>商品信息&nbsp<span style="font-size: 12px;color: #d1d2d3;margin-right: 3px">|&nbsp您要结算的商品</span></h3>
</div>
<div v-for="item in that.cartList">
<div v-for="(good,index) in item.orderDetails" :key="index">
<van-grid :center="false" :column-num="1">
<van-grid-item class="text-left">
<van-row>
<van-col span="8" style="position: relative">
<van-image class="self_center" width="100%" height="100%" lazy-load
:src="good.goodsImg" />
<!--结算页活动角标-->
<div class="sign" v-if="good.subScriptImgUrl">
<img :src="good.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{good.discount}}</div>
</div>
<view style="position: absolute;left: 0;bottom: 0;" v-if="good.conner.dailyIcons[0]">
<span style="margin-right: 5px" v-for="item in good.conner.dailyIcons">
<van-image width="60rpx" height="32rpx" :src="item" />
</span>
</view>
</van-col>
<van-col span="15" offset="1">
<p class="text-l ellipsis line_over2" style="height: 80rpx;">
{{good.goodsInfo}}
</p>
<div style="line-height: 1.2rem">
<p class="text-s">规格:{{good.spec}}</p>
<p class="text-gray text-s" style="color: #5392e2">
交货期:{{good.deliveryDateStatusMsg}}</p>
<p v-if="good.actPrice" class="text-gray text-s"
:class="{'line-through':!good.salePrice}"
>
<span style="float: right;color: #414141"> 件数:x {{good.count}}</span>
零售价¥{{good.productPrice}}</p>
<p v-else class="text-s"
:class="{'line-through':good.salePrice,'text-orange':!good.salePrice,'text-gray':good.salePrice}">
<span style="float: right;color: #666666"> 件数:x {{good.count}}</span>
零售价¥{{good.productPrice}}</p>
<div v-if="good.actPrice">
<p class="text-gray text-s line-through" style="margin-top: .3rem"
v-if="good.salePrice">优惠价¥<text class="text-bold text-l">{{good.salePrice}}</text>
</p>
</div>
<div v-else>
<p class="text-orange text-s" style="margin-top: .3rem"
v-if="good.salePrice">优惠价¥<text class="text-bold text-l">{{good.salePrice}}</text>
</p>
</div>
<p class="text-orange text-s" style="margin-top: .3rem" v-if="good.actPrice"
>活动价¥<text class="text-bold text-l">{{good.actPrice}}</text>
</p>
</div>
</van-col>
</van-row>
</van-grid-item>
<van-divider />
</van-grid>
<van-field
rows="1"
v-model="good.remark"
readonly
autosize
label="商品备注:"
type="textarea"
>
<template #button>
<van-icon name="records" size="20"
@click="that.temIndexRemark=index,showRemark(true,good.remark)" />
</template>
</van-field>
</div>
</div>
<van-field
v-model="that.params.orderRemarks"
readonly
rows="1"
autosize
label="订单备注:"
type="textarea"
style="margin-top: 10px"
>
<template #button>
<van-icon name="records" size="20" @click="showRemark(false,that.params.orderRemarks)" />
</template>
</van-field>
<div style="background: #ffffff;font-size: 13px;text-align: left;padding: .8rem;padding-bottom: 80px">
<h3>支付方式&nbsp<span style="font-size: 12px;color: #d1d2d3;margin-right: 3px">|&nbsp您要结算的商品</span></h3>
<van-divider />
<div>
<van-radio-group v-model="that.checked">
<van-radio name="1"><p style="font-size: 14px"> {{that.payType}}支付(强烈推荐)</p>
<p style="color: #b8b8b8">使用{{that.payType}}担保交易,保障双方利益。</p></van-radio>
</van-radio-group>
</div>
</div>
<van-dialog confirmButtonColor="#ff6800" v-model:show="that.show" :title="`${that.isGood?'商品':'订单'}备注`"
show-cancel-button @confirm="saveRemark">
<van-cell-group inset>
<van-field
v-model="that.temRemarks"
rows="2"
autosize
type="textarea"
maxlength="120"
:placeholder="`请输入${that.isGood?'商品':'订单'}备注...`"
show-word-limit
/>
</van-cell-group>
</van-dialog>
<van-submit-bar :price="that.totalOrderMoney*100" button-text="提交订单" button-color="#ff6600"
:loading="that.loading" @submit="onSubmit">
<template #default>
<span style="float: right">总共:{{that.total}}件商品</span>
</template>
</van-submit-bar>
<van-overlay :show="that.phoneShow" z-index="999">
<div style="text-align: center;position: absolute;bottom: 10px;width: 94%;padding-left: 3%;">
<div class="block" @click.stop style="color: #0099ff">
<van-icon name="phone-o" size="24" style="color: #999999;margin-top: 3px;margin-right: 10px" />
呼叫 <a style="color:#0099ff " href="tel:13148528214">{{that.cartList[0].businessPhone}}</a>
</div>
<div class="block" @click="that.phoneShow = false" style="margin-top: 10px">
取消
</div>
</div>
</van-overlay>
<van-popup v-model:show="that.popupAddress" position="right"
:style="{ width: '100%', height: '100%' }">
<address-component :addrId="that.addressObj.addrId" @change="onAddressChange"
@cancel="that.popupAddress = false" />
</van-popup>
</template>
<script setup lang="ts">
import api from "@/api";
import AddressComponent from '@/pages/my/address.vue'
import {log} from 'console';
import {Dialog, SubmitBar, Toast} from 'vant';
import {onMounted, reactive, getCurrentInstance} from 'vue';
const that = reactive({
payType:'',
total: 0,
totalOrderMoney: 0,
temIndexRemark: 0,
cartList: [],
phoneShow: false,
loading: false,
isGood: false,
temRemarks: '',
checked: '1',
show: false,
actIndex: 4,
params: {
goodRemarks: '',
orderRemarks: ''
},
addressObj: {},
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any
},
popupAddress: false
})
onMounted(() => {
that.payType=window.__wxjs_environment === 'miniprogram'?'微信':'支付宝'
let carts = getCurrentInstance().ctx.$page.options || ''
settleInfo(JSON.parse(decodeURIComponent(carts.list)))
receiveList()
});
function receiveList() {
api.receiveList().then((data: any) => {
if(data.list){
that.addressObj = data.list[0]||{}
}
}).finally(() => {
})
}
function settleInfo(carts) {
api.settleInfo(
{
"carts": carts,
"domain": uni.getStorageSync("subdomain")
}
).then((res: any) => {
that.total = res.total
that.totalOrderMoney = res.totalOrderMoney
that.cartList = res.orderList
})
}
function orderAdd(carList) {
api.orderAdd(
{
"addressId": that.addressObj.addrId,
"carts": carList,
"domain": uni.getStorageSync("subdomain")
}
).then((res: any) => {
let idList = []
res.orderList.forEach(item => {
idList.push(item.orderId)
})
const isWxjs_environment = uni.getStorageSync("isWxjs_environment") || false;
if(isWxjs_environment) {
window._wx.miniProgram.redirectTo({url: "/pages/pay/pay?orderid="+idList[0]})
}else {
orderPay(idList)
}
})
}
function orderPay(idList) {
api.orderPay(
{
"domain": uni.getStorageSync("subdomain"),
"idList": idList,
}
).then((res: any) => {
if(is_weixn()){
Dialog.alert({
confirmButtonColor:'rgb(255, 102, 0)',
confirmButtonText:'*请复制链接后在浏览器打开',
message: res.payUri,
}).then(() => {
let oInput = document.createElement("input");
oInput.value = res.payUri;
document.body.appendChild(oInput);
oInput.select();
document.execCommand("Copy");
Toast.success("复制成功");
oInput.remove();
});
}else {
window.location.href = res.payUri
}
})
}
function is_weixn() {
let ua = navigator.userAgent.toLowerCase()
if(ua.match(/MicroMessenger/i)=='micromessenger'){
return true
}else {
return false
}
}
function onSubmit() {
if(!that.cartList[0].hasAlipayAccount){
Dialog.confirm({
title: '提示',
confirmButtonText:'马上联系',
cancelButtonText:'稍等一会',
confirmButtonColor: '#ff6800',
message:
'商家未绑定支付宝收付款,无法提交订单,马上联系商家?',
})
.then(() => {
that.phoneShow=true
})
.catch(() => {
// on cancel
});
return;
}
uni.setStorageSync('payMoney',that.totalOrderMoney)
let carList = []
that.cartList[0].orderDetails.forEach(item => {
carList.push(
{
"cartId": item.cartId,
"count": item.count,
"orderRemark": that.params.orderRemarks,
"remark": item.remark,
"skuId": item.skuId
}
)
})
orderAdd(carList)
}
function showRemark(isGood, e) {
if (isGood) {
that.isGood = true
} else {
that.isGood = false
}
that.temRemarks = e
that.show = true
}
function saveRemark() {
if (that.isGood) {
that.cartList[0].orderDetails[that.temIndexRemark].remark = that.temRemarks
} else {
that.params.orderRemarks = that.temRemarks
}
}
function sure() {
Dialog.confirm({
title: '提示',
confirmButtonColor: '#ff6800',
message:
'确认收货',
})
.then(() => {
// on confirm
})
.catch(() => {
// on cancel
});
}
function gotoAddress() {
that.popupAddress = true
}
function onceBuy() {
Dialog.confirm({
title: '提示',
confirmButtonColor: '#ff6800',
message:
'是否添加到购物车?',
})
.then(() => {
// on confirm
})
.catch(() => {
// on cancel
});
}
function onClickLeft() {
history.back()
}
function onAddressChange(item: any) {
// Toast('返回参数见console')
// console.log('提示:<address-component/>组件调用那里传一个addrId给我', item)
// console.log('地址信息', item)
that.addressObj = item
that.popupAddress = false
}
</script>
<style lang="scss" scoped>
.sign {
position: absolute;
right: 1.8vw;
top: 0;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
.block {
border-radius: 3px;
color: #52b4ff;
height: 50px;
line-height: 50px;
background-color: #fff;
}
.pro_account {
display: inline-block;
border-left: 2px solid #f1f5f8;
height: 0.3rem;
line-height: .3rem;
font-size: .14rem;
color: #bbb;
margin-top: 0.15rem;
margin-left: 0.2rem;
text-indent: 0.2rem;
}
.border_address {
border: 1px solid;
border-image-source: linear-gradient(to right, #f8e07e, #f88f7e);
border-image-slice: 1;
}
</style>
\ No newline at end of file
<template>
<view>
<van-sticky>
<van-nav-bar
title="客服介入"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
</van-sticky>
<img style="width: 100%" src="../../static/img/pingtai_kefu.png" />
<div style="background: #ffffff;margin:10px 10px;border-radius: 10px;box-shadow: 0 0 6px 0 #ccc;position: relative;top: -50px;"
v-for="item in dataList">
<van-row>
<van-col span="4">
<img v-if="item.avatarUrl" style="padding: .6rem;width: 45px;height: 45px;border-radius: 50%" :src="item.avatarUrl" />
<img v-else style="padding: .6rem;width: 45px;height: 45px" src="../../static/img/kefu1.png" />
</van-col>
<van-col span="19" style="margin-top: .8rem">
<p>{{item.serviceName}} <span style="color: #a8a8a8;font-size: 13px">{{changeName(item.type)}}</span></p>
<div style="background: #f9f9f9;color:#e3947d;font-size: 13px;padding: .5rem;margin: .5rem auto">
<p>负责区域:</p>
<p>
{{item.responsibleArea}}</p>
</div>
<p>
<van-icon name="service-o" style="margin-right: .5rem" />
{{item.serviceWechat}}
<a style="float: right;border: 1px solid #fe8966;color:#fe754d;padding: 3px;display: inline-block;font-size: 12px" @click="showPhone(item.serviceMobile)" :href="`tel:${temPhone}`">一键拨打</a>
</p>
<van-divider />
<p><img src="../../static/img/wxchat.png" style="margin-right: .6rem">{{item.serviceMobile}}
<van-button
@click="handleCopy(item.serviceMobile)"
size="mini"
style="float: right;border: 1px solid #fef0ec;color: #fe754d;background: #fef0ec">
复制
</van-button>
</p>
<van-divider />
</van-col>
</van-row>
</div>
</view>
<van-overlay :show="phoneShow" z-index="999">
<div style="text-align: center;position: absolute;bottom: 10px;width: 94%;padding-left: 3%;">
<div class="block" @click.stop style="color: #0099ff">
<van-icon name="phone-o" size="24" style="color: #999999;margin-top: 3px;margin-right: 10px" />
呼叫 <a style="color:#0099ff " :href="`tel:${temPhone}`">{{temPhone}}</a>
</div>
<div class="block" @click.stop style="margin-top: 10px" @click="phoneShow = false">
取消
</div>
</div>
</van-overlay>
</template>
<script>
import api from "@/api";
import { Toast } from "vant";
export default {
data() {
return {
temPhone:'',
dataList: [{ phone: "13148528214" }, { phone: "2" }, { phone: "32323232" },{ phone: "13148528214" }, { phone: "2" }, { phone: "32323232" }],
phoneShow: false,
};
},
mounted(){
this.platfromlist()
},
methods: {
showPhone(phone){
this.temPhone=phone
// this.phoneShow=true
},
changeName(type){
switch (type){
case 0:
return "市代加盟 "
break;
case 1:
return "经销商加盟 "
break
case 2:
return "平台客服 "
break
case 3:
return "供货商客服 "
break
}
},
platfromlist(){
api.platfromlist().then(res=>{
this.dataList=res
})
},
handleCopy(data) {
let oInput = document.createElement("input");
oInput.value = data;
document.body.appendChild(oInput);
oInput.select();
document.execCommand("Copy");
Toast.success("复制成功");
oInput.remove();
},
onClickLeft() {
history.back();
},
},
};
</script>
<style scoped>
.block {
border-radius: 3px;
color: #52b4ff;
height: 50px;
line-height: 50px;
background-color: #fff;
}
</style>
<template>
<van-sticky>
<van-nav-bar
title="订单详情"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
</van-sticky>
<van-row style="background: #fe9400;height: 5rem">
<van-col span="13">
<div style="text-align: center;margin-top: 1rem;color: #ffffff">
<div v-if="that.actIndex==0">
<p style="font-size: 1rem">等待买家付款</p>
<p>{{formatDuring(that.orderDesc.notPayDownTime)}} 自动关闭</p>
</div>
<div v-if="that.actIndex==1">
<p style="font-size: 1rem">买家已付款</p>
<p>卖家正在组织发货</p>
</div>
<div v-if="that.actIndex==2">
<p style="font-size: 1rem">卖家已发货</p>
<p>{{formatTow(that.orderDesc.confirmReceiptDownTime)}}自动确认</p>
</div>
<div v-if="that.actIndex==3">
<p style="font-size: 1em;margin-top: 1.8rem">交易成功</p>
</div>
<div v-if="that.actIndex==4">
<p style="font-size: 1rem">交易已关闭</p>
<p>系统自动关闭</p>
</div>
</div>
</van-col>
<van-col span="11" style="text-align: center">
<img v-if="that.actIndex==0" style="width: 5.5rem;margin-top: .4rem" src="../../static/img/daifukuang.jpg" alt="">
<img v-if="that.actIndex==1" style="width: 5.5rem;margin-top: .4rem" src="../../static/img/daifahuo.jpg" alt="">
<img v-if="that.actIndex==2" style="width: 5.5rem;margin-top: .2rem" src="../../static/img/yifahuo.jpg" alt="">
<img v-if="that.actIndex==3" style="width: 5.5rem;margin-top: .6rem" src="../../static/img/jiaoyichenggong.jpg" alt="">
<img v-if="that.actIndex==4" style="width:5rem;margin-top: .1rem" src="../../static/img/yiguanbi.jpg" alt="">
</van-col>
</van-row>
<van-row style="background: #ffffff;">
<van-col span="3">
<img style="width: 1.4rem;margin-left: .5rem;margin-top: 45%" src="../../static/img/sub_address.png" alt="">
</van-col>
<van-col span="18">
<div style="text-align: left;margin: 1rem auto">
<p >收货人:{{that.orderDesc.receiver}} {{that.orderDesc.phone}}</p>
<p>收货地址:{{that.orderDesc.address}} </p>
</div>
</van-col>
</van-row>
<div class="border_address"></div>
<van-row style="background: #ffffff;margin-top: .5rem">
<van-cell :title="that.orderDesc.storeName" icon="shop-o" is-link @click="goto('/')">
</van-cell>
<van-divider />
</van-row>
<van-grid :center="false" :column-num="1" v-for="params in that.params">
<!--@click="goto(`/pages/good/detail?skuId`)"-->
<van-grid-item class="text-left" @click.native="goto(`/pages/good/detail?skuId=${params.skuId}&spuId=${params.spuId}`)"
>
<van-row>
<van-col span="8" style="position: relative">
<van-image class="self_center" width="100%" lazy-load
:src="params.imgPath" />
<!--订单详情活动角标-->
<div class="sign" v-if="params.subScriptImgUrl">
<img :src="params.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{params.discount}}</div>
</div>
<van-image :key="index" v-for="(item,index) in params.dailyIcons" :style="{left:index*68+'rpx'}" :src="item" style="position: absolute;bottom: 0" width="60rpx" />
</van-col>
<van-col span="15" offset="1">
<p class="text-l ellipsis line_over2" style="height: 80rpx;">
{{params.title}}
</p>
<div style="line-height: 1.2rem">
<p class="text-s">规格:{{params.size}}</p>
<p class="text-gray text-s" v-if="params.deliveryTime==0">交货期:现货</p>
<p class="text-gray text-s" v-if="params.deliveryTime==1">交货期:15天</p>
<p class="text-gray text-s" v-if="params.deliveryTime==2">交货期:30天</p>
<p class="text-gray text-s" v-if="params.deliveryTime==2">交货期:45天</p>
<div v-if="false">
<p class="text-gray text-s" v-if="params.salePrice">
<span style="float: right;color: #414141;margin-right: 5px"> 件数:x {{params.count}}</span>
零售价¥{{params.productPrice}}</p>
<p class="text-gray text-s " v-else>
<span style="float: right;color: #414141"> 件数:x {{params.count}}</span>
<span :class="{'line-through':params.actPrice}" >零售价¥{{params.productPrice}}</span></p>
<div class="text-orange text-s">
<van-button v-if="that.actIndex!=0&&that.actIndex!=4" type="default" style="float: right;background: #f7f7f7;padding: 12px" size="small" @click.stop="afterSales">申请售后</van-button>
<text class="text-gray text-s line-through" v-if="params.salePrice">优惠价¥{{params.salePrice}}</text>
<text class="text-gray text-s line-through" v-else></text>
<p style="font-size: 13px;color: #ff793e" v-if="params.actPrice">活动价¥{{params.actPrice}}</p>
</div>
</div>
<div v-else>
<!--<p class="text-gray text-s line-through" v-if="params.salePrice">-->
<!--<span style="float: right;color: #414141;margin-right: 5px"> 件数:x {{params.count}}</span>-->
<!--零售价¥{{params.productPrice}}</p>-->
<p class="text-gray text-s ">
<span style="float: right;color: #414141"> 件数:x {{params.count}}</span>
<span style="color: #ff8467">¥{{params.payPrice}}</span></p>
<p class="text-orange text-s" style="margin-top: .3rem">
<van-button v-if="that.actIndex!=0&&that.actIndex!=4" type="default" style="float: right;background: #f7f7f7;padding: 12px" size="small" @click.stop="afterSales">申请售后</van-button>
<!--<text style="font-size: 13px;color: #ff793e" v-if="params.salePrice">优惠价¥{{params.salePrice}}</text>-->
</p>
</div>
</div>
</van-col>
</van-row>
</van-grid-item>
<van-divider />
<van-field v-model="params.remark" readonly
label="商品备注:"
/>
<van-divider />
</van-grid>
<div style="padding-bottom: 10rem;">
<div style="text-align: right;padding: .6rem;background: #ffffff;">共计 {{that.orderDesc.total}} 件商品&nbsp&nbsp 合计 <span style="color: #ff7d60">¥:{{that.orderDesc.totalFee}}</span> </div>
<div style="width: 100%">
<van-field style="margin-top: .6rem" v-model="that.orderDesc.remark" readonly
label="订单备注:"
/>
<van-field style="margin-top: .6rem" readonly v-model="that.orderDesc.payTypeDesc"
label="支付方式:"
/>
<van-field style="margin-top: .6rem" readonly v-model="that.orderDesc.orderCode"
label="订单编号:"
/>
<van-field readonly v-model="that.orderDesc.addDate"
label="创建时间:"
/>
<van-field v-if="that.actIndex==2||that.actIndex==1||that.actIndex==3" readonly v-model="that.orderDesc.onlinePayDate"
label="付款时间:"
/>
<van-field v-if="that.actIndex==2||that.actIndex==3" readonly v-model="that.orderDesc.confirmDate"
label="确认时间:"
/>
<van-field v-if="that.actIndex==2||that.actIndex==3" readonly v-model="that.orderDesc.deliveryDate"
label="发货时间:"
/>
<van-field v-if="that.actIndex==3" readonly v-model="that.orderDesc.completionDate"
label="成交时间:"
/>
<van-field v-if="that.actIndex==4" readonly v-model="that.orderDesc.cancelDate"
label="取消时间:"
/>
</div>
</div>
<van-action-bar v-if="that.actIndex==0" class="sh-t">
<van-action-bar-button @click="cancel" style="background: #ebebeb" text="取消订单" />
<van-action-bar-button @click="onSubmit" style="background: #ff6a00;color: #ffffff" text="付款" />
</van-action-bar>
<van-action-bar v-if="that.actIndex==2" class="sh-t">
<van-action-bar-button style="background: #ff6a00;color: #ffffff" @click="sure" text="确认收货" />
</van-action-bar>
<van-action-bar v-if="that.actIndex==3" class="sh-t">
<van-action-bar-button style="background: #ff6a00;color: #ffffff" @click="onceBuy" text="再买" />
</van-action-bar>
<van-action-bar v-if="that.actIndex==4" class="sh-t">
<van-action-bar-button style="background: #ff6a00;color: #ffffff" @click="onceBuy" text="重新买" />
</van-action-bar>
</template>
<script setup lang="ts">
import api from "@/api";
import { Dialog,Toast } from 'vant';
import {onMounted, reactive,getCurrentInstance,onUnmounted} from 'vue';
const that = reactive({
orderDesc:{},
actIndex:0,
params: [],
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any,
},
temOrderId:'',
})
onMounted(() => {
that.actIndex = getCurrentInstance().ctx.$page.options.act
that.temOrderId=getCurrentInstance().ctx.$page.options.url
getOrderDetail()
})
onUnmounted(()=>{
clearInterval(that.time)
})
// 待付款定时器
function ding() {
if(that.orderDesc.notPayDownTime>0){
that.time = setInterval(() => {
that.orderDesc.notPayDownTime--
if (that.orderDesc.notPayDownTime < 0) {
clearInterval(that.time)
}
}, 1000)
}
}
// 待付款定时器
function ding2() {
if(that.orderDesc.confirmReceiptDownTime>0){
that.time = setInterval(() => {
that.orderDesc.confirmReceiptDownTime--
if (that.orderDesc.confirmReceiptDownTime < 0) {
clearInterval(that.time)
}
}, 1000)
}
}
function onSubmit() {
if(!that.orderDesc.hasAlipayAccount){
Toast('商家未绑定支付宝收付款!');
return
}
uni.setStorageSync('payMoney',that.orderDesc.totalFee)
if(window.__wxjs_environment === 'miniprogram'){
window._wx.miniProgram.redirectTo({url: "/pages/pay/pay?orderid="+[that.orderDesc.orderId]})
}else {
orderPay([that.orderDesc.orderId])
}
}
function orderPay(idList) {
api.orderPay(
{
"domain": uni.getStorageSync("subdomain"),
"idList": idList,
}
).then((res: any) => {
window.location.href = res.payUri
})
}
function goto(url: any) {
url && uni.navigateTo({ url })
}
function cancel() {
Dialog.confirm({
title: '提示',
confirmButtonColor:'#ff6800',
message:
'确认要取消订单?',
})
.then(() => {
api.orderCancel(that.orderDesc.orderId).then((res)=>{
Toast.success(res);
goto(`/pages/order/orderList?index=0`)
})
})
.catch(() => {
// on cancel
});
}
function formatTow(value) {
var theTime = parseInt(value);// 需要转换的时间秒
var theTime1 = 0;// 分
var theTime2 = 0;// 小时
var theTime3 = 0;// 天
if(theTime > 60) {
theTime1 = parseInt(theTime/60);
theTime = parseInt(theTime%60);
if(theTime1 > 60) {
theTime2 = parseInt(theTime1/60);
theTime1 = parseInt(theTime1%60);
if(theTime2 > 24){
//大于24小时
theTime3 = parseInt(theTime2/24);
theTime2 = parseInt(theTime2%24);
}
}
}
var result = '';
if(theTime > 0){
result = ""+parseInt(theTime)+"秒";
}
if(theTime1 > 0) {
result = ""+parseInt(theTime1)+"分"+result;
}
if(theTime2 > 0) {
result = ""+parseInt(theTime2)+"小时"+result;
}
if(theTime3 > 0) {
result = ""+parseInt(theTime3)+"天"+result;
}
return result;
}
function formatDuring(s) {
var t = '';
if (s > -1) {
var hour = Math.floor(s / 3600)
var min = Math.floor(s / 60) % 60
var sec = s % 60
if (hour < 10) {
t = '0' + hour + "小时"
} else {
t = hour + "小时"
}
if (min < 10) {
t += "0"
}
t += min + "分钟"
if (sec < 10) {
t += "0"
}
t += sec.toFixed(0)+'秒'
}
return t
}
function getOrderDetail() {
api.getOrderDetail(that.temOrderId).then((res: any) => {
that.orderDesc=res
that.params=res.details
if(res.notPayDownTime>0){
ding()
}
if(res.confirmReceiptDownTime>0){
ding2()
}
})
}
function afterSales() {
uni.navigateTo({
url: `/pages/order/afterSales`,
});
}
function sure() {
Dialog.confirm({
title: '提示',
confirmButtonColor:'#ff6800',
message:
'确认收货',
})
.then(() => {
let obj = {
orderId: that.orderDesc.orderId,
domain: uni.getStorageSync('subdomain')
}
api.confirmReceipt(obj).then((res: any) => {
Toast.success('成功')
goto(`/pages/order/orderList?index=0`)
})
})
.catch(() => {
// on cancel
});
}
function onceBuy() {
let isBrandAgent = that.params.every(item => {
return item.isBrandAgent
})
if (isBrandAgent) {
let arr = []
that.params.forEach(item => {
arr.push(
{
"skuId": item.skuId,
"link": uni.getStorageSync("subdomain"),
"productQty": item.count
}
)
})
api.batchAdd(arr).then(res => {
uni.navigateTo({ url:`/?index=2` })
})
} else {
Toast.fail('商家未代理该品牌');
}
}
function onClickLeft() {
history.back()
}
</script>
<style lang="scss" scoped>
.sign {
position: absolute;
right: 1.8vw;
top: 0;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
.sd{
font-size: 30px;
}
.border_address{
border: 2px solid;
border-image-source: linear-gradient(to right, #fd942c, #f5180b);
border-image-slice: 1;
}
</style>
\ No newline at end of file
<template>
<view class="text-center pd-b-px-55">
<van-sticky>
<van-nav-bar
title="我的订单"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
<van-tabs v-model:active="state.active" color="#ff6600"
title-active-color="#ff6600" @click-tab="changeTab">
<van-tab title="全部">
</van-tab>
<van-tab title="待付款">
</van-tab>
<van-tab title="待发货">
</van-tab>
<van-tab title="待收货">
</van-tab>
<van-tab title="已完成">
</van-tab>
<van-tab title="已关闭">
</van-tab>
</van-tabs>
</van-sticky>
<div style="margin-top: .2rem"></div>
<van-list :loading="state.good.loading" :finished="state.good.finished" offset="10"
@load="onGoodLoad">
<van-grid :center="false" :column-num="1" v-for="(item, index) in state.good.list" :key="index" v-if="state.good.list.length>0">
<div style="background: #f1f5f8;padding: .8rem;font-size: 13px">
<span>订单号:{{item.orderCode}}</span>
<span style="color: #79abe7;margin-left: 1rem">{{item.statusDesc}}</span>
</div>
<van-grid-item class="text-left" v-for="good in item.details"
@click="goto(`/pages/good/detail?skuId=${good.skuId}&spuId=${good.spuId}`)">
<van-row>
<van-col span="8" style="position: relative">
<van-image class="self_center" width="100%" height="100%" lazy-load
:src="good.goodsImg" />
<!--订单详情活动角标-->
<div class="sign" v-if="good.subScriptImgUrl">
<img :src="good.subScriptImgUrl" alt="" />
<div class="discount" style="color: rgba(247, 103, 67, 1)">{{good.discount}}</div>
</div>
<view style="position: absolute;left: 0;bottom: 0;" v-if="good.conner.dailyIcons[0]">
<span style="margin-right: 5px" v-for="item in good.dailyIcons">
<van-image width="60rpx" height="32rpx" :src="item" />
</span>
</view>
<!--<van-image v-if="good.conner.dailyIcons[0]" :src="good.conner.dailyIcons[0]" style="position: absolute;left: 0;bottom: 0" width="60rpx" />-->
</van-col>
<van-col span="15" offset="1">
<p class="ellipsis line_over2 pd-t-10" style="height: 36px;margin-bottom:6px;font-size: 15px">
{{ good.goodsInfo }}
</p>
<div style="line-height: 1.2rem;font-size: 13px">
<p class="text-s">{{ good.spec }}</p>
<p class="text-gray "></p>
<div v-if="false">
<p class="text-gray " >
<span style="float: right;color: #545858"> 件数 x{{good.count}}</span>
<!--<span class="text-gray" :class="{'line-through':!good.salePrice}" >零售价¥{{ good.productPrice }}</span>-->
</p>
</div>
<div v-else>
<!--<p class="text-gray " v-if="!good.salePrice">-->
<!--<span style="float: right;color: #545858"> 件数 x{{good.count}}</span>-->
<!--<span style="color: #ff8467">零售价¥{{ good.productPrice }}</span>-->
<!--</p>-->
<p > <span style="float: right;color: #545858" class="text-orange">
件数 x{{good.count}}</span> <span class="text-orange">¥{{ good.payPrice }}</span></p>
</div>
<p class="text-orange" style="color: #ff793e;">
<span style="float: right;color:#79abe7" v-if="good.deliveryTime==0"> 交货期:现货</span>
<span style="float: right;color:#79abe7" v-if="good.deliveryTime==1"> 交货期:15天</span>
<span style="float: right;color:#79abe7" v-if="good.deliveryTime==2"> 交货期:30天</span>
<span style="float: right;color:#79abe7" v-if="good.deliveryTime==3"> 交货期:45天</span>
<!--<text v-if="false">-->
<!--<text class="text-gray line-through" v-if="good.salePrice"> 优惠价¥{{ good.salePrice }}</text>-->
<!--</text>-->
<!--<text v-else>-->
<!--<text v-if="good.salePrice"> ¥{{ good.payPrice }}</text>-->
<!--</text>-->
</p>
<!--<text class="text-orange" v-if="good.actPrice"> 活动价¥{{ good.actPrice }}</text>-->
</div>
</van-col>
</van-row>
</van-grid-item>
<van-divider />
<div style="background: #ffffff;display: flex;width: 100%;justify-content: end;flex-direction: column;text-align: right">
<p style="text-align: right;margin-right: .5rem;margin-top: .6rem">共计 {{item.total}} 件商品&nbsp&nbsp 合计 <span style="color: #ff7d60">¥:{{item.totalFee}}</span> </p>
<p style="text-align: right;margin-right: .5rem;margin-bottom: .6rem;margin-top: .6rem">
<van-button v-if="state.active==1||item.statusDesc== '等待买家付款'" type="primary" style="background: #fe6c31;margin-right: 8px;padding: 0 23px" size="small" @click.stop="onSubmit(item.orderId,item)">付款</van-button>
<van-button v-if="state.active==2&&item.hasRemindDelivery==0" type="primary" style="background: #fe6c31;margin-right: 8px;padding: 0 10px" size="small" @click.stop="remindDeliverGoods(item.orderId)">提醒发货</van-button>
<van-button v-if="state.active==2&&item.hasRemindDelivery==1" type="default" style="margin-right: 8px;padding: 0 10px;color:#fe6c31;background: #ffffff;border: 1px solid #fe6c31" size="small" @click.stop="false">已提醒</van-button>
<van-button v-if="state.active==3||item.statusDesc=='卖家已发货'" type="primary" style="background: #fe6c31;margin-right: 8px;padding: 0 10px" size="small" @click.stop="confirmReceipt(item.orderId)">确认收货</van-button>
<van-button type="primary" style="background: #fe6c31;padding: 0 10px" size="small" @click.stop="gotoDetails(item)">查看详情</van-button>
</p>
</div>
<van-divider />
</van-grid>
<div v-else class="justify-center" style="min-height: calc(100vh - 180px)">
<van-empty description="您还没有相关订单" >
<p class="bottom-button">您可以看看有哪些想买的</p>
</van-empty>
<van-button class="text-l" color="linear-gradient(315deg, #FE521F 0%, #FE7902 100%)" round block
style="width: 240rpx" @tap="goto('/')">
随便逛逛
</van-button>
</div>
</van-list>
<view v-if="state.good.fail" class="text-ss text-gray pd-50" @click="failReset">请求失败,点击重试
<van-icon name="replay" />
</view>
</view>
</template>
<script setup lang="ts">
import api from "@/api";
import {onMounted, reactive,getCurrentInstance} from 'vue';
import { Dialog,Toast } from 'vant';
import toTop from '@/components/tool/toTop.vue';
const state = reactive({
skuId: '',
params: {},
active: 0,
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any
}
})
onMounted(() => {
state.active = Number(getCurrentInstance().ctx.$page.options.index)
});
function is_weixn() {
let ua = navigator.userAgent.toLowerCase()
if(ua.match(/MicroMessenger/i)=='micromessenger'){
return true
}else {
return false
}
}
function onSubmit(e,data) {
if(!data.hasAlipayAccount){
Toast('商家未绑定支付宝收付款!');
return
}
uni.setStorageSync('payMoney',data.totalFee)
const isWxjs_environment = uni.getStorageSync("isWxjs_environment") || false;
if(isWxjs_environment) {
window._wx.miniProgram.redirectTo({url: "/pages/pay/pay?orderid="+e+'&wxapplets='+uni.getStorageSync("subdomain")})
}else {
orderPay([e])
}
}
function orderPay(idList) {
api.orderPay(
{
"domain": uni.getStorageSync("subdomain"),
"idList": idList,
}
).then((res: any) => {
if(is_weixn()){
Dialog.alert({
confirmButtonColor:'rgb(255, 102, 0)',
confirmButtonText:'*请复制链接后在浏览器打开',
message: res.payUri,
}).then(() => {
let oInput = document.createElement("input");
oInput.value = res.payUri;
document.body.appendChild(oInput);
oInput.select();
document.execCommand("Copy");
Toast.success("复制成功");
oInput.remove();
});
}else {
window.location.href = res.payUri
}
})
}
function confirmReceipt(e) {
Dialog.confirm({
confirmButtonColor: '#ff6800',
title: '提示',
message:
'确认收货?',
})
.then(() => {
let obj = {
orderId: e,
domain: uni.getStorageSync('subdomain')
}
api.confirmReceipt(obj).then((res: any) => {
Toast.success(res.message || res.msg)
})
onGoodLoad()
})
.catch(() => {
// on cancel
});
}
function gotoDetails(item) {
let status=0
if(item.statusDesc =='等待买家付款'){
status=0
}else if(item.statusDesc =='买家已付款'||item.statusDesc =='卖家正在备货'){
status=1
}else if(item.statusDesc =='卖家已发货'){
status=2
}else if(item.statusDesc =='交易成功'){
status=3
}else if(item.statusDesc =='交易关闭'){
status=4
}
uni.navigateTo({
url: `/pages/order/orderDetails?act=${status}&url=${item.orderId}`
});
}
function onClickLeft() {
uni.navigateTo({
url: `/pages/index?index=3`
});
}
function goto(url: any) {
url && uni.navigateTo({url})
}
function changeTab(e) {
state.good.list = []
state.good.page = 0
uni.pageScrollTo({
scrollTop: 0
});
onGoodLoad()
}
function remindDeliverGoods(orderId) {
api.remindDeliverGoods({orderId:orderId}).then(res=>{
state.active=2
Toast.success('提醒成功')
onGoodLoad()
})
}
function onGoodLoad() {
if (state.good.loading || state.good.fail) return
state.good.loading = true
++state.good.page
api.getOrderList({
domain:uni.getStorageSync("subdomain"),
pageNum: state.good.page,
pageSize: 20,
type:state.active
}).then((data: any) => {
if (!data||!data.hasNextPage){
state.good.finished = true
}
state.good.list.push(...data.list)
})
.catch(() => {
state.good.fail = true
})
.finally(() => {
state.good.loading = false
})
}
function failReset() {
state.good.page -= 1
state.good.finished = false
state.good.fail = false
onGoodLoad()
}
</script>
<style lang="scss" scoped>
.sign {
position: absolute;
right: 1.8vw;
top: 0;
width: 40px;
text-align: center;
img {
width: 40px;
margin-bottom: -18px;
}
.discount {
font-family: MiSans-Semibold;
text-shadow: 0.5px 0.5px #ddd;
color: #A532E0;
font-weight: 1000;
font-size: 12px;
}
}
.bottom-button {
color: #969799;
font-size: 13px;
margin-top: -18px;
}
</style>
<template>
<view class="text-center pd-b-px-55">
<van-sticky>
<van-nav-bar
title="支付成功"
left-arrow
@click-left="onClickLeft"
>
<template #left>
<van-icon name="arrow-left" size="25" color="#323233" />
</template>
</van-nav-bar>
</van-sticky>
<div style="margin-top: .2rem"></div>
<div style="background: #ffffff;height: 10rem;">
<div style="display: flex;align-items: center;margin-left: 20px">
<img src="../../static/img/pay01.jpg" alt=""
style="vertical-align: middle;width: 95px;height: 100px">
<div style="text-align: left">
<div style="white-space: nowrap">支付方式:<span style="color: #ff7f27">支付宝支付</span></div>
<div>订单金额:<span style="color: #ff7f27">¥{{state.money}}</span></div>
</div>
</div>
<div>
<van-button type="default" style="background: #f1f5f8;padding: 0 36px;margin-right: 20px" @click="goto(`/pages/order/orderList?index=0`)">查看订单</van-button>
<van-button type="success" style="background: #ff6600;padding: 0 36px" @click="goto(`/pages/index`)">回到首页</van-button>
</div>
</div>
<div style="margin-top: .2rem"></div>
<div style="background: #ffffff;min-height: 4.2rem;font-size: 13px;text-align: left;padding: .5rem">
<p>安全提醒</p>
<p>付款成功后,我们不会以付款异常、卡单、系统升级为由联系您。</p>
<p style="color: #ff8826;">请勿泄露银行卡号、手机验证码,否则会造成钱款损失。谨防电话诈骗!</p>
</div>
<div style="margin-top: .2rem"></div>
<div style="background: #ffffff;height: 1.6rem;font-size: 13px;text-align: left;padding: .5rem">
<!--<span style="float: right;font-size: 14px;margin-top: 2px">查看更多</span>-->
<h2> 为您推荐&nbsp<span style="font-size: 14px;color: #d1d2d3;margin-right: 3px">|&nbsp大牌任你选</span> </h2>
</div>
<div style="margin-top: .2rem"></div>
<van-list :loading="state.good.loading" :finished="state.good.finished" finished-text="没有更多了" offset="10"
@load="onGoodLoad">
<van-grid :center="false" :column-num="2" :gutter="3">
<van-grid-item class="text-left" v-for="(item, index) in state.good.list" :key="index"
@click="goto(`/pages/good/detail?skuId=${item.skuId}&spuId=${item.spuId}`)">
<van-image class="self_center" width="70%" lazy-load :src="item.mainImg" />
<van-image class="mg-t-30-m" width="60rpx" lazy-load :src="item.zoneIcon" />
<text class="text-s ellipsis line_over2 pd-t-10" style="width: 315rpx;height: 32px;margin-bottom:6px">
{{ item.title }}
</text>
<text class="text-ss">{{ item.size }}</text>
<text class="text-gray text-ss"></text>
<text class="text-gray text-ss line-through">零售价¥{{ item.productPrice }}</text>
<text class="text-orange text-ss">优惠价¥
<text class="text-bold text-l">{{ item.salePrice }}</text>
</text>
</van-grid-item>
</van-grid>
</van-list>
<view v-if="state.good.fail" class="text-ss text-gray pd-50" @click="failReset">请求失败,点击重试
<van-icon name="replay" />
</view>
</view>
</template>
<script setup lang="ts">
import api from "@/api";
import {onMounted, reactive} from 'vue';
import toTop from '@/components/tool/toTop.vue';
const state = reactive({
money:uni.getStorageSync("payMoney"),
skuId: '',
params: {},
active: 0,
good: {
loading: false,
finished: false,
fail: false,
page: 0,
list: [] as any
}
})
onMounted(() => {
});
function gotoDetails() {
uni.navigateTo({
url: `/pages/order/orderDetails`
});
}
function onClickLeft() {
history.back()
}
function goto(url: any) {
url && uni.navigateTo({url})
}
function onGoodLoad() {
if (state.good.loading || state.good.fail) return
state.good.loading = true
++state.good.page
api.productList({
...state.params,
sortType: state.good.page,
pageSize: 20,
link: uni.getStorageSync("subdomain")
}).then((data: any) => {
if (!data) return
if (!data||!data.hasNextPage){
state.good.finished = true
}
state.good.list.push(...data.list)
})
.catch(() => {
state.good.fail = true
})
.finally(() => {
state.good.loading = false
})
}
function failReset() {
state.good.page -= 1
state.good.finished = false
state.good.fail = false
onGoodLoad()
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div style="background: #f1f5f8;height: 100vh">
<div style="display: flex;justify-content: flex-start; align-items: center;background: #ffffff">
<van-search :clearable="false" v-model="search" style="flex: 2" placeholder="请输入搜索关键词" name="etaoSearch" ref="searchField"/>
<van-button type="warning" size="small" style="margin: 0 8px;background: #ff6600" @click="toGoodList(search,'search')">搜索</van-button>
<van-button size="small" style="margin-right: 10px" @click="goback">取消</van-button>
</div>
<div>
<h4 style="color: #5392e2;padding: 10px"><span style="float: right;font-size: 1.3rem;color: #adaeae;"><van-icon
name="delete-o" @click="del" /></span> #历史搜索
</h4>
<div style="background: #ffffff;padding: 10px;line-height: 1.6rem">
<div v-if="historyList.length>0">
<ul v-for="item in historyList">
<li @click="toGoodList(item)" style="border: 1px solid #f1f5f8;margin: 2px auto;">{{item}}</li>
</ul>
</div>
<p v-else>没有任何历史记录</p>
</div>
<!--<h4 style="color: #5392e2;padding: 10px;line-height: 2.3rem">#热门搜索</h4>-->
<!--<div>-->
<!--<ul style="background: #ffffff;padding: 10px" v-for="item in styleList">-->
<!--<li @click="toGoodList(item)">{{item}}</li>-->
<!--</ul>-->
<!--</div>-->
</div>
</div>
</template>
<script>
import { onShow} from "@dcloudio/uni-app";
import { Dialog } from "vant";
import { reactive, toRefs,onMounted, ref } from "vue";
import { PageUtils } from '@/utils/utils'
export default {
setup() {
const that = reactive({
search:'',
historyList: ["随便看看"],
styleList: ["欧式风格", "美式风格", "中式", "亚洲风格"],
goback: () => {
PageUtils.goBack()
},
toGoodList: (search,type) => {
if(type){
if(!search)return
let searchList = localStorage.getItem("searchList");
let arr = null;
if (searchList) {
arr = JSON.parse(searchList);
let index = arr.indexOf(that.search)
if(index===-1){
arr.push(that.search);
}
} else {
arr = [];
arr.push(that.search);
}
localStorage.setItem("searchList", JSON.stringify(arr));
}
const routers = getCurrentPages()
if (routers.length == 1 || routers[routers.length - 2].route != 'pages/goodList/index') {
uni.redirectTo({
url: `/pages/goodList/index?search=${search}`,
});
} else {
uni.navigateBack({
delta: 1,
complete: function () {
setTimeout(() => {
uni.redirectTo({
url: `/pages/goodList/index?search=${search}`,
});
}, 200);
}
});
}
},
del: () => {
Dialog.confirm({
title: "是否清空全部历史记录?",
})
.then(() => {
that.historyList = [];
localStorage.removeItem('searchList')
})
.catch(() => {
// on cancel
});
},
});
const searchField = ref()
onShow(() => {
that.search = ''
that.historyList = localStorage.getItem("searchList")?JSON.parse(localStorage.getItem("searchList")).reverse():[]
});
onMounted(() => {
setTimeout(() => {
searchField.value && searchField.value.focus()
})
})
const refState = toRefs(that);
return {
searchField,
...refState,
};
},
};
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<view class="justify-center pd-b-px-55">
已移除地图
</view>
</template>
<script setup lang="ts">
</script>
<style lang="scss" scoped>
</style>
<template>
<index v-show="state.tabIndex === 0" />
<live v-show="state.tabIndex === 1" />
<activity v-show="state.tabIndex === 2" />
<tabbar :current="state.tabIndex" :list="final.list" @tab-change="(index) => state.tabIndex = index"/>
</template>
<script setup lang="ts">
import { reactive } from "vue";
import activity from "./activity/index.vue";
import index from "./index/index.vue";
import live from "./live/index.vue";
import tabbar from "@/components/layout/tabbar.vue";
const state = reactive({
tabIndex: 0,
});
const final = {
list: [
{
text: "首页",
icon: "wap-home",
},
{
text: "直播",
icon: "bars",
},
{
text: "地图",
icon: "manager",
},
],
};
</script>
<style lang="scss" scoped></style>
<template>
<view class="pd-b-px-55">
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item>bannar1</van-swipe-item>
<van-swipe-item>bannar2</van-swipe-item>
<van-swipe-item>bannar3</van-swipe-item>
<van-swipe-item>bannar4</van-swipe-item>
</van-swipe>
</view>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
$--swiperColor: #39a9ed, #ed39a8, #6939ed, #39ed99;
.my-swipe .van-swipe-item {
color: #fff;
font-size: 20px;
line-height: 150px;
text-align: center;
@for $i from 1 through length($--swiperColor) {
&:nth-of-type(#{$i}n) {
background-color: nth($--swiperColor, $i);
}
}
}
</style>
<template>
<view class="justify-center pd-b-px-55">
已去除直播
</view>
</template>
<script setup lang="ts">
</script>
<style lang="scss" scoped>
</style>
// 用法: text-、line-、bg-,然后拼接上下面的颜色(如:.bg-gradual-orange、.bg-mauve.light)
$--red: #e54d42;
$--orange: #FE521F;
$--yellow: #FF8800;
$--olive: #8dc63f;
$--green: #39b54a;
$--cyan: #1cbbb4;
$--blue: #0081ff;
$--purple: #6739b6;
$--mauve: #9c26b0;
$--pink: #e03997;
$--brown: #a5673f;
$--grey: #8799a3;
$--black: #333333;
$--darkGray: #666666;
$--gray: #aaaaaa;
$--ghostWhite: #f1f1f1;
$--white: #ffffff;
/* 浅色 */
$--redLight: #fadbd9;
$--orangeLight: #fde6d2;
$--yellowLight: #fef2ce;
$--oliveLight: #e8f4d9;
$--greenLight: #d7f0db;
$--cyanLight: #d2f1f0;
$--blueLight: #cce6ff;
$--purpleLight: #e1d7f0;
$--mauveLight: #ebd4ef;
$--pinkLight: #f9d7ea;
$--brownLight: #ede1d9;
$--greyLight: #e7ebed;
/* 渐变色 */
$--gradualRed: linear-gradient(45deg, #f43f3b, #ec008c);
$--gradualOrange: linear-gradient(45deg, #ff9700, #ed1c24);
$--gradualGreen: linear-gradient(45deg, #39b54a, #8dc63f);
$--gradualPurple: linear-gradient(45deg, #9000ff, #5e00ff);
$--gradualPink: linear-gradient(45deg, #ec008c, #6739b6);
$--gradualBlue: linear-gradient(45deg, #0081ff, #1cbbb4);
.text-red,
.line-red {
color: ($--red);
}
.text-orange,
.line-orange {
color: ($--orange);
}
.text-yellow,
.line-yellow {
color: ($--yellow);
}
.text-olive,
.line-olive {
color: ($--olive);
}
.text-green,
.line-green {
color: ($--green);
}
.text-cyan,
.line-cyan {
color: ($--cyan);
}
.text-blue,
.line-blue {
color: ($--blue);
}
.text-purple,
.line-purple {
color: ($--purple);
}
.text-mauve,
.line-mauve {
color: ($--mauve);
}
.text-pink,
.line-pink {
color: ($--pink);
}
.text-brown,
.line-brown {
color: ($--brown);
}
.text-grey,
.line-grey {
color: ($--grey);
}
.text-darkGray,
.line-darkGray {
color: ($--darkGray);
}
.text-gray,
.line-gray {
color: ($--gray);
}
.text-ghost-white,
.line-ghost-white {
color: ($--ghostWhite);
}
.text-black,
.line-black {
color: ($--black);
}
.text-white,
.line-white {
color: ($--white);
}
/* ==================
背景
==================== */
.line-red::after {
border-color: ($--red);
}
.line-orange::after {
border-color: ($--orange);
}
.line-yellow::after {
border-color: ($--yellow);
}
.line-olive::after {
border-color: ($--olive);
}
.line-green::after {
border-color: ($--green);
}
.line-cyan::after {
border-color: ($--cyan);
}
.line-blue::after {
border-color: ($--blue);
}
.line-purple::after {
border-color: ($--purple);
}
.line-mauve::after {
border-color: ($--mauve);
}
.line-pink::after {
border-color: ($--pink);
}
.line-brown::after {
border-color: ($--brown);
}
.line-grey::after {
border-color: ($--grey);
}
.line-darkGray::after {
border-color: ($--darkGray);
}
.line-gray::after {
border-color: ($--gray);
}
.line-black::after {
border-color: ($--black);
}
.line-white::after {
border-color: ($--white);
}
.bg-red {
background-color: ($--red);
color: ($--white);
}
.bg-orange {
background-color: ($--orange);
color: ($--white);
}
.bg-yellow {
background-color: ($--yellow);
color: ($--black);
}
.bg-olive {
background-color: ($--olive);
color: ($--white);
}
.bg-green {
background-color: ($--green);
color: ($--white);
}
.bg-cyan {
background-color: ($--cyan);
color: ($--white);
}
.bg-blue {
background-color: ($--blue);
color: ($--white);
}
.bg-purple {
background-color: ($--purple);
color: ($--white);
}
.bg-mauve {
background-color: ($--mauve);
color: ($--white);
}
.bg-pink {
background-color: ($--pink);
color: ($--white);
}
.bg-brown {
background-color: ($--brown);
color: ($--white);
}
.bg-grey {
background-color: ($--grey);
color: ($--white);
}
.bg-gray {
background-color: #f0f0f0;
color: ($--black);
}
.bg-black {
background-color: ($--black);
color: ($--white);
}
.bg-white {
background-color: ($--white);
color: ($--darkGray);
}
.bg-ghost-white {
background-color: ($--ghostWhite);
color: ($--darkGray);
}
.bg-shadeTop {
background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.01));
color: ($--white);
}
.bg-shadeBottom {
background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 1));
color: ($--white);
}
.bg-red.light {
color: ($--red);
background-color: ($--redLight);
}
.bg-orange.light {
color: ($--orange);
background-color: ($--orangeLight);
}
.bg-yellow.light {
color: ($--yellow);
background-color: ($--yellowLight);
}
.bg-olive.light {
color: ($--olive);
background-color: ($--oliveLight);
}
.bg-green.light {
color: ($--green);
background-color: ($--greenLight);
}
.bg-cyan.light {
color: ($--cyan);
background-color: ($--cyanLight);
}
.bg-blue.light {
color: ($--blue);
background-color: ($--blueLight);
}
.bg-purple.light {
color: ($--purple);
background-color: ($--purpleLight);
}
.bg-mauve.light {
color: ($--mauve);
background-color: ($--mauveLight);
}
.bg-pink.light {
color: ($--pink);
background-color: ($--pinkLight);
}
.bg-brown.light {
color: ($--brown);
background-color: ($--brownLight);
}
.bg-grey.light {
color: ($--grey);
background-color: ($--greyLight);
}
.bg-gradual-red {
background-image: ($--gradualRed);
color: ($--white);
}
.bg-gradual-orange {
background-image: ($--gradualOrange);
color: ($--white);
}
.bg-gradual-green {
background-image: ($--gradualGreen);
color: ($--white);
}
.bg-gradual-purple {
background-image: ($--gradualPurple);
color: ($--white);
}
.bg-gradual-pink {
background-image: ($--gradualPink);
color: ($--white);
}
.bg-gradual-blue {
background-image: ($--gradualBlue);
color: ($--white);
}
// mg-、mg-h-、mg-v-、mg-l-、mg-r-、mg-t-、mg-b-
// pd-、pd-h-、pd-v-、pd-l-、pd-r-、pd-t-、pd-b-
// 0-110
// 额外单位 -px:px, 默认不填为'':rpx
// mg的特殊参数 (-m负数:例mg-100-m, mg-v-px-100-m)
@each $unit, $unitStr in (px: '-px', rpx: '') {
@each $rpx in 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110 {
@each $sufix, $sGrammar in (mg: margin, pd: padding) {
.#{$sufix}#{$unitStr}-#{$rpx} {
#{$sGrammar}: #{$rpx}#{$unit};
}
@each $direction, $dGrammar1, $dGrammar2 in (h, left, right),
(v, top, bottom)
{
.#{$sufix}-#{$direction}#{$unitStr}-#{$rpx} {
#{$sGrammar}-#{$dGrammar1}: #{$rpx}#{$unit};
#{$sGrammar}-#{$dGrammar2}: #{$rpx}#{$unit};
}
@if #{$sufix} == 'mg' {
.#{$sufix}-#{$direction}#{$unitStr}-#{$rpx}-m {
#{$sGrammar}-#{$dGrammar1}: -#{$rpx}#{$unit};
#{$sGrammar}-#{$dGrammar2}: -#{$rpx}#{$unit};
}
}
}
@each $direction, $dGrammar in (l: left, r: right, t: top, b: bottom) {
.#{$sufix}-#{$direction}#{$unitStr}-#{$rpx} {
#{$sGrammar}-#{$dGrammar}: #{$rpx}#{$unit};
}
@if #{$sufix} == 'mg' {
.#{$sufix}-#{$direction}#{$unitStr}-#{$rpx}-m {
#{$sGrammar}-#{$dGrammar}: -#{$rpx}#{$unit};
}
}
}
}
}
}
// br、br-l、br-t、br-r、br-t、br-b
.br {
border: 0.5rpx solid #f1f1f1;
}
@each $direction, $dGrammar in (l: left, r: right, t: top, b: bottom) {
.br-#{$direction} {
border-#{$dGrammar}: 0.5rpx solid #f1f1f1;
}
}
// ra
// 5-60
@each $rpx in 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60 {
.ra-#{$rpx} {
border-radius: #{$rpx}rpx;
}
}
.sh {
box-shadow: 0rpx 1rpx 10rpx #aaaaaa80;
}
.sh-t {
box-shadow: 0rpx -1rpx 10rpx #aaaaaa80;
}
// ------颜色------
@import "./color.scss";
// ------文字------
@import "./text.scss";
// ------布局------
@import "./content.scss";
.justify-center {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.justify-middle {
display: flex;
align-items: center;
}
.justify-between {
display: flex;
justify-content: space-between;
}
.justify-end {
display: flex;
justify-content: flex-end;
}
.justify-around {
display: flex;
justify-content: space-around;
}
.self_center {
align-self: center;
}
.flex {
display: flex;
&.wrap {
flex-wrap: wrap;
}
&.col {
flex-direction: column;
}
}
.inline-block {
display: inline-block;
}
.block {
display: block;
}
.hidden {
display: none;
}
// ------形状------
.bg-max {
height: 100vh;
}
.box {
padding: 20rpx;
box-shadow: 2rpx 10rpx 10rpx #efefef;
&.round {
border-radius: 20rpx;
}
&.action {
&:active {
box-shadow: 5rpx 8rpx 8rpx #dfdfdf;
}
}
}
.top-bar {
height: 44px;
}
.top-left {
position: absolute;
left: 10px;
font-size: 24px;
@extend .btn;
}
.top-center {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 16px;
}
.top-right {
position: absolute;
right: 10px;
font-size: 24px;
@extend .btn;
}
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
.fixed-top {
position: fixed;
top: 0;
left: 0;
right: 0;
}
// ------动画------
.btn {
transition: all ease-in-out 0.2s;
&:active {
opacity: 0.8;
}
}
// ------覆盖------
body {
font-size: 15px;
word-break: break-all;
background: #f1f1f1;
}
// uni
view {
user-select: text;
}
.uni-video-cover {
background-color: unset !important;
}
.uni-video-cover-duration {
display: none !important;
}
.uni-video-cover-play-button {
height: 80rpx !important;
width: 80rpx !important;
background-size: 37% !important;
border-radius: 50%;
border: 1px solid #fff;
background-color: rgba(0, 0, 0, 0.6);
}
// vant
:root {
--orange: #fe521f;
--van-primary-color: var(--orange);
--van-tab-active-text-color: var(--orange);
--van-tabs-bottom-bar-color: var(--orange);
--van-success-color: var(--orange);
--van-stepper-button-round-theme-color: var(--orange);
--van-dialog-border-radius: 10px;
--van-action-bar-icon-width: 54px;
--van-action-bar-icon-font-size: 14px;
--van-action-bar-icon-size: 20px;
--van-action-bar-height: 55px;
--van-tab-font-size: 16px;
}
.van-form {
.van-field__clear {
z-index: 100;
}
&.transparent {
.van-cell {
border-bottom: 1px solid #dfdfdf;
padding: 17px 0 14px 0;
&.field-focus {
padding: 17px 0 13px 0;
border-bottom: 2px solid var(--orange);
}
}
}
&.round {
.van-cell {
border-radius: 19px;
border: 1px solid #dfdfdf;
padding: 7px 16px 4px 16px;
&.field-focus {
padding: 6px 15px 3px 15px;
border: 2px solid var(--orange);
}
}
}
&.transparent,
&.round {
.van-cell-group {
background: unset !important;
}
.van-cell {
background: unset !important;
align-items: center; // 本身有flex参数
transition: all ease-in-out 0.3s;
.van-field__left-icon {
color: #aaaaaa;
padding-left: 1px;
padding-right: 10px;
transition: all ease-in-out 0.3s;
}
&.field-focus {
.van-field__left-icon {
color: var(--orange);
padding-right: 10px;
}
}
}
}
}
.van-grid {
&.small-padding {
.van-grid-item__content {
padding: 5px !important;
}
}
}
.van-action-bar {
&.custom-width {
.van-action-bar-button {
flex: inherit;
}
}
}
.van-collapse {
&.no-padding {
.van-collapse-item__title {
padding-left: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
align-items: center;
}
.van-collapse-item__content {
padding: 0 !important;
}
}
}
.van-action-bar {
z-index: 1;
}
.van-uploader {
&.round {
.van-uploader__upload {
border-radius: 50% !important;
}
.van-uploader__preview-image {
border-radius: 50% !important;
}
}
}
.van-dialog {
&.withBg {
background: url('@/static/img/login_bg.png') no-repeat;
background-size: 100% 50%;
background-color: #fff;
}
}
.van-image {
vertical-align:top !important;
}
.van-field__control {
font-size: 14px;
}
// ------其他------
@font-face {
font-family: "icon"; /* Project id 3475432 */
src: url('iconfont.woff2?t=1655804814204') format('woff2'),
url('iconfont.woff?t=1655804814204') format('woff'),
url('iconfont.ttf?t=1655804814204') format('truetype');
}
.icon {
font-family: "icon" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-yanzhengma:before {
content: "\e61a";
}
.icon-xianshimima:before {
content: "\e653";
}
.icon-yincangmima:before {
content: "\e60c";
}
.icon-mima:before {
content: "\e619";
}
.icon-shoujihao:before {
content: "\e60a";
}
@import "./iconfont/iconfont.css";
.scale-lt {
transform-origin: 0 0;
}
.scale-t {
transform-origin: 50% 0;
}
.scale-rt {
transform-origin: 100% 0;
}
.scale-8 {
transform: scale(0.8);
}
.scale-85 {
transform: scale(0.85);
}
.scale-9 {
transform: scale(0.9);
}
.text-ss {
font-size: 12px;
}
.text-s {
font-size: 13px;
}
.text-m {
font-size: 14px;
}
// ------默认15px------
.text-l {
font-size: 16px;
}
.text-xl {
font-size: 18px;
}
.text-xxl {
font-size: 22px;
}
.text-xxxl {
font-size: 40px;
}
.text-xxxxl {
font-size: 60px;
}
.ellipsis {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
&.line_over2 {
line-height: 1.3em;
white-space: unset;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
.text-bold {
font-weight: bold;
}
.line-through {
text-decoration: line-through;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
"use strict";
var device = navigator.userAgent.toLowerCase();
if (!/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile|mobile/.test(device)) {
if (window.location.port === '3000') {
window.location.href = 'https://etaoh5-pre.edstao.com/pc/';
}
else {
window.location.href = '/pc/';
}
}
//# sourceMappingURL=checkDevice.js.map
\ No newline at end of file
{"version":3,"file":"checkDevice.js","sourceRoot":"","sources":["checkDevice.ts"],"names":[],"mappings":";AAAA,IAAI,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;AAC/C,IAAI,CAAC,4EAA4E,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;IAC9F,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE;QACnC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,mCAAmC,CAAA;KAC3D;SAAM;QACL,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAA;KAC9B;CACF"}
\ No newline at end of file
// var device = navigator.userAgent.toLowerCase();
// const isWxjs_environment = uni.getStorageSync("isWxjs_environment") || false;
// if(!isWxjs_environment){
// if (!/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile|mobile/.test(device)) {
// if (window.location.port === '3000') {
// window.location.href = 'https://etaoh5-pre.edstao.com/pc/'
// } else {
// window.location.href = '/pc/'
// }
// }
// }
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
export function hex_sha1(s) {
return binb2hex(core_sha1(str2binb(s), s.length * chrsz));
}
function b64_sha1(s) {
return binb2b64(core_sha1(str2binb(s), s.length * chrsz));
}
function str_sha1(s) {
return binb2str(core_sha1(str2binb(s), s.length * chrsz));
}
function hex_hmac_sha1(key, data) {
return binb2hex(core_hmac_sha1(key, data));
}
function b64_hmac_sha1(key, data) {
return binb2b64(core_hmac_sha1(key, data));
}
function str_hmac_sha1(key, data) {
return binb2str(core_hmac_sha1(key, data));
}
/*
* Perform a simple self-test to see if the VM is working
*/
function sha1_vm_test() {
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}
/*
* Calculate the SHA-1 of an array of big-endian words, and a bit length
*/
function core_sha1(x, len) {
/* append padding */
x[len >> 5] |= 0x80 << (24 - (len % 32));
x[(((len + 64) >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for (var j = 0; j < 80; j++) {
if (j < 16)
w[j] = x[i + j];
else
w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde);
}
return Array(a, b, c, d, e);
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
function sha1_ft(t, b, c, d) {
if (t < 20)
return (b & c) | (~b & d);
if (t < 40)
return b ^ c ^ d;
if (t < 60)
return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
function sha1_kt(t) {
return t < 20
? 1518500249
: t < 40
? 1859775393
: t < 60
? -1894007588
: -899497514;
}
/*
* Calculate the HMAC-SHA1 of a key and some data
*/
function core_hmac_sha1(key, data) {
var bkey = str2binb(key);
if (bkey.length > 16)
bkey = core_sha1(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for (var i = 0; i < 16; i++) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5c5c5c5c;
}
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_sha1(opad.concat(hash), 512 + 160);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y) {
var lsw = (x & 0xffff) + (y & 0xffff);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xffff);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert an 8-bit or 16-bit string to an array of big-endian words
* In 8-bit function, characters >255 have their hi-byte silently ignored.
*/
function str2binb(str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |=
(str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - (i % 32));
return bin;
}
/*
* Convert an array of big-endian words to a string
*/
function binb2str(bin) {
var str = "";
var mask = (1 << chrsz) - 1;
for (var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i >> 5] >>> (32 - chrsz - (i % 32))) & mask);
return str;
}
/*
* Convert an array of big-endian words to a hex string.
*/
function binb2hex(binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str +=
hex_tab.charAt((binarray[i >> 2] >> ((3 - (i % 4)) * 8 + 4)) & 0xf) +
hex_tab.charAt((binarray[i >> 2] >> ((3 - (i % 4)) * 8)) & 0xf);
}
return str;
}
/*
* Convert an array of big-endian words to a base-64 string
*/
function binb2b64(binarray) {
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for (var i = 0; i < binarray.length * 4; i += 3) {
var triplet = (((binarray[i >> 2] >> (8 * (3 - (i % 4)))) & 0xff) << 16) |
(((binarray[(i + 1) >> 2] >> (8 * (3 - ((i + 1) % 4)))) & 0xff) << 8) |
((binarray[(i + 2) >> 2] >> (8 * (3 - ((i + 2) % 4)))) & 0xff);
for (var j = 0; j < 4; j++) {
if (i * 8 + j * 6 > binarray.length * 32)
str += b64pad;
else
str += tab.charAt((triplet >> (6 * (3 - j))) & 0x3f);
}
}
return str;
}
//# sourceMappingURL=sha1.js.map
\ No newline at end of file
{"version":3,"file":"sha1.js","sourceRoot":"","sources":["sha1.ts"],"names":[],"mappings":"AAAA,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,4DAA4D;AAC7E,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,4DAA4D;AAC7E,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,4DAA4D;AAE3E;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC;AACD,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC;AACD,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC;AACD,SAAS,aAAa,CAAC,GAAW,EAAE,IAAY;IAC9C,OAAO,QAAQ,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAC7C,CAAC;AACD,SAAS,aAAa,CAAC,GAAW,EAAE,IAAY;IAC9C,OAAO,QAAQ,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAC7C,CAAC;AACD,SAAS,aAAa,CAAC,GAAW,EAAE,IAAY;IAC9C,OAAO,QAAQ,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,SAAS,YAAY;IACnB,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,0CAA0C,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,CAAW,EAAE,GAAW;IACzC,oBAAoB;IACpB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC;IAEvC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;IACnB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;IACpB,IAAI,CAAC,GAAG,SAAS,CAAC;IAClB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,IAAI,IAAI,GAAG,CAAC,CAAC;QAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;YAC3B,IAAI,CAAC,GAAG,EAAE;gBAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;;gBACvB,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAChE,IAAI,CAAC,GAAG,QAAQ,CACd,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EACxC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CACxC,CAAC;YACF,CAAC,GAAG,CAAC,CAAC;YACN,CAAC,GAAG,CAAC,CAAC;YACN,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACf,CAAC,GAAG,CAAC,CAAC;YACN,CAAC,GAAG,CAAC,CAAC;SACP;QAED,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtB,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtB,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtB,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtB,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;KACvB;IACD,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,SAAS,OAAO,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS;IACzD,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAC,CAAS;IACxB,OAAO,CAAC,GAAG,EAAE;QACX,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,CAAC,GAAG,EAAE;YACR,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,CAAC,GAAG,EAAE;gBACR,CAAC,CAAC,CAAC,UAAU;gBACb,CAAC,CAAC,CAAC,SAAS,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,GAAW,EAAE,IAAY;IAC/C,IAAI,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;QAAE,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IAEjE,IAAI,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,EAClB,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;QAC3B,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;QAC/B,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;KAChC;IAED,IAAI,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IAC7E,OAAO,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,SAAS,QAAQ,CAAC,CAAS,EAAE,CAAS;IACpC,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;IACtC,IAAI,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAS,GAAG,CAAC,GAAW,EAAE,GAAW;IACnC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,GAAG,GAAG,KAAK,EAAE,CAAC;IAClB,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC,IAAI,KAAK;QAChD,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;YACT,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAClE,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,GAAa;IAC7B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC,IAAI,KAAK;QAC7C,GAAG,IAAI,MAAM,CAAC,YAAY,CACxB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CACjD,CAAC;IACJ,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,QAAkB;IAClC,IAAI,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAChE,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC5C,GAAG;YACD,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBACnE,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;KACnE;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,QAAkB;IAClC,IAAI,GAAG,GAAG,kEAAkE,CAAC;IAC7E,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;QAC/C,IAAI,OAAO,GACT,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1D,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YACrE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,EAAE;gBAAE,GAAG,IAAI,MAAM,CAAC;;gBACnD,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;SAC3D;KACF;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
\ No newline at end of file
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
export function hex_sha1(s: string): string {
return binb2hex(core_sha1(str2binb(s), s.length * chrsz));
}
function b64_sha1(s: string): string {
return binb2b64(core_sha1(str2binb(s), s.length * chrsz));
}
function str_sha1(s: string): string {
return binb2str(core_sha1(str2binb(s), s.length * chrsz));
}
function hex_hmac_sha1(key: string, data: string): string {
return binb2hex(core_hmac_sha1(key, data));
}
function b64_hmac_sha1(key: string, data: string): string {
return binb2b64(core_hmac_sha1(key, data));
}
function str_hmac_sha1(key: string, data: string): string {
return binb2str(core_hmac_sha1(key, data));
}
/*
* Perform a simple self-test to see if the VM is working
*/
function sha1_vm_test(): boolean {
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}
/*
* Calculate the SHA-1 of an array of big-endian words, and a bit length
*/
function core_sha1(x: number[], len: number): number[] {
/* append padding */
x[len >> 5] |= 0x80 << (24 - (len % 32));
x[(((len + 64) >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for (var j = 0; j < 80; j++) {
if (j < 16) w[j] = x[i + j];
else w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
var t = safe_add(
safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
safe_add(safe_add(e, w[j]), sha1_kt(j))
);
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde);
}
return Array(a, b, c, d, e);
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
function sha1_ft(t: number, b: number, c: number, d: number): number {
if (t < 20) return (b & c) | (~b & d);
if (t < 40) return b ^ c ^ d;
if (t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
function sha1_kt(t: number): number {
return t < 20
? 1518500249
: t < 40
? 1859775393
: t < 60
? -1894007588
: -899497514;
}
/*
* Calculate the HMAC-SHA1 of a key and some data
*/
function core_hmac_sha1(key: string, data: string): number[] {
var bkey = str2binb(key);
if (bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
var ipad = Array(16),
opad = Array(16);
for (var i = 0; i < 16; i++) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5c5c5c5c;
}
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_sha1(opad.concat(hash), 512 + 160);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x: number, y: number): number {
var lsw = (x & 0xffff) + (y & 0xffff);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xffff);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function rol(num: number, cnt: number): number {
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert an 8-bit or 16-bit string to an array of big-endian words
* In 8-bit function, characters >255 have their hi-byte silently ignored.
*/
function str2binb(str: string): number[] {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |=
(str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - (i % 32));
return bin;
}
/*
* Convert an array of big-endian words to a string
*/
function binb2str(bin: number[]): string {
var str = "";
var mask = (1 << chrsz) - 1;
for (var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode(
(bin[i >> 5] >>> (32 - chrsz - (i % 32))) & mask
);
return str;
}
/*
* Convert an array of big-endian words to a hex string.
*/
function binb2hex(binarray: number[]): string {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str +=
hex_tab.charAt((binarray[i >> 2] >> ((3 - (i % 4)) * 8 + 4)) & 0xf) +
hex_tab.charAt((binarray[i >> 2] >> ((3 - (i % 4)) * 8)) & 0xf);
}
return str;
}
/*
* Convert an array of big-endian words to a base-64 string
*/
function binb2b64(binarray: number[]): string {
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for (var i = 0; i < binarray.length * 4; i += 3) {
var triplet =
(((binarray[i >> 2] >> (8 * (3 - (i % 4)))) & 0xff) << 16) |
(((binarray[(i + 1) >> 2] >> (8 * (3 - ((i + 1) % 4)))) & 0xff) << 8) |
((binarray[(i + 2) >> 2] >> (8 * (3 - ((i + 2) % 4)))) & 0xff);
for (var j = 0; j < 4; j++) {
if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> (6 * (3 - j))) & 0x3f);
}
}
return str;
}
import api from "@/api";
import { hex_sha1 } from "@/utils/sha1";
export class PageUtils {
// 获取当前路由
static getCurPage(): object {
let pages = getCurrentPages();
let curPage = pages[pages.length - 1];
return curPage;
}
static getCurQuery(): object {
// @ts-ignore
return PageUtils.getCurPage().$page.options;
}
// 微信不需要标题,因为会出现双标题问题,而且我觉得标题上移会简洁一点
// force强制获取
static getTitle(force?: boolean): string {
// @ts-ignore
if (force) return PageUtils.getCurPage().$page.meta.navigationBar.titleText
// @ts-ignore
return uni.getStorageSync('isWX')?'':PageUtils.getCurPage().$page.meta.navigationBar.titleText
}
static object2Query(obj: any): string {
let queryList: Array<string> = [];
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
queryList.push(
encodeURIComponent(key) + "=" + encodeURIComponent(obj[key])
);
}
}
return queryList.join("&");
}
static goBack(url?: string) {
if (getCurrentPages().length == 1) {
uni.navigateTo({ url: url || "/" });
} else {
uni.navigateBack({
delta: 1,
});
}
}
}
declare interface EnumName {
name: 'delivery' | 'userSex';
}
export class Enum {
static delivery = {
0: "现货",
1: "15天",
2: "30天",
3: "45天",
4: "45天以上",
};
static userSex = {
null: "未填写",
0: "女",
1: "男"
};
static get(name: EnumName['name'], value: any) {
if (!Enum.hasOwnProperty(name)) {
console.error('Enum中没有该参数,请在Utils.ts中设置')
return undefined
}
// @ts-ignore
return Enum[name][value];
}
}
export class WXUtils {
static isWeiXin() {
if (/micromessenger/.test(window.navigator.userAgent.toLowerCase())) {
return true;
} else {
return false;
}
}
static initWXConfig(test?: boolean) {
return new Promise((resolve, reject) => {
const wx = window._wx;
api
.getJsApiTicket()
.then((ticket: any) => {
const nonceStr = DataUtils.getRandString(16);
const timestamp = Math.trunc(new Date().getTime() / 1000);
const url = window.location.href;
const signature = hex_sha1(
`jsapi_ticket=${ticket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`
);
const wxConfig = {
debug: !!test, // 上生产,时设置成false
appId: "wx6165c6cc754deeba",
timestamp,
nonceStr,
signature,
jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"],
};
wx.config(wxConfig);
wx.ready(function () {
resolve({
status: true,
message: "初始化成功",
data: wxConfig,
});
});
wx.error(function (data: any) {
reject({
status: false,
message: "初始化失败:微信配置异常",
data,
});
});
})
.catch((data: any) => {
reject({
status: false,
message: "初始化失败:后台异常",
data,
});
});
});
}
}
export class DataUtils {
static getRandString(len: number) {
const chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var str = "";
for (var i = 0; i < len; i++) {
str += chars[Math.floor(Math.random() * chars.length)];
}
return str;
}
}
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["@dcloudio/types", "@types/node", "@types/md5"],
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"exclude": ["node_modules"]
}
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
uni()
],
server: {
proxy: {
'^/pre': {
target: 'https://etaoh5-pre.edstao.com/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/pre/, '')
},
'^/prod': {
target: 'https://etaoh5.edstao.com/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/prod/, '')
}
}
}
});
cb1ab2ae911a9670625565da9793c158
\ No newline at end of file
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册