Compare commits

..

2 Commits
master ... yyw

Author SHA1 Message Date
585404e2ed yyw提交 2025-12-11 15:46:10 +08:00
59ba7005fc commit yyw 2025-12-11 15:38:52 +08:00
9934 changed files with 1346546 additions and 3 deletions

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Build and Release Folders
bin-debug/
bin-release/
[Oo]bj/
[Bb]in/
# Other files and folders
.settings/
unpackage/
dist/**
.DS_Store
# Executables
*.swf
*.air
*.ipa
*.apk
# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
# should NOT be excluded as they contain compiler settings and other important
# information for Eclipse / Flash Builder.

29
.hbuilderx/launch.json Normal file
View File

@ -0,0 +1,29 @@
{
// launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version" : "0.0",
"configurations" : [
{
"app-plus" : {
"launchtype" : "local"
},
"default" : {
"launchtype" : "local"
},
"mp-weixin" : {
"launchtype" : "local"
},
"type" : "uniCloud"
},
{
"openVueDevtools" : true,
"playground" : "standard",
"type" : "uni-app:app-android"
},
{
"openVueDevtools" : true,
"playground" : "standard",
"type" : "uni-app:app-ios"
}
]
}

23
.vite/deps/_metadata.json Normal file
View File

@ -0,0 +1,23 @@
{
"hash": "27ca6c53",
"browserHash": "ddb93c4c",
"optimized": {
"dayjs": {
"src": "../../node_modules/dayjs/dayjs.min.js",
"file": "dayjs.js",
"fileHash": "4f773eae",
"needsInterop": true
},
"dayjs/esm/index": {
"src": "../../node_modules/dayjs/esm/index.js",
"file": "dayjs_esm_index.js",
"fileHash": "a6f15937",
"needsInterop": false
}
},
"chunks": {
"chunk-RSJERJUL": {
"file": "chunk-RSJERJUL.js"
}
}
}

View File

@ -0,0 +1,9 @@
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
export {
__commonJS
};
//# sourceMappingURL=chunk-RSJERJUL.js.map

View File

@ -0,0 +1,7 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}

299
.vite/deps/dayjs.js Normal file
View File

@ -0,0 +1,299 @@
import {
__commonJS
} from "./chunk-RSJERJUL.js";
// ../../../shop_app/node_modules/dayjs/dayjs.min.js
var require_dayjs_min = __commonJS({
"../../../shop_app/node_modules/dayjs/dayjs.min.js"(exports, module) {
!function(t, e) {
"object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
}(exports, function() {
"use strict";
var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), ordinal: function(t2) {
var e2 = ["th", "st", "nd", "rd"], n2 = t2 % 100;
return "[" + t2 + (e2[(n2 - 20) % 10] || e2[n2] || e2[0]) + "]";
} }, m = function(t2, e2, n2) {
var r2 = String(t2);
return !r2 || r2.length >= e2 ? t2 : "" + Array(e2 + 1 - r2.length).join(n2) + t2;
}, v = { s: m, z: function(t2) {
var e2 = -t2.utcOffset(), n2 = Math.abs(e2), r2 = Math.floor(n2 / 60), i2 = n2 % 60;
return (e2 <= 0 ? "+" : "-") + m(r2, 2, "0") + ":" + m(i2, 2, "0");
}, m: function t2(e2, n2) {
if (e2.date() < n2.date())
return -t2(n2, e2);
var r2 = 12 * (n2.year() - e2.year()) + (n2.month() - e2.month()), i2 = e2.clone().add(r2, c), s2 = n2 - i2 < 0, u2 = e2.clone().add(r2 + (s2 ? -1 : 1), c);
return +(-(r2 + (n2 - i2) / (s2 ? i2 - u2 : u2 - i2)) || 0);
}, a: function(t2) {
return t2 < 0 ? Math.ceil(t2) || 0 : Math.floor(t2);
}, p: function(t2) {
return { M: c, y: h, w: o, d: a, D: d, h: u, m: s, s: i, ms: r, Q: f }[t2] || String(t2 || "").toLowerCase().replace(/s$/, "");
}, u: function(t2) {
return void 0 === t2;
} }, g = "en", D = {};
D[g] = M;
var p = "$isDayjsObject", S = function(t2) {
return t2 instanceof _ || !(!t2 || !t2[p]);
}, w = function t2(e2, n2, r2) {
var i2;
if (!e2)
return g;
if ("string" == typeof e2) {
var s2 = e2.toLowerCase();
D[s2] && (i2 = s2), n2 && (D[s2] = n2, i2 = s2);
var u2 = e2.split("-");
if (!i2 && u2.length > 1)
return t2(u2[0]);
} else {
var a2 = e2.name;
D[a2] = e2, i2 = a2;
}
return !r2 && i2 && (g = i2), i2 || !r2 && g;
}, O = function(t2, e2) {
if (S(t2))
return t2.clone();
var n2 = "object" == typeof e2 ? e2 : {};
return n2.date = t2, n2.args = arguments, new _(n2);
}, b = v;
b.l = w, b.i = S, b.w = function(t2, e2) {
return O(t2, { locale: e2.$L, utc: e2.$u, x: e2.$x, $offset: e2.$offset });
};
var _ = function() {
function M2(t2) {
this.$L = w(t2.locale, null, true), this.parse(t2), this.$x = this.$x || t2.x || {}, this[p] = true;
}
var m2 = M2.prototype;
return m2.parse = function(t2) {
this.$d = function(t3) {
var e2 = t3.date, n2 = t3.utc;
if (null === e2)
return new Date(NaN);
if (b.u(e2))
return new Date();
if (e2 instanceof Date)
return new Date(e2);
if ("string" == typeof e2 && !/Z$/i.test(e2)) {
var r2 = e2.match($);
if (r2) {
var i2 = r2[2] - 1 || 0, s2 = (r2[7] || "0").substring(0, 3);
return n2 ? new Date(Date.UTC(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2)) : new Date(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2);
}
}
return new Date(e2);
}(t2), this.init();
}, m2.init = function() {
var t2 = this.$d;
this.$y = t2.getFullYear(), this.$M = t2.getMonth(), this.$D = t2.getDate(), this.$W = t2.getDay(), this.$H = t2.getHours(), this.$m = t2.getMinutes(), this.$s = t2.getSeconds(), this.$ms = t2.getMilliseconds();
}, m2.$utils = function() {
return b;
}, m2.isValid = function() {
return !(this.$d.toString() === l);
}, m2.isSame = function(t2, e2) {
var n2 = O(t2);
return this.startOf(e2) <= n2 && n2 <= this.endOf(e2);
}, m2.isAfter = function(t2, e2) {
return O(t2) < this.startOf(e2);
}, m2.isBefore = function(t2, e2) {
return this.endOf(e2) < O(t2);
}, m2.$g = function(t2, e2, n2) {
return b.u(t2) ? this[e2] : this.set(n2, t2);
}, m2.unix = function() {
return Math.floor(this.valueOf() / 1e3);
}, m2.valueOf = function() {
return this.$d.getTime();
}, m2.startOf = function(t2, e2) {
var n2 = this, r2 = !!b.u(e2) || e2, f2 = b.p(t2), l2 = function(t3, e3) {
var i2 = b.w(n2.$u ? Date.UTC(n2.$y, e3, t3) : new Date(n2.$y, e3, t3), n2);
return r2 ? i2 : i2.endOf(a);
}, $2 = function(t3, e3) {
return b.w(n2.toDate()[t3].apply(n2.toDate("s"), (r2 ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e3)), n2);
}, y2 = this.$W, M3 = this.$M, m3 = this.$D, v2 = "set" + (this.$u ? "UTC" : "");
switch (f2) {
case h:
return r2 ? l2(1, 0) : l2(31, 11);
case c:
return r2 ? l2(1, M3) : l2(0, M3 + 1);
case o:
var g2 = this.$locale().weekStart || 0, D2 = (y2 < g2 ? y2 + 7 : y2) - g2;
return l2(r2 ? m3 - D2 : m3 + (6 - D2), M3);
case a:
case d:
return $2(v2 + "Hours", 0);
case u:
return $2(v2 + "Minutes", 1);
case s:
return $2(v2 + "Seconds", 2);
case i:
return $2(v2 + "Milliseconds", 3);
default:
return this.clone();
}
}, m2.endOf = function(t2) {
return this.startOf(t2, false);
}, m2.$set = function(t2, e2) {
var n2, o2 = b.p(t2), f2 = "set" + (this.$u ? "UTC" : ""), l2 = (n2 = {}, n2[a] = f2 + "Date", n2[d] = f2 + "Date", n2[c] = f2 + "Month", n2[h] = f2 + "FullYear", n2[u] = f2 + "Hours", n2[s] = f2 + "Minutes", n2[i] = f2 + "Seconds", n2[r] = f2 + "Milliseconds", n2)[o2], $2 = o2 === a ? this.$D + (e2 - this.$W) : e2;
if (o2 === c || o2 === h) {
var y2 = this.clone().set(d, 1);
y2.$d[l2]($2), y2.init(), this.$d = y2.set(d, Math.min(this.$D, y2.daysInMonth())).$d;
} else
l2 && this.$d[l2]($2);
return this.init(), this;
}, m2.set = function(t2, e2) {
return this.clone().$set(t2, e2);
}, m2.get = function(t2) {
return this[b.p(t2)]();
}, m2.add = function(r2, f2) {
var d2, l2 = this;
r2 = Number(r2);
var $2 = b.p(f2), y2 = function(t2) {
var e2 = O(l2);
return b.w(e2.date(e2.date() + Math.round(t2 * r2)), l2);
};
if ($2 === c)
return this.set(c, this.$M + r2);
if ($2 === h)
return this.set(h, this.$y + r2);
if ($2 === a)
return y2(1);
if ($2 === o)
return y2(7);
var M3 = (d2 = {}, d2[s] = e, d2[u] = n, d2[i] = t, d2)[$2] || 1, m3 = this.$d.getTime() + r2 * M3;
return b.w(m3, this);
}, m2.subtract = function(t2, e2) {
return this.add(-1 * t2, e2);
}, m2.format = function(t2) {
var e2 = this, n2 = this.$locale();
if (!this.isValid())
return n2.invalidDate || l;
var r2 = t2 || "YYYY-MM-DDTHH:mm:ssZ", i2 = b.z(this), s2 = this.$H, u2 = this.$m, a2 = this.$M, o2 = n2.weekdays, c2 = n2.months, f2 = n2.meridiem, h2 = function(t3, n3, i3, s3) {
return t3 && (t3[n3] || t3(e2, r2)) || i3[n3].slice(0, s3);
}, d2 = function(t3) {
return b.s(s2 % 12 || 12, t3, "0");
}, $2 = f2 || function(t3, e3, n3) {
var r3 = t3 < 12 ? "AM" : "PM";
return n3 ? r3.toLowerCase() : r3;
};
return r2.replace(y, function(t3, r3) {
return r3 || function(t4) {
switch (t4) {
case "YY":
return String(e2.$y).slice(-2);
case "YYYY":
return b.s(e2.$y, 4, "0");
case "M":
return a2 + 1;
case "MM":
return b.s(a2 + 1, 2, "0");
case "MMM":
return h2(n2.monthsShort, a2, c2, 3);
case "MMMM":
return h2(c2, a2);
case "D":
return e2.$D;
case "DD":
return b.s(e2.$D, 2, "0");
case "d":
return String(e2.$W);
case "dd":
return h2(n2.weekdaysMin, e2.$W, o2, 2);
case "ddd":
return h2(n2.weekdaysShort, e2.$W, o2, 3);
case "dddd":
return o2[e2.$W];
case "H":
return String(s2);
case "HH":
return b.s(s2, 2, "0");
case "h":
return d2(1);
case "hh":
return d2(2);
case "a":
return $2(s2, u2, true);
case "A":
return $2(s2, u2, false);
case "m":
return String(u2);
case "mm":
return b.s(u2, 2, "0");
case "s":
return String(e2.$s);
case "ss":
return b.s(e2.$s, 2, "0");
case "SSS":
return b.s(e2.$ms, 3, "0");
case "Z":
return i2;
}
return null;
}(t3) || i2.replace(":", "");
});
}, m2.utcOffset = function() {
return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
}, m2.diff = function(r2, d2, l2) {
var $2, y2 = this, M3 = b.p(d2), m3 = O(r2), v2 = (m3.utcOffset() - this.utcOffset()) * e, g2 = this - m3, D2 = function() {
return b.m(y2, m3);
};
switch (M3) {
case h:
$2 = D2() / 12;
break;
case c:
$2 = D2();
break;
case f:
$2 = D2() / 3;
break;
case o:
$2 = (g2 - v2) / 6048e5;
break;
case a:
$2 = (g2 - v2) / 864e5;
break;
case u:
$2 = g2 / n;
break;
case s:
$2 = g2 / e;
break;
case i:
$2 = g2 / t;
break;
default:
$2 = g2;
}
return l2 ? $2 : b.a($2);
}, m2.daysInMonth = function() {
return this.endOf(c).$D;
}, m2.$locale = function() {
return D[this.$L];
}, m2.locale = function(t2, e2) {
if (!t2)
return this.$L;
var n2 = this.clone(), r2 = w(t2, e2, true);
return r2 && (n2.$L = r2), n2;
}, m2.clone = function() {
return b.w(this.$d, this);
}, m2.toDate = function() {
return new Date(this.valueOf());
}, m2.toJSON = function() {
return this.isValid() ? this.toISOString() : null;
}, m2.toISOString = function() {
return this.$d.toISOString();
}, m2.toString = function() {
return this.$d.toUTCString();
}, M2;
}(), k = _.prototype;
return O.prototype = k, [["$ms", r], ["$s", i], ["$m", s], ["$H", u], ["$W", a], ["$M", c], ["$y", h], ["$D", d]].forEach(function(t2) {
k[t2[1]] = function(e2) {
return this.$g(e2, t2[0], t2[1]);
};
}), O.extend = function(t2, e2) {
return t2.$i || (t2(e2, _, O), t2.$i = true), O;
}, O.locale = w, O.isDayjs = S, O.unix = function(t2) {
return O(1e3 * t2);
}, O.en = D[g], O.Ls = D, O.p = {}, O;
});
}
});
export default require_dayjs_min();
//# sourceMappingURL=dayjs.js.map

7
.vite/deps/dayjs.js.map Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,494 @@
import "./chunk-RSJERJUL.js";
// ../../../shop_app/node_modules/dayjs/esm/constant.js
var SECONDS_A_MINUTE = 60;
var SECONDS_A_HOUR = SECONDS_A_MINUTE * 60;
var SECONDS_A_DAY = SECONDS_A_HOUR * 24;
var SECONDS_A_WEEK = SECONDS_A_DAY * 7;
var MILLISECONDS_A_SECOND = 1e3;
var MILLISECONDS_A_MINUTE = SECONDS_A_MINUTE * MILLISECONDS_A_SECOND;
var MILLISECONDS_A_HOUR = SECONDS_A_HOUR * MILLISECONDS_A_SECOND;
var MILLISECONDS_A_DAY = SECONDS_A_DAY * MILLISECONDS_A_SECOND;
var MILLISECONDS_A_WEEK = SECONDS_A_WEEK * MILLISECONDS_A_SECOND;
var MS = "millisecond";
var S = "second";
var MIN = "minute";
var H = "hour";
var D = "day";
var W = "week";
var M = "month";
var Q = "quarter";
var Y = "year";
var DATE = "date";
var FORMAT_DEFAULT = "YYYY-MM-DDTHH:mm:ssZ";
var INVALID_DATE_STRING = "Invalid Date";
var REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/;
var REGEX_FORMAT = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g;
// ../../../shop_app/node_modules/dayjs/esm/locale/en.js
var en_default = {
name: "en",
weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
ordinal: function ordinal(n) {
var s = ["th", "st", "nd", "rd"];
var v = n % 100;
return "[" + n + (s[(v - 20) % 10] || s[v] || s[0]) + "]";
}
};
// ../../../shop_app/node_modules/dayjs/esm/utils.js
var padStart = function padStart2(string, length, pad) {
var s = String(string);
if (!s || s.length >= length)
return string;
return "" + Array(length + 1 - s.length).join(pad) + string;
};
var padZoneStr = function padZoneStr2(instance) {
var negMinutes = -instance.utcOffset();
var minutes = Math.abs(negMinutes);
var hourOffset = Math.floor(minutes / 60);
var minuteOffset = minutes % 60;
return (negMinutes <= 0 ? "+" : "-") + padStart(hourOffset, 2, "0") + ":" + padStart(minuteOffset, 2, "0");
};
var monthDiff = function monthDiff2(a, b) {
if (a.date() < b.date())
return -monthDiff2(b, a);
var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month());
var anchor = a.clone().add(wholeMonthDiff, M);
var c = b - anchor < 0;
var anchor2 = a.clone().add(wholeMonthDiff + (c ? -1 : 1), M);
return +(-(wholeMonthDiff + (b - anchor) / (c ? anchor - anchor2 : anchor2 - anchor)) || 0);
};
var absFloor = function absFloor2(n) {
return n < 0 ? Math.ceil(n) || 0 : Math.floor(n);
};
var prettyUnit = function prettyUnit2(u) {
var special = {
M,
y: Y,
w: W,
d: D,
D: DATE,
h: H,
m: MIN,
s: S,
ms: MS,
Q
};
return special[u] || String(u || "").toLowerCase().replace(/s$/, "");
};
var isUndefined = function isUndefined2(s) {
return s === void 0;
};
var utils_default = {
s: padStart,
z: padZoneStr,
m: monthDiff,
a: absFloor,
p: prettyUnit,
u: isUndefined
};
// ../../../shop_app/node_modules/dayjs/esm/index.js
var L = "en";
var Ls = {};
Ls[L] = en_default;
var IS_DAYJS = "$isDayjsObject";
var isDayjs = function isDayjs2(d) {
return d instanceof Dayjs || !!(d && d[IS_DAYJS]);
};
var parseLocale = function parseLocale2(preset, object, isLocal) {
var l;
if (!preset)
return L;
if (typeof preset === "string") {
var presetLower = preset.toLowerCase();
if (Ls[presetLower]) {
l = presetLower;
}
if (object) {
Ls[presetLower] = object;
l = presetLower;
}
var presetSplit = preset.split("-");
if (!l && presetSplit.length > 1) {
return parseLocale2(presetSplit[0]);
}
} else {
var name = preset.name;
Ls[name] = preset;
l = name;
}
if (!isLocal && l)
L = l;
return l || !isLocal && L;
};
var dayjs = function dayjs2(date, c) {
if (isDayjs(date)) {
return date.clone();
}
var cfg = typeof c === "object" ? c : {};
cfg.date = date;
cfg.args = arguments;
return new Dayjs(cfg);
};
var wrapper = function wrapper2(date, instance) {
return dayjs(date, {
locale: instance.$L,
utc: instance.$u,
x: instance.$x,
$offset: instance.$offset
// todo: refactor; do not use this.$offset in you code
});
};
var Utils = utils_default;
Utils.l = parseLocale;
Utils.i = isDayjs;
Utils.w = wrapper;
var parseDate = function parseDate2(cfg) {
var date = cfg.date, utc = cfg.utc;
if (date === null)
return new Date(NaN);
if (Utils.u(date))
return new Date();
if (date instanceof Date)
return new Date(date);
if (typeof date === "string" && !/Z$/i.test(date)) {
var d = date.match(REGEX_PARSE);
if (d) {
var m = d[2] - 1 || 0;
var ms = (d[7] || "0").substring(0, 3);
if (utc) {
return new Date(Date.UTC(d[1], m, d[3] || 1, d[4] || 0, d[5] || 0, d[6] || 0, ms));
}
return new Date(d[1], m, d[3] || 1, d[4] || 0, d[5] || 0, d[6] || 0, ms);
}
}
return new Date(date);
};
var Dayjs = function() {
function Dayjs2(cfg) {
this.$L = parseLocale(cfg.locale, null, true);
this.parse(cfg);
this.$x = this.$x || cfg.x || {};
this[IS_DAYJS] = true;
}
var _proto = Dayjs2.prototype;
_proto.parse = function parse(cfg) {
this.$d = parseDate(cfg);
this.init();
};
_proto.init = function init() {
var $d = this.$d;
this.$y = $d.getFullYear();
this.$M = $d.getMonth();
this.$D = $d.getDate();
this.$W = $d.getDay();
this.$H = $d.getHours();
this.$m = $d.getMinutes();
this.$s = $d.getSeconds();
this.$ms = $d.getMilliseconds();
};
_proto.$utils = function $utils() {
return Utils;
};
_proto.isValid = function isValid() {
return !(this.$d.toString() === INVALID_DATE_STRING);
};
_proto.isSame = function isSame(that, units) {
var other = dayjs(that);
return this.startOf(units) <= other && other <= this.endOf(units);
};
_proto.isAfter = function isAfter(that, units) {
return dayjs(that) < this.startOf(units);
};
_proto.isBefore = function isBefore(that, units) {
return this.endOf(units) < dayjs(that);
};
_proto.$g = function $g(input, get, set) {
if (Utils.u(input))
return this[get];
return this.set(set, input);
};
_proto.unix = function unix() {
return Math.floor(this.valueOf() / 1e3);
};
_proto.valueOf = function valueOf() {
return this.$d.getTime();
};
_proto.startOf = function startOf(units, _startOf) {
var _this = this;
var isStartOf = !Utils.u(_startOf) ? _startOf : true;
var unit = Utils.p(units);
var instanceFactory = function instanceFactory2(d, m) {
var ins = Utils.w(_this.$u ? Date.UTC(_this.$y, m, d) : new Date(_this.$y, m, d), _this);
return isStartOf ? ins : ins.endOf(D);
};
var instanceFactorySet = function instanceFactorySet2(method, slice) {
var argumentStart = [0, 0, 0, 0];
var argumentEnd = [23, 59, 59, 999];
return Utils.w(_this.toDate()[method].apply(
// eslint-disable-line prefer-spread
_this.toDate("s"),
(isStartOf ? argumentStart : argumentEnd).slice(slice)
), _this);
};
var $W = this.$W, $M = this.$M, $D = this.$D;
var utcPad = "set" + (this.$u ? "UTC" : "");
switch (unit) {
case Y:
return isStartOf ? instanceFactory(1, 0) : instanceFactory(31, 11);
case M:
return isStartOf ? instanceFactory(1, $M) : instanceFactory(0, $M + 1);
case W: {
var weekStart = this.$locale().weekStart || 0;
var gap = ($W < weekStart ? $W + 7 : $W) - weekStart;
return instanceFactory(isStartOf ? $D - gap : $D + (6 - gap), $M);
}
case D:
case DATE:
return instanceFactorySet(utcPad + "Hours", 0);
case H:
return instanceFactorySet(utcPad + "Minutes", 1);
case MIN:
return instanceFactorySet(utcPad + "Seconds", 2);
case S:
return instanceFactorySet(utcPad + "Milliseconds", 3);
default:
return this.clone();
}
};
_proto.endOf = function endOf(arg) {
return this.startOf(arg, false);
};
_proto.$set = function $set(units, _int) {
var _C$D$C$DATE$C$M$C$Y$C;
var unit = Utils.p(units);
var utcPad = "set" + (this.$u ? "UTC" : "");
var name = (_C$D$C$DATE$C$M$C$Y$C = {}, _C$D$C$DATE$C$M$C$Y$C[D] = utcPad + "Date", _C$D$C$DATE$C$M$C$Y$C[DATE] = utcPad + "Date", _C$D$C$DATE$C$M$C$Y$C[M] = utcPad + "Month", _C$D$C$DATE$C$M$C$Y$C[Y] = utcPad + "FullYear", _C$D$C$DATE$C$M$C$Y$C[H] = utcPad + "Hours", _C$D$C$DATE$C$M$C$Y$C[MIN] = utcPad + "Minutes", _C$D$C$DATE$C$M$C$Y$C[S] = utcPad + "Seconds", _C$D$C$DATE$C$M$C$Y$C[MS] = utcPad + "Milliseconds", _C$D$C$DATE$C$M$C$Y$C)[unit];
var arg = unit === D ? this.$D + (_int - this.$W) : _int;
if (unit === M || unit === Y) {
var date = this.clone().set(DATE, 1);
date.$d[name](arg);
date.init();
this.$d = date.set(DATE, Math.min(this.$D, date.daysInMonth())).$d;
} else if (name)
this.$d[name](arg);
this.init();
return this;
};
_proto.set = function set(string, _int2) {
return this.clone().$set(string, _int2);
};
_proto.get = function get(unit) {
return this[Utils.p(unit)]();
};
_proto.add = function add(number, units) {
var _this2 = this, _C$MIN$C$H$C$S$unit;
number = Number(number);
var unit = Utils.p(units);
var instanceFactorySet = function instanceFactorySet2(n) {
var d = dayjs(_this2);
return Utils.w(d.date(d.date() + Math.round(n * number)), _this2);
};
if (unit === M) {
return this.set(M, this.$M + number);
}
if (unit === Y) {
return this.set(Y, this.$y + number);
}
if (unit === D) {
return instanceFactorySet(1);
}
if (unit === W) {
return instanceFactorySet(7);
}
var step = (_C$MIN$C$H$C$S$unit = {}, _C$MIN$C$H$C$S$unit[MIN] = MILLISECONDS_A_MINUTE, _C$MIN$C$H$C$S$unit[H] = MILLISECONDS_A_HOUR, _C$MIN$C$H$C$S$unit[S] = MILLISECONDS_A_SECOND, _C$MIN$C$H$C$S$unit)[unit] || 1;
var nextTimeStamp = this.$d.getTime() + number * step;
return Utils.w(nextTimeStamp, this);
};
_proto.subtract = function subtract(number, string) {
return this.add(number * -1, string);
};
_proto.format = function format(formatStr) {
var _this3 = this;
var locale = this.$locale();
if (!this.isValid())
return locale.invalidDate || INVALID_DATE_STRING;
var str = formatStr || FORMAT_DEFAULT;
var zoneStr = Utils.z(this);
var $H = this.$H, $m = this.$m, $M = this.$M;
var weekdays = locale.weekdays, months = locale.months, meridiem = locale.meridiem;
var getShort = function getShort2(arr, index, full, length) {
return arr && (arr[index] || arr(_this3, str)) || full[index].slice(0, length);
};
var get$H = function get$H2(num) {
return Utils.s($H % 12 || 12, num, "0");
};
var meridiemFunc = meridiem || function(hour, minute, isLowercase) {
var m = hour < 12 ? "AM" : "PM";
return isLowercase ? m.toLowerCase() : m;
};
var matches = function matches2(match) {
switch (match) {
case "YY":
return String(_this3.$y).slice(-2);
case "YYYY":
return Utils.s(_this3.$y, 4, "0");
case "M":
return $M + 1;
case "MM":
return Utils.s($M + 1, 2, "0");
case "MMM":
return getShort(locale.monthsShort, $M, months, 3);
case "MMMM":
return getShort(months, $M);
case "D":
return _this3.$D;
case "DD":
return Utils.s(_this3.$D, 2, "0");
case "d":
return String(_this3.$W);
case "dd":
return getShort(locale.weekdaysMin, _this3.$W, weekdays, 2);
case "ddd":
return getShort(locale.weekdaysShort, _this3.$W, weekdays, 3);
case "dddd":
return weekdays[_this3.$W];
case "H":
return String($H);
case "HH":
return Utils.s($H, 2, "0");
case "h":
return get$H(1);
case "hh":
return get$H(2);
case "a":
return meridiemFunc($H, $m, true);
case "A":
return meridiemFunc($H, $m, false);
case "m":
return String($m);
case "mm":
return Utils.s($m, 2, "0");
case "s":
return String(_this3.$s);
case "ss":
return Utils.s(_this3.$s, 2, "0");
case "SSS":
return Utils.s(_this3.$ms, 3, "0");
case "Z":
return zoneStr;
default:
break;
}
return null;
};
return str.replace(REGEX_FORMAT, function(match, $1) {
return $1 || matches(match) || zoneStr.replace(":", "");
});
};
_proto.utcOffset = function utcOffset() {
return -Math.round(this.$d.getTimezoneOffset() / 15) * 15;
};
_proto.diff = function diff(input, units, _float) {
var _this4 = this;
var unit = Utils.p(units);
var that = dayjs(input);
var zoneDelta = (that.utcOffset() - this.utcOffset()) * MILLISECONDS_A_MINUTE;
var diff2 = this - that;
var getMonth = function getMonth2() {
return Utils.m(_this4, that);
};
var result;
switch (unit) {
case Y:
result = getMonth() / 12;
break;
case M:
result = getMonth();
break;
case Q:
result = getMonth() / 3;
break;
case W:
result = (diff2 - zoneDelta) / MILLISECONDS_A_WEEK;
break;
case D:
result = (diff2 - zoneDelta) / MILLISECONDS_A_DAY;
break;
case H:
result = diff2 / MILLISECONDS_A_HOUR;
break;
case MIN:
result = diff2 / MILLISECONDS_A_MINUTE;
break;
case S:
result = diff2 / MILLISECONDS_A_SECOND;
break;
default:
result = diff2;
break;
}
return _float ? result : Utils.a(result);
};
_proto.daysInMonth = function daysInMonth() {
return this.endOf(M).$D;
};
_proto.$locale = function $locale() {
return Ls[this.$L];
};
_proto.locale = function locale(preset, object) {
if (!preset)
return this.$L;
var that = this.clone();
var nextLocaleName = parseLocale(preset, object, true);
if (nextLocaleName)
that.$L = nextLocaleName;
return that;
};
_proto.clone = function clone() {
return Utils.w(this.$d, this);
};
_proto.toDate = function toDate() {
return new Date(this.valueOf());
};
_proto.toJSON = function toJSON() {
return this.isValid() ? this.toISOString() : null;
};
_proto.toISOString = function toISOString() {
return this.$d.toISOString();
};
_proto.toString = function toString() {
return this.$d.toUTCString();
};
return Dayjs2;
}();
var proto = Dayjs.prototype;
dayjs.prototype = proto;
[["$ms", MS], ["$s", S], ["$m", MIN], ["$H", H], ["$W", D], ["$M", M], ["$y", Y], ["$D", DATE]].forEach(function(g) {
proto[g[1]] = function(input) {
return this.$g(input, g[0], g[1]);
};
});
dayjs.extend = function(plugin, option) {
if (!plugin.$i) {
plugin(option, Dayjs, dayjs);
plugin.$i = true;
}
return dayjs;
};
dayjs.locale = parseLocale;
dayjs.isDayjs = isDayjs;
dayjs.unix = function(timestamp) {
return dayjs(timestamp * 1e3);
};
dayjs.en = Ls[L];
dayjs.Ls = Ls;
dayjs.p = {};
var esm_default = dayjs;
export {
esm_default as default
};
//# sourceMappingURL=dayjs_esm_index.js.map

File diff suppressed because one or more lines are too long

1
.vite/deps/package.json Normal file
View File

@ -0,0 +1 @@
{"type":"module"}

196
Api/request.js Normal file
View File

@ -0,0 +1,196 @@
import { showToast } from '../components/common.js'
let authToken = ''
export function toLogin(url) {
return new Promise((resolve, reject) => {
let saveTime = uni.getStorageSync('saveTime')
let expires_in = uni.getStorageSync('expires_in')
let token = uni.getStorageSync('token')
if(url.indexOf('api/v1') !== -1 && ((saveTime && expires_in && Date.now() > saveTime + expires_in) || !expires_in || !saveTime || !token)) {
uni.redirectTo({
url: '/pages/user/login'
})
reject()
} else {
resolve()
}
})
}
export function get (url = '', data = {}, flag = true) {
return new Promise(async (resolve, reject) => {
let orgin_shop_id = (uni.getStorageSync('orgin_shop_id') || 0) * 1
let shop_id = (uni.getStorageSync('shop_id') || 0) * 1
let appId = uni.getStorageSync('appId')
if(!shop_id || (orgin_shop_id && orgin_shop_id != shop_id) || (!appId && !url.includes('/live/shop') && !url.includes('login/weChat/webRedirectUrl'))) {
uni.removeStorageSync('token')
uni.removeStorageSync('saveTime')
uni.removeStorageSync('expires_in')
uni.redirectTo({
url: '/pages/user/login'
})
reject()
}
if(!url.includes('/pay/') && !url.includes('/login/weChat/webRedirectUrl') && !url.includes('/live/shop')) {
await toLogin(url)
}
uni.request({
url: url,
data: data,
method: 'GET',
header: {
Authorization: uni.getStorageSync('token') || authToken,
accept: "application/json",
appid: uni.getStorageSync('appId'),
'X-App-Type': 'h5'
},
success: res => {
if (res.statusCode === 200 || res.statusCode === 201) {
resolve(res.data)
} else if (res.statusCode === 404){
showToast(res.data.message || res.data.error)
reject(res.data.message || res.data.error)
setTimeout(function() {
uni.navigateBack({delta: 1})
}, 1000)
} else if(res.statusCode === 401 && flag) {
get(url, data, false)
} else if(res.statusCode === 429) {
resolve(res.data)
showToast('系统繁忙,请稍后重试')
} else {
let msg = res.data.message || res.data.error
if(msg) {
if(msg == 'Unauthenticated') {
uni.removeStorageSync('token')
uni.removeStorageSync('saveTime')
uni.removeStorageSync('expires_in')
uni.redirectTo({
url: '/pages/user/login'
})
}
}
reject(msg)
}
},
fail:(err)=>{
console.log('fail', err)
},
complete: async(complete) => {
}
})
})
}
export function getReq (url = '', data = {}, flag = true) {
return new Promise((resolve, reject) => {
uni.request({
url: url,
data: data,
method: 'GET',
header: {
Authorization: uni.getStorageSync('token') || authToken,
accept: "application/json",
appid: uni.getStorageSync('appId'),
'X-App-Type': 'h5'
},
success: res => {
if (res.statusCode === 200 || res.statusCode === 201) {
resolve(res.data)
} else if(res.statusCode === 401 && flag) {
reject(res.data)
getReq(url, data, false)
} else if (res.statusCode === 401 && !flag){
showToast(res.data.message || res.data.error)
resolve(res.data)
} else if (res.statusCode === 404){
reject(res.data.message)
} else if(res.statusCode === 429) {
showToast('系统繁忙,请稍后重试')
resolve(res.data)
} else {
let msg = res.data.message || res.data.error
if(msg) {
if(msg == 'Unauthenticated') {
uni.removeStorageSync('token')
uni.removeStorageSync('saveTime')
uni.removeStorageSync('expires_in')
uni.redirectTo({
url: '/pages/user/login'
})
}
}
reject(msg)
reject(res.data.message || res.data.error)
}
},
fail:(err)=>{
},
complete: async(complete) => {
}
})
})
}
export function post (url = '', data = {}, requestType = 'POST', flag = true) {
return new Promise(async(resolve, reject) => {
let orgin_shop_id = (uni.getStorageSync('orgin_shop_id') || 0) * 1
let shop_id = (uni.getStorageSync('shop_id') || 0) * 1
let appId = uni.getStorageSync('appId')
if(!shop_id || (orgin_shop_id && orgin_shop_id != shop_id) || (!appId && !url.includes('/live/shop') && !url.includes('login/weChat/webRedirectUrl'))) {
uni.removeStorageSync('token')
uni.removeStorageSync('saveTime')
uni.removeStorageSync('expires_in')
uni.redirectTo({
url: '/pages/user/login'
})
reject()
}
if(!url.includes('order/create') && !url.includes('user/vip') && !url.includes('auth/login') && !url.includes('live/liveIm/config')) {
await toLogin(url)
}
uni.request({
method: requestType,
url: url,
data,
header: {
Authorization: uni.getStorageSync('token') || authToken,
accept: "application/json",
appid: uni.getStorageSync('appId'),
'X-App-Type': 'h5'
},
success: res => {
if (res.statusCode === 200 || res.statusCode === 201) {
resolve(res.data)
} else if (res.statusCode === 404){
showToast(res.data.message || res.data.error)
reject(res.data.message)
} else if(res.statusCode === 401 && flag) {
post(url, data, requestType, false)
} else if(res.statusCode === 429) {
showToast('系统繁忙,请稍后重试')
resolve(res.data)
} else {
let msg = res.data.message || res.data.error
if(url.indexOf('decrypt/data') === -1 && msg == 'Unauthenticated') {
uni.removeStorageSync('token')
uni.removeStorageSync('saveTime')
uni.removeStorageSync('expires_in')
uni.redirectTo({
url: '/pages/user/login'
})
}
reject(msg)
}
},
fail:(err) => {
},
complete: async (complete) => {
}
})
})
}

279
App.vue Normal file
View File

@ -0,0 +1,279 @@
<script>
import { get, post } from './Api/request.js'
import { getShopInfo } from './components/common.js'
export default {
onLaunch: async function(options) {
uni.removeStorageSync('liveId')
// http://localhost:8082/web/?wxwork_userid=XiaoZhuShou9201#/pages/live/index?live_id=26&user_id=7319946&shopId=31
let url = window.location.href.split('?')
let length = url.length
let Param = new URLSearchParams(url[length - 1])
console.log('Param', Param)
if(Param.get('shopId')) {
uni.setStorageSync('orgin_shop_id', Param.get('shopId') * 1)
let appId = uni.getStorageSync('appId')
if(appId) {
getShopInfo()
}
}
uni.setStorageSync('from_page', window.location.href)
let script = document.createElement('script');
script.src = "https://tcsdk.com/player/tcplayer/release/v5.3.3/tcplayer.v5.3.3.min.js";
document.head.appendChild(script);
},
onShow: function(options) {
// #ifdef APP-PLUS
uni.hideTabBar()
// #endif
},
onHide: function() {
}
}
</script>
<style lang="scss">
/*每个页面公共css */
@import "@/uni_modules/uview-plus/index.scss";
@import url("/static/icon/iconfont.css");
@import url('https://tcsdk.com/player/tcplayer/release/v5.3.3/tcplayer.min.css');
page {
width: 100%;
height: 100%;
background: $uni-bg-color;
overflow: auto;
-webkit-text-size-adjust: 100%;
font-family: 'Microsoft YaHei';
position: static !important;
}
body{
height: initial;
}
.tabbar .u-badge{
position: absolute;
left: 50%;
margin-left: 4px;
top: 4px;
}
uni-view uni-button, button {
padding: 0;
margin: 0;
background-color: #fff;
}
button:after, uni-view uni-button:after{
border:none;
}
.u-icon{
display: inline-flex !important;
}
.u-transition{
display: inline-block;
}
.u-tag-wrapper{
display: inline-block;
}
.u-tag{
display: inline-flex;
}
.u-tag+.u-tag {
margin-left: 4px;
}
.u-tag--mini{
height: 18px !important;
line-height: 18px !important;
margin-right: 4px !important;
}
.solid{
font-size: 22rpx;
color: #888;
border: 1rpx solid #999;
display: inline-block;
padding: 4rpx 8rpx;
line-height: 1;
border-radius: 3px;
}
.scrollbar::-webkit-scrollbar {
width: 12px;
height: 4px;
color:#ffffff;
display: block;
}
/*定义滚动条轨道 内阴影+圆角*/
.scrollbar::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3);
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
border-radius: 6px;
background-color:#FFFFFF;
display: block;
}
/*定义滑块 内阴影+圆角*/
.scrollbar::-webkit-scrollbar-thumb {
border-radius: 6px;
-webkit-box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3);
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #F14939;
display: block;
}
.kuajing{
background: linear-gradient(to bottom , #A500FF, #63009B);
color: #fff;
font-size: 22rpx;
margin-right: 10rpx;
display: inline-block;
height: 32rpx;
vertical-align: middle;
width: 100rpx;
border-radius: 6rpx;
text-align: center;
line-height: 32rpx;
}
.u-button{
width: auto !important;
}
.u-number-box__plus, .u-number-box__minus{
width: 25px !important;
height: 25px !important;
}
.u-number-box__plus .u-icon__icon, .u-number-box__minus .u-icon__icon{
font-size: 12px !important;
}
.u-number-box__input{
background-color: #fff !important;
height: 25px !important;
}
.flex3{
display: flex;
align-items: center;
justify-content: center;
}
.flex4{
display: flex;
align-items: center;
justify-content: space-between;
}
.flex5{
display: flex;
align-items: center;
}
.ellipsis{
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.ellipsis2{
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.welf{
background: linear-gradient(to right , #FBE9CE, #FEDBAF);
color: #444;
font-size: 22rpx;
margin-right: 10rpx;
display: inline-block;
height: 36rpx;
vertical-align: middle;
padding: 0 14rpx;
border-radius: 6rpx;
text-align: center;
line-height: 36rpx;
font-weight: 500;
}
.selfbuy{
background: #FFCC13;
color: #6F3405;
font-size: 22rpx;
margin-right: 10rpx;
display: inline-block;
height: 36rpx;
vertical-align: middle;
padding: 0 8rpx;
border-radius: 6rpx;
text-align: center;
line-height: 36rpx;
font-weight: 500;
}
.morez{
margin-bottom: 10rpx;
image{
width: 45px;
height: 18px;
display: block;
position: relative;
z-index: 2;
}
.text{
background-color: #FFE197;
color: #77411F;
line-height: 18px;
padding: 0 8px 0 12px;
font-size: 24rpx;
border-radius: 0 5px 0 0;
margin-left: -10px;
font-weight: 600;
}
&.mini{
image{
width: 40px;
height: 15px;
}
.text{
font-size: 20rpx;
line-height: 15px;
}
}
}
.mxjc{
position: absolute;
bottom: 10rpx;
left: 12rpx;
width: calc(100% - 24rpx);
image{
width: 67px;
height: 17px;
}
.wb{
background: #fff;
padding: 10rpx 14rpx;
line-height: 1;
color: #3D3D3D;
font-size: 18rpx;
border-radius: 20rpx;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.1);
width: fit-content;
max-width: 100%;
box-sizing: border-box;
}
&.mini{
bottom: 6rpx;
left: 8rpx;
width: calc(100% - 16rpx);
image{
width: 46px;
height: 11px;
}
.wb{
padding: 4rpx 8rpx;
font-size: 14rpx;
}
}
&.large{
image{
width: 78px;
height: 20px;
}
.wb{
padding: 8rpx 12rpx;
font-size: 22rpx;
}
}
}
</style>

View File

@ -1,3 +1,2 @@
# shop_h5 ## UniApp H5端
1. 访问地址(http://shop.chutang66.com/web#/pages/index/index?shopId=1)
H5

39
androidPrivacy.json Normal file
View File

@ -0,0 +1,39 @@
{
"version" : "1", //
"prompt" : "template",
"title" : "用户协议和隐私政策",
"message" : "  您在使用系统前,请认真阅读并充分理解相关用户条款、平台规则及隐私政策,当您点击同意相关条款,并开始使用产品或服务,即表示您已理解并同意该条款。<br/>  您可阅读<a href=\"static/userAgreement.html\">《用户协议》</a>和<a href=\"static/privacyPolicy.html\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
"buttonAccept" : "同意并接受",
"buttonRefuse" : "暂不同意",
"hrefLoader" : "default",
"backToExit" : "true",
"second" : {
"title" : "温馨提示",
"message" : "",
// "message": "  进入应用前,您需先同意<a href=\"\">《用户协议》</a>和<a href=\"\">《隐私政策》</a>,否则将退出应用。", //
"buttonAccept" : "同意并继续",
"buttonRefuse" : "退出应用"
},
"disagreeMode" : {
"support" : false,
"loadNativePlugins" : false,
"visitorEntry" : false,
"showAlways" : false
},
"styles" : {
"backgroundColor" : "#eee",
"borderRadius" : "5px",
"title" : {
"color" : "#000"
},
"buttonAccept" : {
"color" : "#DFA656"
},
"buttonRefuse" : {
"color" : "#333"
},
"buttonVisitor" : {
"color" : "#00ffff"
}
}
}

View File

@ -0,0 +1,533 @@
<!-- eslint-disable -->
<template>
<view
class="player-wrapper"
:id="videoWrapperId"
:parentId="id"
:randomNum="randomNum"
:change:randomNum="domVideoPlayer.randomNumChange"
:viewportProps="viewportProps"
:change:viewportProps="domVideoPlayer.viewportChange"
:videoSrc="videoSrc"
:change:videoSrc="domVideoPlayer.initVideoPlayer"
:command="eventCommand"
:change:command="domVideoPlayer.triggerCommand"
:func="renderFunc"
:change:func="domVideoPlayer.triggerFunc"
/>
</template>
<script>
export default {
props: {
src: {
type: String,
default: ''
},
autoplay: {
type: Boolean,
default: false
},
loop: {
type: Boolean,
default: false
},
controls: {
type: Boolean,
default: false
},
objectFit: {
type: String,
default: 'contain'
},
muted: {
type: Boolean,
default: false
},
playbackRate: {
type: Number,
default: 1
},
isLoading: {
type: Boolean,
default: false
},
poster: {
type: String,
default: ''
},
id: {
type: String,
default: ''
}
},
data() {
return {
randomNum: Math.floor(Math.random() * 100000000),
videoSrc: '',
// video
eventCommand: null,
// renderjs
renderFunc: {
name: null,
params: null
},
//
currentTime: 0,
duration: 0,
playing: false
}
},
watch: {
//
src: {
handler(val) {
if (!val) return
setTimeout(() => {
this.videoSrc = val
}, 0)
},
immediate: true
}
},
computed: {
videoWrapperId() {
return `video-wrapper-${this.randomNum}`
},
// renderjs
viewportProps() {
return {
autoplay: this.autoplay,
muted: this.muted,
controls: this.controls,
loop: this.loop,
objectFit: this.objectFit,
poster: this.poster,
isLoading: this.isLoading,
playbackRate: this.playbackRate
}
}
},
//
methods: {
//
eventEmit({ event, data }) {
this.$emit(event, data)
},
// viewdata
setViewData({ key, value }) {
key && this.$set(this, key, value)
},
//
resetEventCommand() {
this.eventCommand = null
},
//
play() {
this.eventCommand = 'play'
},
//
pause() {
this.eventCommand = 'pause'
},
//
resetFunc() {
this.renderFunc = {
name: null,
params: null
}
},
// -
remove(params) {
this.renderFunc = {
name: 'removeHandler',
params
}
},
// -
fullScreen(params) {
this.renderFunc = {
name: 'fullScreenHandler',
params
}
},
// -
toSeek(sec, isDelay = false) {
this.renderFunc = {
name: 'toSeekHandler',
params: { sec, isDelay }
}
}
}
}
</script>
<script module="domVideoPlayer" lang="renderjs">
const PLAYER_ID = 'DOM_VIDEO_PLAYER'
export default {
data() {
return {
num: '',
videoEl: null,
loadingEl: null,
//
delayFunc: null,
renderProps: {}
}
},
computed: {
playerId() {
return `${PLAYER_ID}_${this.num}`
},
wrapperId() {
return `video-wrapper-${this.num}`
}
},
methods: {
isApple() {
const ua = navigator.userAgent.toLowerCase()
return ua.indexOf('iphone') !== -1 || ua.indexOf('ipad') !== -1
},
async initVideoPlayer(src) {
this.delayFunc = null
await this.$nextTick()
if (!src) return
if (this.videoEl) {
//
if (!this.isApple() && this.loadingEl) {
this.loadingEl.style.display = 'block'
}
this.videoEl.src = src
return
}
const videoEl = document.createElement('video')
this.videoEl = videoEl
//
this.listenVideoEvent()
const { autoplay, muted, controls, loop, playbackRate, objectFit, poster } = this.renderProps
videoEl.src = src
videoEl.autoplay = autoplay
videoEl.controls = controls
videoEl.loop = loop
videoEl.muted = muted
videoEl.playbackRate = playbackRate
videoEl.id = this.playerId
// videoEl.setAttribute('x5-video-player-type', 'h5')
videoEl.setAttribute('preload', 'auto')
videoEl.setAttribute('playsinline', true)
videoEl.setAttribute('webkit-playsinline', true)
videoEl.setAttribute('crossorigin', 'anonymous')
videoEl.setAttribute('controlslist', 'nodownload')
videoEl.setAttribute('disablePictureInPicture', true)
videoEl.style.objectFit = objectFit
poster && (videoEl.poster = poster)
videoEl.style.width = '100%'
videoEl.style.height = '100%'
//
// document.getElementById(this.wrapperId).appendChild(videoEl)
const playerWrapper = document.getElementById(this.wrapperId)
playerWrapper.insertBefore(videoEl, playerWrapper.firstChild)
// loading
this.createLoading()
},
// loading
createLoading() {
const { isLoading } = this.renderProps
if (!this.isApple() && isLoading) {
const loadingEl = document.createElement('div')
this.loadingEl = loadingEl
loadingEl.className = 'loading-wrapper'
loadingEl.style.position = 'absolute'
loadingEl.style.top = '0'
loadingEl.style.left = '0'
loadingEl.style.zIndex = '1'
loadingEl.style.width = '100%'
loadingEl.style.height = '100%'
loadingEl.style.backgroundColor = 'black'
document.getElementById(this.wrapperId).appendChild(loadingEl)
// loading
const animationEl = document.createElement('div')
animationEl.className = 'loading'
animationEl.style.zIndex = '2'
animationEl.style.position = 'absolute'
animationEl.style.top = '50%'
animationEl.style.left = '50%'
animationEl.style.marginTop = '-15px'
animationEl.style.marginLeft = '-15px'
animationEl.style.width = '30px'
animationEl.style.height = '30px'
animationEl.style.border = '2px solid #FFF'
animationEl.style.borderTopColor = 'rgba(255, 255, 255, 0.2)'
animationEl.style.borderRightColor = 'rgba(255, 255, 255, 0.2)'
animationEl.style.borderBottomColor = 'rgba(255, 255, 255, 0.2)'
animationEl.style.borderRadius = '100%'
animationEl.style.animation = 'circle infinite 0.75s linear'
loadingEl.appendChild(animationEl)
// loading keyframes
const style = document.createElement('style')
const keyframes = `
@keyframes circle {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
`
style.type = 'text/css'
if (style.styleSheet) {
style.styleSheet.cssText = keyframes
} else {
style.appendChild(document.createTextNode(keyframes))
}
document.head.appendChild(style)
}
},
//
listenVideoEvent() {
//
const playHandler = () => {
this.$ownerInstance.callMethod('eventEmit', { event: 'play' })
this.$ownerInstance.callMethod('setViewData', {
key: 'playing',
value: true
})
if (this.loadingEl) {
this.loadingEl.style.display = 'none'
}
}
this.videoEl.removeEventListener('play', playHandler)
this.videoEl.addEventListener('play', playHandler)
//
const pauseHandler = () => {
this.$ownerInstance.callMethod('eventEmit', { event: 'pause' })
this.$ownerInstance.callMethod('setViewData', {
key: 'playing',
value: false
})
}
this.videoEl.removeEventListener('pause', pauseHandler)
this.videoEl.addEventListener('pause', pauseHandler)
//
const endedHandler = () => {
this.$ownerInstance.callMethod('eventEmit', { event: 'ended' })
this.$ownerInstance.callMethod('resetEventCommand')
}
this.videoEl.removeEventListener('ended', endedHandler)
this.videoEl.addEventListener('ended', endedHandler)
//
const canPlayHandler = () => {
this.$ownerInstance.callMethod('eventEmit', { event: 'canplay' })
this.execDelayFunc()
}
this.videoEl.removeEventListener('canplay', canPlayHandler)
this.videoEl.addEventListener('canplay', canPlayHandler)
//
const errorHandler = (e) => {
if (this.loadingEl) {
this.loadingEl.style.display = 'block'
}
this.$ownerInstance.callMethod('eventEmit', { event: 'error' })
}
this.videoEl.removeEventListener('error', errorHandler)
this.videoEl.addEventListener('error', errorHandler)
// loadedmetadata
const loadedMetadataHandler = () => {
this.$ownerInstance.callMethod('eventEmit', { event: 'loadedmetadata' })
//
const duration = this.videoEl.duration
this.$ownerInstance.callMethod('eventEmit', {
event: 'durationchange',
data: duration
})
this.$ownerInstance.callMethod('setViewData', {
key: 'duration',
value: duration
})
//
this.loadFirstFrame()
}
this.videoEl.removeEventListener('loadedmetadata', loadedMetadataHandler)
this.videoEl.addEventListener('loadedmetadata', loadedMetadataHandler)
//
const timeupdateHandler = (e) => {
const currentTime = e.target.currentTime
this.$ownerInstance.callMethod('eventEmit', {
event: 'timeupdate',
data: currentTime
})
this.$ownerInstance.callMethod('setViewData', {
key: 'currentTime',
value: currentTime
})
}
this.videoEl.removeEventListener('timeupdate', timeupdateHandler)
this.videoEl.addEventListener('timeupdate', timeupdateHandler)
//
const ratechangeHandler = (e) => {
const playbackRate = e.target.playbackRate
this.$ownerInstance.callMethod('eventEmit', {
event: 'ratechange',
data: playbackRate
})
}
this.videoEl.removeEventListener('ratechange', ratechangeHandler)
this.videoEl.addEventListener('ratechange', ratechangeHandler)
//
if (this.isApple()) {
const webkitbeginfullscreenHandler = () => {
const presentationMode = this.videoEl.webkitPresentationMode
let isFullScreen = null
if (presentationMode === 'fullscreen') {
isFullScreen = true
} else {
isFullScreen = false
}
this.$ownerInstance.callMethod('eventEmit', {
event: 'fullscreenchange',
data: isFullScreen
})
}
this.videoEl.removeEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
this.videoEl.addEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
} else {
const fullscreenchangeHandler = () => {
let isFullScreen = null
if (document.fullscreenElement) {
isFullScreen = true
} else {
isFullScreen = false
}
this.$ownerInstance.callMethod('eventEmit', {
event: 'fullscreenchange',
data: isFullScreen
})
}
document.removeEventListener('fullscreenchange', fullscreenchangeHandler)
document.addEventListener('fullscreenchange', fullscreenchangeHandler)
}
},
//
loadFirstFrame() {
let { autoplay, muted } = this.renderProps
if (this.isApple()) {
this.videoEl.play()
if (!autoplay) {
this.videoEl.pause()
}
} else {
// optimize: timeout `https://goo.gl/LdLk22`
/**
* 原因chromium 内核中谷歌协议规定视频不允许在非静音状态下进行自动播放
* 解决在自动播放时先将视频静音然后延迟调用 play 方法播放视频
* 说明iOS Safari 内核不会有这个仅在 Android 设备出现即使有这个报错也不影响的所以不介意控制台报错的话是可以删掉这个 timeout
*/
this.videoEl.muted = true
setTimeout(() => {
this.videoEl.play()
this.videoEl.muted = muted
if (!autoplay) {
setTimeout(() => {
this.videoEl.pause()
}, 100)
}
}, 10)
}
},
triggerCommand(eventType) {
if (eventType) {
this.$ownerInstance.callMethod('resetEventCommand')
this.videoEl && this.videoEl[eventType]()
}
},
triggerFunc(func) {
const { name, params } = func || {}
if (name) {
this[name](params)
this.$ownerInstance.callMethod('resetFunc')
}
},
removeHandler() {
if (this.videoEl) {
this.videoEl.pause()
this.videoEl.src = ''
this.$ownerInstance.callMethod('setViewData', {
key: 'videoSrc',
value: ''
})
this.videoEl.load()
}
},
fullScreenHandler() {
if (this.isApple()) {
this.videoEl.webkitEnterFullscreen()
} else {
this.videoEl.requestFullscreen()
}
},
toSeekHandler({ sec, isDelay }) {
const func = () => {
if (this.videoEl) {
this.videoEl.currentTime = sec
}
}
//
if (isDelay) {
this.delayFunc = func
} else {
func()
}
},
//
execDelayFunc() {
this.delayFunc && this.delayFunc()
this.delayFunc = null
},
viewportChange(props) {
this.renderProps = props
const { autoplay, muted, controls, loop, playbackRate } = props
if (this.videoEl) {
this.videoEl.autoplay = autoplay
this.videoEl.controls = controls
this.videoEl.loop = loop
this.videoEl.muted = muted
this.videoEl.playbackRate = playbackRate
}
},
randomNumChange(val) {
this.num = val
}
}
}
</script>
<style scoped>
.player-wrapper {
overflow: hidden;
height: 100%;
padding: 0;
position: relative;
}
</style>

View File

@ -0,0 +1,512 @@
<template>
<view class="Popover" :style="{'--theme-bg-color':bgStyleColor}">
<view class="mark" @click="close()" v-show="inited"></view>
<view @click.stop="handleClick" class="zb-button-popover">
<slot></slot>
</view>
<view class="zb-popover" v-show="inited" ref="zb-transition" :class="[classes,`zb-popover-${placement}`]"
:style="[mergeStyle]" @touchmove="noop">
<view class="zb-popover-arrow" :style="[arrowStyle]" :class="[{
'zb_popper__up':placement.indexOf('bottom')===0,
'zb_popper__arrow':placement.indexOf('top')===0,
'zb_popper__right':placement.indexOf('right')===0,
'zb_popper__left':placement.indexOf('left')===0,
}]">
</view>
<slot name="content">
<view :class="[{'horizontal__action':actionsDirection==='horizontal'}]">
<view @click.stop="actionAction(item)" v-for="item,index in options" class="zb-popover__action"
:class="[{'dark__action':theme==='dark'}]" :key="index">
<up-icon :name="item.icon" size="18" color="#333" />
<view class="zb-popover__action-text">{{item.text}}</view>
</view>
</view>
</slot>
</view>
</view>
</template>
<script>
const tranClass = {
enter: "zb-fade-zoom-enter zb-fade-zoom-enter-active",
'enter-to': "zb-fade-zoom-enter-to zb-fade-zoom-enter-active",
leave: "zb-fade-zoom-leave zb-fade-zoom-leave-active",
'leave-to': "zb-fade-zoom-leave-to zb-fade-zoom-leave-active",
}
export default {
props: {
options: {
type: Array,
default: () => []
},
placement: {
type: String,
default: 'bottom-start'
},
bgColor: {
type: String,
},
// light dark
theme: {
type: String,
default: 'light'
},
// horizontal vertical
actionsDirection: {
type: String,
default: 'vertical'
}
},
name: "Popover",
watch: {
show: {
handler(newVal) {
newVal ? this.vueEnter() : this.vueLeave()
},
// propsshow
immediate: true
}
},
data() {
return {
show: false,
inited: false, // /
classes: '', //
display: false, //
duration: 100,
popoverStyle: {
},
arrowOldStyle: {}
};
},
computed: {
bgStyleColor() {
if (this.bgColor) {
return this.bgColor
}
if (this.theme === 'light') {
return 'white'
}
if (this.theme === 'dark') {
return '#4a4a4a'
}
},
mergeStyle() {
return {
transitionDuration: `${this.duration}ms`,
transitionTimingFunction: `ease-out`,
...this.popoverStyle
}
},
arrowStyle() {
return {
...this.arrowOldStyle
}
}
},
mounted() {
// window.addEventListener('click', () => {
// this.show = false
// })
},
methods: {
handleClick() {
if (this.show) {
this.show = false
} else {
this.show = true
}
this.$emit('handleClick', this.show)
},
close() {
this.show = false
},
actionAction(item) {
this.$emit('select', item)
this.show = false
},
sleep(value) {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, value)
})
},
vueEnter() {
this.inited = true
this.getPosition()
this.classes = tranClass.enter
this.$nextTick(async () => {
await this.sleep(30)
this.classes = tranClass['enter-to']
})
},
vueLeave() {
this.classes = tranClass.leave
this.$nextTick(async () => {
this.classes = tranClass['leave-to']
await this.sleep(120)
this.inited = false
})
},
//
preventEvent(e) {
e && typeof(e.stopPropagation) === 'function' && e.stopPropagation()
},
getPosition() {
return new Promise((resolve) => {
this.$nextTick(() => {
let selectorQuery = uni.createSelectorQuery().in(this).selectAll(
'.zb-button-popover,.zb-popover')
selectorQuery.boundingClientRect(async (data) => {
let {
left,
bottom,
right,
top,
width,
height
} = data[0]
let popoverClientRect = data[1]
let popoverStyle = {}
let arrowOldStyle = {}
switch (this.placement) {
case 'top':
if (popoverClientRect.width > width) {
popoverStyle.left =
`-${(popoverClientRect.width - width)/2}px`
} else {
popoverStyle.left =
`${Math.abs(popoverClientRect.width - width)/2}px`
}
popoverStyle.bottom = `${height+8}px`
arrowOldStyle.left = (popoverClientRect.width / 2 - 6) +
'px'
break;
case 'top-start':
popoverStyle.left = `0px`
popoverStyle.bottom = `${height+8}px`
arrowOldStyle.left = '16px'
break;
case 'top-end':
popoverStyle.right = `0px`
popoverStyle.bottom = `${height+8}px`
arrowOldStyle.right = '16px'
break;
case 'bottom':
if (popoverClientRect.width > width) {
popoverStyle.left =
`-${(popoverClientRect.width - width)/2}px`
} else {
popoverStyle.left =
`${Math.abs(popoverClientRect.width - width)/2}px`
}
popoverStyle.top = `${height+8}px`
arrowOldStyle.left = (popoverClientRect.width / 2 - 6) +
'px'
break;
case 'bottom-start':
popoverStyle.top = `${height+8}px`
popoverStyle.left = `0px`
arrowOldStyle.left = '16px'
break;
case 'bottom-end':
popoverStyle.top = `${height+8}px`
popoverStyle.right = `0px`
arrowOldStyle.right = '16px'
break;
case 'right':
popoverStyle.left = `${width+8}px`
if (popoverClientRect.height > height) {
popoverStyle.top =
`-${(popoverClientRect.height - height)/2}px`
} else {
popoverStyle.top =
`${Math.abs((popoverClientRect.height - height)/2)}px`
}
arrowOldStyle.top = `${popoverClientRect.height/2-6}px`
break;
case 'right-start':
popoverStyle.left = `${width+8}px`
popoverStyle.top = `0px`
arrowOldStyle.top = `8px`
break;
case 'right-end':
popoverStyle.left = `${width+8}px`
popoverStyle.bottom = `0px`
arrowOldStyle.bottom = `8px`
break;
case 'left':
popoverStyle.right = `${width+8}px`
if (popoverClientRect.height > height) {
popoverStyle.top =
`-${(popoverClientRect.height - height)/2}px`
} else {
popoverStyle.top =
`${Math.abs((popoverClientRect.height - height)/2)}px`
}
arrowOldStyle.top = `${popoverClientRect.height/2-6}px`
break;
case 'left-start':
popoverStyle.right = `${width+8}px`
popoverStyle.top = `0px`
arrowOldStyle.top = `8px`
break;
case 'left-end':
popoverStyle.right = `${width+8}px`
popoverStyle.bottom = `0px`
arrowOldStyle.bottom = `8px`
break;
}
this.popoverStyle = popoverStyle
this.arrowOldStyle = arrowOldStyle
resolve()
}).exec()
})
})
},
//
noop(e) {
this.preventEvent(e)
}
}
}
</script>
<style lang="scss" scoped>
.mark { position: fixed; left: 0; right: 0; top: 0; bottom: 0; z-index: 1; background-color: rgba(0, 0, 0, 0.4); }
$theme-bg-color: var(--theme-bg-color);
.Popover {
position: relative;
}
.zb-button-popover {
display: inline-block;
}
.zb-popover {
border-radius: 8px;
z-index: 2144;
position: absolute;
background-color: $theme-bg-color;
box-shadow: 0 2px 12px #3232331f;
}
.zb-popover-top {
transform-origin: 50% bottom;
}
.zb-popover-top-start {
transform-origin: 50% bottom;
}
.zb-popover-top-end {
transform-origin: 0 bottom;
}
.zb-popover-bottom {
transform-origin: 50% 0;
}
.zb-popover-bottom-end {
transform-origin: 100% 0;
}
.zb-popover-bottom-start {
transform-origin: 0 0;
}
.zb-popover-right {
transform-origin: left 50%;
}
.zb-popover-right-start {
transform-origin: left 0;
}
.zb-popover-right-end {
transform-origin: left 100%;
}
.zb-popover-left {
transform-origin: right 50%;
}
.zb-popover-left-start {
transform-origin: right 0;
}
.zb-popover-left-end {
transform-origin: right 100%;
}
.zb-popover-arrow {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
color: $theme-bg-color;
}
.zb_popper__up {
border-top-width: 0;
border-bottom-color: currentColor;
top: -6px;
}
.zb_popper__right {
border-left-width: 0;
border-right-color: currentColor;
left: -5px;
}
.zb_popper__left {
border-right-width: 0;
border-left-color: currentColor;
right: -5px;
}
.zb_popper__arrow {
border-bottom-width: 0;
border-top-color: currentColor;
bottom: -6px;
}
.zb-popover__action {
position: relative;
display: flex;
box-sizing: border-box;
height: 88rpx;
padding: 0 30rpx;
font-size: 30rpx;
cursor: pointer;
}
.zb-popover__action-text {
display: flex;
flex: 1;
align-items: center;
height: 100%;
padding: 0 24rpx;
border-bottom: 1rpx solid #ebedf0;
word-wrap: break-word;
white-space: nowrap;
}
.zb-popover__action:last-child {
.zb-popover__action-text {
border-bottom: none;
}
}
.dark__action {
color: white;
.zb-popover__action-text {
border-bottom: 1rpx solid #ebedf033
}
}
.horizontal__action {
display: flex;
.zb-popover__action {
padding: 0 20rpx;
border-right: 1rpx solid #ebedf0;
}
.zb-popover__action-text {
padding: 0;
//border-right:1rpx solid #ebedf0;
}
}
$u-zoom-scale: scale(0.95);
.zb-fade-enter-active,
.zb-fade-leave-active {
transition-property: opacity;
}
.zb-fade-enter,
.zb-fade-leave-to {
opacity: 0
}
.zb-fade-zoom-enter,
.zb-fade-zoom-leave-to {
transform: $u-zoom-scale;
opacity: 0;
}
.zb-fade-zoom-enter-active,
.zb-fade-zoom-leave-active {
transition-property: transform, opacity;
}
.zb-fade-down-enter-active,
.zb-fade-down-leave-active,
.zb-fade-left-enter-active,
.zb-fade-left-leave-active,
.zb-fade-right-enter-active,
.zb-fade-right-leave-active,
.zb-fade-up-enter-active,
.zb-fade-up-leave-active {
transition-property: opacity, transform;
}
.zb-fade-up-enter,
.zb-fade-up-leave-to {
transform: translate3d(0, 100%, 0);
opacity: 0
}
.zb-fade-down-enter,
.zb-fade-down-leave-to {
transform: translate3d(0, -100%, 0);
opacity: 0
}
.zb-fade-left-enter,
.zb-fade-left-leave-to {
transform: translate3d(-100%, 0, 0);
opacity: 0
}
.zb-fade-right-enter,
.zb-fade-right-leave-to {
transform: translate3d(100%, 0, 0);
opacity: 0
}
.zb-popover__action {
&:active {
background-color: rgba(0, 0, 0, 0.2);
}
&--disabled {
color: var(--van-popover-dark-action-disabled-text-color);
&:active {
background-color: transparent;
}
}
}
</style>

View File

@ -0,0 +1,87 @@
<template>
<div
:style="{ width: size + 'px', height: size + 'px' }"
class="progress-circle"
>
<svg :width="size" :height="size" viewBox="0 0 100 100">
<circle
class="background"
cx="50"
cy="50"
r="45"
stroke-width="5"
fill="none"
/>
<circle
class="progress"
cx="50"
cy="50"
r="45"
stroke-width="5"
:stroke="color"
fill="none"
stroke-dasharray="282"
:stroke-dashoffset="282 - (computedProgress / 100) * 282"
style="transition: stroke-dashoffset 0.6s"
/>
</svg>
<div class="text" :style="{ fontSize: size / 5 + 'px' }">{{ text }}</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const props = defineProps<{
progress?: number
color?: string
size?: number
text?: string
duration?: number
}>()
//
const defaultProgress = 50
const defaultColor = 'red'
const defaultSize = 100
const defaultDuration = 500
const defaultText = '50%' //
const computedProgress = ref(0)
const color = ref(props.color ?? defaultColor) // 使
const size = ref(props.size ?? defaultSize) // 使
const text = ref(props.text ?? defaultText) // 使
onMounted(() => {
setTimeout(() => {
computedProgress.value = props.progress ?? defaultProgress
}, props.duration ?? defaultDuration)
})
</script>
<style scoped>
.progress-circle {
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
svg {
transform: rotate(-90deg);
}
circle.background {
stroke: #eee;
}
circle.progress {
stroke-linecap: round;
transition: stroke-dashoffset 0.8s ease;
}
.text {
position: absolute;
font-weight: bold;
}
</style>

12046
components/areaList.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
<template>
<!-- 购买成功弹窗 -->
<view>
<up-popup :show="showBuy" :customStyle="customStyle" closeable @close="close" catchtouchmove="preventD" :close-on-click-overlay="false" mode="center">
<view class="buy">
<up-icon name="checkmark-circle-fill" size="60" :color="Color" />
<view class="title">恭喜购买成功</view>
<view class="user">
<image :src="avatar"></image>
<text>{{nickname}}</text>
</view>
<view class="text">转发到群聊,通知团长你已下单,尽快发货</view>
<view class="label">
<button @click="shareOrder" class="btn">分享到群聊</button>
<text v-if="score_on && role && !from" class="text1">积分再+{{score_trade_share}}</text>
</view>
<view class="box" v-if="score_on && role && !from && !link_id">
<view class="left">
<image src="../../static/image/gift.png" mode="widthFix" class="img"></image>
<view class="">
<view class="tit">积分商城&nbsp;<text class="text1">+{{score_trade * pay_price}}</text></view>
<view class="tit">累计积分兑换奖品</view>
</view>
</view>
<view class="to" @click="toScoreShop">去兑换</view>
</view>
</view>
</up-popup>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
export default {
props: {
showBuy: {
type: Boolean,
default: false
},
payPrice: {
type: String
},
from: {
type: Number
}
},
setup(props, context) {
const data = reactive({
nickname: uni.getStorageSync('nickname'),
avatar: uni.getStorageSync('avatar'),
role: Number(uni.getStorageSync('role')) !== 1,
score_trade_share: Number(uni.getStorageSync('score_trade_share')),
score_on: Number(uni.getStorageSync('score_on')) === 1,
score_trade: Number(uni.getStorageSync('score_trade')),
pay_price: 0,
from: 0,
link_id: 0,
customStyle: {
width: '86%',
'border-radius': '10px'
},
Color: uni.getStorageSync('theme_color')
})
function close() {
context.emit('close')
}
function preventD() {
return
}
function toScoreShop() {
uni.navigateTo({
url: '/pages/mine/scoreShop/index'
})
}
function shareOrder() {
context.emit('share')
close()
}
watch(props, (newProps) => {
if(newProps.showBuy) {
data.nickname = uni.getStorageSync('nickname')
data.avatar = uni.getStorageSync('avatar')
data.pay_price = newProps.payPrice * 1
data.from = newProps.from
data.link_id = (newProps.link_id || 0) * 1
}
})
return {
...toRefs(data),
close,
preventD,
toScoreShop,
shareOrder
}
}
}
</script>
<style lang="scss" scoped>
.buy {
text-align: center;
padding: 60rpx 0;
.title {
font-size: 34rpx;
color: v-bind('Color');
margin-top: 30rpx;
font-weight: 600;
}
.user {
display: flex;
align-items: center;
justify-content: center;
margin-top: 40rpx;
image {
width: 70rpx;
height: 70rpx;
background: #98989f;
border-radius: 50%;
margin-right: 15rpx;
}
}
.text {
color: #666666;
font-size: 26rpx;
margin-top: 30rpx;
}
.label{
position: relative;
margin: 36rpx auto 0;
width: 88%;
.text1{
border-radius: 20rpx 20rpx 20rpx 0;
border: 1px solid #fff;
background-color: v-bind('Color');
font-size: 22rpx;
color: #fff;
padding: 6rpx 10rpx;
position: absolute;
top: -26rpx;
left: 64%;
}
.btn {
width: 100%;
height: 86rpx;
line-height: 86rpx;
background: v-bind('Color');
border-radius: 10rpx;
color: #fff;
font-size: 30rpx;
text-align: center;
}
}
.box{
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx;
width: 88%;
margin: 30rpx auto 0;
background: #F9F6E5;
border-radius: 10rpx;
box-sizing: border-box;
.left{
width: calc(100% - 160rpx);
display: flex;
.img{
width: 90rpx;
}
.tit{
font-size: 28rpx;
color: #744928;
padding-left: 10rpx;
text-align: left;
.text1{
color: v-bind('Color');
font-weight: 600;
}
}
}
.to{
display: flex;
align-items: center;
justify-content: center;
height: 50rpx;
width: 140rpx;
border-radius: 50rpx;
background: v-bind('Color');
font-size: 26rpx;
color: #fff;
}
}
}
</style>

View File

@ -0,0 +1,224 @@
<template>
<!-- 客服 -->
<view>
<up-overlay :show="showService" :zIndex="999">
<view class="serviceBox">
<view class="block" @click.stop="preventD()">
<!-- <image v-if="qrCodeBg" :src="qrCodeBg + '?x-oss-process=image/format,webp'" :webp="true" mode="widthFix" class="img" /> -->
<image src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2022/11/07/tqVXV68gUSoUl5iOfRI72IvrdRHtcmZLb0ztnCa4.png?x-oss-process=image/format,webp" mode="widthFix" class="img" :webp="true" />
<view class="openbox">
<image :src="qrCodeImg" :webp="true" mode="widthFix" @longpress="toShare(qrCodeImg)" class="image"/>
<view class="btn">
<view class="icon" :style="{backgroundImage: 'url(' + sp2 + ')'}"></view>
<text>长按图片分享到微信</text>
</view>
</view>
<view class="btnBox">
<view class="btn on" @click="close()">关闭</view>
<view class="btn" @click="toPage">我要投诉</view>
</view>
</view>
</view>
</up-overlay>
<!-- <up-modal
:show="showService"
:showCancelButton="true"
@confirm="toMiniProgram"
@cancel="showService = false"
:confirmColor="Color">
<text>将跳转到小程序</text>
</up-modal> -->
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { get } from '@/Api/request.js'
import { sp2 } from '@/components/img.js'
import { func } from '../../uni_modules/uview-plus/libs/function/test'
export default {
props: {
show: {
type: Boolean,
default: false
},
type: {
type: Number,
default: 1
},
orderId: {
type: Number
}
},
setup(props, context) {
const data = reactive({
sp2: sp2,
qrCodeBg: '',
qrCodeImg: '',
showService: false,
Color: uni.getStorageSync('theme_color'),
orderId: 0,
sweixin: null
})
function getPlus() {
var pages = getCurrentPages()
var page = pages[pages.length - 1]
var shares = null
var pusher = plus.share.getServices(function(s){
shares = {}
for(var i in s){
var t = s[i]
shares[t.id] = t
}
data.sweixin = shares['weixin']
}, function(e) {
console.log("获取分享服务列表失败:" + e.message)
})
}
const toMiniProgram = () => {
data.sweixin.launchMiniProgram({
id: 'gh_ca74730c9f77',
path: 'pages/user/index?type=kefu'
})
data.showService = false
}
async function getQrCodeImg(type, orderId) {
let url = `/api/v1/orderRefund/qrCode/${orderId}`
if(type == 1) {
url = '/api/v1/user/qrCode'
}
await get(url).then((res) => {
data.qrCodeImg = res.data.qr_code
data.qrCodeBg = res.data.service_background_img
})
}
const preventD = () => {
return
}
function close() {
context.emit('close')
}
function toPage() {
close()
uni.navigateTo({url: '/pages/mine/msg/select?order_id=' + data.orderId})
}
function toShare(img) {
uni.share({
provider: "weixin",
scene: "WXSceneSession",
type: 2,
imageUrl: img,
success: function (res) {
console.log("success:" + JSON.stringify(res));
},
fail: function (err) {
console.log("fail:" + JSON.stringify(err));
}
})
}
watch(props, async (newProps) => {
if (newProps.show) {
await getQrCodeImg(newProps.type, newProps.orderId)
data.showService = true
data.orderId = newProps.orderId || 0
// getPlus()
} else {
data.showService = false
}
})
return {
...toRefs(data),
getQrCodeImg,
preventD,
close,
toPage,
getPlus,
toMiniProgram,
toShare
}
}
}
</script>
<style lang="scss" scoped>
.serviceBox{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding-top: 80rpx;
box-sizing: border-box;
.block{
width: 90%;
padding: 0 0 100rpx;
background: #fff;
border-radius: 24rpx;
.img{
width: 100%;
border-radius: 24rpx 24rpx 0 0;
}
.openbox{
margin: 60rpx auto;
width: 400rpx;
.image{
width: 100%;
float: left;
}
.btn{
color: #fff;
font-size: 30rpx;
width: 100%;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
background: v-bind('Color');
border-radius: 0 0 16rpx 16rpx;
.icon{
width: 22.5px;
height: 22.5px;
background-repeat: no-repeat;
background-size: 678px 612px;
background-position: -357px -286.5px;
margin-right: 10rpx;
}
}
}
.btnBox{
display: flex;
align-items: center;
justify-content: space-between;
width: 70%;
margin: 0 auto;
.btn{
color: v-bind('Color');
font-size: 28rpx;
width: 44%;
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid v-bind('Color');
border-radius: 10rpx;
box-sizing: border-box;
&.on{
background: v-bind('Color');
color: #fff;
}
}
}
}
}
</style>

View File

@ -0,0 +1,71 @@
<template>
<!-- 技术支持 -->
<view class="cloudbox" v-if="technical_support">
<view class="tit">
<view class="tu" :style="{backgroundImage: 'url(' + sp2 + ')'}"></view>
<text>{{technical_support_title}}提供技术支持</text>
<view class="tu" :style="{backgroundImage: 'url(' + sp2 + ')'}"></view>
</view>
<view class="more" @click="toPage">了解更多<up-icon color="#fff" size="10" name="arrow-right" /></view>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { sp2 } from '@/components/img.js'
export default {
setup(props, context) {
const data = reactive({
sp2: sp2,
technical_support: uni.getStorageSync('technical_support') || 0,
technical_support_title: uni.getStorageSync('technical_support_title')
})
const toPage = () => {
uni.navigateTo({ url: '/pages/mine/aboutUs/join' })
}
watch(props, async (newProps) => {
})
return {
...toRefs(data),
toPage
}
}
}
</script>
<style lang="scss" scoped>
.cloudbox{
text-align: center;
padding: 30rpx 0;
.tit{
font-size: 22rpx;
color: #A1A1A1;
display: flex;
align-items: center;
justify-content: center;
.tu{
background-repeat: no-repeat;
background-size: 339px 306px;
background-position: -218.5px -105px;
height: 8.25px;
width: 15.5px;
margin-top: 3px;
}
}
.more{
padding: 2px 4px 2px 7px;
font-size: 20rpx;
background-color: #A1A1A1;
border-radius: 10px;
color: #fff;
display: inline-flex;
align-items: center;
}
}
</style>

998
components/common.js Normal file
View File

@ -0,0 +1,998 @@
import { ref } from "vue"
import { get, post } from '../Api/request.js'
import { Style } from '../utils/list.js'
import { areaList } from './areaList.js'
// 登录
export function login() {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: res => {
let { code } = res
uni.request({
method: 'POST',
url: '/api/v1/auth/login',
data: {code, from: uni.getStorageSync('fromId') || 0},
header: {
Authorization: uni.getStorageSync('token') || '',
accept: "application/json",
appid: uni.getStorageSync('appId')
},
success: (val) => {
if(!Array.isArray(val.data)) {
let token = val.data.token_type + ' ' + val.data.access_token
uni.setStorageSync('token', token)
uni.setStorageSync('subscribe', val.data.is_subscribe)
uni.setStorageSync('avatar', val.data.avatar)
uni.setStorageSync('nickname', val.data.nickname)
uni.setStorageSync('role', 0)
uni.setStorageSync('login_type', 'mini-app')
uni.setStorageSync('is_vip', val.data.is_vip)
uni.setStorageSync('is_new', val.data.is_new)
uni.setStorageSync('is_authorized', val.data.is_authorized)
uni.setStorageSync('is_default_avatar', val.data.is_default_avatar)
uni.setStorageSync('sessionKey', val.data.session_key)
uni.setStorageSync('saveTime', Date.now()) // 存储时间
uni.setStorageSync('expires_in', val.data.expires_in * 1000) // 失效时间
uni.setStorageSync('is_crop_user', val.data.crop_user)
}
resolve(val.data)
}
})
},
fail(err) {
reject(err)
}
})
})
}
// 获取用户信息
export function getUserInfo() {
return new Promise((resolve, reject) => {
uni.hideLoading();
uni.getUserProfile ({
desc: '展示用户信息',
success: user=> {
post('/api/v1/user', {
nickname: user.userInfo.nickName,
avatar: user.userInfo.avatarUrl,
}, 'PUT').then( res => {
uni.setStorageSync('nickname', user.userInfo.nickName)
uni.setStorageSync('avatar', user.userInfo.avatarUrl)
uni.setStorageSync('is_authorized', 1)
uni.setStorageSync('is_default_avatar', false)
resolve(res)
})
},
fail(err) {
reject(err)
},
complete() {
}
})
})
}
export function getUserPhone(detail) {
return new Promise((resolve, reject) => {
uni.showLoading({
title: '获取中...',
mask: true
})
// 如果有code直接调接口
if(detail.code) {
post('/api/v1/user/phone', { code: detail.code }).then((res) => {
uni.setStorageSync('is_authorized', 1)
uni.hideLoading()
resolve(res)
}).catch((err) => {
reject(err)
})
} else {
// detail.encryptedDatadetail.iv根据code获取sessionkey再根据sessionkey、encryptedData、iv获取手机号
uni.checkSession({
success: function (req) {
post('/api/v1/user/phoneByEncrypted', { session_key: uni.getStorageSync('sessionKey'), encrypted_data: detail.encryptedData, iv: detail.iv }).then((res) => {
uni.setStorageSync('is_authorized', 1)
uni.hideLoading()
resolve(res)
}).catch((err) => {
reject(err)
})
},
fail: async function (error) {
uni.hideLoading()
await login()
getUserPhone(detail)
}
})
}
})
}
// 绑定分享信息
export async function userBind(params) {
let from = params.from || 0,
s = params.s || 0,
u = params.u || 0,
group_id = params.group_id || 0,
company_id = params.company_id || '',
scene = params.scene
let has_sale = uni.getStorageSync('has_sale')
let index = getCurrentPages().length - 1
let link = getCurrentPages()[index].route
if (from > 0 || company_id || !has_sale) {
await post('/api/v1/user/bind', {from, s, u, group_id, scene, company_id, link}).then((res) => {
uni.setStorageSync('has_sale', true)
})
}
}
export async function judgePrivacy() {
return new Promise((resolve, reject) => {
if(uni.getPrivacySetting) {
uni.getPrivacySetting({
success: res => {
console.log("是否需要授权:", res.needAuthorization)
if (res.needAuthorization) {
resolve(true)
} else{
resolve(false)
}
}
})
} else {
// 低版本基础库不支持 wx.getPrivacySetting 接口,隐私接口可以直接调用
resolve(false)
}
})
}
export async function uvRecord(id) {
await get('/api/v1/banner/' + id + '/uv/record').then((res) => {
})
}
// 消息提示框
export function showToast(title = '', icon = 'none') {
uni.showToast({
title,
icon
})
}
export function goodsItem () {
function toGoods (id) {
uni.navigateTo({
url: '/pages/groups/index?id=' + id
})
}
// 商品规格
const showSku = ref(false)
const groupId = ref(0)
const sourceId = ref(0)
const sourceType = ref('normal')
const skuInfo = ref([])
const skuId = ref(0)
const sku = ref({})
const showBtn = ref(true)
async function getGoodsSku (item) {
groupId.value = item.shop_group_goods_id
// 判断用户授权状态
await getgoodsgku(item)
}
// 获取商品规格
async function getgoodsgku (item) {
if (item.specs_type === 1) {
skuInfo.value = await getGoodsSpecs(item.id)
skuInfo.value.shop_group_goods_id = item.pivot.shop_group_goods_id
showSku.value = true
} else if (item.shop_goods_id){
skuInfo.value = await getGoodsSpecs(item.shop_goods_id)
skuId.value = item.shop_goods_sku_id || 0
if (item.goods && item.goods.sku) {
sku.value = {...item.goods.sku, num: item.num, cart_id: item.id || ''}
}
if(item.shop_group_goods_id !=0) {
skuInfo.value.shop_group_goods_id = item.shop_group_goods_id || item.pivot.shop_group_goods_id
} else {
skuInfo.value.shop_group_goods_id = 0
}
showSku.value = true
} else if (item.specs_type === 0) {
if (item.stock > 0 || item.goods.stock > 0) {
await addCart(item)
} else {
showToast('商品库存不足')
return
}
}
}
const skus_1 = ref(false)
async function getGoodsSpecs (id) {
let res = await get(`/api/v1/goods/spec/${id}`)
if(res.data.skus.length == 1) {
skus_1.value = true
}
else {
skus_1.value = false
}
return res.data
}
// 添加到购物车
async function addCart (item) {
let res = await post('/api/v1/carts', {
shop_goods_id: item.id,
shop_goods_sku_id: 0,
num:item.goods.limit_type==1 ? item.goods.start_sale_num : 1,
shop_group_goods_id: item.pivot.shop_group_goods_id,
source_id: sourceId.value,
source_type: sourceType.value,
})
if (res.code === 0) {
showToast('已加入购物车')
getNum()
showBtn.value = true
}
}
let num = ref(uni.getStorageSync('cartNum') * 1)
// 获取购物车数量
async function getNum () {
let res = await get('/api/v1/carts/num')
num.value = Number(res.data.num)
uni.setStorageSync('cartNum', num.value)
}
return {
sourceId,
sourceType,
toGoods,
showSku, getGoodsSku, skuInfo, skuId, sku,skus_1,
addCart,
getNum, num,
showBtn,
getGoodsSpecs
}
}
let isclick = true
// 重新支付
export function payAgain(id, link_id = 0) {
if(isclick){
uni.showLoading({ mask: true, title: '加载中' })
isclick = false
get(`/api/v1/pay/${id}`, { pay_style: 'h5_pay' }).then((res) => {
uni.hideLoading()
setTimeout(() => {
isclick = true
}, 1000)
wxPay(res.data, id, 0, false, 0, link_id)
}).catch(() => {
isclick = true
})
}
}
// 微信支付
export function wxPay(paymentData, id, type, flag = false, from = 0, link_id = 0) {
uni.showLoading({
title: '加载中...',
mask: true
})
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId": paymentData.appId, //公众号ID由商户传入
"timeStamp": paymentData.timeStamp, //时间戳自1970年以来的秒数
"nonceStr": paymentData.nonceStr, //随机串
"package": paymentData.package,
"signType": paymentData.signType, //微信签名方式
"paySign": paymentData.paySign //微信签名
}, function(res){
uni.hideLoading()
if(res.err_msg == "get_brand_wcpay_request:ok" ){
// 在此判断订单是否已经支付成功
isPayOrder(paymentData.pay_id, id, type, flag, from, link_id)
} else {
showToast('支付失败')
if(flag){
get(`/api/v1/order/close/${id}`).then((res) => {
})
}
if (type) {
uni.redirectTo({ url: '/pages/order/list/index' })
}
}
})
}
export function isPayOrder(pay_id, id, type, flag, from, link_id) {
uni.showLoading({
title: '加载中...',
mask: true
})
get(`/api/v1/pay/check/${data.pay_id}`).then(async(res) => {
uni.hideLoading()
if(res.data.status) {
if (id) {
if(link_id) {
uni.redirectTo({
url: '/pages/success/two?id=' + id + '&type=' + type + '&pay_id=' + paymentData.pay_id + '&from=' + from + '&link_id=' + link_id
})
} else {
uni.redirectTo({
url: '/pages/success/index?id=' + id + '&type=' + type + '&pay_id=' + paymentData.pay_id + '&from=' + from
})
}
} else {
showToast('支付成功')
uni.navigateBack({ delta:1 })
}
} else {
showToast('支付失败')
if(flag){
await get(`/api/v1/order/close/${id}`).then((res) => {
})
}
if (type) {
uni.redirectTo({ url: '/pages/order/list/index' })
}
}
})
}
/**
* 获取本周本季度本月
*/
var now = new Date() //当前日期
var nowDayOfWeek = now.getDay() //今天本周的第几天
var nowDay = now.getDate() //当前日
var nowMonth = now.getMonth() //当前月
var nowYear = now.getYear() //当前年
nowYear += (nowYear < 2000) ? 1900 : 0
// 获取当前日期前几天的日期
export function getOldDay(str = 'y-m-d h:i:s', day = 0) {
var dd = new Date()
dd.setDate(dd.getDate() - day) //获取AddDayCount天后的日期
return dateTimeStr(str, new Date(dd))
}
// 获取某个时间后几天的时间
export function getRangeTime(date, day) {
let odate = new Date(date.replace(/-/g, '/')).getTime()
odate = odate + (day * 24 * 60 * 60 * 1000)
odate = new Date(odate)
// 当前时间年月日
let month1 = (nowMonth + 1) >= 1 && (nowMonth + 1) <= 9 ? '0' + (nowMonth + 1) : (nowMonth + 1)
let day1 = nowDay >= 1 && nowDay <= 9 ? '0' + nowDay : nowDay
let nowTime = nowYear + '-' + month1 + '-' + day1
// 计算的日期
let month2 = (odate.getMonth() + 1) >= 1 && (odate.getMonth() + 1) <= 9 ? '0' + (odate.getMonth() + 1) : (odate.getMonth() + 1)
let day2 = odate.getDate() >= 1 && odate.getDate() <= 9 ? '0' + odate.getDate() : odate.getDate()
let time = odate.getFullYear() + '-' + month2 + '-' + day2
console.log(nowTime, time)
let timeStr = (odate.getMonth() + 1) + '月' + odate.getDate() + '日'
if(nowTime == time) {
timeStr = '今天'
} else if(getOldDay('y-m-d', -1) == time){
timeStr = '明天'
}
return timeStr
}
// 获取某个时间后几天的时间
// (2023-11-10 12:12:11, 3) => 2023-11-13 12:12:11
export function getNextTime(date, day) {
let odate = new Date(date.replace(/-/g, "/")).getTime()
odate = odate + (day * 24 * 60 * 60 * 1000)
odate = new Date(odate)
// 计算的日期
let year2 = odate.getFullYear()
let month2 = (odate.getMonth()+1) >= 1 && (odate.getMonth()+1) <= 9 ? '0' + (odate.getMonth()+1) : (odate.getMonth()+1)
let day2 = odate.getDate() >= 1 && odate.getDate() <= 9 ? '0' + odate.getDate() : odate.getDate()
let hour = odate.getHours() < 10 ? '0' + odate.getHours() : odate.getHours()
let minute = odate.getMinutes() < 10 ? '0' + odate.getMinutes() : odate.getMinutes() //分
let second = odate.getSeconds() < 10 ? '0' + odate.getSeconds() : odate.getSeconds() //秒
let time = year2 + '-' + month2 + '-' + day2 + ' ' + hour + ':' + minute + ':' + second
return time
}
export function compareDate(date1, date2) {
let str1 = new Date(date1.replace(/-/g, "/")).getTime()
let str2 = new Date(date2.replace(/-/g, "/")).getTime()
return str2 - str1 >= 0
}
// 时间戳转日期
export function dateTimeStr(str = "y-m-d h:i:s", day){
var date = new Date(day),
year = date.getFullYear(), //年
month = date.getMonth() + 1, //月
day = date.getDate(), //日
hour = date.getHours(), //时
minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(), //分
second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds(); //秒
month >= 1 && month <= 9 ? (month = "0" + month) : "";
day >= 0 && day <= 9 ? (day = "0" + day) : "";
hour >= 0 && hour <= 9 ? (hour = "0" + hour) : "";
if(str.indexOf('y') != -1){
str = str.replace('y', year)
}
if(str.indexOf('m') != -1){
str = str.replace('m', month)
}
if(str.indexOf('d') != -1){
str = str.replace('d', day)
}
if(str.indexOf('h') != -1){
str = str.replace('h', hour)
}
if(str.indexOf('i') != -1){
str = str.replace('i', minute)
}
if(str.indexOf('s') != -1){
str = str.replace('s', second)
}
return str
}
// 获得本周的开始日期
export function getWeekStartDate() {
var weekStartDate = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek + 1)
return dateTimeStr("y-m-d", weekStartDate)
}
// 获得本月的开始日期
export function getMonthStartDate(){
var monthStartDate = new Date(nowYear, nowMonth, 1)
return dateTimeStr("y-m-d", monthStartDate)
}
// 保存图片到相册
export function saveImg (url, text) {
const elink = document.createElement('a')
elink.download = '图片'
elink.style.display = 'none'
elink.href = url
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
document.body.removeChild(elink)
showToast(text || '保存成功', 'success')
}
// 图片预览
export async function getImg () {
let imgsArray = [];
let res = await get('/api/v1/user/qrCode')
if (res.code === 0) {
imgsArray.push(res.data.qr_code)
}
uni.previewImage({
urls: imgsArray,
current: 0
})
}
// 批量加购物车
export function adddCartBatch (items) {
const goods = items.map(item => {
return {
shop_goods_id: item.shop_goods_id,
shop_goods_sku_id: item.shop_sku_id,
num: item.number,
shop_group_goods_id: item.shop_group_goods_id,
source_id: 0,
source_type: 'normal'
}
})
post('/api/v1/carts/batch', {goods}).then(res => {
showToast('已添加到购物车')
setTimeout(function() {
uni.switchTab({
url: '/pages/cart/index'
})
}, 1000)
})
}
// 去评论
export function toWrite (id) {
uni.navigateTo({
url: `/pages/order/comment/write?id=${id}`
})
}
// 获取店铺信息
export async function getShopInfo () {
let res = await get('/api/app/shop')
uni.setStorageSync('page_rule', res.data.home_page_rule)
uni.setStorageSync('vip_on', res.data.vip_on)
uni.setStorageSync('shop_id', res.data.id)
uni.setStorageSync('official_link', res.data.official_link)
uni.setStorageSync('vip_price_show', res.data.vip_price_show === 1)
uni.setStorageSync('refund_mode', res.data.refund_mode)
uni.setStorageSync('show_identity', res.data.show_identity)
uni.setStorageSync('vip_detail_on', res.data.vip_detail_on)
uni.setStorageSync('score_on', res.data.score_on)
uni.setStorageSync('score_trade_share', res.data.score_trade_share)
uni.setStorageSync('score_comment', res.data.score_comment)
uni.setStorageSync('score_trade', res.data.score_trade)
uni.setStorageSync('deduct_overtime_ship_on', res.data.deduct_overtime_ship_on)
uni.setStorageSync('img_preview_suffix', res.data.img_preview_suffix)
uni.setStorageSync('rule', res.data.home_special_rule)
uni.setStorageSync('logo', res.data.logo)
uni.setStorageSync('name', res.data.name)
uni.setStorageSync('describe', res.data.describe)
uni.setStorageSync('theme_index', res.data.show_style_type || 0)
uni.setStorageSync('theme_color', Style[res.data.show_style_type || 0].color)
uni.setStorageSync('show_explain_video', res.data.show_explain_video)
uni.setStorageSync('user_bg', res.data.user_background_img)
uni.setStorageSync('has_multi_group', res.data.has_multi_group)
uni.setStorageSync('technical_support', res.data.extendInfo ? res.data.extendInfo.technical_support : 0)
uni.setStorageSync('technical_support_title', res.data.extendInfo ? res.data.extendInfo.technical_support_title : '')
uni.setStorageSync('check_logo', res.data.extendInfo ? res.data.extendInfo.check_report_logo : '')
return res.data
}
/**
* @desc 格式化日期字符串
* @param { Nubmer} - 时间戳
* @returns { String } 格式化后的日期字符串
*/
export function formatDate(timestamp) {
// 补全为13位
let arrTimestamp = (timestamp + '').split('');
for (let start = 0; start < 13; start++) {
if (!arrTimestamp[start]) {
arrTimestamp[start] = '0';
}
}
timestamp = arrTimestamp.join('') * 1;
let minute = 1000 * 60;
let hour = minute * 60;
let day = hour * 24;
let month = day * 30;
let now = new Date().getTime();
let diffValue = now - timestamp;
// 如果本地时间反而小于变量时间
if (diffValue < 0) {
return '不久前';
}
// 计算差异时间的量级
let monthC = diffValue / month;
let weekC = diffValue / (7 * day);
let dayC = diffValue / day;
let hourC = diffValue / hour;
let minC = diffValue / minute;
// 数值补0方法
let zero = function (value) {
if (value < 10) {
return '0' + value;
}
return value;
};
// 使用
if (monthC > 4) {
// 超过1年直接显示年月日
return (function () {
let date = new Date(timestamp);
return date.getFullYear() + '年' + zero(date.getMonth() + 1) + '月' + zero(date.getDate()) + '日';
})();
} else if (monthC >= 1) {
return parseInt(monthC) + '月前';
} else if (weekC >= 1) {
return parseInt(weekC) + '周前';
} else if (dayC >= 1) {
return parseInt(dayC) + '天前';
} else if (hourC >= 1) {
return parseInt(hourC) + '小时前';
} else if (minC >= 1) {
return parseInt(minC) + '分钟前';
}
return '刚刚';
}
// 监听网络变化
export function NetWork() {
uni.getNetworkType({
success: (res) => {
if (res.networkType == 'none') {
uni.showToast({
icon: "none",
title: '网络错误,请重试!'
})
}
}
})
// 监听网络状态变化
uni.onNetworkStatusChange((res) => {
if (!res.isConnected) {
uni.showToast({
icon: "none",
title: '网络错误,请重试!'
})
}
})
}
/**
* @desc 封装倒计时组件
* @param endTime 结束时间
* @param type 返回的类型
* @return {*}
*/
export function DownTime( endTime, type) {
let thisEndTime = new Date(endTime) // 获取截
if(type == 3){
var downFn = setInterval(() => {
let newTime = new Date().getTime()//获取当前时间
let backTime = thisEndTime - newTime//计算剩余时间
var d = Math.floor(backTime / (1000 * 60 * 60 * 24)); //计算天数
var h = Math.floor(backTime / (1000 * 60 * 60) % 24); //计算小时数
var m = Math.floor(backTime / (1000 * 60) % 60); //计算分钟数
var s = Math.floor(backTime / 1000 % 60); //计算秒数
return {d: d, h: h, m: m, s: s}
}, 1000)
}else if(type == 1 || type == 2) {
var to = new Date(endTime.replace(/-/g, "/"))
var now = new Date()
var backTime = to.getTime() - now.getTime()
var d = Math.floor(backTime / (1000 * 60 * 60 * 24)) //计算天数
var h = Math.floor(backTime / (1000 * 60 * 60) % 24) //计算小时数
var m = Math.floor(backTime / (1000 * 60) % 60) //计算分钟数
var s = Math.floor(backTime / 1000 % 60); //计算秒数
if( type == 1){
if(d > 0){
return '距结束<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">'+ d + '</span>天'
}else if(h||m||s){
let time1='距结束<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + h + '</span>时<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + m + '</span>分<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + s + '</span>秒'
let time2='已结束'
return backTime > 0 ? time1 : time2
}else{
return ''
}
}else if(type == 2) {
d = d > 9 ? d : '0' + d
h = h > 9 ? h : '0' + h
m = m > 9 ? m : '0' + m
let time1='距结束<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + d + '</span>天<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + h + '</span>时<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + m + '</span>分'
if(d == 0) {
time1='距结束<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + h + '</span>时<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + m + '</span>分'
}
let time2='已结束'
return backTime > 0 ? time1 : time2
}
}
}
export function UpTime( startTime, type) {
let stTime = new Date(startTime.replace(/-/g, "/"))
if(new Date().getTime() - stTime < 0) {
if(type == 3){
setInterval(() => {
let newTime = new Date().getTime()//获取当前时间
let backTime = stTime - newTime//计算剩余时间
var d = Math.floor(backTime / (1000 * 60 * 60 * 24)); //计算天数
var h = Math.floor(backTime / (1000 * 60 * 60) % 24); //计算小时数
var m = Math.floor(backTime / (1000 * 60) % 60); //计算分钟数
var s = Math.floor(backTime / 1000 % 60); //计算秒数
return {d: d, h: h, m: m, s: s}
}, 1000)
}
if(type == 1 || type == 2) {
var to = new Date(startTime.replace(/-/g, "/"))
var now = new Date()
var backTime = to.getTime() - now.getTime()
var d = Math.floor(backTime / (1000 * 60 * 60 * 24)) //计算天数
var h = Math.floor(backTime / (1000 * 60 * 60) % 24) //计算小时数
var m = Math.floor(backTime / (1000 * 60) % 60) //计算分钟数
var s = Math.floor(backTime / 1000 % 60); //计算秒数
if(type == 1){
if(d > 0){
return '距开始<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">'+ d + '</span>天'
}else if(h || m || s){
let time1 = '距开始<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + h + '</span>时<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + m + '</span>分<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + s + '</span>秒'
return time1
}
} else if(type == 2) {
d = d > 9 ? d : '0' + d
h = h > 9 ? h : '0' + h
m = m > 9 ? m : '0' + m
let time1='距开始<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + d + '</span>天<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + h + '</span>时<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + m + '</span>分'
if(d == 0) {
time1='距开始<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + h + '</span>时<span style="color:#2C2C2C;font-weight:bold;margin:0 2px;">' + m + '</span>分'
}
let time2='已结束'
return time1
}
}
} else {
return ''
}
}
export function gapTime(startTime) {
let stTime = new Date(startTime.replace(/-/g, "/"))
var to = new Date(startTime.replace(/-/g, "/"))
var now = new Date()
var backTime = to.getTime() - now.getTime()
var d = Math.floor(backTime / (1000 * 60 * 60 * 24)) //计算天数
var h = Math.floor(backTime / (1000 * 60 * 60) % 24) //计算小时数
var m = Math.floor(backTime / (1000 * 60) % 60) //计算分钟数
var s = Math.floor(backTime / 1000 % 60); //计算秒数
if(d > 0){
return d + '天'
} else if(h > 0){
return h + '小时'
} else if(m > 0) {
return m + '分钟'
} else {
return s + '秒'
}
}
export function parseTime(Time) {
let date = Time.split(' ')[0]
let start = Time.split(' ')[1].substr(0, 5)
let today = new Date().setHours(0, 0, 0, 0)
let dayStr = new Date(date.replace(/-/g, "/")).setHours(0, 0, 0, 0)
let dateObj = {
0: '今天',
86400000: '明天',
172800000: '后天'
}
return (dateObj[dayStr - today] || date) + ' ' + start
}
export const writePhotosAlbum = (successFun, failFun) => {
uni.getSetting({
success(res) {
if (!res.authSetting['scope.writePhotosAlbum']) {
uni.authorize({
scope: 'scope.writePhotosAlbum',
success: function () {
successFun && successFun()
},
fail: function (res) {
uni.hideLoading()
uni.showModal({
title: '提示',
content: "微信授权保存图片,是否重新授权?",
showCancel: true,
cancelText: "否",
confirmText: "是",
success: function (res2) {
if (res2.confirm) {
uni.openSetting({
success: (res3) => {
if (res3.authSetting['scope.writePhotosAlbum']) {
successFun && successFun()
} else {
failFun && failFun()
}
}
})
} else {
failFun && failFun()
}
}
})
}
})
} else {
successFun && successFun()
}
}
})
}
export const getDayDiff = (date1, date2) => {
const oneDay = 1000 * 60 * 60 * 24
const timeDiff = Math.abs(new Date(date1.replace(/-/g, '/')).getTime() - new Date(date2.replace(/-/g, '/')).getTime())
const dayDiff = Math.ceil(timeDiff / oneDay)
let str = dayDiff == 0 ? '当天' : dayDiff + '天后'
return str
}
export const getIntervalDay = (date1, date2) => {
const oneDay = 1000 * 60 * 60 * 24
const timeDiff = Math.abs(new Date(date1.replace(/-/g, '/')).getTime() - new Date(date2.replace(/-/g, '/')).getTime())
const dayDiff = Math.ceil(timeDiff / oneDay)
let flag = dayDiff < 180 ? true : false
return flag
}
export const getAreaCode = (prov_name, city_name, area_name) => {
return new Promise((resolve, reject) => {
let list = []
for(let a = 0; a < areaList.length; a++){
let prov = areaList[a]
if (prov.name == prov_name) {
list.push({ code: prov.id, name: prov_name })
for(let b = 0; b < prov.children.length; b++){
let city = prov.children[b]
if (city.name == city_name) {
list.push({ code: city.id, name: city_name })
for(let c = 0; c < city.children.length; c++){
let area = city.children[c]
if (area.name == area_name) {
list.push({ code: area.id, name: area_name })
break
}
}
break
}
}
break
}
}
resolve(list)
})
}
export const downloadVideo = (url) => {
uni.showLoading({
mask: true,
title: '加载中'
})
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
uni.hideLoading()
uni.saveVideoToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
showToast('保存成功')
},
fail: (err) => {
if (err.errMsg === 'saveVideoToPhotosAlbum:fail auth deny') {
uni.showModal({
title: '提示',
content: '需要您授权保存相册',
showCancel: false,
success() {
uni.openSetting({
success(settingdata) {
if (settingdata.authSetting['scope.writePhotosAlbum']) {
uni.showModal({
title: '提示',
content: '获取权限成功, 请重新保存图片',
showCancel: false
})
} else {
uni.showModal({
title: '提示',
content: '获取权限失败,将无法保存到相册哦~',
showCancel: false
})
}
},
fail(failData) {
},
complete(finishData) {
}
})
}
})
}
}
})
}
},
fail: (err) => {
uni.hideLoading()
uni.showToast({
title: err.errMsg,
icon: 'none'
})
}
})
}
export const toMiniProgram = (path) => {
uni.showModal({
title: '提示',
content: '请至小程序进行操作喔',
showCancel: false
// success(res) {
// if (res.confirm) {
// var pages = getCurrentPages()
// var page = pages[pages.length - 1]
// var shares = null, sweixin = null
// plus.share.getServices(function(s){
// shares = {}
// for(var i in s){
// var t = s[i]
// shares[t.id] = t
// }
// sweixin = shares['weixin']
// sweixin.launchMiniProgram({
// id: 'gh_ca74730c9f77',
// path: path
// })
// }, function(e) {
// console.log("获取分享服务列表失败:" + e.message)
// })
// }
// }
})
}
export const whetherLogin = () => {
let flag = true
let saveTime = uni.getStorageSync('saveTime')
let expires_in = uni.getStorageSync('expires_in')
let token = uni.getStorageSync('token')
if((saveTime && expires_in && Date.now() > saveTime + expires_in) || !expires_in || !saveTime || !token) {
flag = false
}
return flag
}
export async function judgeShop(){
return new Promise((resolve, reject) => {
let url = window.location.href.split('?')
let Param = new URLSearchParams(url[1])
let shopId = uni.getStorageSync('shop_id')
let appId = uni.getStorageSync('appId')
if(shopId) {
if(Param.get('shopId') && Param.get('shopId') !== shopId) {
console.log(Param.get('shopId'))
uni.setStorageSync('shop_id', Param.get('shopId'))
getShopInfo()
uni.removeStorageSync('token')
uni.removeStorageSync('saveTime')
uni.removeStorageSync('expires_in')
uni.redirectTo({
url: '/pages/user/login'
})
reject()
} else {
if(!appId) {
get('/api/v1/live/shop', {id: Param.get('shopId')}).then((res) => {
uni.setStorageSync('appId', res.data.appid)
getShopInfo()
})
resolve()
} else {
resolve()
}
}
} else {
uni.removeStorageSync('token')
uni.removeStorageSync('saveTime')
uni.removeStorageSync('expires_in')
uni.redirectTo({
url: '/pages/user/login'
})
reject()
}
})
}
export function copyText(text){
uni.setClipboardData({
data: text,
success: () => {
uni.showToast({
title: '复制成功',
icon: 'success'
})
}
})
}

View File

@ -0,0 +1,122 @@
<template>
<up-overlay :show="showGifts" :zIndex="9999">
<view class="serviceBox">
<view class="block">
<view class="title">恭喜您获得</view>
<view class="openbox">
<image src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2022/11/08/l5SAwF75s4IQ5tglcLQo5bUlfixoFtnODw5CH4hT.png" mode="widthFix" class="image" />
<view class="coupon">
<view class="coupon-left">{{info.days}}</view>
<view class="coupon-right">会员权益</view>
</view>
</view>
<view class="btn" @click="getHandle()">立即领取</view>
</view>
</view>
</up-overlay>
</template>
<script>
import { ref, reactive, toRefs } from 'vue'
import { get, post } from '@/Api/request.js'
import { showToast } from '../common.js'
export default {
props: {
showGifts: {
type: Boolean,
default: false
},
info: {
type: Object,
default: {}
}
},
setup(props, context) {
const data = reactive({
})
function getHandle() {
showToast('领取成功')
context.emit('close')
}
return {
...toRefs(data),
getHandle
}
}
}
</script>
<style lang="scss" scoped>
.serviceBox{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding-bottom: 80rpx;
box-sizing: border-box;
.block{
width: 80%;
background: #fff;
padding-bottom: 80rpx;
position: relative;
border-radius: 20rpx;
.title{
padding: 40rpx 0;
color: #333;
font-size: 34rpx;
font-weight: bold;
text-align: center;
}
.openbox{
margin: 0 auto;
width: 86%;
position: relative;
.image{
width: 100%;
}
.coupon{
width: 100%;
position: absolute;
top: 0;
left: 0;
height: 100%;
padding: 20rpx;
box-sizing: border-box;
display: flex;
color: #F14939;
.coupon-left {
width: 36%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 44rpx;
font-weight: bold;
}
.coupon-right {
width: 64%;
padding-left: 40rpx;
display: flex;
align-items: center;
font-size: 32rpx;
}
}
}
.btn{
color: #fff;
font-size: 32rpx;
margin: 40rpx auto 0;
width: 86%;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
background: #F14939;
border-radius: 12rpx;
}
}
}
</style>

2813
components/groups/detail.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,455 @@
<template>
<!-- 团购纵向布局 -->
<view class="shop" :class="type == 1 ? '' : 'home'">
<view class="shop-goods" :class="type == 1 ? 'fenlei' : ''">
<view class="shop-goods-group">
<scroll-view scroll-y="true" class="scroll">
<template v-for="(item, index) in groupList" :key="item.id">
<view class="item" v-if="item.is_more !== 1" :class="groupId === item.id ? 'choose' : ''" @click="chooseGroup(item.id)">
{{item.name}}
</view>
</template>
</scroll-view>
</view>
<view class="shop-goods-list">
<view class="sort_box" v-if="type == 1">
<view class="sort_item" v-for="(item, index) in sortList" :key="index" @click.stop="chooseSort(index)">
<text :class="sortIndex === index ? 'choose' : ''">{{item}}</text>
<view class="icon" v-if="index === 2">
<up-icon name="arrow-up" size="10" :color="priceType && sortIndex === 2 ? Color : ''" />
<up-icon name="arrow-down" size="10" :color="!priceType && sortIndex === 2 ? Color : ''" />
</view>
</view>
</view>
<scroll-view scroll-y="true" class="goodbox" :class="type == 1 ? '' : 'padtop'" @scrolltolower="scorllBottom">
<view class="goods" v-for="item in goodsList" :key="item.id" @click="toGoods(item.id)">
<image class="goods-img" :src="item.face_img + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill"></image>
<view class="goods-info">
<view>
<view class="name">{{item.title}}</view>
<view v-if="item.actives && item.actives.length">
<view v-for="it in item.actives" class="move_img">{{it.name}}</view>
</view>
</view>
<view class="goods-info-price goods-info-vip">
<view class="goods-info-price-left" v-if="item.group_goods.length === 1">
<text class="icon"></text>
<text class="price">
<text v-if="item.group_goods[0].specs_type === 0">{{item.group_goods[0].price}}</text>
<text v-else>
<text v-if="item.group_goods[0].max_price === item.group_goods[0].min_price">{{item.group_goods[0].min_price}}</text>
<text v-else>{{item.group_goods[0].min_price}}~{{item.group_goods[0].max_price}}</text>
</text>
</text>
</view>
<view class="goods-info-vip" v-else>
<text class="icon"></text>
<text class="price">
<text v-if="item.max_price === item.min_price">{{item.min_price}}</text>
<text v-else>{{item.min_price}}~{{item.max_price}}</text>
</text>
</view>
<view v-if="item.group_goods.length === 1">
<template v-if="item.group_goods[0].specs_type == 0 && item.group_goods[0].goods.limit_type == 0">
<view @click.stop="getGoodsSkus(item.group_goods[0])" class="goods-info-price-right">
+
</view>
</template>
<template v-else-if="item.group_goods[0].specs_type == 0 && item.group_goods[0].goods.limit_type != 0">
<view class="goods-info-price-right">+</view>
</template>
<template v-if="item.group_goods[0].specs_type == 1">
<view @click.stop="getGoodsSkus(item.group_goods[0])" class="goods-info-price-right">
+
</view>
</template>
</view>
<view class="goods-info-price-right" v-else>
+
</view>
</view>
</view>
</view>
<view class="bottom" v-if="page >= lastPage">- 没有更多了 -</view>
<view class="bottom" v-else>加载中...</view>
</scroll-view>
</view>
</view>
<choose-sku :show-sku="showSku" :show1='true' :sku-info="skuInfo" :skus_1="skus_1" @close="showSku = false" :isTabbar="true" @getnum="getnum" />
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import ChooseSku from '../sku/ChooseSku.vue'
import { get } from '@/Api/request.js'
import { goodsItem } from '../common.js'
import { Style } from '@/utils/list.js'
export default {
components: {
ChooseSku
},
props: {
groupList: Array,
type: {
type: Number,
default: 0
},
vipOn: Number
},
setup(props, context) {
const data = reactive({
goodsList: [],
groupId: '',
page: 1,
lastPage: 0,
sortList: ['综合', '销量', '价格', '上新'],
sortIndex: 0,
priceType: false,
sortFilter: {
sales: '',
price: '',
score: 2,
new: ''
},
Color: uni.getStorageSync('theme_color'),
priceColor: Style[uni.getStorageSync('theme_index') * 1].priceColor
})
//
async function getGoodsList() {
uni.showLoading({
title: '加载中...'
})
let params = {
shop_group_id: data.groupId,
page: data.page,
sales: data.sortFilter.sales,
price: data.sortFilter.price,
score: data.sortFilter.score,
new: data.sortFilter.new
}
await get('/api/app/search', params).then((res) => {
data.goodsList = data.goodsList.concat(res.data)
data.lastPage = res.meta.last_page
uni.hideLoading()
})
}
//
function chooseGroup(id) {
if (id !== data.groupId) {
data.groupId = id
data.page = 1
data.goodsList = []
getGoodsList()
}
}
const { toGoods, showSku, getGoodsSku, skuInfo, getNum, skus_1 } = goodsItem()
const getGoodsSkus = (item) => {
getGoodsSku(item).then((res) => {
if (item.specs_type === 0) {
getnum()
}
})
}
//
function chooseSort(index) {
data.sortIndex = index
if (index === 2) {
data.priceType = !data.priceType
data.sortFilter.price = data.priceType ? 1 : 2
data.sortFilter.new = ''
} else {
data.sortFilter.price = ''
}
data.sortFilter.sales = index === 1 ? 2 : ''
data.sortFilter.score = index === 0 ? 2 : ''
data.sortFilter.new = index === 3 ? 2 : ''
data.page = 1
data.goodsList = []
getGoodsList()
}
const getnum = () => {
context.emit('getnum')
}
getGoodsList()
function scorllBottom() {
if (data.page < data.lastPage) {
data.page++
getGoodsList()
}
}
return {
...toRefs(data),
chooseGroup,
showSku,
getGoodsSku,
toGoods,
skuInfo,
getNum,
skus_1,
getnum,
getGoodsSkus,
getGoodsList,
chooseSort,
scorllBottom
}
}
}
</script>
<style lang="scss" scoped>
.shop {
height: calc(100vh - env(safe-area-inset-bottom));
&.home{
height: calc(100vh - 184rpx - env(safe-area-inset-bottom));
}
.shop-coupon {
display: flex;
height: 130rpx;
padding: 15rpx 40rpx;
box-sizing: border-box;
background-color: #fff;
box-shadow: 0rpx 0rpx 20rpx rgba(34, 34, 34, 0.1);
border-radius: 10rpx;
margin-bottom: 30rpx;
&-price {
display: flex;
align-items: center;
font-size: 24rpx;
padding-right: 40rpx;
border-right: 2rpx solid #555555;
.price {
font-size: 40rpx;
color: v-bind('priceColor');
margin: 0 10rpx;
font-weight: bold;
}
}
&-text {
display: flex;
align-items: center;
flex: 1;
justify-content: space-between;
margin-left: 30rpx;
.left {
.title {
font-size: 32rpx;
font-weight: bold;
}
.text {
font-size: 24rpx;
color: #555555;
margin-top: 14rpx;
}
}
.btn {
font-size: 24rpx;
height: 50rpx;
line-height: 50rpx;
width: 140rpx;
border-radius: 40rpx;
background: v-bind('Color');
text-align: center;
color: #fff;
}
}
}
.shop-goods {
display: flex;
overflow: auto;
height: 100%;
&.fenlei{
height: calc(100% - 110rpx);
}
&-group,
&-list {
background-color: #fff;
height: 100%;
}
&-group {
width: 25%;
flex-shrink: 0;
.scroll {
height: 100%;
.item {
height: 90rpx;
line-height: 90rpx;
padding-left: 30rpx;
font-size: 24rpx;
&.choose {
background-color: #f9f9f9;
color: v-bind('Color');
font-weight: bold;
}
}
}
}
&-list {
flex: 1;
height: 100%;
overflow: auto;
position: relative;
width: 75%;
.goods {
display: flex;
padding: 20rpx 0;
margin: 0 30rpx;
&-img {
width: 140rpx;
height: 140rpx;
background: #cbcacb;
border-radius: 10rpx;
flex-shrink: 0;
margin-right: 18rpx;
}
&-info {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
overflow: hidden;
min-height: 140rpx;
.name {
font-size: 28rpx;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&-tag {
display: flex;
overflow-x: auto;
&-item {
font-size: 24rpx;
color: v-bind('Color');
background-color: #fff3f4;
padding: 0 15rpx;
margin-right: 5rpx;
border-radius: 15rpx;
flex-shrink: 0;
}
}
&-vip {
display: flex;
align-items: center;
color: v-bind('priceColor');
.price {
font-size: 34rpx;
}
.icon {
font-size: 24rpx;
}
.tag {
margin-left: 10rpx;
font-size: 20rpx;
color: #fbe6c3;
background: #353648;
border-radius: 20rpx 0 0 0;
padding: 2rpx 10rpx;
}
}
&-price {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 24rpx;
&-left {
.old {
margin-left: 8rpx;
font-size: 20rpx;
color: #999999;
text-decoration: line-through;
}
}
&-right {
background-color: v-bind('Color');
border-radius: 2px;
color: #fff;
font-size: 19px;
height: 17px;
line-height: 15px;
text-align: center;
width: 17px;
}
}
}
}
.goods:not(:first-child) {
border-top: 1px solid #f2f2f2;
}
.bottom {
text-align: center;
font-size: 24rpx;
color: #999999;
margin: auto;
line-height: 80rpx;
}
}
}
}
.sort_box {
display: flex;
background-color: #fff;
height: 90rpx;
align-items: center;
justify-content: space-around;
border-bottom: 1px solid #eee;
box-sizing: border-box;
width: 100%;
.sort_item {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
color: #666;
font-size: 28rpx;
.icon {
display: flex;
flex-direction: column;
margin-left: 10rpx;
.iconfont {
font-size: 24rpx;
line-height: 16rpx;
}
}
}
.choose {
color: v-bind('Color');
font-weight: bold;
}
}
.goodbox{
height: calc(100% - 90rpx);
box-sizing: border-box;
&.padtop{
height: 100%;
}
}
.move_img {
display: inline-block;
font-size: 22rpx;
color: #fff;
margin: 8rpx 10px 10rpx 0;
background-image: url('@/static/image/move_img.png');
background-repeat: no-repeat;
padding: 0px 3px 0px 12px;
height: 40rpx;
background-size: 100% 100%;
line-height: 40rpx;
}
</style>

View File

@ -0,0 +1,243 @@
<template>
<view class="customBox">
<scroll-view scroll-y="true" class="contentBox" @scrolltolower="scorllBottom" :scroll-top="topNum">
<view class="goodbox">
<view class="item" @click="toGroups(item.id)" v-for="(item, index) in goodsList" :key="item.id">
<div class="imgbox">
<image :src="item.face_img + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill" class="img"></image>
<view class="out" v-if="item.sold_status === 2">
<img src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2024/01/16/Cr6cRRhhqYNhScigxIyumyV9hXXMI3vKvsE1jgt0.png" class="out_img" />
</view>
<view class="out" v-else-if="item.sold_status === 0">
<img src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2024/08/21/QBhUheeYWSJ3OGM27fkAufJAlFSA8GBhWjpY5oNy.png" class="out_img" />
</view>
<view class="out" v-else-if="item.total_stock === 0">
<img src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2024/08/21/pMTv6QiZZEpSqkJmk7hMcbEzIuNzMyp7YVBbe42H.png" class="out_img" />
</view>
</div>
<view class="box">
<view class="tit">{{item.title}}</view>
<view class="bot">
<view class="text">
<text class="prefix"></text>
<text class="txt1" v-if="parseFloat(item.min_price) == parseFloat(item.max_price)">{{item.min_price}}</text>
<text class="txt1" v-else>{{item.min_price * 1}}~{{item.max_price}}</text>
</view>
<view class="icon"><up-icon name="shopping-cart" :color="Color" size="22" /></view>
</view>
</view>
</view>
</view>
<view class="bottom" v-if="goodsList.length && page >= last_page && !loading1">
没有更多了
</view>
<view v-if="!goodsList.length && !loading1" class="empty">暂无数据</view>
</scroll-view>
<!-- 返回顶部 -->
<view @click="handleTop" v-if="showTop" class="top">
<up-icon name="arrow-upward" color="#000" size="24" />
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, onMounted } from 'vue'
import { get, post } from '@/Api/request.js'
import { Style } from '@/utils/list.js'
export default {
options: {
styleIsolation: 'shared'
},
props: {
},
setup(props, context) {
const data = reactive({
topNum: 0,
showTop: false,
goodsList: [],
page: 1,
last_page: 0,
shareUrl: '',
loading1: false,
Color: uni.getStorageSync('theme_color'),
priceColor: Style[uni.getStorageSync('theme_index') * 1].priceColor,
imgHeight: 0
})
async function getFetchList(val = 1) {
data.loading1 = true
uni.showLoading({
title: '加载中...',
mask: true
})
let params = {
page: data.page,
pageSize: 20
}
await get('/api/app/groupGoods/all', params).then((res) => {
data.goodsList = val == 1 ? data.goodsList.concat(res.data) : res.data
data.last_page = res.meta.last_page
data.loading1 = false
uni.hideLoading()
}).catch(() => {
data.loading1 = false
})
}
function scorllBottom() {
if (data.page < data.last_page) {
data.page ++
getFetchList()
}
}
const toGroups = (id) => {
uni.navigateTo({
url: '/pages/groups/index?id=' + id
})
}
const handleTop = () => {
data.topNum = data.topNum == 0 ? 0.1 : 0
}
onMounted(() => {
data.Color = uni.getStorageSync('theme_color')
getFetchList(0)
})
return {
...toRefs(data),
getFetchList,
scorllBottom,
handleTop,
toGroups
}
},
onPageScroll(e) {
if (e.scrollTop > 300) {
this.showTop = true
} else {
this.showTop = false
}
},
}
</script>
<style lang="scss" scoped>
.customBox{
padding: 0 0 1rpx;
height: calc(100vh - 242rpx);
box-sizing: border-box;
.contentBox{
height: 100%;
overflow-y: auto;
position: relative;
}
.goodbox{
padding: 24rpx 24rpx 1rpx;
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
.item{
background: #fff;
padding: 24rpx;
box-sizing: border-box;
border-radius: 10rpx;
width: calc(50% - 14rpx);
margin: 0 24rpx 24rpx 0;
&:nth-child(2n+2){
margin: 0 0 24rpx 0;
}
.imgbox{
position: relative;
.out{
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
.out_img{
width: 150rpx;
height: 150rpx;
}
}
}
.img{
border-radius: 10rpx;
width: 100%;
height: 292rpx;
}
.box{
display: flex;
flex-direction: column;
color: #333;
justify-content: space-between;
width: 100%;
height: auto;
.tit{
font-size: 28rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
line-height: 40rpx;
height: 80rpx;
margin: 10rpx 0;
}
.txt1{
font-size: 28rpx;
}
.bot{
display: flex;
align-items: center;
justify-content: space-between;
}
.text{
color: v-bind('priceColor');
.prefix{
font-size: 24rpx;
}
text{
font-size: 30rpx;
}
}
}
}
}
.empty{
font-size: 24rpx;
text-align: center;
padding: 60rpx 0;
}
.bottom {
text-align: center;
font-size: 24rpx;
color: #999;
margin: auto;
padding: 0 0 60rpx;
width: 100%;
}
.top {
position: fixed;
bottom: 15%;
right: 5%;
background: #fff;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
z-index: 2;
}
}
</style>

View File

@ -0,0 +1,480 @@
<template>
<view class="customBox" :style="{background: pageInfo.background_color || '#F5F5F5'}">
<scroll-view scroll-y="true" class="contentBox" @scrolltolower="scorllBottom" :scroll-top="topNum" @scroll="scrollView">
<!-- 头图 -->
<view class="bg" v-if="pageInfo.image">
<image :src="pageInfo.image + '?x-oss-process=image/format,webp'" :webp="true" mode="widthFix" class="image" @load="loadPageImage"></image>
</view>
<!-- 分类 -->
<view :style="{background: pageInfo.nav_bg_color || '#f3f3f3'}" class="tabsBox" :class="isFixed ? 'fixed' : ''" v-if="typeList.length">
<up-tabs
:list="typeList"
:lineColor="pageInfo.nav_text_color"
:inactiveStyle="{ color: pageInfo.nav_text_color }"
:activeStyle="{ color: pageInfo.nav_text_color }"
@click="changeTabs">
</up-tabs>
</view>
<!-- 排序 -->
<view class="sort_box">
<view class="sort_item" v-for="(item, index) in sortList" :key="index" @click.stop="chooseSort(index)">
<text :class="sortIndex === index ? 'choose' : ''">{{item}}</text>
<view class="icon" v-if="index === 2">
<up-icon name="arrow-up" size="10" :color="priceType && sortIndex === 2 ? Color : ''" />
<up-icon name="arrow-down" size="10" :color="!priceType && sortIndex === 2 ? Color : ''" />
</view>
</view>
</view>
<view class="wholeBox">
<view class="goodbox" :class="pageInfo.show_type === 2 ? 'two' : pageInfo.show_type === 3 ? 'three' : ''">
<view class="item" @click="toGroups(item.id)" v-for="(item, index) in goodsList" :key="item.id">
<div class="imgbox">
<image :src="item.face_img + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill" class="img"></image>
<view class="out" v-if="item.sold_status === 2">
<img src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2024/01/16/Cr6cRRhhqYNhScigxIyumyV9hXXMI3vKvsE1jgt0.png" class="out_img" />
</view>
<view class="out" v-else-if="item.sold_status === 0">
<img src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2024/08/21/QBhUheeYWSJ3OGM27fkAufJAlFSA8GBhWjpY5oNy.png" class="out_img" />
</view>
<view class="out" v-else-if="item.total_stock === 0">
<img src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2024/08/21/pMTv6QiZZEpSqkJmk7hMcbEzIuNzMyp7YVBbe42H.png" class="out_img" />
</view>
</div>
<view class="box">
<view class="tit">{{item.title}}</view>
<view class="bot">
<view class="text">
<text class="prefix"></text>
<text class="txt1" v-if="parseFloat(item.min_price) == parseFloat(item.max_price)">{{item.min_price}}</text>
<text class="txt1" v-else>{{item.min_price * 1}}~{{item.max_price}}</text>
</view>
<view class="icon"><up-icon name="shopping-cart" :color="Color" size="22" /></view>
</view>
</view>
</view>
</view>
</view>
<view class="bottom" v-if="goodsList.length && page >= last_page && !loading1" :style="{color: modifyTextColor(pageInfo.background_color)}">
没有更多了
</view>
<view v-if="!goodsList.length && !loading1" class="empty" :style="{color: modifyTextColor(pageInfo.background_color)}">暂无数据</view>
</scroll-view>
<!-- 返回顶部 -->
<view @click="hanletop" v-if="showTop" class="top">
<up-icon name="arrow-upward" color="#000" size="24" />
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, onMounted, watch } from 'vue'
import { modifyTextColor } from '@/utils/index.js'
import { Style } from '@/utils/list.js'
import { get, post } from '@/Api/request.js'
export default {
options: {
styleIsolation: 'shared'
},
props: {
groupId: {
type: Number,
default: 0
}
},
setup(props, context) {
const data = reactive({
topNum: 0,
isFixed: false,
showTop: false,
goodsList: [],
loading: false,
pageInfo: {
image: ''
},
page: 1,
last_page: 0,
shareUrl: '',
typeId: 0,
typeList: [],
sortList: ['综合', '销量', '价格', '上新'],
sortIndex: 0,
priceType: false,
sortFilter: {
sales: '',
price: '',
score: 2,
new: ''
},
loading1: false,
Color: uni.getStorageSync('theme_color'),
imgHeight: 0,
priceColor: Style[uni.getStorageSync('theme_index') * 1].priceColor
})
async function getPageInfo() {
data.id && await get('/api/v1/showcase/type/category/' + data.id).then((res) => {
data.pageInfo = res
context.emit('handleShareInfo', res.share_image + '&&' + res.share_title)
if(res.recommend_shop_group.length) {
data.typeId = res.recommend_shop_group[0]
data.typeList.push({id: data.typeId, name: '推荐'})
getFetchList()
getCategoryList(res.recommend_shop_group[0])
}
data.loading = true
})
}
async function getCategoryList(id) {
await get('/api/app/group', { parent_id: id }).then((res) => {
data.typeList = data.typeList.concat(res.data)
})
}
async function getFetchList() {
data.loading1 = true
uni.showLoading({
title: '加载中...',
mask: true
})
let params = {
page: data.page,
pageSize: 24,
sales: data.sortFilter.sales,
price: data.sortFilter.price,
score: data.sortFilter.score,
new: data.sortFilter.new,
keyword: '',
shop_group_id: data.typeId
}
await get('/api/app/search', params).then((res) => {
data.goodsList = data.goodsList.concat(res.data)
data.last_page = res.meta.last_page
data.loading1 = false
uni.hideLoading()
}).catch(() => {
data.loading1 = false
})
}
//
function chooseSort(index) {
data.sortIndex = index
if (index === 2) {
data.priceType = !data.priceType
data.sortFilter.price = data.priceType ? 1 : 2
data.sortFilter.new = ''
} else {
data.sortFilter.price = ''
}
data.sortFilter.sales = index === 1 ? 2 : ''
data.sortFilter.score = index === 0 ? 2 : ''
data.sortFilter.new = index === 3 ? 2 : ''
data.page = 1
data.goodsList = []
getFetchList()
}
const changeTabs = (event) => {
if (event.id == data.typeId) {
return
}
data.typeId = event.id
data.page = 1
data.goodsList = []
getFetchList()
}
function scorllBottom() {
if (data.page < data.last_page) {
data.page ++
getFetchList()
}
}
function scrollView(e) {
data.isFixed = e.detail.scrollTop > data.imgHeight
}
function loadPageImage(e) {
uni.getSystemInfo({
success: (res) => {
data.imgHeight = res.windowWidth * e.detail.height / e.detail.width
}
})
}
const toGroups = (id) => {
uni.navigateTo({
url: '/pages/groups/index?id=' + id + '&source_id=' + data.id + '&source_type=exclusive'
})
}
const hanletop = () => {
data.topNum = data.topNum == 0 ? 0.1 : 0
}
watch(props, (newProps) => {
if(newProps.groupId) {
data.id = newProps.groupId
data.goodsList = []
data.typeList = []
getPageInfo()
}
})
onMounted(() => {
data.Color = uni.getStorageSync('theme_color')
data.id = props.groupId
getPageInfo()
})
return {
modifyTextColor,
...toRefs(data),
getPageInfo,
getFetchList,
chooseSort,
changeTabs,
scorllBottom,
hanletop,
toGroups,
scrollView,
loadPageImage
}
},
onPageScroll(e) {
if (e.scrollTop > 300) {
this.showTop = true
} else {
this.showTop = false
}
},
}
</script>
<style lang="scss" scoped>
.customBox{
padding: 0 0 1rpx;
height: calc(100vh - 242rpx);
box-sizing: border-box;
.contentBox{
height: 100%;
overflow-y: auto;
position: relative;
}
.bg{
width: 100%;
box-sizing: border-box;
.image{
width: 100%;
vertical-align: bottom;
}
}
.tabsBox{
width: 100%;
&.fixed{
position: fixed;
top: 132rpx;
z-index: 100;
}
}
.sort_box {
display: flex;
background-color: #fff;
height: 90rpx;
align-items: center;
justify-content: space-around;
.sort_item {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
color: #666;
font-size: 28rpx;
.icon {
display: flex;
flex-direction: column;
margin-left: 10rpx;
.iconfont {
font-size: 24rpx;
line-height: 16rpx;
}
}
}
.choose {
color: v-bind('Color');
font-weight: bold;
}
}
.goodbox{
padding: 24rpx 24rpx 1rpx;
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
.item{
margin: 0 0 24rpx 0;
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
padding: 24rpx;
box-sizing: border-box;
border-radius: 10rpx;
width: 100%;
.imgbox{
position: relative;
.out{
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
.out_img{
width: 100rpx;
height: 100rpx;
}
}
}
.img{
width: 200rpx;
height: 200rpx;
border-radius: 10rpx;
}
.box{
display: flex;
height: 200rpx;
width: calc(100% - 220rpx);
flex-direction: column;
color: #333;
justify-content: space-between;
.tit{
font-size: 28rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
line-height: 40rpx;
}
.bot{
display: flex;
align-items: center;
justify-content: space-between;
}
.text{
color: v-bind('priceColor');
.prefix{
font-size: 24rpx;
}
text{
font-size: 34rpx;
}
}
}
}
&.two{
.item{
width: calc(50% - 14rpx);
margin: 0 24rpx 24rpx 0;
display: block;
&:nth-child(2n+2){
margin: 0 0 24rpx 0;
}
.img{
width: 100%;
height: 292rpx;
}
.box{
width: 100%;
height: auto;
.tit{
height: 80rpx;
margin: 10rpx 0;
}
.txt1{
font-size: 28rpx;
}
}
.imgbox{
.out{
.out_img{
width: 150rpx;
height: 150rpx;
}
}
}
}
}
&.three{
.item{
width: calc(33.3% - 18rpx);
margin: 0 24rpx 24rpx 0;
display: block;
padding: 18rpx;
&:nth-child(3n+3){
margin: 0 0 24rpx 0;
}
.img{
width: 100%;
height: 184rpx;
}
.box{
width: 100%;
height: auto;
.text{
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.tit{
height: 80rpx;
margin: 10rpx 0;
font-size: 24rpx;
}
.txt1{
font-size: 26rpx;
}
.icon{
display: none;
}
}
}
}
}
.empty{
font-size: 24rpx;
text-align: center;
padding: 60rpx 0;
}
.bottom {
text-align: center;
font-size: 24rpx;
color: #fff;
margin: auto;
padding: 0 0 60rpx;
width: 100%;
}
.top {
position: fixed;
bottom: 15%;
right: 5%;
background: #fff;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
z-index: 2;
}
}
</style>

View File

@ -0,0 +1,380 @@
<template>
<view style="background: #f5f5f5; padding-bottom: 1rpx;">
<view class="home-top">
<swiper v-if="images.length !== 0" class="home-top-swiper" :autoplay="true" :interval="5000" :duration="500" :indicator-dots="true" :circular="true">
<swiper-item v-for="(item,index) in images" :key="index">
<image class="item_img" :src="item.pic_url + '?x-oss-process=image/format,webp'" :webp="true" @click="onSwiperItem(item.link)"></image>
</swiper-item>
</swiper>
</view>
<view class="Minute">
<view class="box" @click="hanlejump('/pages/sale/index')">
<view class="h3">超级爆品&nbsp;<view class="small">GO <up-icon name="arrow-right" size="10" /></view></view>
<view style="display: flex;">
<template v-for="(item, index) in hot" :key="index">
<view v-if="index < 2">
<view class="red">{{item.title}}</view>
<view><image :src="item.face_img + '?x-oss-process=image/format,webp'" :webp="true" class="imgs" mode="aspectFill"></image></view>
</view>
</template>
</view>
</view>
<view class="box" @click="hanlejump('/pages/sale/list?type=1')">
<view class="h3">TOP榜单&nbsp;<view class="small1">GO <up-icon name="arrow-right" size="10" /></view></view>
<view style="display: flex;">
<template v-for="(item, index) in top" :key="index">
<view v-if="index < 2">
<view class="bule">{{item.title}}</view>
<view><image :src="item.face_img + '?x-oss-process=image/format,webp'" :webp="true" class="imgs" mode="aspectFill"></image></view>
</view>
</template>
</view>
</view>
</view>
<template v-for="(list, index) in merchant" :key="list.id">
<view v-if="list.shop_goods.length !== 0" class="shop">
<view v-if="list.sold_status != 2">
<view class="banner" @click="jumpHall(list.id)">
<image :src="list.ad_image + '?x-oss-process=image/format,webp'" :webp="true" mode="widthFix" class="img"></image>
</view>
<view class="title">
<view class="activeTitle">
<view class="name">{{list.name}}</view>
<view class="toActive" @click="jumpHall(list.id)">进入会场</view>
</view>
<view class="activeTitle" style="margin-top: 10rpx;height: 44rpx;">
<view>
<view class="move" v-if="list.actives && list.actives.length > 0">
{{list.actives && list.actives.length > 0 ? list.actives[0].name : ''}}
</view>
<view class="move">7天无理由</view>
</view>
<view class="endtime" v-if="list.sold_status == 1 && list.sold_off_time" v-html="DownTime(list.sold_off_time, 1)"></view>
<view class="endtime" v-if="list.sold_status == 0" v-html="UpTime(list.sold_start_time, 1)"></view>
</view>
<view class="goodscommodity">
<view class="goodsgun" v-for="(it, index) in list.shop_goods" :key="index" @click="toDetail(it.id)">
<image :src="it.face_img + '?x-oss-process=image/resize,m_fill,w_300,h_300'" :webp="true" class="img" mode="aspectFill"></image>
<view class="price_list">
<text class="icon"></text>
<text v-if="it.price > 0">{{it.price}}</text>
<block v-else>
<text v-if="it.max_price == it.min_price">{{it.min_price}}</text>
<text v-else>{{it.min_price * 1}}~{{it.max_price}}</text>
</block>
</view>
</view>
<view v-if="list.shop_goods.length" @click="jumpHall(list.id)" class="viewmore">
<text>查看更多</text>
<view class="line"></view>
</view>
</view>
</view>
</view>
</view>
</template>
</view>
</template>
<script>
import { ref, reactive, toRefs, onMounted } from 'vue'
import { get, post } from '@/Api/request.js'
import { UpTime, DownTime } from '@/components/common.js'
export default {
props: {
},
setup() {
const data = reactive({
images: [],
hot: [],
top: [],
merchant: [],
total: 0,
page: 1,
endTime: '',
Color: ''
})
//
const hanlejump = (url) => {
uni.navigateTo({
url
})
}
//
const getbanner = async () => {
let res = await get('/api/v1/special/banner')
data.images = res.data
}
//
const gethot = async () => {
let res = await get('/api/v1/special/goods/hot')
data.hot = res.data
}
//top
const gettop = async () => {
let res = await get('/api/v1/special/goods/top')
data.top = res.data
}
//
const getmerchant = async () => {
uni.showLoading({
title: '加载中...'
})
let res = await get('/api/v1/special/merchant', {
page: data.page,
limit: 5
})
data.merchant = data.merchant.concat(res.data)
data.total = res.meta.last_page
uni.hideLoading()
}
//
function onSwiperItem(url) {
if (url) {
if(url.indexOf('type=category') !== -1) {
uni.navigateTo({ url: '/pages/lotRecom/index?' + url.split('?')[1] })
} else if(url.indexOf('type=shop_group') !== -1) {
uni.navigateTo({ url: '/pages/subset/index?' + url.split('?')[1] })
} else {
uni.navigateTo({ url: url })
}
}
}
const toDetail = (id) => {
uni.navigateTo({
url: '/pages/productDetails/index?id=' + id
})
}
const jumpHall = (id) => {
uni.navigateTo({
url: '/pages/smallshop/index?id=' + id
})
}
onMounted(() => {
data.Color = uni.getStorageSync('theme_color')
getbanner()
gethot()
gettop()
getmerchant()
})
return {
...toRefs(data),
hanlejump,
onSwiperItem,
toDetail,
jumpHall,
getmerchant,
DownTime,
UpTime
}
},
onReachBottom() {
if (this.page < this.total) {
this.page++
this.getmerchant()
}
}
}
</script>
<style lang="scss" scoped>
.activeTitle {
display: flex;
justify-content: space-between;
.toActive {
background-color: v-bind('Color');
border-radius: 44rpx;
color: #fff;
padding: 4rpx 22rpx;
font-size: 28rpx;
height: 38rpx;
line-height: 38rpx;
}
.move {
display: inline-block;
border: 1px solid v-bind('Color');
color:v-bind('Color');
padding: 6rpx 10rpx;
font-size: 24rpx;
border-radius: 6rpx;
line-height: 1;
margin-left: 8rpx;
}
.endtime {
font-size: 24rpx;
color: #999999;
line-height: 44rpx;
b{
color: #2c2c2c;
}
}
}
.market_price {
display: block;
color: #676767;
text-decoration: line-through;
font-size: 25rpx;
}
.go1 {
margin-top: 108rpx;
}
.go {
margin-top: 133rpx;
}
.shop {
background: #fff;
border-radius: 10rpx;
margin: 24rpx 20rpx;
.banner {
width: 100%;
.img {
width: 100%;
height: 100%;
border-top-left-radius: 10rpx;
border-top-right-radius: 10rpx;
}
}
.title {
padding: 25rpx 13rpx;
.name {
font-weight: bolder;
font-size: 30rpx;
margin-left: 15rpx;
}
.goodscommodity {
display: flex;
margin-top: 25rpx;
overflow: auto;
.goodsgun {
padding: 0 10rpx;
box-sizing: border-box;
overflow: hidden;
flex-shrink: 0;
width: 36%;
.img {
width: 214rpx;
height: 214rpx;
border-radius: 6rpx;
}
.title_list {
font-size: 26rpx;
color: #2c2c2c;
margin: 10rpx 0;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.price_list {
font-size: 26rpx;
margin-top: 16rpx;
.icon {
font-size: 24rpx;
}
}
}
.viewmore{
width: 214rpx;
height: 214rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6rpx;
font-size: 28rpx;
flex-direction: column;
background-color: #F5F5F5;
.line{
width: 70%;
height: 2px;
background-color: #333;
margin-top: 30rpx;
}
}
}
}
}
.home-top-swiper {
width: 100%;
height: 500rpx;
.item_img {
width: 100%;
height: 100%;
}
}
.Minute {
display: flex;
border-radius: 20rpx;
align-items: center;
justify-content: center;
background: #fff;
margin: 24rpx 20rpx;
padding: 26rpx 26rpx;
box-sizing: border-box;
.box {
width: 50%;
.h3 {
font-weight: bolder;
font-size: 30rpx;
display: flex;
align-items: center;
}
.small {
background: #F14939;
color: #fff;
font-size: 24rpx;
font-weight: normal;
border-radius: 15rpx;
display: inline-flex;
width: 60rpx;
height: 30rpx;
align-items: center;
justify-content: space-between;
padding: 0 10rpx;
}
.red {
color: #F14939;
font-size: 26rpx;
margin: 20rpx 0;
width: 166rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bule {
color: #6bb3f2;
font-size: 26rpx;
margin: 20rpx 0;
width: 166rpx;
overflow: hidden; /*内容超出后隐藏*/
text-overflow: ellipsis; /* 超出内容显示为省略号 */
white-space: nowrap; /* 文本不进行换行 */
}
.small1 {
background: #6bb3f2;
color: #fff;
font-size: 24rpx;
font-weight: normal;
border-radius: 15rpx;
display: inline-flex;
width: 60rpx;
height: 30rpx;
align-items: center;
justify-content: space-between;
padding: 0 10rpx;
}
.imgs {
width: 140rpx;
height: 140rpx;
}
}
}
</style>

View File

@ -0,0 +1,230 @@
<template>
<view class="customBox">
<scroll-view scroll-y="true" class="contentBox" @scrolltolower="scorllBottom" :scroll-top="topNum">
<view class="content">
<view class="left">
<template v-for="(item, index) in list" :key="item.id">
<view class="row" @click="toPage(item.id)" v-if="index % 2 == 0">
<view class="img">
<image :src="item.explain_video + '?x-oss-process=video/snapshot,t_1000,m_fast'" mode="widthFix"></image>
<view class="icon"><up-icon name="play-right-fill" size="14" color="#fff" /></view>
</view>
<view class="desc">{{item.description}}</view>
<view class="num">{{item.visitor}}人看过 | {{item.order_count}}人跟团</view>
</view>
</template>
</view>
<view class="left">
<template v-for="(item, index) in list" :key="item.id">
<view class="row" @click="toPage(item.id)" v-if="index % 2 == 1">
<view class="img">
<image :src="item.explain_video + '?x-oss-process=video/snapshot,t_1000,m_fast'" mode="widthFix"></image>
<view class="icon"><up-icon name="play-right-fill" size="14" color="#fff" /></view>
</view>
<view class="desc">{{item.description}}</view>
<view class="num">{{item.visitor}}人看过 | {{item.order_count}}人跟团</view>
</view>
</template>
</view>
</view>
<view class="noMore" v-if="list.length && !has_more && !loading"> 没有更多了 </view>
<view v-if="!list.length && !loading">
<up-empty mode="list" icon="https://ct-upimg.yx090.com/g.ii090/images/sprite/empty/list.png" text="暂无数据"></up-empty>
</view>
<view v-if="loading" class="loadbox">
<up-loading-icon text="加载中..." textSize="14"></up-loading-icon>
</view>
</scroll-view>
<!-- 返回顶部 -->
<view @click="handleTop" v-if="showTop" class="top">
<up-icon name="arrow-upward" color="#000" size="24" />
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, onMounted } from 'vue'
import { get } from '@/Api/request.js'
export default {
options: {
styleIsolation: 'shared'
},
props: {
},
setup(props, context) {
const data = reactive({
topNum: 0,
showTop: false,
last_id: 0,
loading: true,
has_more: true,
list: []
})
async function getFetchList() {
data.loading = true
uni.showLoading({
title: '加载中...',
mask: true
})
let params = {
last_id: data.last_id,
pageSize: 20
}
await get('/api/app/goods/videos', params).then((res) => {
data.list = data.list.concat(res.data)
data.last_id = res.last_id
data.has_more = res.has_more
data.loading = false
uni.hideLoading()
}).catch(() => {
data.loading = false
})
}
function scorllBottom() {
if (data.has_more && !data.loading) {
getFetchList()
}
}
function toPage(id) {
uni.navigateTo({
url: '/pages/groups/video?id=' + id
})
}
const handleTop = () => {
data.topNum = data.topNum == 0 ? 0.1 : 0
}
onMounted(() => {
getFetchList()
})
return {
...toRefs(data),
getFetchList,
scorllBottom,
handleTop,
toPage
}
},
onPageScroll(e) {
if (e.scrollTop > 300) {
this.showTop = true
} else {
this.showTop = false
}
},
}
</script>
<style lang="scss" scoped>
.customBox{
padding: 0 0 1rpx;
height: calc(100vh - 242rpx);
box-sizing: border-box;
.contentBox{
height: 100%;
overflow-y: auto;
position: relative;
}
.content{
padding: 24rpx 1.5%;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
.left{
width: 50%;
padding: 0 1.5%;
box-sizing: border-box;
}
.row{
background-color: #fff;
border-radius: 10rpx;
width: 100%;
margin-bottom: 24rpx;
overflow: hidden;
.img{
width: 100%;
position: relative;
image{
width: 100%;
height: auto;
}
.icon{
position: absolute;
top: 20rpx;
right: 20rpx;
background-color: rgba(0,0,0,0.5);
border-radius: 50%;
width: 26px;
height: 26px;
display: flex;
align-items: center;
justify-content: center;
}
}
.desc{
font-size: 28rpx;
overflow: hidden !important;
text-overflow: ellipsis !important;
display: -webkit-box !important;
-webkit-line-clamp: 2 !important;
-webkit-box-orient: vertical !important;
white-space: break-spaces !important;
padding: 0 20rpx;
margin: 10rpx 0;
}
.num{
font-size: 24rpx;
padding: 10rpx 20rpx 20rpx;
color: #999;
}
}
}
.noMore{
text-align: center;
font-size: 24rpx;
color: #999;
margin: auto;
padding: 0 0 60rpx;
width: 100%;
}
.noMsg{
width: 100%;
height: 100vh;
display: flex;
align-items: center;
flex-direction: column;
padding-top: 20%;
box-sizing: border-box;
font-size: 26rpx;
color: #9D9D9D;
}
.loadbox{
padding: 30rpx 0;
text-align: center;
color: #666;
}
.top {
position: fixed;
bottom: 15%;
right: 5%;
background: #fff;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
z-index: 2;
}
}
</style>

4
components/img.js Normal file
View File

@ -0,0 +1,4 @@
// 雪碧图
export const sp2 = 'https://ct-upimg.yx090.com/g.ii090/images/sprite/11791720144991.jpg'
export const provTxt = { 110000:'北京',120000:'天津',130000:'河北',140000:'山西',150000:'内蒙古',210000:'辽宁',220000:'吉林',230000:'黑龙江',310000:'上海',320000:'江苏',330000:'浙江',340000:'安徽',350000:'福建',360000:'江西',370000:'山东',410000:'河南',420000:'湖北',430000:'湖南',440000:'广东',450000:'广西',460000:'海南',500000:'重庆',510000:'四川',520000:'贵州',530000:'云南',540000:'西藏',610000:'陕西',620000:'甘肃',630000:'青海',640000:'宁夏',650000:'新疆',710000:'台湾',810000:'香港',820000:'澳门'}

249
components/ktt/comment.vue Normal file
View File

@ -0,0 +1,249 @@
<template>
<view class="dialogBox" v-if="show">
<view class="dialog" @click="close()"></view>
<view class="block">
<view class="title">
<text>本团评价</text>
<view class="close" @click="close()"><up-icon name="close" color="#666" /></view>
</view>
<scroll-view scroll-y="true" class="contentBox" @scrolltolower="scorllBottom">
<view class="item" v-for="item in list" :key="item.id">
<view class="user" v-if="item.user">
<image :src="item.user.avatar"></image>
<view class="box">
<view class="name">{{item.user.nickname}}</view>
<view class="time">{{item.date}}</view>
</view>
</view>
<view v-if="item.item && item.item.sku_name" class="sku_name">规格{{item.item.sku_name}}</view>
<text class="comment">{{item.comment}}</text>
<view class="box_zong" v-if="item.material.length">
<view class="box_imgs" v-for="(it, index) in item.material" :key="index">
<image :src="it.url" v-if="it.type === 1" @click="viewImg(it, item.material)" mode="aspectFill"></image>
</view>
</view>
</view>
<view class="noMore" v-if="list.length && page >= lastPage && !loading"> 没有更多了 </view>
<view class="empty" v-if="!list.length && !loading">
<up-empty mode="comment" icon="https://ct-upimg.yx090.com/g.ii090/images/sprite/empty/comment.png" text="暂无评价喔"></up-empty>
</view>
<view v-if="loading" class="loadbox">
<up-loading-icon text="加载中..." textSize="14"></up-loading-icon>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { get } from '@/Api/request.js'
import { showToast } from '../common.js'
export default {
props: {
show: {
type: Boolean,
default: true
},
id: {
type: Number,
default: 0
}
},
setup(props, context) {
const data = reactive({
id: 0,
show: false,
list: [],
loading: false,
page: 1,
lastPage: 0
})
function getInfo(val) {
data.loading = true
get(`/api/v1/goods/comment/${data.id}`, {
page: data.page,
pageSize: 20,
type: 1
}).then((res) => {
data.list = val == 1 ? data.list.concat(res.data) : res.data
data.lastPage = res.meta.last_page
data.loading = false
}).catch(() => {
data.loading = false
})
}
function scorllBottom() {
if (data.page < data.lastPage) {
data.page ++
getInfo(1)
}
}
const viewImg = (it, imgs) => {
var img = []
imgs.forEach((res) => {
if (res.type == 1) {
img.push(res.url)
}
})
uni.previewImage({
current: it.url,
urls: img
})
}
function close() {
context.emit('close')
}
watch(props, async (newProps) => {
if (newProps.show) {
data.show = true
data.id = newProps.id * 1
data.page = 1
data.list = []
getInfo(0)
} else {
data.show = false
}
})
return {
...toRefs(data),
getInfo,
close,
scorllBottom,
viewImg
}
}
}
</script>
<style lang="scss" scoped>
.dialogBox{
width: 100%;
height: 100vh;
position: fixed;
left: 0;
top: 0;
z-index: 200;
overflow: hidden;
.dialog{
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.block{
width: 100%;
position: absolute;
left: 0;
bottom: 0;
background: #fff;
height: 78vh;
border-radius: 20rpx 20rpx 0 0;
.title{
color: #333;
font-size: 30rpx;
height: 100rpx;
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
.close{
padding: 10rpx;
}
}
.contentBox{
height: calc(100% - 100rpx);
overflow-y: auto;
.item{
padding: 24rpx;
box-sizing: border-box;
border-bottom: 1px solid #f1f1f1;
.user{
display: flex;
justify-content: space-between;
align-items: center;
image{
width: 60rpx;
height: 60rpx;
border-radius: 6rpx;
}
.box{
width: calc(100% - 80rpx);
.name{
font-size: 28rpx;
color: #333;
font-weight: bold;
margin-right: 10rpx;
}
.time{
font-size: 24rpx;
color: #999;
}
}
}
.sku_name{
color: #999;
margin-top: 10rpx;
font-size: 24rpx;
}
.comment{
font-size: 28rpx;
line-height: 40rpx;
}
.box_zong{
margin-top: 20rpx;
display: flex;
flex-wrap: wrap;
.box_imgs{
margin-right: 20rpx;
&:nth-child(3n+3) {
margin-right: 0;
}
image{
width: 200rpx;
height: 200rpx;
margin-bottom: 20rpx;
}
}
}
}
}
}
}
.noMore{
text-align: center;
font-size: 24rpx;
color: #999;
margin: auto;
padding: 30rpx 0 60rpx;
width: 100%;
}
.empty{
width: 100%;
padding: 120rpx 0;
text-align: center;
.img{
width: 400rpx;
}
text{
display: block;
font-size: 24rpx;
color: #aaa;
margin-top: 20rpx;
}
}
.loadbox{
padding: 30rpx 0;
text-align: center;
color: #666;
}
</style>

View File

@ -0,0 +1,187 @@
<template>
<view class="jj-expandable-text">
<view class="text" :class="{'expandable': !collapse}" :style="{'--lineheight':lineHeight + 'rpx',
'line-height': lineHeight + 'rpx',
'max-height': collapse ? (lineHeight * line) + 'rpx' : '1000px'}">
<view class="btn" v-if="lines > line" @click="collapse = !collapse"
:class="{'clearboth': !collapse || line > 1}" :style="{'height': lineHeight + 'rpx'}">
<template v-if="useExpandSlot">
<slot v-if="collapse" name="expand-icon"></slot>
<slot v-else name="fold-icon"></slot>
</template>
<text v-else class="opt-hint">{{collapse ? expandText : foldText}}</text>
</view>
<text class="jj-content">
<slot>{{ longText ? longText : '' }}</slot>
</text>
</view>
</view>
</template>
<script>
export default {
name: 'ExpandableText',
props: {
//
line: {
type: [Number, String],
default: 1
},
// rpx
lineHeight: {
type: [Number],
default: 32
},
longText: {
type: [String],
default: ''
},
useExpandSlot: { //
type: Boolean,
default: false
},
//
expandText: {
type: String,
default: "展开"
},
//
foldText: {
type: String,
default: "收起"
},
collapsev: {
type: Boolean,
default: true
}
},
data() {
return {
isHide: true, //
// lineHeight: 33, // rpx
textHeight: 0, //
// placeholder: '', //
collapse: true, //
};
},
watch: {
longText() {
let that = this
that.collapse = true
setTimeout(() => {
let query = uni.createSelectorQuery().in(that);
// html
query.select('.jj-content').boundingClientRect(data => {
that.textHeight = data.height
}).exec();
console.log('文字改变')
}, 100)
}
},
mounted() {
let query = uni.createSelectorQuery().in(this);
setTimeout(() => {
// html
query.select('.jj-content').boundingClientRect(data => {
this.textHeight = data.height
}).exec();
console.log('collapse')
}, 200)
},
computed: {
//
lines() {
let ll = 0
if (this.textHeight > 0 && this.lineHeight > 0) {
const actual = uni.upx2px(this.lineHeight)
ll = Math.ceil(this.textHeight / actual)
}
return ll
}
}
}
</script>
<style scoped lang="less">
.clearboth {
clear: both;
}
.jj-expandable-text {
display: flex;
}
.jj-expandable-text .text {
position: relative;
line-height: 1.5;
max-height: 1.5em;
overflow: hidden;
// transition: .3s max-height;
}
.jj-expandable-text .text::before {
content: '';
float: right;
width: 0;
/*设置为0或者不设置宽度*/
height: calc(100% - var(--lineheight));
/*先随便设置一个高度*/
background: red;
}
.jj-expandable-text .text::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
background: #fff;
}
.jj-expandable-text .expandable {
max-height: 1000px;
/*超出最大行高度就可以了*/
}
.jj-expandable-text .expandable::after {
visibility: hidden;
}
.jj-expandable-text .btn {
float: right;
position: relative;
margin-left: 1em;
}
.jj-expandable-text .btn .opt-hint {
color: #999;
}
.jj-expandable-text .btn::before {
content: '...';
position: absolute;
letter-spacing: 2rpx;
left: -6rpx;
bottom: -2rpx;
color: inherit;
transform: translateX(-100%)
}
.jj-expandable-text .btn::after {
content: '.';
opacity: 0;
width: 0;
}
.jj-expandable-text .expandable .btn::after {
content: '.';
opacity: 0;
width: 0;
}
.jj-expandable-text .expandable .btn::before {
visibility: hidden;
/*在展开状态下隐藏省略号*/
}
// .jj-placeholder {
// visibility: hidden;
// }
</style>

1170
components/ktt/goods.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,396 @@
<template>
<view>
<up-popup :show="show" :round="10" mode="bottom" @close="handleClose" closeable catchtouchmove="preventD" :z-index="200">
<view class="skuBox">
<view class="oneBox">
<image :src="info.face_img" mode="aspectFill"></image>
<view class="box">
<view class="tit">{{info.title}}</view>
<view class="pricebox">
<view class="text1" v-if="vipOn && info.vip_price > 0 && (is_vip || (!is_vip && vip_price_show))">
<text class="icon1"></text>
<text>{{info.price}}</text>
</view>
<view>
<!-- 显示会员价 -->
<view v-if="vipOn && info.vip_price > 0 && (is_vip || (!is_vip && vip_price_show))" class="vip">
<view class="vip-tag"><text>会员价&nbsp;</text>{{info.vip_price}}</view>
</view>
<!-- 显示普通价格 -->
<view v-else class="vip">
<text class="icon1"></text>
<text>{{info.price}}</text>
</view>
</view>
</view>
<view class="text" v-if="show_stock === 1">剩余{{info.stock <= 0 ? 0 : info.stock}}</view>
</view>
</view>
<scroll-view class="scrollbox" scroll-y="true" enhanced="true">
<view class="twoBox">
<text>数量</text>
<view class="stepper">
<view class="minus flex" @click="minusNum()"><up-icon name="minus" size="12" :color="Color" /></view>
<view class="num">{{num}}</view>
<view class="plus flex" @click="plusNum()"><up-icon name="plus" size="12" color="#fff" /></view>
</view>
</view>
<view class="sku-buy" v-if="sales > 0">
<view class="img" v-for="img in info.avatars" :key="img">
<image :src="img"></image>
</view>
<view class="text">已有<text class="num">{{sales}}</text>个社群好友购买</view>
</view>
<view class="edition">
<view v-for="(item, index) in info.text_modules" :key="item.id">
<view v-if="item.type == 1" class="edition_box" @click="viewImg(item.imgs[0])">
<view v-for="(imgs, index) in item.imgs" :key="index">
<image :src="imgs" mode="widthFix" style="width: 100%;"></image>
</view>
</view>
<view class="edition_box" v-if="item.type == 2">
<view class="small_img">
<view v-for="(list, index) in item.img" :key="index" class="imgs" @click="viewImg(list)">
<image :src="list" mode="aspectFill"></image>
</view>
</view>
</view>
<!-- 文字 -->
<view class="edition_box text1_box" v-if="item.type == 4">
<text user-select="true" class="text">{{item.text}}</text>
</view>
</view>
<view class="imgbox">
<image v-for="(img, idx) in info.gallery" :key="idx" :src="img" class="img" mode="widthFix" @click="viewImg(img)"></image>
</view>
</view>
</scroll-view>
<view class="btn" :class="info.stock <= 0 || !canBuy ? 'dis' : ''" @click="(info.stock > 0 && canBuy) ? addCart():''">加入购物车</view>
</view>
</up-popup>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { get, post } from '@/Api/request.js'
import { showToast } from '../common.js'
export default {
props: {
show: {
type: Boolean,
default: true
},
id: {
type: Number,
default: 0
},
show_stock: {
type: Number,
default: 0
},
canBuy: {
type: Boolean,
default: true
},
shortStatus: {
type: Number,
default: 1
},
groupId: {
type: Number,
default: 0
},
sales: {
type: Number,
default: 0
}
},
setup(props, context) {
const data = reactive({
id: 0,
show: false,
info: {},
vipOn: uni.getStorageSync('vip_on') === 1,
is_vip: uni.getStorageSync('is_vip'),
vip_price_show: uni.getStorageSync('vip_price_show') || false,
Color: uni.getStorageSync('theme_color'),
show_stock: 0,
canBuy: true,
num: 1,
groupId: 0,
shortStatus: 1
})
function getSpecInfo(val) {
get(`/api/v1/goods/spec/${data.id}`).then((res) => {
data.info = res.data
data.info.avatars = res.data.avatars || []
data.info.text_modules = res.data.text_modules || []
data.info.gallery = res.data.gallery || []
//
data.num = 1
if(res.data.limit_type == 1) {
data.num = parseInt(res.data.start_sale_num)
}
if(data.shortStatus == 0) {
data.info.stock = 0
}
})
}
// -
function minusNum() {
// &&1
if((data.info.limit_type == 1 && data.num == parseInt(data.info.start_sale_num)) || data.num == 1) {
} else {
data.num -= 1
}
}
// -
function plusNum() {
// &&
if((data.info.limit_type == 2 && data.num == parseInt(data.info.limit)) || (data.num >= data.info.stock)) {
} else {
data.num += 1
}
}
const viewImg = (img) => {
uni.previewImage({
current: 0,
urls: [img]
})
}
function handleClose() {
context.emit('close')
}
const preventD = () => {
return
}
function addCart() {
let params = {
num: data.num,
shop_goods_id: data.id,
shop_goods_sku_id: 0,
shop_group_goods_id: data.groupId,
source_id: 0,
source_type: 'normal'
}
post('/api/v1/carts', params).then((res) => {
context.emit('refresh')
})
}
watch(props, async (newProps) => {
if (newProps.show) {
data.show = true
data.id = newProps.id
data.groupId = newProps.groupId
data.canBuy = newProps.canBuy
data.shortStatus = newProps.shortStatus
data.show_stock = newProps.show_stock
getSpecInfo()
} else {
data.show = false
}
})
return {
...toRefs(data),
getSpecInfo,
handleClose,
viewImg,
preventD,
minusNum,
plusNum,
addCart
}
}
}
</script>
<style lang="scss" scoped>
.skuBox{
background: #fff;
height: 78vh;
overflow: hidden;
.oneBox{
display: flex;
justify-content: space-between;
padding: 24rpx;
box-sizing: border-box;
image{
width: 200rpx;
height: 200rpx;
}
.box{
width: calc(100% - 220rpx);
.tit{
font-size: 30rpx;
}
.pricebox{
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 8rpx 0 20rpx;
.text1{
font-size: 34rpx;
color: #f66d2d;
font-weight: 600;
margin-right: 12rpx;
}
.icon1{
font-size: 24rpx;
}
.vip{
display: flex;
align-items: center;
font-size: 34rpx;
color: #f66d2d;
font-weight: bold;
}
}
.text{
font-size: 24rpx;
color: #999999;
}
.vip-tag {
font-size: 32rpx;
color: #fbe6c3;
background: #353648;
border-radius: 20rpx 0 0 0;
padding: 8rpx 10rpx;
line-height: 1;
text{
font-size: 22rpx;
}
}
}
}
.scrollbox{
width: 100%;
height: calc(78vh - 358rpx);
}
.twoBox{
font-size: 28rpx;
padding: 30rpx 24rpx;
box-sizing: border-box;
border-top: 1rpx solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
.stepper{
display: flex;
align-items: center;
.flex{
width: 40rpx;
height: 40rpx;
box-sizing: border-box;
border-radius: 4rpx;
display: flex;
align-items: center;
justify-content: center;
}
.num{
width: 80rpx;
font-size: 28rpx;
text-align: center;
}
.minus{
border: 1px solid v-bind('Color');
}
.plus{
background-color: v-bind('Color');
}
}
}
.sku-buy{
display: flex;
align-items: center;
padding: 30rpx;
border-top: 1rpx solid #eee;
border-bottom: 1rpx solid #eee;
.img{
width: 50rpx;
height: 50rpx;
margin-left: -10rpx;
border: 4rpx solid #fff;
box-sizing: border-box;
image{
width: 100%;
height: 100%;
border-radius: 10rpx;
}
}
.text {
margin-left: 20rpx;
font-size: 28rpx;
.num{
color: v-bind('Color');
}
}
}
.edition{
padding-bottom: 50rpx;
.edition_box{
margin: 8rpx 0;
position: relative;
padding: 0 20rpx;
.img{
width: 100%;
}
.small_img{
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.imgs{
width: calc(33% - 11rpx);
height: 220rpx;
margin: 16rpx 16rpx 0 0;
image{
width: 100%;
height: 100%;
object-fit: cover;
}
}
.imgs:nth-child(3n+3){
margin: 16rpx 0 0 0;
}
}
.text{
line-height: 55rpx;
font-size: 30rpx;
color: #222;
}
}
.imgbox{
padding: 20rpx 0;
.img{
width: 100%;
}
}
}
.btn{
height: 110rpx;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
background-color: v-bind('Color');
color: #fff;
font-size: 30rpx;
&.dis{
opacity: 0.65;
}
}
}
</style>

80
components/live/entry.vue Normal file
View File

@ -0,0 +1,80 @@
<template>
<view class="float" v-if="showDialog" @click="toPage">
<view class="icon"><text class="iconfont icon-zhibo"></text></view>
<view class="tit">直播间</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, onMounted, onActivated } from 'vue'
import { get, post } from '@/Api/request.js'
import { showToast } from '../common.js'
export default {
props: {
},
setup(props, context) {
const data = reactive({
Color: uni.getStorageSync('theme_color'),
showDialog: false,
liveId: 0
})
function toPage() {
uni.navigateTo({
url: `/pages/live/index?live_id=${data.liveId}`
})
}
function isShowLive() {
data.liveId = uni.getStorageSync('liveId')
if(data.liveId) {
data.showDialog = true
} else {
data.showDialog = false
}
}
onMounted(() => {
isShowLive()
})
onActivated(() => {
isShowLive()
})
return {
...toRefs(data),
toPage,
isShowLive
}
}
}
</script>
<style lang="scss" scoped>
.float{
position: fixed;
right: 24rpx;
bottom: 200rpx;
padding: 16rpx;
border-radius: 10rpx;
font-size: 24rpx;
background: #fff;
text-align: center;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
.icon{
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-bottom: 6rpx;
display: inline-flex;
align-items: center;
justify-content: center;
text{
color: v-bind('Color');
font-size: 36px;
}
}
}
</style>

362
components/live/share.vue Normal file
View File

@ -0,0 +1,362 @@
<template>
<view>
<up-overlay :show="showDialog" :zIndex="999">
<view class="serviceBox">
<view class="imgBox flex1">
<!-- <view class="picBox" id="capture">
<view class="top">
<image :src="avatar" mode="widthFix"></image>&nbsp;
<text>{{nickname}}邀请您观看</text>
</view>
<image :src="share_img" mode="aspectFill" class="share_img"></image>
<view class="mid">
<image :src="cover_img" mode="widthFix"></image>
<text>&nbsp;{{live_title}}</text>
</view>
<view class="btm">
<image :src="logo" mode="aspectFill" class="logo"></image>
<view class="ewm">
<image :src="code" mode="aspectFill" class="code"></image>
<view>长按保存图片</view>
</view>
</view>
<image :src="canvasImage" class="diaimg" mode="aspectFill"></image>
</view>
<view class="txt flex1">
<up-icon name="fingerprint" color="#fff" size="20" />
<text>长按图片保存</text>
</view> -->
</view>
<view class="bbox">
<view class="close flex1" @click="closeDialog"><up-icon name="close" color="#666" size="20" /></view>
<view class="btnBox">
<view class="row" @click="showTips = true">
<view class="icon flex1"><up-icon name="weixin-fill" color="#28C445" size="26" /></view>
<view class="tit">微信分享</view>
</view>
<view class="row" @click="copyLink">
<view class="icon flex1"><text class="iconfont icon-link"></text></view>
<view class="tit">复制链接</view>
</view>
</view>
</view>
<view class="wx_mask_wrapper" v-if="showTips">
<view class="wx_contentbox" @click="showTips = false">
<view class="note_box">请点击右上角<text class="icon_more"></text>分享给好友</view>
<view class="icon_arrow"></view>
</view>
</view>
</view>
</up-overlay>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { get } from '@/Api/request.js'
import { showToast } from '@/components/common.js'
import html2canvas from 'html2canvas';
import '@/static/js/html2canvas.js'
export default {
props: {
show: {
type: Boolean,
default: false
},
userId: {
type: Number,
default: 0
},
id: {
type: Number
},
info: {
type: Object,
default: {}
}
},
setup(props, context) {
const data = reactive({
showDialog: false,
userId: 0,
liveId: 0,
showTips: false,
avatar: '',
nickname: '',
share_img: '',
cover_img: '',
live_title: '',
logo: uni.getStorageSync('logo'),
code: 'https://g.csdnimg.cn/side-toolbar/3.4/images/qr_app.png',
canvasImage: ''
})
function copyLink() {
let shopId = (uni.getStorageSync('shop_id') || 0) * 1
let href = window.location.origin
let value = href + '/web#/pages/live/index?live_id=' + data.liveId + '&user_id=' + data.userId + '&shopId=' + shopId
var input = document.createElement('input')
input.value = value
document.body.appendChild(input)
input.select()
var copy_result = document.execCommand('copy')
if (copy_result) {
showToast('分享链接复制成功', 'success')
} else {
showToast('复制失败')
}
document.body.removeChild(input)
}
function closeDialog() {
data.showDialog = false
context.emit('close')
}
function getAvatar(info) {
let avatar = '', nickname = ''
for (let index = 0; index < info.streamers.length; index++) {
let item = info.streamers[index]
if(item.pivot.live_status == 1) {
avatar = item.avatar
nickname = item.nickname
break
}
}
if(!avatar) {
avatar = info.streamers[0].avatar
nickname = info.streamers[0].nickname
}
data.avatar = avatar
data.nickname = nickname
}
async function getShareCode() {
let shopId = (uni.getStorageSync('shop_id') || 0) * 1
let href = window.location.origin
let url = href + '/web#/pages/live/index?live_id=' + data.liveId + '&user_id=' + data.userId + '&shopId=' + shopId
await get('/api/v1/user/webCode', {url: url}).then((res) => {
})
}
function drawImg() {
uni.showLoading({
title: '图片生成中...',
mask: true
})
setTimeout(async() => {
const canvas = await html2canvas(document.getElementById("capture"), {
useCORS: true,
dpi: 300,
scale: 4
})
let imgUrl = canvas.toDataURL("image/jpeg", 1);
data.canvasImage = imgUrl
uni.hideLoading()
}, 1000)
}
watch(props, async (newProps) => {
if (newProps.show) {
console.log(newProps.info)
data.showDialog = true
data.liveId = newProps.id
data.userId = newProps.userId
getAvatar(newProps.info)
data.share_img = newProps.info.share_img
data.cover_img = newProps.info.cover_img
data.live_title = newProps.info.name
// await getShareCode()
// await drawImg()
}
})
return {
...toRefs(data),
copyLink,
closeDialog,
getShareCode,
getAvatar
}
}
}
</script>
<style lang="scss" scoped>
.flex1{
display: flex;
align-items: center;
justify-content: center;
}
.flex2{
display: flex;
align-items: center;
justify-content: space-between;
}
.serviceBox{
height: 100vh;
width: 100%;
.imgBox{
height: calc(100% - 130px);
box-sizing: border-box;
padding-top: 20px;
flex-direction: column;
.picBox{
background-color: #fff;
border-radius: 10px;
margin: 0 auto;
width: 280px;
height: 430px;
position: relative;
box-sizing: border-box;
padding: 12px;
.top{
display: flex;
align-items: center;
font-size: 16px;
image{
width: 30px;
height: 30px;
border-radius: 50%;
}
}
.share_img{
width: 100%;
height: 160px;
vertical-align: bottom;
margin-top: 10px;
border-radius: 12rpx;
}
.mid{
display: flex;
align-items: center;
font-size: 14px;
color: #666;
margin-top: 10px;
image{
width: 20px;
height: 20px;
border-radius: 50%;
}
}
.btm{
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
margin-top: 40px;
color: #777;
.code{
width: 100px;
height: 100px;
}
.ewm{
width: 140px;
text-align: center;
}
.logo{
width: 60px;
height: 60px;
}
}
.diaimg{
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
}
}
.txt{
font-size: 28rpx;
color: #fff;
height: 40px;
}
}
.bbox{
height: 130px;
position: relative;
background-color: #fff;
box-sizing: border-box;
padding-top: 40px;
border-radius: 20px 20px 0 0;
.close{
position: absolute;
right: 15px;
top: 15px;
width: 30px;
height: 15px;
}
.btnBox{
display: flex;
align-items: center;
justify-content: space-around;
.row{
font-size: 28rpx;
text-align: center;
.icon{
background-color: #e9e9e9;
width: 40px;
height: 40px;
border-radius: 50%;
display: inline-flex;
text{
font-size: 20px;
}
}
.tit{
margin-top: 10rpx;
}
}
}
}
.wx_mask_wrapper{
position: absolute;
top: 0;
left: 0;
z-index: 999;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,.7);
.wx_contentbox{
position: relative;
width: 100%;
height: 100%;
.note_box{
position: absolute;
right: 105px;
top: 70px;
line-height: 40rpx;
font-size: 28rpx;
color: #fff;
.icon_more{
display: inline-flex;
vertical-align: middle;
width: 20px;
height: 20px;
margin: 0 5px;
background: url(https://ct-upimg.yx090.com/ju8hn6/shop/image/2025/02/19/xufMNFWmg5F5irxll3wLyy8wCQVXEyCk4flQW4zP.png) no-repeat;
background-size: 100% 100%;
}
}
.icon_arrow{
position: absolute;
top: 15px;
right: 20px;
width: 70px;
height: 70px;
background: url(https://ct-upimg.yx090.com/ju8hn6/shop/image/2025/02/19/NgTzZE30DfkLuaXKHmJSFoqGF9kAxzbq1AA8JPJa.png) no-repeat;
background-size: 100% 100%;
}
}
}
}
</style>

179
components/newVip/index.vue Normal file
View File

@ -0,0 +1,179 @@
<template>
<!-- 新人专享优惠 -->
<up-overlay :show="showVan" :zIndex="9999" class="new_overlay">
<view class="serviceBox" @click="close()">
<view class="block" @click.stop="preventD">
<view class="title">恭喜获得</view>
<view class="close" @click="close()"><up-icon name="close" /></view>
<view class="box">
<view v-for="it in couponInfo" :key="it.id" class="openbox">
<image src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2022/11/08/l5SAwF75s4IQ5tglcLQo5bUlfixoFtnODw5CH4hT.png" mode="widthFix" class="image" />
<view class="coupon">
<view class="coupon-left">
<text class="sign">¥<text class="money">{{it.amount * 1}}</text></text>
<view class="desc" v-if="it.full_amount * 1 == 0">无门槛</view>
<view class="desc" v-else>{{it.full_amount * 1}}{{it.amount * 1}}</view>
</view>
<view class="coupon-right">
<view class="tit">新人专享优惠</view>
<view class="text">所有团可用</view>
<text class="time">有效期{{it.valid_days}}</text>
</view>
</view>
</view>
</view>
<!-- <view class="btn" @click="getHandle()">领取</view> -->
<view class="btn" @click="close()">好的</view>
</view>
</view>
</up-overlay>
</template>
<script>
import { ref, reactive, toRefs } from 'vue'
import { get, post } from '@/Api/request.js'
import { showToast } from '../common.js'
export default {
props: {
showVan: {
type: Boolean,
default: false
},
couponInfo: {
type: Array,
default: []
}
},
setup(props, context) {
const data = reactive({
})
function getHandle() {
post('/api/v1/userCoupon/newUser/receive').then((res) => {
showToast('领取成功')
close()
}).catch(() => {
close()
})
}
const preventD = () => {
return
}
function close() {
context.emit('close')
}
return {
...toRefs(data),
getHandle,
preventD,
close
}
}
}
</script>
<style lang="scss" scoped>
.serviceBox{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding-bottom: 80rpx;
box-sizing: border-box;
.block{
width: 80%;
background: #fff;
padding-bottom: 80rpx;
position: relative;
border-radius: 20rpx;
.close{
position: absolute;
top: 30rpx;
right: 30rpx;
}
.title{
padding: 40rpx 0;
color: #333;
font-size: 34rpx;
font-weight: bold;
text-align: center;
}
.box{
max-height: 450px;
overflow: auto;
}
.openbox{
margin: 0 auto;
width: 86%;
position: relative;
.image{
width: 100%;
}
.coupon{
width: 100%;
position: absolute;
top: 0;
left: 0;
height: 100%;
padding: 20rpx;
box-sizing: border-box;
display: flex;
.coupon-left {
width: 36%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
color: #F14939;
.sign {
font-size: 34rpx;
font-weight: bold;
}
.money {
font-size: 60rpx;
}
.desc{
font-size: 24rpx;
}
}
.coupon-right {
width: 64%;
padding-left: 36rpx;
display: flex;
justify-content: center;
flex-direction: column;
.tit {
font-size: 32rpx;
color: #F14939;
margin-bottom: 14rpx;
}
.text{
font-size: 24rpx;
color: #333333;
}
.time {
font-size: 20rpx;
color: #9C9C9C;
}
}
}
}
.btn{
color: #fff;
font-size: 32rpx;
margin: 40rpx auto 0;
width: 86%;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
background: #F14939;
border-radius: 12rpx;
}
}
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<!-- 取消订单弹窗 -->
<view class="">
<up-popup :show="showCancel" mode="bottom" :round="10" @close="close" catchtouchmove="preventD">
<view class="cancel">
<view class="cancel-title">订单取消</view>
<view class="tip">请选择取消订单原因</view>
<view class="cancel-list">
<view class="cancel-list-item" v-for="item in list" :key="item.id" @click="checked = item.id">
<text>{{item.name}}</text>
<span class="iconfont icon-checked" v-if="item.id === checked"></span>
<span class="iconfont icon-circle" v-else></span>
</view>
</view>
<view class="cancel-btn">
<view class="btn1" @click="close">暂不取消</view>
<view class="btn2" @click="cancelOrder">确定取消</view>
</view>
</view>
</up-popup>
</view>
</template>
<script>
import { ref, reactive, toRefs } from 'vue'
import { showToast } from '../common.js'
import { Style } from '@/utils/list.js'
export default {
props: {
showCancel: {
type: Boolean,
default: false
}
},
setup(props, context) {
const data = reactive({
list: [
{ id: 0, name: '价格有点贵' },
{ id: 1, name: '规格/款式/数量拍错' },
{ id: 2, name: '收货地址拍错' },
{ id: 3, name: '暂时不需要了' },
{ id: 4, name: '其他' }
],
checked: '',
Color: uni.getStorageSync('theme_color'),
cartColor: Style[uni.getStorageSync('theme_index') * 1].cartColor
})
function change(e) {
console.log(e)
data.checked = e.detail
}
function cancelOrder() {
if (data.checked !== '') {
context.emit('cancelOrder', data.list[Number(data.checked)].name)
data.checked = ''
} else {
showToast('请选择取消订单原因')
}
}
function close() {
context.emit('close')
data.checked = ''
}
function preventD() {
return
}
return {
...toRefs(data),
close,
change,
cancelOrder,
preventD
}
}
}
</script>
<style lang="scss" scoped>
.cancel {
font-size: 28rpx;
padding: 30rpx 30rpx;
&-title {
text-align: center;
padding: 0 0 20rpx;
font-size: 30rpx;
font-weight: bold;
letter-spacing: 5rpx;
}
.tip {
color: #98989f;
padding: 20rpx 0;
}
&-list {
padding-bottom: 60rpx;
&-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 0;
}
}
&-btn {
display: flex;
.btn1,
.btn2 {
width: 50%;
height: 80rpx;
line-height: 80rpx;
text-align: center;
color: #fff;
}
.btn1 {
background-color: v-bind('cartColor');
border-radius: 40rpx 0px 0px 40rpx;
}
.btn2 {
background-color: v-bind('Color');
border-radius: 0rpx 40rpx 40rpx 0rpx;
}
}
}
.icon-checked{
color: v-bind('Color');
}
</style>

View File

@ -0,0 +1,322 @@
<template>
<view>
<up-popup :show="showPopup" mode="bottom" :round="10" @close="close" catchtouchmove="preventD">
<view class="topTitle">选择地址</view>
<view class="listbox">
<view class="row flex1" v-for="(item, index) in addrList" :key="item.id" @click="selectAddr(item)">
<span class="iconfont icon-checked" v-if="item.id === addr_id"></span>
<span class="iconfont icon-circle" v-else></span>
<view class="txt">
<text>{{item.name}}&nbsp;&nbsp;{{item.mobile}}</text><text v-if="item.is_default === 1" class="default">默认</text><br>
<text>
{{item.province && item.province.name}}{{item.city && item.city.name}}{{item.area && item.area.name}}{{item.address}}
</text>
</view>
</view>
<view v-if="addrList.length === 0">
<up-empty mode="list" icon="https://ct-upimg.yx090.com/g.ii090/images/sprite/empty/address.png" text="暂无地址信息"></up-empty>
</view>
</view>
<view class="bottom flex" @click="showAddr = true"><van-icon name="plus" color="#fff" size="18" />添加新地址</view>
<!-- 新增编辑地址 -->
<up-popup :show="showAddr" mode="bottom" :round="10" close-on-click-overlay closeable @close="showAddr = false">
<view class="addrbox">
<view class="title">添加地址</view>
<view class="box">
<view class="row_it flex1">
<text>收件人</text>
<input v-model="addrData.name" class="inpt" placeholder="请输入收件人姓名" />
</view>
<view class="row_it flex1">
<text>联系电话</text>
<input v-model="addrData.mobile" class="inpt" placeholder="请输入收件人联系电话" />
</view>
<view class="row_it flex1" @click="showArea = true">
<text>位置</text>
<view style="flex: 1;">
<uni-data-picker
placeholder="请选择"
popup-title="请选择"
:localdata="areaList"
v-model="addrData.area_id"
@change="chooseArea"
:map="{text:'name',value:'id'}">
</uni-data-picker>
</view>
</view>
<view class="row_it flex1">
<text>详细地址</text>
<input v-model="addrData.address" class="inpt" placeholder="请输入详细地址" />
</view>
</view>
<view class="anniu">
<view class="btn flex" @click="commitAddress()">保存并使用</view>
</view>
</view>
</up-popup>
</up-popup>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { showToast } from '../common.js'
import { get, post } from '@/Api/request.js'
import { areaList } from '@/components/areaList.js'
import { Style } from '@/utils/list.js'
export default {
props: {
show: {
type: Boolean,
default: false
},
addrId: {
type: Number,
default: 0
}
},
setup(props, context) {
const data = reactive({
showPopup: false,
addrList: [
{}
],
addr_id: '',
showAddr: false,
curAddrId: '',
curAddrIndex: '',
addrData: {
comment: ''
},
areaNames: '',
areaId: '',
showArea: false,
Color: uni.getStorageSync('theme_color')
})
async function getAddrList() {
await get(`/api/v1/address`).then((res) => {
data.addrList = res.data
})
}
function selectAddr(item) {
uni.showModal({
title: '提示',
content: '确定要修改当前订单的地址吗?',
confirmColor: '#42b983',
success(res) {
if(res.confirm) {
data.addr_id = item.id
close()
context.emit('choose', item)
}
}
})
}
function commitAddress() {
if(!data.addrData.name) {
showToast('请输入收件人姓名')
return
}
if(!data.addrData.mobile) {
showToast('请输入收件人联系电话')
return
}
if(!data.addrData.area_id) {
showToast('请选择位置信息')
return
}
if(!data.addrData.address) {
showToast('请输入详细地址')
return
}
let params = {
name: data.addrData.name,
mobile: data.addrData.mobile,
province_id: data.addrData.province_id,
city_id: data.addrData.city_id,
area_id: data.addrData.area_id,
address: data.addrData.address,
postal_code: '',
is_default: 0
}
post(`/api/v1/address`, params).then(async (res) => {
await getAddrList()
data.showAddr = false
resetPopup()
})
}
function chooseArea(e) {
console.log(e)
if(e.detail.value.length) {
let list = []
for (let i = 0; i < e.detail.value.length; i++) {
if (e.detail.value[i].text === '') {
showToast('请选择完整地区信息')
return
}
list.push({id: e.detail.value[i].value, name: e.detail.value[i].text})
}
data.addrData.province_id = list[0].id
data.addrData.city_id = list[1].id
data.addrData.area_id = list[2].id
} else {
data.addrData.province_id = ''
data.addrData.city_id = ''
data.addrData.area_id = ''
}
}
function resetPopup() {
data.curAddrId = ''
data.addrData.name = ''
data.addrData.mobile = ''
data.addrData.address = ''
data.areaId = ''
data.areaNames = ''
}
function close() {
data.showPopup = false
context.emit('close')
}
function preventD() {
return
}
watch(props, (newProps) => {
if (newProps.show) {
data.addr_id = newProps.addrId
data.showPopup = true
getAddrList()
}
})
return {
areaList,
...toRefs(data),
close,
selectAddr,
getAddrList,
resetPopup,
commitAddress,
chooseArea,
preventD
}
}
}
</script>
<style lang="scss" scoped>
.flex1{
display: flex;
align-items: center;
justify-content: space-between;
}
.flex{
display: flex;
align-items: center;
justify-content: center;
}
.topTitle{
font-size: 30rpx;
color: #303030;
font-weight: bold;
padding: 24rpx;
box-sizing: border-box;
border-bottom: 1rpx solid #E5E5E5;
}
.listbox{
height: 65vh;
overflow: auto;
background: #fff;
.row{
padding: 0 24rpx;
font-size: 28rpx;
box-sizing: border-box;
.txt{
padding: 24rpx 0;
width: calc(100% - 60rpx);
border-bottom: 1px solid #f5f5f5;
}
text{
line-height: 50rpx;
color: #333;
font-size: 28rpx;
}
.default{
padding: 2rpx 8rpx;
font-size: 22rpx;
color: v-bind('Color');
border: 1px solid v-bind('Color');
border-radius: 6rpx;
line-height: 1;
margin-left: 6rpx;
}
}
}
.bottom{
width: 92%;
height: 90rpx;
background: v-bind('Color');
font-size: 30rpx;
color: #fff;
border-radius: 90rpx;
margin: 24rpx auto;
}
.addrbox{
padding: 0 30rpx 40rpx;
.title{
font-size: 30rpx;
color: #303030;
font-weight: bold;
padding: 30rpx 0;
border-bottom: 1rpx solid #E5E5E5;
}
.box{
padding-bottom: 200rpx;
.row_it{
padding: 20rpx 0;
font-size: 28rpx;
text{
width: 130rpx;
display: block;
}
.inpt{
width: calc(100% - 130rpx);
}
}
}
.anniu{
display: flex;
align-items: center;
justify-content: space-around;
.btn{
height: 80rpx;
font-size: 30rpx;
width: 100%;
border-radius: 80rpx;
box-sizing: border-box;
border: 1px solid v-bind('Color');
color: #fff;
background: v-bind('Color');
}
}
}
.icon-checked{
color: v-bind('Color');
}
</style>

View File

@ -0,0 +1,120 @@
<template>
<!-- 催发货 -->
<view class="">
<up-popup :show="show" mode="bottom" :round="10" @close="close()" closeable>
<view class="urgwBox">
<view class="success"><up-icon name="checkbox-mark" size="36" :color="Color" /></view>
<view class="title">已提醒卖家尽快发货</view>
<view v-if="urge_status === 0" class="info">
<template v-if="orderInfo.delivery_time">卖家承诺最晚于<text>{{orderInfo.delivery_time}}</text>发货</template>
</view>
<view v-else class="info">卖家超时发货<template v-if="urge_status === 2 && deduct_amount">为您补偿<text>{{deduct_amount}}</text>元优惠券<br>已自动发放到账户</template>团长联系卖家尽快发货</view>
<view class="box">
<view class="btn" @click="comfirm()">联系团长</view>
<view class="btn btn1" @click="close()">我知道了</view>
</view>
</view>
</up-popup>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { typeList, returnList, refundList, Style } from '@/utils/list.js'
export default {
props: {
show: {
type: Boolean,
default: false
},
info: Object
},
setup(props, context) {
const data = reactive({
deduct_amount: 0,
urge_status: 0,
orderInfo: {},
Color: uni.getStorageSync('theme_color'),
bgColor: Style[uni.getStorageSync('theme_index') * 1].bgColor
})
watch(props, (newProps) => {
if (newProps.show) {
data.orderInfo = newProps.info
data.deduct_amount = newProps.info.deduct_amount
console.log(typeof newProps.info.urge_status, newProps.info.urge_status)
data.urge_status = newProps.info.urge_status
}
})
function comfirm() {
close()
context.emit('contactTeamer', data.orderInfo.id)
}
function close() {
context.emit('close')
}
return {
...toRefs(data),
close,
comfirm
}
}
}
</script>
<style lang="scss" scoped>
.urgwBox {
padding: 70rpx 30rpx 30rpx;
.success{
width: 140rpx;
height: 140rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: v-bind('bgColor');
border-radius: 50%;
margin: 0 auto;
}
.title {
text-align: center;
font-size: 32rpx;
font-weight: bold;
color: #2c2c2c;
margin: 60rpx 0 20rpx;
}
.info{
text-align: center;
font-size: 28rpx;
line-height: 50rpx;
color: #666;
}
.box{
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 80rpx;
font-size: 30rpx;
}
.btn {
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
color: #333;
background-color: #fff;
text-align: center;
border-radius: 8rpx;
border: 1px solid #9D9D9D;
box-sizing: border-box;
width: 48%;
&.btn1{
background-color: v-bind('Color');
color: #fff;
border: 1px solid v-bind('Color');
}
}
}
</style>

1951
components/pay/index.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
<template>
<up-popup :show="showDialog" round mode="bottom" @close="close()" catchtouchmove="preventD" :zIndex="202">
<view class="pageBox">
<view class="title">温馨提示</view>
<view class="box">
<view class="text">为给您提供更好的服务允许我们在必要场景下合理使用您的个人信息并充分保障您的合法权利
请您在使用前仔细查阅以下协议条款点击"允许"即表示您已阅读并同意对应的协议内容
</view>
<view class="link" @click="openPrivacyContract">隐私协议</view>
</view>
<view class="btnbox">
<button type="default" open-type="agreePrivacyAuthorization" id="agree-btn" class="agree" @agreeprivacyauthorization="handleAgree">允许</button>
<view class="btn" @click="refuse()">拒绝</view>
</view>
</view>
</up-popup>
</template>
<script>
import { ref, reactive, toRefs } from 'vue'
import { get, post } from '@/Api/request.js'
export default {
props: {
showDialog: {
type: Boolean,
default: false
}
},
setup(props, context) {
const data = reactive({
Color: uni.getStorageSync('theme_color')
})
function handleAgree() {
context.emit('agree')
}
const preventD = () => {
return
}
function openPrivacyContract() {
uni.openPrivacyContract({
success: res => {
console.log('openPrivacyContract success')
},
fail: res => {
console.error('openPrivacyContract fail', res)
}
})
}
//
function refuse() {
context.emit('refuse')
}
function close() {
context.emit('close')
}
return {
...toRefs(data),
handleAgree,
openPrivacyContract,
preventD,
refuse,
close
}
}
}
</script>
<style lang="scss" scoped>
.pageBox{
padding-bottom: 200rpx;
.title{
font-size: 32rpx;
color: #000;
font-weight: bold;
padding: 30rpx 0;
text-align: center;
}
.box{
padding: 0 30rpx;
font-size: 28rpx;
.text{
color: #555;
line-height: 50rpx;
}
.link{
color: #155BD4;
}
}
.btnbox{
width: 100%;
padding: 0 30rpx;
box-sizing: border-box;
font-size: 28rpx;
text-align: center;
margin-top: 60rpx;
.agree {
height: 70rpx;
display: flex;
font-size: 28rpx;
align-items: center;
justify-content: center;
width: 100%;
background-color: v-bind('Color');
color: #fff;
border-radius: 10rpx;
}
.btn{
padding: 30rpx 0;
color: #666;
}
}
}
</style>

1
components/scene.js Normal file
View File

@ -0,0 +1 @@
export const provTxt = { 110000:'北京',120000:'天津',130000:'河北',140000:'山西',150000:'内蒙古',210000:'辽宁',220000:'吉林',230000:'黑龙江',310000:'上海',320000:'江苏',330000:'浙江',340000:'安徽',350000:'福建',360000:'江西',370000:'山东',410000:'河南',420000:'湖北',430000:'湖南',440000:'广东',450000:'广西',460000:'海南',500000:'重庆',510000:'四川',520000:'贵州',530000:'云南',540000:'西藏',610000:'陕西',620000:'甘肃',630000:'青海',640000:'宁夏',650000:'新疆',710000:'台湾',810000:'香港',820000:'澳门'}

View File

@ -0,0 +1,94 @@
<template>
<!-- 搜索输入框 -->
<view class="searchBox">
<view class="cont">
<view class="box">
<up-icon name="search" size="17" color="#A8A8A8"></up-icon>
<input class="input"
:auto-focus="show"
type="text"
:value="keyword"
placeholder="搜索商品"
@input="getValue"
@confirm="search" />
</view>
<view class="btn" @click="search">搜索</view>
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
export default {
props: {
searchValue: {
type: String,
default: ''
},
show: {
type: Boolean,
default: false
}
},
setup(props, context) {
const data = reactive({
Color: uni.getStorageSync('theme_color')
})
watch(props, async (newProps) => {
if (newProps) {
keyword.value = newProps.searchValue
}
})
const keyword = ref('')
function getValue(e) {
keyword.value = e.detail.value
context.emit('getvalue', e.detail.value)
}
function search() {
context.emit('searchBtn', keyword.value)
}
return {
...toRefs(data),
keyword,
getValue,
search
}
}
}
</script>
<style lang="scss" scoped>
.searchBox{
.cont{
display: flex;
background-color: #fff;
padding: 10rpx 30rpx;
box-sizing: border-box;
.box{
display: flex;
align-items: center;
flex: 1;
height: 66rpx;
border-radius: 33rpx;
background-color: #f5f5f5;
padding: 0 30rpx;
.input{
font-size: 28rpx;
flex: 1;
}
}
.btn{
color: v-bind('Color');
font-size: 30rpx;
text-align: center;
line-height: 66rpx;
width: 100rpx;
height: 66rpx;
}
}
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<!-- 分享海报 -->
<div class="content">
<div class="share">
<image class="poster" :src="posterImg" show-menu-by-longpress="{{true}}"
@load="imgLoad"
:style="{ width: imgWidth + 'px', height: imgHeight + 'px' }"
></image>
<view class="close" @click="closeShow"><up-icon name="close" color="#fff" size="26"/></view>
<text>长按图片分享好友</text>
</div>
</div>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
export default {
props: {
posterImg: String
},
setup(props, context) {
const data = reactive({
imgWidth: 1,
imgHeight: 1
})
//
function closeShow() {
context.emit('closeShow')
}
function imgLoad(e) {
let imgWidth = e.detail.width
let imgHeight = e.detail.height
let pWid = uni.getSystemInfoSync().windowWidth
let pHig = uni.getSystemInfoSync().windowHeight
let imgRate = imgWidth / imgHeight
let pRate = pWid / pHig
//
if(imgWidth > imgHeight) {
//
if(imgWidth > pWid) {
data.imgWidth = pWid
data.imgHeight = (pWid / imgRate).toFixed(2)
} else {
data.imgWidth = imgWidth
data.imgHeight = imgHeight
}
} else {
if(imgHeight > pHig * 0.65) {
data.imgWidth = (pHig * 0.65 * imgRate).toFixed(2)
data.imgHeight = (pHig * 0.65).toFixed(2)
} else {
data.imgWidth = imgWidth
data.imgHeight = imgHeight
}
}
}
return {
...toRefs(data),
closeShow,
imgLoad
}
}
}
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgba($color: #000000, $alpha: 0.7);
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
.share{
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
flex-direction: column;
.close{
position: absolute;
right: 0;
top: -70rpx;
}
text{
font-size: 26rpx;
color: #fff;
margin-top: 20rpx;
}
.poster{
border-radius: 16rpx;
}
}
}
</style>

120
components/share/share.vue Normal file
View File

@ -0,0 +1,120 @@
<template>
<div class="shareBox" v-if="showShare" @click="close">
<div class="box1">
<view class="share">
<view class="share-btn">
<button class="share-btn-item" v-for="(item, index) in iconList" :key="index"
@click="shareBtn(index)" :open-type="index === 5 ? 'share' : ''">
<view class="icon" :class="item.icon" :style="{backgroundImage: 'url(' + sp2 + ')'}"></view>
<text>{{item.text}}</text>
</button>
</view>
<view class="share-cancel" @click="close">取消</view>
</view>
</div>
</div>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { post } from '@/Api/request.js'
import { sp2 } from '@/components/img.js'
export default {
props: {
showShare: {
type: Boolean,
default: false
}
},
setup(props, context) {
const data = reactive({
sp2: sp2,
iconList: [
{ icon: 'wechat', text: '分享到微信' },
{ icon: 'friends', text: '分享到朋友圈' },
{ icon: 'link', text: '复制链接' }
]
})
const shareBtn = (index) => {
close()
if (index === 0) {
context.emit('getSaleShare')
} else if (index === 1) {
context.emit('creatShare')
} else {
context.emit('getLink')
}
}
const close = () => {
context.emit('close')
}
return {
...toRefs(data),
shareBtn,
close
}
}
}
</script>
<style lang="scss" scoped>
.shareBox{
position: fixed;
top: 0;
left: 0;
z-index: 1001;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
.box1 {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #fff;
}
.share {
&-btn {
display: flex;
justify-content: space-around;
padding: 30rpx 0;
border-bottom: 1rpx solid #d5d5d5;
&-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 24rpx;
color: #666;
.icon{
width: 42px;
height: 42px;
background-repeat: no-repeat;
background-size: 452px 408px;
background-position: -15px -15.67px;
&.wechat{
background-position: -15px -15.67px;
}
&.friends{
background-position: -68.33px -15.67px;
}
&.link{
background-position: -121.33px -15.67px;
}
}
}
}
&-cancel {
height: 110rpx;
text-align: center;
line-height: 110rpx;
font-size: 30rpx;
color: #656565;
}
}
}
</style>

View File

@ -0,0 +1,110 @@
<template>
<div class="box" v-if="showShare" @click="close">
<div class="box1">
<view class="share">
<view class="share-btn">
<button class="share-btn-item" v-for="(item, index) in iconList" :key="index" @click="shareBtn(index)" :open-type="index === 5 ? 'share' : ''">
<view class="img" :class="'img' + index" :style="{backgroundImage: 'url(' + sp2 + ')'}"></view>
<text>{{item}}</text>
</button>
</view>
<view class="share-cancel" @click="close">取消</view>
</view>
</div>
</div>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { post } from '@/Api/request.js'
import { sp2 } from '@/components/img.js'
export default {
props: {
showShare: {
type: Boolean,
default: false
}
},
setup(props, context) {
const data = reactive({
iconList: ['分享到朋友圈', '复制链接'],
sp2: sp2
})
const shareBtn = (index) => {
close()
if (index === 0) {
context.emit('creatShare')
} else {
context.emit('getLink')
}
}
const close = () => {
context.emit('close')
}
return {
...toRefs(data),
shareBtn,
close
}
}
}
</script>
<style lang="scss" scoped>
.box {
position: fixed;
top: 0;
left: 0;
z-index: 1001;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
.box1 {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #fff;
.img{
width: 42px;
height: 42px;
background-repeat: no-repeat;
background-size: 452px 408px;
background-position: -15px -15.67px;
&.img1{
background-position: -121.33px -15.67px;
}
}
}
}
.share {
&-btn {
display: flex;
justify-content: space-around;
padding: 30rpx 0;
border-bottom: 1rpx solid #d5d5d5;
&-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 26rpx;
color: #666;
image {
width: 100rpx;
height: 100rpx;
margin-bottom: 15rpx;
}
}
}
&-cancel {
height: 110rpx;
text-align: center;
line-height: 110rpx;
font-size: 36rpx;
color: #656565;
}
}
</style>

View File

@ -0,0 +1,232 @@
<template>
<!-- 分享海报 -->
<view class="share">
<view class="box">
<view class="cont" id="capture">
<view class="top">
<image :src="avatar" mode="widthFix"></image>
<view class="tit">
<text>{{nickname}}</text>
<view class="time">{{time}}</view>
</view>
</view>
<image :src="faceImg" class="face_img" mode="aspectFill"></image>
<view class="title">{{title}}</view>
<view class="desc">{{desc}}</view>
<view class="btm">
<view class="">
<view class="price">¥2.00~9.00</view>
<view class="bg">
<text>长按识别图中小程序</text><br />
<text>跟团购买>></text>
</view>
</view>
<image :src="showImage" class="code" mode="aspectFill"></image>
</view>
<image :src="canvasImage" class="diaimg" mode="aspectFill"></image>
</view>
<view class="btn" @click="closeShow"><up-icon name="close" color="#fff" size="30" /></view>
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, onMounted } from 'vue'
import { getOldDay, showToast } from '../common.js'
import { post } from '@/Api/request.js'
import html2canvas from 'html2canvas';
import '@/static/js/html2canvas.js'
export default {
props: {
goods: Object
},
setup(props, context) {
const data = reactive({
canvasWidth: {},
ctx: null,
showImage: '',
avatar: uni.getStorageSync('avatar'),
faceImg: props.goods.face_img,
title: props.goods.title,
desc: props.goods.description,
loading: false,
shareImg: '',
Color: uni.getStorageSync('theme_color'),
nickname: uni.getStorageSync('nickname'),
showPrivacy: false,
time: getOldDay(),
canvasImage: ''
})
//
function closeShow() {
context.emit('closeShow')
}
//
const getImg = () => {
return new Promise((resolve, reject) => {
uni.request({
url: '/api/v1/user/code',
method: 'POST',
data: {
page: 'pages/groups/index',
shop_goods_id: props.goods.id
},
header: {
Authorization: uni.getStorageSync('token') || '',
appid: uni.getStorageSync('appId')
},
responseType: 'arraybuffer',
success: (res) => {
if (res.statusCode === 200) {
let base64 = ''
const bytes = new Uint8Array(res.data)
const len = bytes.byteLength
for (let i = 0; i < len; i++) {
base64 += String.fromCharCode(bytes[i])
}
base64 = `data:image/png;base64,${btoa(base64)}`
resolve(base64)
} else {
reject('')
}
},
})
})
}
onMounted(async() => {
uni.showLoading({
title: '海报生成中...',
mask: true
})
data.showImage = await getImg()
setTimeout(async() => {
const canvas = await html2canvas(document.getElementById("capture"), {
useCORS: true,
dpi: 300,
scale: 4
})
let imgUrl = canvas.toDataURL("image/jpeg", 1);
console.log(imgUrl)
data.canvasImage = imgUrl
uni.hideLoading()
}, 1000)
})
return {
...toRefs(data),
closeShow,
getImg
}
}
}
</script>
<style lang="scss" scoped>
.share {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgba($color: #000000, $alpha: 0.7);
z-index: 202;
display: flex;
flex-direction: column;
justify-content: center;
.cont{
width: 275px;
height: 510px;
box-sizing: border-box;
margin: 0 auto;
background-color: #fff;
border-radius: 10rpx;
padding: 12px;
position: relative;
.top{
display: flex;
align-items: center;
image{
width: 30px;
height: 30px;
}
.tit{
margin-left: 10px;
font-size: 14px;
.time{
font-size: 12px;
color: #999;
margin-top: 3px;
}
}
}
.face_img{
width: 100%;
height: 250px;
vertical-align: bottom;
margin-top: 10px;
}
.title{
font-size: 15px;
font-weight: 600;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc{
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
white-space: break-spaces;
margin: 5px 0;
color: #999999;
font-weight: 600;
}
.btm{
display: flex;
justify-content: space-between;
margin-top: 10px;
.price{
color: v-bind('Color');
font-weight: 600;
padding-top: 10px;
}
.bg{
background-color: #F7F7F7;
font-size: 12px;
padding: 10px;
color: #999999;
font-weight: 600;
margin-top: 5px;
}
.code{
width: 90px;
height: 90px;
vertical-align: bottom;
}
}
.diaimg{
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
}
}
.btn{
text-align: center;
margin: 20px auto 0;
}
}
</style>

View File

@ -0,0 +1,209 @@
<template>
<!-- 分享海报 -->
<view class="share" @click="closeShow" catchtouchmove="preventD">
<view v-show="!showPrivacy">
<canvas class="canvas" id="myCanvas" canvas-id="myCanvas"></canvas>
<view class="btn" @tap.stop="saveImage">保存图片</view>
</view>
</view>
<!-- 隐私协议弹窗 -->
<privacy-popup :show-dialog="showPrivacy" @close="showPrivacy = false" @agree.stop="showPrivacy = false" @refuse="showPrivacy = false" />
</template>
<script>
import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
import { getOldDay, saveImg, judgePrivacy } from '../common.js'
import { post } from '@/Api/request.js'
import privacyPopup from '../privacyPopup/index.vue'
export default {
components: {
privacyPopup
},
props: {
shareImage: {
type: String,
default: '',
}
},
setup(props, context) {
const data = reactive({
canvasWidth: {},
ctx: null,
showImage: '',
avatar: '',
faceImg: '',
Color: uni.getStorageSync('theme_color'),
showPrivacy: false,
shareImage: '',
rate: 0
})
//
function closeShow() {
context.emit('closeShow')
}
const getShareImg = async () => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: props.shareImage,
success: function(res) {
data.rate = res.height / res.width
resolve(res.path)
},
fail(err) {
reject()
}
})
})
}
function drawCanvas() {
console.log(data.ctx)
data.ctx.setFontSize(20)
data.ctx.setFillStyle('white')
data.ctx.fillRect(0, 0, data.canvasWidth.width, data.canvasWidth.height)
data.ctx.drawImage(data.avatar, 20, 20, 40, 40)
data.ctx.setFontSize(14)
data.ctx.setFillStyle('#222')
var nickname = uni.getStorageSync('nickname')
data.ctx.fillText(nickname, 70, 35)
data.ctx.setFontSize(13)
data.ctx.setFillStyle('#777')
data.ctx.fillText(getOldDay(), 70, 55)
data.ctx.drawImage(data.shareImage, 30, 80, 211, 211 * data.rate)
data.ctx.drawImage(data.faceImg, 90, 220, 92, 92)
data.ctx.draw()
}
//
const getImageInfo = async (imgSrc) => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: imgSrc,
success: function(image) {
resolve(image.path)
},
fail(err) {
reject()
}
})
})
}
//
const getFaceImg = () => {
return new Promise((resolve, reject) => {
uni.request({
url: '/api/v1/user/code',
method: 'POST',
data: {
page: 'pages/index/index'
},
header: {
Authorization: uni.getStorageSync('token') || '',
appid: uni.getStorageSync('appId')
},
responseType: 'arraybuffer',
success: (res) => {
if (res.statusCode === 200) {
let base64 = ''
const bytes = new Uint8Array(res.data)
const len = bytes.byteLength
for (let i = 0; i < len; i++) {
base64 += String.fromCharCode(bytes[i])
}
base64 = `data:image/png;base64,${btoa(base64)}`
resolve(base64)
} else {
reject('')
}
}
})
})
}
onMounted(() => {
uni.showLoading({
title: '二维码生成中...'
})
const instance = getCurrentInstance()
setTimeout(() => {
const query = uni.createSelectorQuery().in(instance)
query.select('#myCanvas').boundingClientRect(async (res) => {
data.canvasWidth = res
data.ctx = uni.createCanvasContext('myCanvas', instance)
data.avatar = await getImageInfo(uni.getStorageSync('avatar'))
data.faceImg = await getFaceImg()
data.shareImage = await getShareImg()
await drawCanvas()
uni.hideLoading()
}).exec()
}, 200)
})
return {
...toRefs(data),
drawCanvas,
closeShow,
getFaceImg,
getImageInfo,
getShareImg
}
},
methods: {
async saveImage() {
if(await judgePrivacy()) {
this.showPrivacy = true
return false
}
//
const _this = this
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
success(res) {
saveImg(res.tempFilePath)
},
fail(err) {
}
}, _this)
}
}
}
</script>
<style lang="scss" scoped>
.share {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgba($color: #000000, $alpha: 0.7);
z-index: 202;
display: flex;
flex-direction: column;
justify-content: center;
.canvas {
width: 275px;
height: 355px;
box-sizing: border-box;
margin: 0 auto;
background-color: #fff;
}
.btn {
color: #fff;
background-color: v-bind('Color');
font-size: 28rpx;
width: 300rpx;
height: 70rpx;
line-height: 70rpx;
text-align: center;
margin: 60rpx auto 0;
border-radius: 10rpx;
}
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<!-- 销售分享模板 -->
<view>
<up-overlay :show="showShareSwiper" @click="closeSwiper" z-index="1001">
<view class="share">
<swiper class="share-swiper" :indicator-dots="true" :circular="true" indicator-active-color="#fff"
indicator-color="rgba(255, 255, 255, 0.4)" previous-margin='100rpx' next-margin='100rpx'
:current="choose" @change="changeChoose">
<swiper-item v-for="(item, index) in saleShareImg" :key="index">
<button class="share-swiper-item" :open-type="index === choose ? 'share' : ''">
<view class="shop" v-if="goodsInfo.shop">
<image class="img" :src="goodsInfo.shop.logo"></image>
<text>{{goodsInfo.shop.name}}</text>
</view>
<view class="title">{{goodsInfo.description}}</view>
<image class="image" :src="item.image" mode="widthFix"></image>
<view class="text">
<image src="https://ct-upimg.yx090.com/ju8hn6/shop/image/2022/07/01/0jXVQFuf0rVJA0c8qLSAyCDsDtiHzOgodoIR0Fo3.png"
mode="widthFix" class="img"></image>
小程序
</view>
</button>
</swiper-item>
</swiper>
</view>
</up-overlay>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { post } from '../../Api/request.js'
export default {
props: {
showShareSwiper: {
type: Boolean,
default: false
},
saleShareImg: Array,
goodsInfo: Object
},
setup(props, context) {
const data = reactive({
choose: 0
})
const changeChoose = (e) => {
data.choose = e.detail.current
let img = props.saleShareImg[data.choose].image
context.emit('changeShareImg', img)
}
const shareBtn = () => {}
const close = () => {
context.emit('close')
}
const closeSwiper = () => {
context.emit('closeSwiper')
}
return {
...toRefs(data),
changeChoose,
closeSwiper
}
}
}
</script>
<style lang="scss" scoped>
.share {
position: relative;
width: 100%;
height: 100%;
.share-swiper {
position: absolute;
transform: translate(-50%, -50%);
top: 45%;
left: 50%;
width: 100%;
height: 50%;
.share-swiper-item {
width: 80%;
margin: auto;
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx 30rpx 0;
text-align: start;
line-height: 30rpx;
.shop {
display: flex;
align-items: center;
font-size: 24rpx;
color: #b3b3b3;
.img {
width: 50rpx;
height: 50rpx;
background-color: #b3b3b3;
border-radius: 50%;
margin-right: 20rpx;
}
}
.title {
margin: 20rpx 0;
font-size: 30rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.image {
width: 100%;
margin-bottom: 15rpx;
border-radius: 10rpx;
}
.text {
border-top: 2rpx solid #e1e1e1;
padding-top: 10rpx;
font-size: 26rpx;
color: #b3b3b3;
padding-bottom: 25rpx;
.img {
width: 20rpx;
}
}
}
}
}
</style>

1117
components/sku/ChooseSku.vue Normal file

File diff suppressed because it is too large Load Diff

2185
components/sku/directPay.vue Normal file

File diff suppressed because it is too large Load Diff

719
components/sku/multiple.vue Normal file
View File

@ -0,0 +1,719 @@
<template>
<!-- 选规格弹窗 -->
<view>
<up-popup :show="showSku" mode="bottom" :round="10" @close="close" :safe-area-inset-bottom="true" catchtouchmove="preventD" :lock-scroll="true" :z-index="202">
<view class="wholeBox">
<view class="skuTop">
<image class="img" :src="viewImg" @click="preViewImg(viewImg)" :style="{width: imgWidth + 'rpx', height: imgWidth + 'rpx'}" mode="aspectFill" />
<view class="topInfo" :class="imgWidth == 200 ? '' : 'smallfont'">
<view class="title" v-if="imgWidth == 200">{{skuInfo.title}}</view>
<view class="priceBox">
<!-- 会员下普通价格 -->
<view class="text1" v-if="vipOn && chooseItem.vip_price > 0 && (is_vip || (!is_vip && vip_price_show))">
<text class="icon1"></text>
<text>{{chooseItem.price}}</text>
</view>
<view>
<!-- 显示会员价 -->
<view v-if="vipOn && chooseItem.vip_price > 0 && (is_vip || (!is_vip && vip_price_show))" class="vip">
<view class="vip-tag"><text class="txt">会员价&nbsp;</text>{{chooseItem.vip_price}}</view>
</view>
<!-- 显示普通价格 -->
<view v-else class="vip">
<text class="icon1"></text>
<text>{{chooseItem.price}}</text>
</view>
</view>
</view>
<view class="text" v-if="show_stock === 1">剩余{{ chooseItem.stock > 0 ? chooseItem.stock : 0 }}</view>
<view class="sel">已选{{skuName}}</view>
</view>
</view>
<scroll-view class="goodBox" scroll-y="true" enhanced="true" @scroll="skuScroll" :scroll-top="topNum">
<view class="skuBox">
<view class="sku_list" v-for="(items, idx) in specsList" :key="idx">
<view class="title">{{idx + 1}}件商品</view>
<view class="sku_item" v-for="(item, index) in items" :key="index">
<view class="spec_name">{{item.spec_name}}</view>
<view class="sku_tag">
<view class="tag" v-for="(it, i) in item.value" :key="it.id"
@click="!it.show ? chooseSku(it, index, i, idx, items) :''"
:class="pickSkuList[idx]['v'+ (index + 1) +'_id'] === it.id ? 'choose' : it.show ? 'dis' : '' ">
<image :src="it.img" v-if="it.img" class="tag_img"></image>
<text>{{it.value}}</text>
</view>
</view>
</view>
</view>
<view class="sku_num">
<view class="num">
<text>购买数量</text>
<text v-if="show_stock === 1">最多{{ chooseItem.stock > 0 ? chooseItem.stock : 0 }}</text>
<view v-if="skuInfo.limit_type == 2" class="box_red">限购{{skuInfo.limit}}</view>
<view v-if="skuInfo.limit_type == 1" class="box_red">{{skuInfo.start_sale_num}}件起购</view>
</view>
<up-number-box
v-model="chooseItem.num"
:min="skuInfo.limit_type == 1 ? parseInt(skuInfo.start_sale_num) : skuInfo.limit_type === 0 ? 1 : 1 "
:max="skuInfo.limit_type == 2 ? parseInt(skuInfo.limit) : skuInfo.limit_type === 0 ? (chooseItem.stock > 0 ? chooseItem.stock : 0) : 0"
@overlimit="plusBtn(skuInfo.limit_type == 1 ? 0 : skuInfo.limit_type == 2 ? 1 : 2 ,chooseItem.num, skuInfo.limit)"
disabledInput
bgColor="#f2f3f5"
:longPress="false"
@change="changeNum">
</up-number-box>
</view>
<view class="sku_buy" v-if="sales > 0">
<view class="img" v-for="img in skuInfo.avatars" :key="img">
<image :src="img" class="sku-buy-img"></image>
</view>
<view class="text">已有<text class="num">{{sales}}</text>个社群好友购买</view>
</view>
</view>
<view class="edition" v-if="textModule.length != 0">
<view v-for="(item, index) in textModule" :key="index">
<!-- 大图 -->
<view v-if="item.type == 1" class="edition_box" @click="preViewImg(item.imgs[0])">
<view v-for="(imgs, i) in item.imgs" :key="i">
<image :src="imgs + '?x-oss-process=image/format,webp'" :webp="true" mode="widthFix" :lazy-load="true" style="width:100%"></image>
</view>
</view>
<!-- 小图 -->
<view class="edition_box" v-if="item.type == 2">
<view class="small_img">
<view v-for="(list, index1) in item.img" :key="index1" class="imgs" @click="getTextimg(item.img, list)">
<image :src="list + '?x-oss-process=image/format,webp'" mode="aspectFill" :webp="true" class="image"></image>
</view>
</view>
</view>
<!-- 视频 -->
<view class="edition_box" v-if="item.type == 3">
<video :src="item.video[0]" height="100%" width="250" class="video_box" style="display: block;margin: 0 auto;"></video>
</view>
<!-- 文字 -->
<view class="edition_box text1_box" v-if="item.type == 4">
<text selectable="true" :user-select="true" class="text">{{item.text}}</text>
</view>
</view>
</view>
<view v-else-if="images.length != 0" class="imgbox">
<image v-for="img in images" :key="img" :lazy-load="true" :src="img" class="img" mode="widthFix"></image>
</view>
<view v-if="images.length === 0 && mainImg.length !== 0" class="imgbox">
<image v-for="img in mainImg" :key="img" :lazy-load="true" :src="img" class="img" mode="widthFix"></image>
</view>
</scroll-view>
<view class="sku_btn" v-if="soldStatus == 2" @click="arrivalNotice()">
<view class="btn" v-if="!remindStock">到货提醒</view>
<view class="btn dis" v-else>取消到货提醒</view>
</view>
<view class="sku_btn" v-else @click="(chooseItem.stock > 0 && canBuy) ? addToCart() : ''">
<view class="btn" :class="(chooseItem.stock <= 0 || !canBuy) ? 'dis' : ''">加入购物车</view>
</view>
</view>
</up-popup>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { showToast, goodsItem, toMiniProgram } from '../common.js'
import { get, post } from '@/Api/request.js'
import { Style } from '@/utils/list.js'
export default {
props: {
show: {
type: Boolean,
default: false
},
show_stock: {
type: Number,
default: 0
},
sourceId: {
type: Number,
default: 0
},
sourceType: {
type: String,
default: 'normal'
},
canBuy: {
type: Boolean,
default: true
},
goodId: {
type: Number,
default: 0
},
groupId: {
type: Number,
default: 0
},
specsNum: {
type: Number,
default: 0
},
remindStock: {
type: Boolean,
default: false
},
soldStatus: {
type: Number,
default: 0
},
sales: {
type: Number,
default: 0
},
remindTmplId: {
type: String,
default: ''
}
},
setup(props, context) {
const data = reactive({
showSku: false,
Color: uni.getStorageSync('theme_color'),
priceColor: Style[uni.getStorageSync('theme_index') * 1].priceColor,
cartColor: Style[uni.getStorageSync('theme_index') * 1].cartColor,
bgColor: Style[uni.getStorageSync('theme_index') * 1].bgColor,
vipOn: uni.getStorageSync('vip_on') === 1,
vip_price_show: uni.getStorageSync('vip_price_show'),
sourceId: 0,
sourceType: '',
viewImg: '',
imgWidth: 200,
skuInfo: {},
skuName: '',
is_vip: uni.getStorageSync('is_vip'),
specsList: [],
textModule: [],
mainImg: [],
images: [],
chooseItem: {},
goodId: 0,
choose: [],
sku_skuInfo: {},
chooseIndex: [],
pickSkuList: [],
curIndex: 0,
action: false,
topNum: 0,
specsNum: 0,
canClick: true,
remindStock: false
})
const preventD = () => {
return
}
//
const preViewImg = (img) => {
let img_preview_suffix = uni.getStorageSync('img_preview_suffix') || ''
let imurl = img + img_preview_suffix
if(img.indexOf('.gif') >= 0 || img.indexOf('.GIF') >= 0) {
imurl = img
}
uni.previewImage({
urls: [imurl],
current: 0
})
}
const hanleShare = () => {
context.emit('buttomShow', true)
}
function skuScroll(e) {
if(e.detail.scrollTop > 200){
data.imgWidth = 120
} else {
data.imgWidth = 200
}
}
function chooseSku(e, index, i_index, idx, items) {
data.action = true
if (e.img || e.img_800) {
data.viewImg = e.img_800 || e.img
}
data.curIndex = idx
data.choose[idx]['v' + (index + 1) + '_id'] = items[index].value[i_index].id
data.pickSkuList[idx]['v' + (index + 1) + '_id'] = items[index].value[i_index].id
data.pickSkuList[idx]['v' + (index + 1)] = items[index].value[i_index].value
data.chooseIndex[idx].push(index)
data.chooseIndex[idx] = Array.from(new Set(data.chooseIndex[idx]))
}
watch(props, (newProps) => {
if(newProps.show) {
data.showSku = true
data.chooseItem = {}
data.chooseItem.num = 1
data.goodId = newProps.goodId
data.sourceId = newProps.sourceId
data.sourceType = newProps.sourceType
data.specsNum = newProps.specsNum
data.remindStock = newProps.remindStock
data.images = []
data.specsList = []
data.pickSkuList = []
data.choose = []
data.chooseIndex = []
get(`/api/v1/goods/spec/${data.goodId}`).then((res) => {
data.topNum = data.topNum == 0 ? 0.1 : 0
data.skuInfo = res.data
data.viewImg = res.data.face_img
data.mainImg = res.data.gallery || []
data.limit = res.data.limit
if(res.data.specs) {
res.data.specs[0].value.forEach((it) => {
if(it.img_800){
data.images.push(it.img_800)
}
})
let tempSpecs = JSON.parse(JSON.stringify(res.data.specs))
if (res.data.specs.length === 1) {
let sku = []
res.data.skus.forEach((ress) => {
if (ress.stock <= 0 || ress.price == 0) {
sku.push(ress.v1_id)
}
})
tempSpecs.forEach((res, i) => {
res.value.forEach((req) => {
if (sku.includes(req.id)) {
req.show = true
} else {
req.show = false
}
})
})
}
for (let index = 0; index < data.specsNum; index++) {
data.pickSkuList[index] = {}
for (let i = 0; i < tempSpecs.length; i++) {
data.pickSkuList[index]['v' + (i + 1) + '_id'] = 0
}
data.specsList.push(JSON.parse(JSON.stringify(tempSpecs)))
data.choose.push({})
data.chooseIndex.push([])
}
}
data.textModule = res.data.text_modules || []
if(props.soldStatus == 2) {
res.data.stock = 0
res.data.skus.forEach((ress) => {
ress.stock = 0
})
}
data.sku_skuInfo = res.data.skus
data.chooseItem = JSON.parse(JSON.stringify(res.data.skus[0]))
data.chooseItem.stock = res.data.stock
setTimeout(() => {
data.imgWidth = 200
}, 100)
})
}
})
watch(
() => data.choose,
(newChoose) => {
if(!data.action) {
return
}
if (data.specsList[data.curIndex].length - Object.keys(data.choose[data.curIndex]).length == 1) {
//
data.specsList[data.curIndex].forEach((req, i) => {
if (data.chooseIndex[data.curIndex].indexOf(i) == -1) {
req.value.forEach((rej, j) => {
data.sku_skuInfo.forEach((ress, m) => {
let flag = [rej.id === ress['v' + (i + 1) + '_id']]
for (const key in data.choose[data.curIndex]) {
flag.push(ress[key] == data.choose[data.curIndex][key])
}
if (flag.findIndex(target => target === false) == -1) {
if (ress.stock <= 0 || ress.price == 0) {
rej.show = true
} else {
rej.show = false
}
}
})
})
}
})
} else if (data.specsList[data.curIndex].length == Object.keys(data.choose[data.curIndex]).length) {
for (const key in data.choose[data.curIndex]) {
let i = parseInt(key.substr(1, 1))
data.specsList[data.curIndex][i - 1].value.forEach((req) => {
data.sku_skuInfo.forEach((ress, m) => {
let flag = [req.id == ress['v' + i + '_id']]
for (const k in data.choose[data.curIndex]) {
let j = parseInt(k.substr(1, 1))
if (i != j) {
flag.push(ress[k] == data.choose[data.curIndex][k])
}
}
if (flag.findIndex(target => target === false) == -1) {
if ((ress.stock <= 0 || ress.price == 0)) {
req.show = true
} else {
req.show = false
}
}
})
})
}
}
//
for (let i = data.specsList[data.curIndex].length; i >= 1; i--) {
if (!newChoose[data.curIndex]['v' + i + '_id']) {
return
}
}
//
data.sku_skuInfo.forEach((sku, s_index) => {
let num = data.chooseItem.num
if (
sku.v1_id === newChoose[data.curIndex].v1_id &&
sku.v2_id === newChoose[data.curIndex].v2_id &&
sku.v3_id === newChoose[data.curIndex].v3_id &&
sku.v4_id === newChoose[data.curIndex].v4_id
) {
data.chooseItem = {
...sku
}
if (num > 0) {
data.chooseItem.num = num < sku.stock ? num : (sku.stock > 0 ? sku.stock : 0)
} else if (sku.stock > 0) {
data.chooseItem.num = data.skuInfo.limit_type == 0 ? 1 : data.skuInfo.limit_type == 1 ? parseInt(data.skuInfo.start_sale_num) : 1
} else {
data.chooseItem.num = 0
}
}
})
}, {
deep: true
}
)
watch(() => data.pickSkuList, (newPickList) => {
data.skuName = ''
newPickList.forEach((item) => {
let name = []
for (let i = 0; i < data.specsNum; i++) {
if(item['v' + (i + 1)]) {
name.push(item['v' + (i + 1)])
}
}
if(name.length) {
data.skuName += '【' + name.join('-') + '】'
}
})
}, {
deep: true
})
function addToCart() {
let params = [], flag = true
for (let i = 0; i < data.pickSkuList.length; i++) {
let pick = data.pickSkuList[i]
for (let m = 0; m < data.sku_skuInfo.length; m++) {
let sku = data.sku_skuInfo[m]
if(pick.v1_id == sku.v1_id && pick.v2_id == sku.v2_id && pick.v3_id == sku.v3_id && pick.v4_id == sku.v4_id) {
params.push({
shop_goods_id: sku.shop_goods_id,
shop_goods_sku_id: sku.id,
shop_group_goods_id: props.groupId,
num: data.chooseItem.num,
source_id: data.sourceId,
source_type: data.sourceType
})
}
}
}
console.log(params)
if(params.length != data.specsNum) {
showToast('请选择完整规格')
return
}
post('/api/v1/carts/batch', { goods: params}).then((res) => {
showToast('已加入购物车')
getNum()
context.emit('getnum')
close()
})
}
function close(e) {
data.action = false
data.showSku = false
context.emit('close')
}
//
function changeNum(e) {
data.chooseItem.num = e
}
async function arrivalNotice() {
//
if(data.remindStock) {
post(`/api/v1/goods/remind/cancel/${data.groupId}`, {type: 1}).then((res) => {
data.remindStock = false
uni.showToast({
title: '已取消到货提醒',
icon: 'none'
})
context.emit('remind', false)
})
} else {
toMiniProgram('pages/groups/index?id=' + data.groupId)
}
}
const { getNum } = goodsItem()
return {
toMiniProgram,
...toRefs(data),
preventD,
preViewImg,
hanleShare,
skuScroll,
chooseSku,
close,
addToCart,
getNum,
changeNum,
arrivalNotice
}
}
}
</script>
<style lang="scss" scoped>
.wholeBox{
background-color: #fff;
height: 70vh;
position: relative;
overflow: hidden;
.skuTop{
display: flex;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
.img{
background: #bbbbbb;
border-radius: 8rpx;
margin-right: 30rpx;
transition: all 0.3s;
width: 200rpx;
height: 200rpx;
}
.topInfo{
display: flex;
width: calc(100% - 250rpx);
flex-direction: column;
&.smallfont{
.title{
display: none;
}
.price{
font-size: 28rpx;
}
.text{
display: none;
}
.sel{
font-size: 24rpx;
margin-top: 10rpx;
}
}
.title{
width: calc(100% - 50rpx);
margin-bottom: 10rpx;
}
.priceBox{
display: flex;
align-items: center;
flex-wrap: wrap;
.text1{
font-size: 32rpx;
color: v-bind('priceColor');
margin-right: 10rpx;
font-weight: 600;
}
.icon1{
font-size: 24rpx;
font-weight: normal;
}
.vip{
display: flex;
align-items: center;
font-size: 34rpx;
color: v-bind('priceColor');
}
}
.text{
font-size: 24rpx;
color: #999999;
margin-top: 20rpx;
display: block;
}
.sel{
margin-top: 20rpx;
font-size: 28rpx;
}
}
}
.goodBox{
height: calc(70vh - 280rpx);
.skuBox{
margin-bottom: 30rpx;
.sku_list{
padding: 10rpx 30rpx 30rpx;
border-bottom: 1rpx solid #eee;
position: relative;
.title{
font-size: 30rpx;
font-weight: 600;
margin-top: 10rpx;
}
.sku_item{
.spec_name{
font-size: 26rpx;
margin-top: 20rpx;
}
.sku_tag{
display: flex;
flex-wrap: wrap;
font-size: 24rpx;
.tag{
display: flex;
align-items: center;
justify-content: center;
color: #000;
background-color: #f4f4f4;
margin-right: 22rpx;
margin-top: 20rpx;
padding: 10rpx 18rpx;
box-sizing: border-box;
border-radius: 6rpx;
.tag_img{
width: 35rpx;
height: 35rpx;
margin-right: 15rpx;
}
}
.dis{
opacity: 0.35;
}
.choose {
background-color: v-bind('bgColor');
color: v-bind('Color');
border-radius: 8rpx;
}
}
}
}
.sku_num{
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
.num{
font-size: 28rpx;
display: flex;
align-items: center;
.box_red{
padding: 5rpx 10rpx;
box-sizing: border-box;
font-size: 25rpx;
display: inline-block;
color: #656565;
}
}
}
.sku_buy{
display: flex;
align-items: center;
padding: 30rpx;
border-top: 1rpx solid #eee;
border-bottom: 1rpx solid #eee;
.img{
width: 50rpx;
height: 50rpx;
margin-left: -10rpx;
border: 4rpx solid #fff;
box-sizing: border-box;
.sku-buy-img {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
}
.text{
margin-left: 20rpx;
font-size: 28rpx;
.num {
color: v-bind('Color');
}
}
}
}
}
.sku_btn{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 2;
background-color: #fff;
display: flex;
.btn{
height: 104rpx;
color: #fff;
font-size: 30rpx;
text-align: center;
line-height: 104rpx;
background: v-bind('Color');
width: 100%;
}
.dis{
opacity: 0.7;
color: #eee;
}
}
}
.vip-tag {
font-size: 32rpx;
color: #fbe6c3;
background: #353648;
border-radius: 20rpx 0 0 0;
padding: 8rpx 10rpx;
line-height: 1;
.txt{
font-size: 22rpx;
}
}
</style>

View File

@ -0,0 +1,123 @@
<template>
<view>
<up-overlay :show="show" :z-index="9999">
<view class="contBox" @click="close()">
<view class="num">{{index + 1}}/{{specsList.length}}</view>
<swiper class="swiper" :autoplay="false" :indicator-dots="false" :circular="true" @change="changeSwiper" :current="index">
<swiper-item v-for="(item, index) in specsList" :key="index">
<view class="box">
<image class="img" mode="widthFix" :src="(item.img_800 || item.img) + '?x-oss-process=image/format,webp'" :webp="true"></image>
<view class="title"><text>{{item.value}}</text></view>
</view>
</swiper-item>
</swiper>
</view>
</up-overlay>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { showToast } from '../common.js'
import { get, post } from '@/Api/request.js'
import { Style } from '@/utils/list.js'
export default {
props: {
show: {
type: Boolean,
default: false
},
list: {
type: Object,
default: []
},
current: {
type: Number,
default: 0
}
},
setup(props, context) {
const data = reactive({
show: false,
index: 0,
specsList: [],
Color: uni.getStorageSync('theme_color'),
bgColor: Style[uni.getStorageSync('theme_index') * 1].bgColor
})
function close() {
data.show = false
context.emit('close', data.index)
}
function changeSwiper(event) {
data.index = event.detail.current
}
watch(props, (newProps) => {
if(newProps.show) {
data.show = true
data.index = newProps.current
data.specsList = newProps.list[0].value
}
})
return {
...toRefs(data),
close,
changeSwiper
}
}
}
</script>
<style lang="scss" scoped>
.contBox{
width: 100%;
height: 100vh;
overflow: hidden;
background-color: #191919;
position: relative;
.num{
font-size: 32rpx;
color: #fff;
text-align: center;
width: 100%;
top: 80rpx;
position: absolute;
left: 0;
}
.swiper{
width: 100%;
height: 100%;
.box{
position: relative;
width: 100%;
height: 100%;
display: flex;
position: relative;
align-items: center;
justify-content: center;
}
.img{
width: 100%;
}
.title{
text-align: center;
width: 100%;
bottom: 80rpx;
position: absolute;
left: 0;
text{
font-size: 28rpx;
color: #fff;
border-radius: 30rpx;
padding: 10rpx 28rpx;
background-color: #5E5E5E;
}
}
}
}
</style>

312
components/sku/tileSku.vue Normal file
View File

@ -0,0 +1,312 @@
<template>
<view class="skuBox" v-if="showSku">
<view class="item" v-for="(items, idx) in specsList" :key="idx">
<view class="title" v-if="specsNum > 1">{{idx + 1}}件商品</view>
<view class="col" v-for="(item, index) in items" :key="index">
<view class="name">{{item.spec_name}}</view>
<view class="tagBox">
<view class="tag" v-for="(it, i) in item.value" :key="it.id"
@click="!it.show ? chooseSku(it, index, i, idx, items) :''"
:class="pickSkuList[idx]['v'+ (index + 1) +'_id'] === it.id ? 'choose' : it.show ? 'dis' : '' ">
<image :src="it.img" v-if="it.img" class="tag_img"></image>
<text>{{it.value}}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { showToast, goodsItem } from '../common.js'
import { get, post } from '@/Api/request.js'
import { Style } from '@/utils/list.js'
export default {
props: {
show: {
type: Boolean,
default: false
},
specsNum: {
type: Number,
default: 0
},
goodId: {
type: Number,
default: 0
},
},
setup(props, context) {
const data = reactive({
showSku: false,
goodId: 0,
Color: uni.getStorageSync('theme_color'),
bgColor: Style[uni.getStorageSync('theme_index') * 1].bgColor,
choose: [],
skuName: '',
skuInfo: {},
mainImg: [],
images: [],
chooseItem: {},
sku_skuInfo: {},
chooseIndex: [],
pickSkuList: [],
curIndex: 0,
specsList: [],
action: false,
specsNum: 0
})
function chooseSku(e, index, i_index, idx, items) {
data.action = true
if (e.img || e.img_800) {
data.viewImg = e.img_800 || e.img
}
data.curIndex = idx
data.pickSkuList[idx]['v' + (index + 1) + '_id'] = items[index].value[i_index].id
data.pickSkuList[idx]['v' + (index + 1)] = items[index].value[i_index].value
data.chooseIndex[idx].push(index)
data.chooseIndex[idx] = Array.from(new Set(data.chooseIndex[idx]))
data.choose[idx]['v' + (index + 1) + '_id'] = items[index].value[i_index].id
}
watch(props, (newProps) => {
if(newProps.show) {
data.showSku = true
data.goodId = newProps.goodId
data.chooseItem = {}
data.chooseItem.num = 1
data.specsNum = newProps.specsNum
data.images = []
data.specsList = []
data.pickSkuList = []
data.choose = []
data.chooseIndex = []
get(`/api/v1/goods/spec/${data.goodId}`).then((res) => {
data.skuInfo = res.data
data.viewImg = res.data.face_img
data.mainImg = res.data.gallery || []
if(res.data.specs) {
res.data.specs[0].value.forEach((it) => {
if(it.img_800){
data.images.push(it.img_800)
}
})
for (let index = 0; index < data.specsNum; index++) {
data.pickSkuList[index] = {}
for (let i = 0; i < res.data.specs.length; i++) {
data.pickSkuList[index]['v' + (i + 1) + '_id'] = 0
}
data.specsList.push(JSON.parse(JSON.stringify(res.data.specs)))
data.choose.push({})
data.chooseIndex.push([])
}
}
data.sku_skuInfo = res.data.skus
data.viewImg = res.data.specs[0].value[0].img_800 || res.data.specs[0].value[0].img || res.data.face_img
setTimeout(() => {
if(res.data.skus[0].stock > 0) {
// sku
data.curIndex = data.specsNum
for (let m = 0; m < data.specsNum; m++) {
res.data.specs.forEach((it, n) => {
data.choose[m]['v' + (n + 1) + '_id'] = data.sku_skuInfo[0]['v' + (n + 1) + '_id']
data.pickSkuList[m]['v' + (n + 1) + '_id'] = data.sku_skuInfo[0]['v' + (n + 1) + '_id']
data.pickSkuList[m]['v' + (n + 1)] = data.sku_skuInfo[0]['v' + (n + 1)]
})
data.chooseIndex.push(m)
}
data.chooseItem = data.sku_skuInfo[0]
context.emit('back', data.pickSkuList, data.viewImg, data.chooseItem)
} else {
// sku
if(res.data.specs.length == 1) { //
//
data.specsList.forEach((item) => {
item.forEach((itm) => {
itm.value.forEach((it, i) => {
it.show = res.data.skus[i].stock <= 0 || res.data.skus[i].price * 1 == 0 ? true : false
})
})
})
}
}
}, 1000)
})
}
})
watch(
() => data.choose,
(newChoose) => {
if(!data.action) {
return
}
if (data.specsList[data.curIndex].length - Object.keys(data.choose[data.curIndex]).length == 1) {
//
data.specsList[data.curIndex].forEach((req, i) => {
if (data.chooseIndex[data.curIndex].indexOf(i) == -1) {
req.value.forEach((rej, j) => {
data.sku_skuInfo.forEach((ress, m) => {
let flag = [rej.id === ress['v' + (i + 1) + '_id']]
for (const key in data.choose[data.curIndex]) {
flag.push(ress[key] == data.choose[data.curIndex][key])
}
if (flag.findIndex(target => target === false) == -1) {
if (ress.stock <= 0 || ress.price == 0) {
rej.show = true
} else {
rej.show = false
}
}
})
})
}
})
} else if (data.specsList[data.curIndex].length == Object.keys(data.choose[data.curIndex]).length) {
for (const key in data.choose[data.curIndex]) {
let i = parseInt(key.substr(1, 1))
data.specsList[data.curIndex][i - 1].value.forEach((req) => {
data.sku_skuInfo.forEach((ress, m) => {
let flag = [req.id == ress['v' + i + '_id']]
for (const k in data.choose[data.curIndex]) {
let j = parseInt(k.substr(1, 1))
if (i != j) {
flag.push(ress[k] == data.choose[data.curIndex][k])
}
}
if (flag.findIndex(target => target === false) == -1) {
if ((ress.stock <= 0 || ress.price == 0)) {
req.show = true
} else {
req.show = false
}
}
})
})
}
}
//
for (let i = data.specsList[data.curIndex].length; i >= 1; i--) {
if (!newChoose[data.curIndex]['v' + i + '_id']) {
return
}
}
//
data.sku_skuInfo.forEach((sku, s_index) => {
let num = data.chooseItem.num
if (
sku.v1_id === newChoose[data.curIndex].v1_id &&
sku.v2_id === newChoose[data.curIndex].v2_id &&
sku.v3_id === newChoose[data.curIndex].v3_id &&
sku.v4_id === newChoose[data.curIndex].v4_id
) {
data.chooseItem = {
...sku
}
if (num > 0) {
data.chooseItem.num = num < sku.stock ? num : (sku.stock > 0 ? sku.stock : 0)
} else if (sku.stock > 0) {
data.chooseItem.num = data.skuInfo.limit_type == 0 ? 1 : data.skuInfo.limit_type == 1 ? parseInt(data.skuInfo.start_sale_num) : 1
} else {
data.chooseItem.num = 0
}
}
})
context.emit('back', data.pickSkuList, data.viewImg, data.chooseItem)
}, {
deep: true
}
)
watch(() => data.pickSkuList, (newPickList) => {
data.skuName = ''
newPickList.forEach((item) => {
let name = []
for (let i = 0; i < data.specsNum; i++) {
if(item['v' + (i + 1)]) {
name.push(item['v' + (i + 1)])
}
}
if(name.length) {
data.skuName += '【' + name.join('-') + '】'
}
})
}, {
deep: true
})
return {
...toRefs(data),
chooseSku,
}
}
}
</script>
<style lang="scss" scoped>
.skuBox{
margin-bottom: 20rpx;
background-color: #fff;
.item{
padding: 10rpx 30rpx 30rpx;
border-bottom: 1rpx solid #eee;
position: relative;
.title{
font-size: 30rpx;
font-weight: 600;
margin-top: 10rpx;
}
.col{
.name{
font-size: 30rpx;
margin-top: 20rpx;
}
.tagBox{
display: flex;
flex-wrap: wrap;
font-size: 28rpx;
.tag{
display: flex;
align-items: center;
justify-content: center;
color: #000;
background-color: #f4f4f4;
margin-right: 22rpx;
margin-top: 20rpx;
padding: 10rpx 18rpx;
box-sizing: border-box;
border-radius: 6rpx;
.tag_img{
width: 40rpx;
height: 40rpx;
margin-right: 15rpx;
}
}
.dis{
opacity: 0.35;
}
.choose {
background-color: v-bind('bgColor');
color: v-bind('Color');
border-radius: 8rpx;
}
}
}
}
}
</style>

197
components/tabbar/index.vue Normal file
View File

@ -0,0 +1,197 @@
<template>
<!-- 自定义导航栏 -->
<view class="tabbar">
<view class="index" v-for="(item, index) in tabbarList" :key="index" @click="jumpTo(item.url, item.id)">
<view class="icon" :class="index == chooseIndex ? 'choose' : ''">
<text v-if="index == chooseIndex" class="iconfont" :class="'icon-' + item.fill"></text>
<text v-else class="iconfont" :class="'icon-' + item.type"></text>
</view>
<text :class="index == chooseIndex ? 'choose text' : 'text' ">{{ item.title }}</text>
<up-badge :bgColor="priceColor" max="99" v-if="item.id == 2" :value="num"></up-badge>
<up-badge :bgColor="priceColor" max="99" v-if="item.id == 4 && msgNum" :value="msgNum"></up-badge>
</view>
</view>
</template>
<script>
import { ref, reactive, toRefs, onMounted } from 'vue'
import { whetherLogin } from '@/components/common.js'
import { get } from '@/Api/request.js'
import { Style } from '@/utils/list.js'
export default {
props: {
chooseIndex: {
type: Number,
default: 1
},
num: {
type: Number,
default: 0
},
msgNum: {
type: Number,
default: 0
}
},
setup(props, context) {
const data = reactive({
tabbarList: [
{
id: 1,
title: '首页',
url: '/pages/index/index',
type: 'home',
fill: 'homefill'
},
{
id: 5,
title: '分类',
url: '/pages/classify/new',
type: 'fenlei',
fill: 'fenleifill'
},
{
id: 4,
title: '互动',
url: '/pages/message/index',
type: 'msg',
fill: 'msgfill'
},
{
id: 2,
title: '购物车',
url: '/pages/cart/index',
type: 'cart',
fill: 'cartfill'
},
{
id: 3,
title: '我的',
url: '/pages/user/index',
type: 'mine',
fill: 'minefill'
}
],
role: uni.getStorageSync('role'),
Color: '#F14939',
Theme: '',
priceColor: '#F14939',
interval: null,
has_multi_group: uni.getStorageSync('has_multi_group') || true
})
const jumpTo = (url, id) => {
if(id == 5) {
if(data.has_multi_group) {
uni.switchTab({
url: '/pages/classify/new'
})
} else {
uni.switchTab({
url: '/pages/classify/index'
})
}
} else {
if((id == 2 || id == 3 || id == 4) && !whetherLogin()) {
uni.navigateTo({
url: '/pages/user/login'
})
} else {
uni.switchTab({ url })
}
}
}
function setColor() {
data.Color = uni.getStorageSync('theme_color')
data.Theme = uni.getStorageSync('theme_index') * 1
data.priceColor = Style[uni.getStorageSync('theme_index') * 1] && Style[uni.getStorageSync('theme_index') * 1].priceColor
}
onMounted(() => {
setColor()
if(!data.Color) {
data.interval = setInterval(() => {
if(!data.Color) {
setColor()
} else {
clearInterval(data.interval)
data.interval = null
}
}, 300)
}
setTimeout(() => {
setColor()
}, 1200)
// #ifdef APP-PLUS
uni.hideTabBar()
// #endif
})
return {
whetherLogin,
...toRefs(data),
jumpTo,
setColor
}
},
onShow() {
uni.hideTabBar()
}
}
</script>
<style lang="scss" scoped>
.tabbar {
width: 100%;
height: 55px;
position: fixed;
z-index: 999;
display: flex;
background: #fff;
box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.16);
//ios线
bottom: 0;
// padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-sizing: content-box;
.index {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: #999;
font-size: 12px;
position: relative;
.text {
margin-top: 2px;
}
.choose {
color: v-bind('Color');
}
.tag{
position: absolute;
top: 0;
transform: translate(60%, 0);
}
}
.icon{
font-size: 20px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
.iconfont{
font-size: 20px;
}
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

View File

@ -0,0 +1,257 @@
<template>
<view class="sliderBox">
<view class="content">
<view class="headbox">
<text class="text">请完成安全验证</text>
<view class="tf-close" @click.stop="close_"><up-icon name="close" /></view>
</view>
<canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }" class="canvasBox" canvas-id="mycanvas" id="mycanvas"></canvas>
<movable-area class="moveArea">
<view class="text">滑动滑块完成拼图</view>
<movable-view class="moveView" direction="all" :x="canvasX2" @change="changePath" @touchend="endTouch" @mouseup="endTouch">
<view class="moveBox"></view>
</movable-view>
</movable-area>
</view>
</view>
</template>
<script>
export default {
props:{
verifyImgs:{
type:Array,
default: function(){
return []
}
}
},
data() {
return {
verifyIndex: 0,
canvasW: '',
canvasH: '',
canvasX2: 0,
canvasX: 0,
ctx: null,
jgX: 0,
dqImgPath:'',
Color: uni.getStorageSync('theme_color')
}
},
created() {
this.canvasW = uni.upx2px(580)
this.canvasH = uni.upx2px(290)
},
mounted() {
this.$nextTick(()=>{
this.init()
})
},
methods: {
// minNummaxNum
randomNum(minNum,maxNum){
switch(arguments.length){
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
break;
default:
return 0;
break;
}
},
close_(){
this.$emit('close')
},
async init(){
if(this.verifyImgs.length == 0){
uni.showToast({
title: '背景图不能为空',
icon: 'none'
})
return
}
this.canvasX2--
this.canvasX = 0
this.verifyIndex = this.randomNum(0, this.verifyImgs.length - 1)
this.ctx = uni.createCanvasContext('mycanvas', this)
this.jgX = this.randomNum(uni.upx2px(150),uni.upx2px(450))
this.dqImgPath = await this.parseImagePath(this.verifyImgs[this.verifyIndex].src)
this.huatu()
},
endTouch(){
if(Math.abs(this.canvasX - this.jgX) <= 5){
this.$emit('succeed')
}else{
uni.showToast({
title: '验证失败',
icon:"error"
});
this.init()
}
},
huatu(){
let this_ = this
let r = uni.upx2px(10)
let XX = this.canvasX
let YY = uni.upx2px(100)
let cs = uni.upx2px(20)
this_.ctx.drawImage(this_.dqImgPath, 0, 0, this_.canvasW, this_.canvasH)
//
this_.ctx.beginPath()
this_.ctx.moveTo(-2*r+this_.jgX+cs+2*r, YY-2*r+2*r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+5.5*r, YY-2*r+2*r)
this_.ctx.arcTo(-2*r+this_.jgX+cs+5.5*r, YY-2*r+3*r, XX-2+this_.jgX*r+cs+6.5*r, YY-2*r+3*r, r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+7.5*r, YY-2*r+3*r)
this_.ctx.arcTo(-2*r+this_.jgX+cs+8.5*r, YY-2*r+3*r, -2*r+this_.jgX+cs+8.5*r, YY-2*r+2*r, r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+12*r, YY-2*r+2*r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+12*r, YY-2*r+11*r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+8.5*r, YY-2*r+11*r)
this_.ctx.arcTo(-2*r+this_.jgX+cs+8.5*r, YY-2*r+12*r, -2*r+this_.jgX+cs+7.5*r, YY-2*r+12*r, r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+6.5*r, YY-2*r+12*r)
this_.ctx.arcTo(-2*r+this_.jgX+cs+5.5*r, YY-2*r+12*r, -2*r+this_.jgX+cs+5.5*r, YY-2*r+11*r, r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+2*r, YY-2*r+11*r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+2*r, YY-2*r+8*r)
this_.ctx.arcTo(-2*r+this_.jgX+cs+3*r, YY-2*r+8*r, -2*r+this_.jgX+cs+3*r, YY-2*r+7*r, r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+3*r, YY-2*r+6*r)
this_.ctx.arcTo(-2*r+this_.jgX+cs+3*r, YY-2*r+5*r, -2*r+this_.jgX+cs+2*r, YY-2*r+5*r, r)
this_.ctx.lineTo(-2*r+this_.jgX+cs+2*r, YY-2*r+2*r)
this_.ctx.shadowBlur = 10
this_.ctx.shadowColor="#ffffff"
this_.ctx.fillStyle = "rgba(0,0,0,0.5)"
this_.ctx.fill()
this_.ctx.restore()
//
this_.ctx.beginPath()
this_.ctx.save()
this_.ctx.moveTo(XX-2*r+cs+2*r, YY-2*r+2*r)
this_.ctx.lineTo(XX-2*r+cs+5.5*r, YY-2*r+2*r)
this_.ctx.arcTo(XX-2*r+cs+5.5*r, YY-2*r+3*r, XX-2*r+cs+6.5*r, YY-2*r+3*r, r)
this_.ctx.lineTo(XX-2*r+cs+7.5*r, YY-2*r+3*r)
this_.ctx.arcTo(XX-2*r+cs+8.5*r, YY-2*r+3*r, XX-2*r+cs+8.5*r, YY-2*r+2*r, r)
this_.ctx.lineTo(XX-2*r+cs+12*r, YY-2*r+2*r)
this_.ctx.lineTo(XX-2*r+cs+12*r, YY-2*r+11*r)
this_.ctx.lineTo(XX-2*r+cs+8.5*r, YY-2*r+11*r)
this_.ctx.arcTo(XX-2*r+cs+8.5*r, YY-2*r+12*r, XX-2*r+cs+7.5*r, YY-2*r+12*r, r)
this_.ctx.lineTo(XX-2*r+cs+6.5*r, YY-2*r+12*r)
this_.ctx.arcTo(XX-2*r+cs+5.5*r, YY-2*r+12*r, XX-2*r+cs+5.5*r, YY-2*r+11*r, r)
this_.ctx.lineTo(XX-2*r+cs+2*r, YY-2*r+11*r)
this_.ctx.lineTo(XX-2*r+cs+2*r, YY-2*r+8*r)
this_.ctx.arcTo(XX-2*r+cs+3*r, YY-2*r+8*r, XX-2*r+cs+3*r, YY-2*r+7*r, r)
this_.ctx.lineTo(XX-2*r+cs+3*r, YY-2*r+6*r)
this_.ctx.arcTo(XX-2*r+cs+3*r, YY-2*r+5*r, XX-2*r+cs+2*r, YY-2*r+5*r, r)
this_.ctx.lineTo(XX-2*r+cs+2*r, YY-2*r+2*r)
this_.ctx.shadowBlur = 10
this_.ctx.shadowColor = '#ffffff'
this_.ctx.fill()
this_.ctx.clip()
this_.ctx.drawImage(this_.dqImgPath, this_.canvasX - this_.jgX, 0, this_.canvasW, this_.canvasH)
this_.ctx.restore()
//
this_.ctx.draw()
},
changePath(e) {
this.canvasX = e.detail.x
this.huatu()
},
async parseImagePath(imgSrc) {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: imgSrc,
success: function(image) {
resolve(image.path)
},
fail(err) {
reject()
}
})
})
}
}
}
</script>
<style lang="less">
.sliderBox{
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 100;
background-color: rgba(0,0,0,.3);
display: flex;
align-items: center;
justify-content: center;
.content{
width: 640upx;
height: 584upx;
background-color: #fff;
border-radius: 6upx;
box-shadow: 0 0 50upx 0upx rgba(0, 0, 0, 0.2);
.headbox{
height: 100upx;
line-height: 100upx;
padding: 0 32upx;
border-bottom: 1px solid #E1E3E9;
flex-direction: row;
display: flex;
align-items: center;
justify-content: space-between;
.text{
font-size: 32upx;
flex: 1;
}
}
.canvasBox{
margin: 30rpx auto;
align-self: center;
}
.moveArea{
margin: 30rpx auto;
align-self: center;
width: 580upx;
height: 75upx;
line-height: 75upx;
text-align: center;
font-size: 28upx;
border-radius: 6upx;
border: 1px solid #E1E3E9;
background-color: #F7F8F9;
overflow: hidden;
position: relative;
.text{
width: 100%;
height: 75upx;
position: absolute;
top: 0;
left: 0;
color: #424649;
text-align: center;
}
.moveView{
height: 75upx;
width: 75upx;
background-color: #fff;
box-shadow: 0 0 10upx 0upx rgba(0, 0, 0, 0.2);
background-image: url(img/tf-arrows.png);
background-size: 34upx;
background-position: center;
background-repeat: no-repeat;
.moveBox{
position: absolute;
background-color: v-bind('Color');
top: 0;
left: -580upx;
width: 580upx;
height: 100%;
}
}
}
}
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<up-overlay :show="show" :z-index="1500" :custom-style="customStyle" :overlay-style="overlayStyle">
<view class="BBox">
<view style="width: 100%;height: calc(100vh - 120px);">
<DomVideoPlayer
ref="domVideoPlayer"
object-fit="contain"
:controls="true"
:autoplay="true"
:loop="true"
:src="url" />
</view>
<view class="close" @click="close">
<up-icon name="close" color="#ddd" size="30" />
</view>
</view>
</up-overlay>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import DomVideoPlayer from '@/components/DomVideoPlayer/index.vue'
export default {
components: { DomVideoPlayer },
props: {
show: {
type: Boolean,
default: false
},
url: {
type: String
}
},
setup(props, context) {
const data = reactive({
url: '',
show: false,
customStyle: {},
overlayStyle: {
background: '#000',
height: '100vh',
width: '100%'
},
playing: false,
duration: 0,
currentTime: 0,
playbackRate: 1
})
const close = () => {
data.show = false
context.emit('close')
}
const onPlay = () => {
data.playing = true
}
const onPause = () => {
data.playing = false
}
const onEnded = () => {
data.playing = false
}
const onDurationChange = (e) => {
console.log('onDurationChange', e)
data.duration = e
}
const onTimeUpdate = (e) => {
data.currentTime = e
}
const onRateChange = (e) => {
console.log('onRateChange', e)
data.playbackRate = e
}
watch(props, async (newProps) => {
if (newProps.show) {
data.show = true
data.url = newProps.url
}
})
return {
...toRefs(data),
close,
onPlay,
onPause,
onEnded,
onDurationChange,
onTimeUpdate,
onRateChange,
}
}
}
</script>
<style lang="scss" scoped>
.BBox{
width: 100%;
height: 100vh;
box-sizing: border-box;
padding: 60px 0 0;
background-color: #000;
.video{
width: 100%;
height: calc(100vh - 120px);
}
.close{
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
}
}
</style>

39
index.html Normal file
View File

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no">
<meta http-equiv="pragram" content="no-cache">
<meta name="referrer" content="no-referrer" />
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="expires" content="0">
<link rel="icon" href="./favicon.ico">
<!-- <link href="https://tcsdk.com/player/tcplayer/release/v5.3.3/tcplayer.min.css" rel="stylesheet"/> -->
<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' : '') + '" />')
</script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/vconsole@3.3.4/dist/vconsole.min.js"></script> -->
<script>
// new VConsole();
</script>
<script src="https://video.sdk.qcloudecdn.com/web/TXLivePlayer-1.3.6.min.js"></script>
<!-- <link href="https://tcsdk.com/player/tcplayer/release/v5.3.3/tcplayer.min.css" rel="stylesheet"/>
<script src="https://cloudcache.tencent-cloud.com/open/qcloud/video/tcplayer/libs/hls.min.0.13.2m.js"></script>
<script src="https://tcsdk.com/player/tcplayer/release/v5.3.3/tcplayer.v5.3.3.min.js"></script> -->
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

7706
js_sdk/u-charts.js Normal file

File diff suppressed because it is too large Load Diff

BIN
logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

41
main.js Normal file
View File

@ -0,0 +1,41 @@
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
Vue.prototype.$onLaunched = new Promise(resolve => {
Vue.prototype.$isResolve = resolve
})
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// import uviewPlus from '@/uni_modules/uview-plus'
import uviewPlus, {setConfig} from '@/uni_modules/uview-plus'
setConfig({
// config: {
// unit: 'rpx'
// }
})
// import Vconsole from 'vconsole'
// new Vconsole()
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
app.config.globalProperties.$onLaunched = new Promise(resolve => {
app.config.globalProperties.$isResolve = resolve
})
app.use(uviewPlus)
return {
app
}
}
// #endif

223
manifest.json Normal file
View File

@ -0,0 +1,223 @@
{
"name" : "春分有品直播",
"appid" : "__UNI__743F2C0",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : 100,
"transformPx" : false,
/* 5+App */
"app-plus" : {
"runmode" : "liberate",
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {
"OAuth" : {},
"Payment" : {},
"Share" : {},
"VideoPlayer" : {},
"Camera" : {}
},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
"minSdkVersion" : 21,
"targetSdkVersion" : 30,
"schemes" : "miaoxuan"
},
/* ios */
"ios" : {
"dSYMs" : false,
"urlschemewhitelist" : "alipays,alipay,safepay,weixin,wechat",
"capabilities" : {
"entitlements" : {
"com.apple.developer.associated-domains" : [ "guan.chutang66.com" ]
}
}
},
/* SDK */
"sdkConfigs" : {
"ad" : {},
"oauth" : {
"weixin" : {
"appid" : "wx18808d86a1251e0b",
"appsecret" : "5bcae9d1e5da7cf6282675ba685f70a0",
"UniversalLinks" : "https://guan.chutang66.com/app/"
}
},
"payment" : {
"weixin" : {
"__platform__" : [ "ios", "android" ],
"appid" : "wx18808d86a1251e0b",
"UniversalLinks" : "https://guan.chutang66.com/app/"
},
"alipay" : {
"__platform__" : [ "ios", "android" ]
}
},
"share" : {
"weixin" : {
"appid" : "wx18808d86a1251e0b",
"UniversalLinks" : "https://guan.chutang66.com/app/"
}
},
"statics" : {}
},
"splashscreen" : {
"useOriginalMsgbox" : true,
"androidStyle" : "common"
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
},
"uniStatistics" : {
"enable" : false
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx73163c7bace1750b",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"mp-alipay" : {
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"mp-baidu" : {
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"mp-toutiao" : {
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"vueVersion" : "3",
"locale" : "zh-Hans",
"fallbackLocale" : "zh-Hans",
"h5": {
"devServer" : {
"host" : "127.0.0.1",
"port" : "8082",
"client" : {
"progress" : true,
"overlay" : false //
},
"proxy" : {
"/api" : {
"target" : "https://shop.chutang66.com/",
// "target": "https://shop.dev.chutang66.com/",
"changeOrigin" : true,
"pathRewrite": {
"^/api": "api"
}
}
}
},
"router" : {
"mode" : "hash",
"base" : "/web"
},
"title" : "春分有品直播",
"crossorigin": "anonymous",
"domainWhiteList": ["*.yx090.com"]
},
"mp-jd" : {
"uniStatistics" : {
"enable" : false
}
},
"mp-kuaishou" : {
"uniStatistics" : {
"enable" : false
}
},
"mp-lark" : {
"uniStatistics" : {
"enable" : false
}
},
"mp-qq" : {
"uniStatistics" : {
"enable" : false
}
},
"quickapp-webview-huawei" : {
"uniStatistics" : {
"enable" : false
}
},
"quickapp-webview-union" : {
"uniStatistics" : {
"enable" : false
}
}
}

15
node_modules/.bin/nanoid generated vendored Normal file
View File

@ -0,0 +1,15 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../nanoid/bin/nanoid.cjs" "$@"
ret=$?
else
node "$basedir/../nanoid/bin/nanoid.cjs" "$@"
ret=$?
fi
exit $ret

17
node_modules/.bin/nanoid.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
"%_prog%" "%dp0%\..\nanoid\bin\nanoid.cjs" %*
ENDLOCAL
EXIT /b %errorlevel%
:find_dp0
SET dp0=%~dp0
EXIT /b

18
node_modules/.bin/nanoid.ps1 generated vendored Normal file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
& "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
$ret=$LASTEXITCODE
} else {
& "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
$ret=$LASTEXITCODE
}
exit $ret

15
node_modules/.bin/parser generated vendored Normal file
View File

@ -0,0 +1,15 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../@babel/parser/bin/babel-parser.js" "$@"
ret=$?
else
node "$basedir/../@babel/parser/bin/babel-parser.js" "$@"
ret=$?
fi
exit $ret

17
node_modules/.bin/parser.cmd generated vendored Normal file
View File

@ -0,0 +1,17 @@
@ECHO off
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
"%_prog%" "%dp0%\..\@babel\parser\bin\babel-parser.js" %*
ENDLOCAL
EXIT /b %errorlevel%
:find_dp0
SET dp0=%~dp0
EXIT /b

18
node_modules/.bin/parser.ps1 generated vendored Normal file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
& "$basedir/node$exe" "$basedir/../@babel/parser/bin/babel-parser.js" $args
$ret=$LASTEXITCODE
} else {
& "node$exe" "$basedir/../@babel/parser/bin/babel-parser.js" $args
$ret=$LASTEXITCODE
}
exit $ret

22
node_modules/@babel/helper-string-parser/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

19
node_modules/@babel/helper-string-parser/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# @babel/helper-string-parser
> A utility package to parse strings
See our website [@babel/helper-string-parser](https://babeljs.io/docs/babel-helper-string-parser) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-string-parser
```
or using yarn:
```sh
yarn add @babel/helper-string-parser
```

295
node_modules/@babel/helper-string-parser/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,295 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.readCodePoint = readCodePoint;
exports.readInt = readInt;
exports.readStringContents = readStringContents;
var _isDigit = function isDigit(code) {
return code >= 48 && code <= 57;
};
const forbiddenNumericSeparatorSiblings = {
decBinOct: new Set([46, 66, 69, 79, 95, 98, 101, 111]),
hex: new Set([46, 88, 95, 120])
};
const isAllowedNumericSeparatorSibling = {
bin: ch => ch === 48 || ch === 49,
oct: ch => ch >= 48 && ch <= 55,
dec: ch => ch >= 48 && ch <= 57,
hex: ch => ch >= 48 && ch <= 57 || ch >= 65 && ch <= 70 || ch >= 97 && ch <= 102
};
function readStringContents(type, input, pos, lineStart, curLine, errors) {
const initialPos = pos;
const initialLineStart = lineStart;
const initialCurLine = curLine;
let out = "";
let firstInvalidLoc = null;
let chunkStart = pos;
const {
length
} = input;
for (;;) {
if (pos >= length) {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
out += input.slice(chunkStart, pos);
break;
}
const ch = input.charCodeAt(pos);
if (isStringEnd(type, ch, input, pos)) {
out += input.slice(chunkStart, pos);
break;
}
if (ch === 92) {
out += input.slice(chunkStart, pos);
const res = readEscapedChar(input, pos, lineStart, curLine, type === "template", errors);
if (res.ch === null && !firstInvalidLoc) {
firstInvalidLoc = {
pos,
lineStart,
curLine
};
} else {
out += res.ch;
}
({
pos,
lineStart,
curLine
} = res);
chunkStart = pos;
} else if (ch === 8232 || ch === 8233) {
++pos;
++curLine;
lineStart = pos;
} else if (ch === 10 || ch === 13) {
if (type === "template") {
out += input.slice(chunkStart, pos) + "\n";
++pos;
if (ch === 13 && input.charCodeAt(pos) === 10) {
++pos;
}
++curLine;
chunkStart = lineStart = pos;
} else {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
}
} else {
++pos;
}
}
return {
pos,
str: out,
firstInvalidLoc,
lineStart,
curLine,
containsInvalid: !!firstInvalidLoc
};
}
function isStringEnd(type, ch, input, pos) {
if (type === "template") {
return ch === 96 || ch === 36 && input.charCodeAt(pos + 1) === 123;
}
return ch === (type === "double" ? 34 : 39);
}
function readEscapedChar(input, pos, lineStart, curLine, inTemplate, errors) {
const throwOnInvalid = !inTemplate;
pos++;
const res = ch => ({
pos,
ch,
lineStart,
curLine
});
const ch = input.charCodeAt(pos++);
switch (ch) {
case 110:
return res("\n");
case 114:
return res("\r");
case 120:
{
let code;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 2, false, throwOnInvalid, errors));
return res(code === null ? null : String.fromCharCode(code));
}
case 117:
{
let code;
({
code,
pos
} = readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors));
return res(code === null ? null : String.fromCodePoint(code));
}
case 116:
return res("\t");
case 98:
return res("\b");
case 118:
return res("\u000b");
case 102:
return res("\f");
case 13:
if (input.charCodeAt(pos) === 10) {
++pos;
}
case 10:
lineStart = pos;
++curLine;
case 8232:
case 8233:
return res("");
case 56:
case 57:
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(pos - 1, lineStart, curLine);
}
default:
if (ch >= 48 && ch <= 55) {
const startPos = pos - 1;
const match = /^[0-7]+/.exec(input.slice(startPos, pos + 2));
let octalStr = match[0];
let octal = parseInt(octalStr, 8);
if (octal > 255) {
octalStr = octalStr.slice(0, -1);
octal = parseInt(octalStr, 8);
}
pos += octalStr.length - 1;
const next = input.charCodeAt(pos);
if (octalStr !== "0" || next === 56 || next === 57) {
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(startPos, lineStart, curLine);
}
}
return res(String.fromCharCode(octal));
}
return res(String.fromCharCode(ch));
}
}
function readHexChar(input, pos, lineStart, curLine, len, forceLen, throwOnInvalid, errors) {
const initialPos = pos;
let n;
({
n,
pos
} = readInt(input, pos, lineStart, curLine, 16, len, forceLen, false, errors, !throwOnInvalid));
if (n === null) {
if (throwOnInvalid) {
errors.invalidEscapeSequence(initialPos, lineStart, curLine);
} else {
pos = initialPos - 1;
}
}
return {
code: n,
pos
};
}
function readInt(input, pos, lineStart, curLine, radix, len, forceLen, allowNumSeparator, errors, bailOnError) {
const start = pos;
const forbiddenSiblings = radix === 16 ? forbiddenNumericSeparatorSiblings.hex : forbiddenNumericSeparatorSiblings.decBinOct;
const isAllowedSibling = radix === 16 ? isAllowedNumericSeparatorSibling.hex : radix === 10 ? isAllowedNumericSeparatorSibling.dec : radix === 8 ? isAllowedNumericSeparatorSibling.oct : isAllowedNumericSeparatorSibling.bin;
let invalid = false;
let total = 0;
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
const code = input.charCodeAt(pos);
let val;
if (code === 95 && allowNumSeparator !== "bail") {
const prev = input.charCodeAt(pos - 1);
const next = input.charCodeAt(pos + 1);
if (!allowNumSeparator) {
if (bailOnError) return {
n: null,
pos
};
errors.numericSeparatorInEscapeSequence(pos, lineStart, curLine);
} else if (Number.isNaN(next) || !isAllowedSibling(next) || forbiddenSiblings.has(prev) || forbiddenSiblings.has(next)) {
if (bailOnError) return {
n: null,
pos
};
errors.unexpectedNumericSeparator(pos, lineStart, curLine);
}
++pos;
continue;
}
if (code >= 97) {
val = code - 97 + 10;
} else if (code >= 65) {
val = code - 65 + 10;
} else if (_isDigit(code)) {
val = code - 48;
} else {
val = Infinity;
}
if (val >= radix) {
if (val <= 9 && bailOnError) {
return {
n: null,
pos
};
} else if (val <= 9 && errors.invalidDigit(pos, lineStart, curLine, radix)) {
val = 0;
} else if (forceLen) {
val = 0;
invalid = true;
} else {
break;
}
}
++pos;
total = total * radix + val;
}
if (pos === start || len != null && pos - start !== len || invalid) {
return {
n: null,
pos
};
}
return {
n: total,
pos
};
}
function readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors) {
const ch = input.charCodeAt(pos);
let code;
if (ch === 123) {
++pos;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, input.indexOf("}", pos) - pos, true, throwOnInvalid, errors));
++pos;
if (code !== null && code > 0x10ffff) {
if (throwOnInvalid) {
errors.invalidCodePoint(pos, lineStart, curLine);
} else {
return {
code: null,
pos
};
}
}
} else {
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 4, false, throwOnInvalid, errors));
}
return {
code,
pos
};
}
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

63
node_modules/@babel/helper-string-parser/package.json generated vendored Normal file
View File

@ -0,0 +1,63 @@
{
"_from": "@babel/helper-string-parser@^7.27.1",
"_id": "@babel/helper-string-parser@7.27.1",
"_inBundle": false,
"_integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"_location": "/@babel/helper-string-parser",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "@babel/helper-string-parser@^7.27.1",
"name": "@babel/helper-string-parser",
"escapedName": "@babel%2fhelper-string-parser",
"scope": "@babel",
"rawSpec": "^7.27.1",
"saveSpec": null,
"fetchSpec": "^7.27.1"
},
"_requiredBy": [
"/@babel/types"
],
"_resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"_shasum": "54da796097ab19ce67ed9f88b47bb2ec49367687",
"_spec": "@babel/helper-string-parser@^7.27.1",
"_where": "C:\\Users\\chunfen\\Documents\\HBuilderProjects\\shop_h5\\node_modules\\@babel\\types",
"author": {
"name": "The Babel Team",
"url": "https://babel.dev/team"
},
"bugs": {
"url": "https://github.com/babel/babel/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "A utility package to parse strings",
"devDependencies": {
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"homepage": "https://babel.dev/docs/en/next/babel-helper-string-parser",
"license": "MIT",
"main": "./lib/index.js",
"name": "@babel/helper-string-parser",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/babel/babel.git",
"directory": "packages/babel-helper-string-parser"
},
"type": "commonjs",
"version": "7.27.1"
}

View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,19 @@
# @babel/helper-validator-identifier
> Validate identifier/keywords name
See our website [@babel/helper-validator-identifier](https://babeljs.io/docs/babel-helper-validator-identifier) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-validator-identifier
```
or using yarn:
```sh
yarn add @babel/helper-validator-identifier
```

View File

@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isIdentifierChar = isIdentifierChar;
exports.isIdentifierName = isIdentifierName;
exports.isIdentifierStart = isIdentifierStart;
let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088f\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5c\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdc-\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7dc\ua7f1-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
let nonASCIIidentifierChars = "\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1add\u1ae0-\u1aeb\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65";
const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 7, 25, 39, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 5, 57, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 24, 43, 261, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 33, 24, 3, 24, 45, 74, 6, 0, 67, 12, 65, 1, 2, 0, 15, 4, 10, 7381, 42, 31, 98, 114, 8702, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 208, 30, 2, 2, 2, 1, 2, 6, 3, 4, 10, 1, 225, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4381, 3, 5773, 3, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 8489];
const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 78, 5, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 199, 7, 137, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 55, 9, 266, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 233, 0, 3, 0, 8, 1, 6, 0, 475, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
function isInAstralSet(code, set) {
let pos = 0x10000;
for (let i = 0, length = set.length; i < length; i += 2) {
pos += set[i];
if (pos > code) return false;
pos += set[i + 1];
if (pos >= code) return true;
}
return false;
}
function isIdentifierStart(code) {
if (code < 65) return code === 36;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes);
}
function isIdentifierChar(code) {
if (code < 48) return code === 36;
if (code < 58) return true;
if (code < 65) return false;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
}
function isIdentifierName(name) {
let isFirst = true;
for (let i = 0; i < name.length; i++) {
let cp = name.charCodeAt(i);
if ((cp & 0xfc00) === 0xd800 && i + 1 < name.length) {
const trail = name.charCodeAt(++i);
if ((trail & 0xfc00) === 0xdc00) {
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff);
}
}
if (isFirst) {
isFirst = false;
if (!isIdentifierStart(cp)) {
return false;
}
} else if (!isIdentifierChar(cp)) {
return false;
}
}
return !isFirst;
}
//# sourceMappingURL=identifier.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "isIdentifierChar", {
enumerable: true,
get: function () {
return _identifier.isIdentifierChar;
}
});
Object.defineProperty(exports, "isIdentifierName", {
enumerable: true,
get: function () {
return _identifier.isIdentifierName;
}
});
Object.defineProperty(exports, "isIdentifierStart", {
enumerable: true,
get: function () {
return _identifier.isIdentifierStart;
}
});
Object.defineProperty(exports, "isKeyword", {
enumerable: true,
get: function () {
return _keyword.isKeyword;
}
});
Object.defineProperty(exports, "isReservedWord", {
enumerable: true,
get: function () {
return _keyword.isReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindOnlyReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindReservedWord;
}
});
Object.defineProperty(exports, "isStrictReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictReservedWord;
}
});
var _identifier = require("./identifier.js");
var _keyword = require("./keyword.js");
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["_identifier","require","_keyword"],"sources":["../src/index.ts"],"sourcesContent":["export {\n isIdentifierName,\n isIdentifierChar,\n isIdentifierStart,\n} from \"./identifier.ts\";\nexport {\n isReservedWord,\n isStrictBindOnlyReservedWord,\n isStrictBindReservedWord,\n isStrictReservedWord,\n isKeyword,\n} from \"./keyword.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA","ignoreList":[]}

View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isKeyword = isKeyword;
exports.isReservedWord = isReservedWord;
exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
exports.isStrictBindReservedWord = isStrictBindReservedWord;
exports.isStrictReservedWord = isStrictReservedWord;
const reservedWords = {
keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
strictBind: ["eval", "arguments"]
};
const keywords = new Set(reservedWords.keyword);
const reservedWordsStrictSet = new Set(reservedWords.strict);
const reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
function isReservedWord(word, inModule) {
return inModule && word === "await" || word === "enum";
}
function isStrictReservedWord(word, inModule) {
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
}
function isStrictBindOnlyReservedWord(word) {
return reservedWordsStrictBindSet.has(word);
}
function isStrictBindReservedWord(word, inModule) {
return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
}
function isKeyword(word) {
return keywords.has(word);
}
//# sourceMappingURL=keyword.js.map

View File

@ -0,0 +1 @@
{"version":3,"names":["reservedWords","keyword","strict","strictBind","keywords","Set","reservedWordsStrictSet","reservedWordsStrictBindSet","isReservedWord","word","inModule","isStrictReservedWord","has","isStrictBindOnlyReservedWord","isStrictBindReservedWord","isKeyword"],"sources":["../src/keyword.ts"],"sourcesContent":["const reservedWords = {\n keyword: [\n \"break\",\n \"case\",\n \"catch\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"do\",\n \"else\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"return\",\n \"switch\",\n \"throw\",\n \"try\",\n \"var\",\n \"const\",\n \"while\",\n \"with\",\n \"new\",\n \"this\",\n \"super\",\n \"class\",\n \"extends\",\n \"export\",\n \"import\",\n \"null\",\n \"true\",\n \"false\",\n \"in\",\n \"instanceof\",\n \"typeof\",\n \"void\",\n \"delete\",\n ],\n strict: [\n \"implements\",\n \"interface\",\n \"let\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"static\",\n \"yield\",\n ],\n strictBind: [\"eval\", \"arguments\"],\n};\nconst keywords = new Set(reservedWords.keyword);\nconst reservedWordsStrictSet = new Set(reservedWords.strict);\nconst reservedWordsStrictBindSet = new Set(reservedWords.strictBind);\n\n/**\n * Checks if word is a reserved word in non-strict mode\n */\nexport function isReservedWord(word: string, inModule: boolean): boolean {\n return (inModule && word === \"await\") || word === \"enum\";\n}\n\n/**\n * Checks if word is a reserved word in non-binding strict mode\n *\n * Includes non-strict reserved words\n */\nexport function isStrictReservedWord(word: string, inModule: boolean): boolean {\n return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode, but it is allowed as\n * a normal identifier.\n */\nexport function isStrictBindOnlyReservedWord(word: string): boolean {\n return reservedWordsStrictBindSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode\n *\n * Includes non-strict reserved words and non-binding strict reserved words\n */\nexport function isStrictBindReservedWord(\n word: string,\n inModule: boolean,\n): boolean {\n return (\n isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word)\n );\n}\n\nexport function isKeyword(word: string): boolean {\n return keywords.has(word);\n}\n"],"mappings":";;;;;;;;;;AAAA,MAAMA,aAAa,GAAG;EACpBC,OAAO,EAAE,CACP,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,UAAU,EACV,SAAS,EACT,IAAI,EACJ,MAAM,EACN,SAAS,EACT,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,QAAQ,CACT;EACDC,MAAM,EAAE,CACN,YAAY,EACZ,WAAW,EACX,KAAK,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,CACR;EACDC,UAAU,EAAE,CAAC,MAAM,EAAE,WAAW;AAClC,CAAC;AACD,MAAMC,QAAQ,GAAG,IAAIC,GAAG,CAACL,aAAa,CAACC,OAAO,CAAC;AAC/C,MAAMK,sBAAsB,GAAG,IAAID,GAAG,CAACL,aAAa,CAACE,MAAM,CAAC;AAC5D,MAAMK,0BAA0B,GAAG,IAAIF,GAAG,CAACL,aAAa,CAACG,UAAU,CAAC;AAK7D,SAASK,cAAcA,CAACC,IAAY,EAAEC,QAAiB,EAAW;EACvE,OAAQA,QAAQ,IAAID,IAAI,KAAK,OAAO,IAAKA,IAAI,KAAK,MAAM;AAC1D;AAOO,SAASE,oBAAoBA,CAACF,IAAY,EAAEC,QAAiB,EAAW;EAC7E,OAAOF,cAAc,CAACC,IAAI,EAAEC,QAAQ,CAAC,IAAIJ,sBAAsB,CAACM,GAAG,CAACH,IAAI,CAAC;AAC3E;AAMO,SAASI,4BAA4BA,CAACJ,IAAY,EAAW;EAClE,OAAOF,0BAA0B,CAACK,GAAG,CAACH,IAAI,CAAC;AAC7C;AAOO,SAASK,wBAAwBA,CACtCL,IAAY,EACZC,QAAiB,EACR;EACT,OACEC,oBAAoB,CAACF,IAAI,EAAEC,QAAQ,CAAC,IAAIG,4BAA4B,CAACJ,IAAI,CAAC;AAE9E;AAEO,SAASM,SAASA,CAACN,IAAY,EAAW;EAC/C,OAAOL,QAAQ,CAACQ,GAAG,CAACH,IAAI,CAAC;AAC3B","ignoreList":[]}

View File

@ -0,0 +1,64 @@
{
"_from": "@babel/helper-validator-identifier@^7.28.5",
"_id": "@babel/helper-validator-identifier@7.28.5",
"_inBundle": false,
"_integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"_location": "/@babel/helper-validator-identifier",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "@babel/helper-validator-identifier@^7.28.5",
"name": "@babel/helper-validator-identifier",
"escapedName": "@babel%2fhelper-validator-identifier",
"scope": "@babel",
"rawSpec": "^7.28.5",
"saveSpec": null,
"fetchSpec": "^7.28.5"
},
"_requiredBy": [
"/@babel/types"
],
"_resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"_shasum": "010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4",
"_spec": "@babel/helper-validator-identifier@^7.28.5",
"_where": "C:\\Users\\chunfen\\Documents\\HBuilderProjects\\shop_h5\\node_modules\\@babel\\types",
"author": {
"name": "The Babel Team",
"url": "https://babel.dev/team"
},
"bugs": {
"url": "https://github.com/babel/babel/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Validate identifier/keywords name",
"devDependencies": {
"@unicode/unicode-17.0.0": "^1.6.10",
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"homepage": "https://github.com/babel/babel#readme",
"license": "MIT",
"main": "./lib/index.js",
"name": "@babel/helper-validator-identifier",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/babel/babel.git",
"directory": "packages/babel-helper-validator-identifier"
},
"type": "commonjs",
"version": "7.28.5"
}

1073
node_modules/@babel/parser/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

19
node_modules/@babel/parser/LICENSE generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (C) 2012-2014 by various contributors (see AUTHORS)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

19
node_modules/@babel/parser/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# @babel/parser
> A JavaScript parser
See our website [@babel/parser](https://babeljs.io/docs/babel-parser) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20parser%22+is%3Aopen) associated with this package.
## Install
Using npm:
```sh
npm install --save-dev @babel/parser
```
or using yarn:
```sh
yarn add @babel/parser --dev
```

14662
node_modules/@babel/parser/lib/index.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

1
node_modules/@babel/parser/lib/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

84
node_modules/@babel/parser/package.json generated vendored Normal file
View File

@ -0,0 +1,84 @@
{
"# dependencies": "This package doesn't actually have runtime dependencies. @babel/types is only needed for type definitions.",
"_from": "@babel/parser@^7.28.5",
"_id": "@babel/parser@7.28.5",
"_inBundle": false,
"_integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
"_location": "/@babel/parser",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "@babel/parser@^7.28.5",
"name": "@babel/parser",
"escapedName": "@babel%2fparser",
"scope": "@babel",
"rawSpec": "^7.28.5",
"saveSpec": null,
"fetchSpec": "^7.28.5"
},
"_requiredBy": [
"/@vue/compiler-core",
"/@vue/compiler-sfc"
],
"_resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz",
"_shasum": "0b0225ee90362f030efd644e8034c99468893b08",
"_spec": "@babel/parser@^7.28.5",
"_where": "C:\\Users\\chunfen\\Documents\\HBuilderProjects\\shop_h5\\node_modules\\@vue\\compiler-core",
"author": {
"name": "The Babel Team",
"url": "https://babel.dev/team"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"bugs": {
"url": "https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A+parser+%28babylon%29%22+is%3Aopen"
},
"bundleDependencies": false,
"dependencies": {
"@babel/types": "^7.28.5"
},
"deprecated": false,
"description": "A JavaScript parser",
"devDependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/helper-check-duplicate-nodes": "^7.27.1",
"@babel/helper-fixtures": "^7.28.0",
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5",
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.0.0"
},
"files": [
"bin",
"lib",
"typings/babel-parser.d.ts",
"index.cjs"
],
"homepage": "https://babel.dev/docs/en/next/babel-parser",
"keywords": [
"babel",
"javascript",
"parser",
"tc39",
"ecmascript",
"@babel/parser"
],
"license": "MIT",
"main": "./lib/index.js",
"name": "@babel/parser",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/babel/babel.git",
"directory": "packages/babel-parser"
},
"type": "commonjs",
"types": "./typings/babel-parser.d.ts",
"version": "7.28.5"
}

262
node_modules/@babel/parser/typings/babel-parser.d.ts generated vendored Normal file
View File

@ -0,0 +1,262 @@
// This file is auto-generated! Do not modify it directly.
// Run `yarn gulp bundle-dts` to re-generate it.
/* eslint-disable @typescript-eslint/consistent-type-imports, @typescript-eslint/no-redundant-type-constituents */
import { File, Expression } from '@babel/types';
declare class Position {
line: number;
column: number;
index: number;
constructor(line: number, col: number, index: number);
}
type SyntaxPlugin = "flow" | "typescript" | "jsx" | "pipelineOperator" | "placeholders";
type ParseErrorCode = "BABEL_PARSER_SYNTAX_ERROR" | "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED";
interface ParseErrorSpecification<ErrorDetails> {
code: ParseErrorCode;
reasonCode: string;
syntaxPlugin?: SyntaxPlugin;
missingPlugin?: string | string[];
loc: Position;
details: ErrorDetails;
pos: number;
}
type ParseError$1<ErrorDetails> = SyntaxError & ParseErrorSpecification<ErrorDetails>;
type BABEL_8_BREAKING = false;
type IF_BABEL_7<V> = false extends BABEL_8_BREAKING ? V : never;
type Plugin$1 =
| "asyncDoExpressions"
| IF_BABEL_7<"asyncGenerators">
| IF_BABEL_7<"bigInt">
| IF_BABEL_7<"classPrivateMethods">
| IF_BABEL_7<"classPrivateProperties">
| IF_BABEL_7<"classProperties">
| IF_BABEL_7<"classStaticBlock">
| IF_BABEL_7<"decimal">
| "decorators-legacy"
| "deferredImportEvaluation"
| "decoratorAutoAccessors"
| "destructuringPrivate"
| "deprecatedImportAssert"
| "doExpressions"
| IF_BABEL_7<"dynamicImport">
| IF_BABEL_7<"explicitResourceManagement">
| "exportDefaultFrom"
| IF_BABEL_7<"exportNamespaceFrom">
| "flow"
| "flowComments"
| "functionBind"
| "functionSent"
| "importMeta"
| "jsx"
| IF_BABEL_7<"jsonStrings">
| IF_BABEL_7<"logicalAssignment">
| IF_BABEL_7<"importAssertions">
| IF_BABEL_7<"importReflection">
| "moduleBlocks"
| IF_BABEL_7<"moduleStringNames">
| IF_BABEL_7<"nullishCoalescingOperator">
| IF_BABEL_7<"numericSeparator">
| IF_BABEL_7<"objectRestSpread">
| IF_BABEL_7<"optionalCatchBinding">
| IF_BABEL_7<"optionalChaining">
| "partialApplication"
| "placeholders"
| IF_BABEL_7<"privateIn">
| IF_BABEL_7<"regexpUnicodeSets">
| "sourcePhaseImports"
| "throwExpressions"
| IF_BABEL_7<"topLevelAwait">
| "v8intrinsic"
| ParserPluginWithOptions[0];
type ParserPluginWithOptions =
| ["decorators", DecoratorsPluginOptions]
| ["discardBinding", { syntaxType: "void" }]
| ["estree", { classFeatures?: boolean }]
| IF_BABEL_7<["importAttributes", { deprecatedAssertSyntax: boolean }]>
| IF_BABEL_7<["moduleAttributes", { version: "may-2020" }]>
| ["optionalChainingAssign", { version: "2023-07" }]
| ["pipelineOperator", PipelineOperatorPluginOptions]
| ["recordAndTuple", RecordAndTuplePluginOptions]
| ["flow", FlowPluginOptions]
| ["typescript", TypeScriptPluginOptions];
type PluginConfig = Plugin$1 | ParserPluginWithOptions;
interface DecoratorsPluginOptions {
decoratorsBeforeExport?: boolean;
allowCallParenthesized?: boolean;
}
interface PipelineOperatorPluginOptions {
proposal: BABEL_8_BREAKING extends false
? "minimal" | "fsharp" | "hack" | "smart"
: "fsharp" | "hack";
topicToken?: "%" | "#" | "@@" | "^^" | "^";
}
interface RecordAndTuplePluginOptions {
syntaxType: "bar" | "hash";
}
type FlowPluginOptions = BABEL_8_BREAKING extends true
? {
all?: boolean;
enums?: boolean;
}
: {
all?: boolean;
};
interface TypeScriptPluginOptions {
dts?: boolean;
disallowAmbiguousJSXLike?: boolean;
}
type Plugin = PluginConfig;
type SourceType = "script" | "commonjs" | "module" | "unambiguous";
interface Options {
/**
* By default, import and export declarations can only appear at a program's top level.
* Setting this option to true allows them anywhere where a statement is allowed.
*/
allowImportExportEverywhere?: boolean;
/**
* By default, await use is not allowed outside of an async function.
* Set this to true to accept such code.
*/
allowAwaitOutsideFunction?: boolean;
/**
* By default, a return statement at the top level raises an error.
* Set this to true to accept such code.
*/
allowReturnOutsideFunction?: boolean;
/**
* By default, new.target use is not allowed outside of a function or class.
* Set this to true to accept such code.
*/
allowNewTargetOutsideFunction?: boolean;
/**
* By default, super calls are not allowed outside of a method.
* Set this to true to accept such code.
*/
allowSuperOutsideMethod?: boolean;
/**
* By default, exported identifiers must refer to a declared variable.
* Set this to true to allow export statements to reference undeclared variables.
*/
allowUndeclaredExports?: boolean;
/**
* By default, yield use is not allowed outside of a generator function.
* Set this to true to accept such code.
*/
allowYieldOutsideFunction?: boolean;
/**
* By default, Babel parser JavaScript code according to Annex B syntax.
* Set this to `false` to disable such behavior.
*/
annexB?: boolean;
/**
* By default, Babel attaches comments to adjacent AST nodes.
* When this option is set to false, comments are not attached.
* It can provide up to 30% performance improvement when the input code has many comments.
* @babel/eslint-parser will set it for you.
* It is not recommended to use attachComment: false with Babel transform,
* as doing so removes all the comments in output code, and renders annotations such as
* /* istanbul ignore next *\/ nonfunctional.
*/
attachComment?: boolean;
/**
* By default, Babel always throws an error when it finds some invalid code.
* When this option is set to true, it will store the parsing error and
* try to continue parsing the invalid input file.
*/
errorRecovery?: boolean;
/**
* Indicate the mode the code should be parsed in.
* Can be one of "script", "commonjs", "module", or "unambiguous". Defaults to "script".
* "unambiguous" will make @babel/parser attempt to guess, based on the presence
* of ES6 import or export statements.
* Files with ES6 imports and exports are considered "module" and are otherwise "script".
*
* Use "commonjs" to parse code that is intended to be run in a CommonJS environment such as Node.js.
*/
sourceType?: SourceType;
/**
* Correlate output AST nodes with their source filename.
* Useful when generating code and source maps from the ASTs of multiple input files.
*/
sourceFilename?: string;
/**
* By default, all source indexes start from 0.
* You can provide a start index to alternatively start with.
* Useful for integration with other source tools.
*/
startIndex?: number;
/**
* By default, the first line of code parsed is treated as line 1.
* You can provide a line number to alternatively start with.
* Useful for integration with other source tools.
*/
startLine?: number;
/**
* By default, the parsed code is treated as if it starts from line 1, column 0.
* You can provide a column number to alternatively start with.
* Useful for integration with other source tools.
*/
startColumn?: number;
/**
* Array containing the plugins that you want to enable.
*/
plugins?: Plugin[];
/**
* Should the parser work in strict mode.
* Defaults to true if sourceType === 'module'. Otherwise, false.
*/
strictMode?: boolean;
/**
* Adds a ranges property to each node: [node.start, node.end]
*/
ranges?: boolean;
/**
* Adds all parsed tokens to a tokens property on the File node.
*/
tokens?: boolean;
/**
* By default, the parser adds information about parentheses by setting
* `extra.parenthesized` to `true` as needed.
* When this option is `true` the parser creates `ParenthesizedExpression`
* AST nodes instead of using the `extra` property.
*/
createParenthesizedExpressions?: boolean;
/**
* The default is false in Babel 7 and true in Babel 8
* Set this to true to parse it as an `ImportExpression` node.
* Otherwise `import(foo)` is parsed as `CallExpression(Import, [Identifier(foo)])`.
*/
createImportExpressions?: boolean;
}
type ParserOptions = Partial<Options>;
type ParseError = ParseError$1<object>;
type ParseResult<Result extends File | Expression = File> = Result & {
comments: File["comments"];
errors: null | ParseError[];
tokens?: File["tokens"];
};
/**
* Parse the provided code as an entire ECMAScript program.
*/
declare function parse(input: string, options?: ParserOptions): ParseResult<File>;
declare function parseExpression(input: string, options?: ParserOptions): ParseResult<Expression>;
declare const tokTypes: {
// todo(flow->ts) real token type
[name: string]: any;
};
export { DecoratorsPluginOptions, FlowPluginOptions, ParseError, ParseResult, ParserOptions, PluginConfig as ParserPlugin, ParserPluginWithOptions, PipelineOperatorPluginOptions, RecordAndTuplePluginOptions, TypeScriptPluginOptions, parse, parseExpression, tokTypes };

22
node_modules/@babel/runtime/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

19
node_modules/@babel/runtime/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# @babel/runtime
> babel's modular runtime helpers
See our website [@babel/runtime](https://babeljs.io/docs/babel-runtime) for more information.
## Install
Using npm:
```sh
npm install --save @babel/runtime
```
or using yarn:
```sh
yarn add @babel/runtime
```

4
node_modules/@babel/runtime/helpers/AwaitValue.js generated vendored Normal file
View File

@ -0,0 +1,4 @@
function _AwaitValue(t) {
this.wrapped = t;
}
module.exports = _AwaitValue, module.exports.__esModule = true, module.exports["default"] = module.exports;

4
node_modules/@babel/runtime/helpers/OverloadYield.js generated vendored Normal file
View File

@ -0,0 +1,4 @@
function _OverloadYield(e, d) {
this.v = e, this.k = d;
}
module.exports = _OverloadYield, module.exports.__esModule = true, module.exports["default"] = module.exports;

View File

@ -0,0 +1,9 @@
function _applyDecoratedDescriptor(i, e, r, n, l) {
var a = {};
return Object.keys(n).forEach(function (i) {
a[i] = n[i];
}), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function (r, n) {
return n(i, e, r) || r;
}, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a;
}
module.exports = _applyDecoratedDescriptor, module.exports.__esModule = true, module.exports["default"] = module.exports;

236
node_modules/@babel/runtime/helpers/applyDecs.js generated vendored Normal file
View File

@ -0,0 +1,236 @@
var _typeof = require("./typeof.js")["default"];
var setFunctionName = require("./setFunctionName.js");
var toPropertyKey = require("./toPropertyKey.js");
function old_createMetadataMethodsForProperty(e, t, a, r) {
return {
getMetadata: function getMetadata(o) {
old_assertNotFinished(r, "getMetadata"), old_assertMetadataKey(o);
var i = e[o];
if (void 0 !== i) if (1 === t) {
var n = i["public"];
if (void 0 !== n) return n[a];
} else if (2 === t) {
var l = i["private"];
if (void 0 !== l) return l.get(a);
} else if (Object.hasOwnProperty.call(i, "constructor")) return i.constructor;
},
setMetadata: function setMetadata(o, i) {
old_assertNotFinished(r, "setMetadata"), old_assertMetadataKey(o);
var n = e[o];
if (void 0 === n && (n = e[o] = {}), 1 === t) {
var l = n["public"];
void 0 === l && (l = n["public"] = {}), l[a] = i;
} else if (2 === t) {
var s = n.priv;
void 0 === s && (s = n["private"] = new Map()), s.set(a, i);
} else n.constructor = i;
}
};
}
function old_convertMetadataMapToFinal(e, t) {
var a = e[Symbol.metadata || Symbol["for"]("Symbol.metadata")],
r = Object.getOwnPropertySymbols(t);
if (0 !== r.length) {
for (var o = 0; o < r.length; o++) {
var i = r[o],
n = t[i],
l = a ? a[i] : null,
s = n["public"],
c = l ? l["public"] : null;
s && c && Object.setPrototypeOf(s, c);
var d = n["private"];
if (d) {
var u = Array.from(d.values()),
f = l ? l["private"] : null;
f && (u = u.concat(f)), n["private"] = u;
}
l && Object.setPrototypeOf(n, l);
}
a && Object.setPrototypeOf(t, a), e[Symbol.metadata || Symbol["for"]("Symbol.metadata")] = t;
}
}
function old_createAddInitializerMethod(e, t) {
return function (a) {
old_assertNotFinished(t, "addInitializer"), old_assertCallable(a, "An initializer"), e.push(a);
};
}
function old_memberDec(e, t, a, r, o, i, n, l, s) {
var c;
switch (i) {
case 1:
c = "accessor";
break;
case 2:
c = "method";
break;
case 3:
c = "getter";
break;
case 4:
c = "setter";
break;
default:
c = "field";
}
var d,
u,
f = {
kind: c,
name: l ? "#" + t : toPropertyKey(t),
isStatic: n,
isPrivate: l
},
p = {
v: !1
};
if (0 !== i && (f.addInitializer = old_createAddInitializerMethod(o, p)), l) {
d = 2, u = Symbol(t);
var v = {};
0 === i ? (v.get = a.get, v.set = a.set) : 2 === i ? v.get = function () {
return a.value;
} : (1 !== i && 3 !== i || (v.get = function () {
return a.get.call(this);
}), 1 !== i && 4 !== i || (v.set = function (e) {
a.set.call(this, e);
})), f.access = v;
} else d = 1, u = t;
try {
return e(s, Object.assign(f, old_createMetadataMethodsForProperty(r, d, u, p)));
} finally {
p.v = !0;
}
}
function old_assertNotFinished(e, t) {
if (e.v) throw Error("attempted to call " + t + " after decoration was finished");
}
function old_assertMetadataKey(e) {
if ("symbol" != _typeof(e)) throw new TypeError("Metadata keys must be symbols, received: " + e);
}
function old_assertCallable(e, t) {
if ("function" != typeof e) throw new TypeError(t + " must be a function");
}
function old_assertValidReturnValue(e, t) {
var a = _typeof(t);
if (1 === e) {
if ("object" !== a || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
void 0 !== t.get && old_assertCallable(t.get, "accessor.get"), void 0 !== t.set && old_assertCallable(t.set, "accessor.set"), void 0 !== t.init && old_assertCallable(t.init, "accessor.init"), void 0 !== t.initializer && old_assertCallable(t.initializer, "accessor.initializer");
} else if ("function" !== a) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
}
function old_getInit(e) {
var t;
return null == (t = e.init) && (t = e.initializer) && void 0 !== console && console.warn(".initializer has been renamed to .init as of March 2022"), t;
}
function old_applyMemberDec(e, t, a, r, o, i, n, l, s) {
var c,
d,
u,
f,
p,
v,
y,
h = a[0];
if (n ? (0 === o || 1 === o ? (c = {
get: a[3],
set: a[4]
}, u = "get") : 3 === o ? (c = {
get: a[3]
}, u = "get") : 4 === o ? (c = {
set: a[3]
}, u = "set") : c = {
value: a[3]
}, 0 !== o && (1 === o && setFunctionName(a[4], "#" + r, "set"), setFunctionName(a[3], "#" + r, u))) : 0 !== o && (c = Object.getOwnPropertyDescriptor(t, r)), 1 === o ? f = {
get: c.get,
set: c.set
} : 2 === o ? f = c.value : 3 === o ? f = c.get : 4 === o && (f = c.set), "function" == typeof h) void 0 !== (p = old_memberDec(h, r, c, l, s, o, i, n, f)) && (old_assertValidReturnValue(o, p), 0 === o ? d = p : 1 === o ? (d = old_getInit(p), v = p.get || f.get, y = p.set || f.set, f = {
get: v,
set: y
}) : f = p);else for (var m = h.length - 1; m >= 0; m--) {
var b;
void 0 !== (p = old_memberDec(h[m], r, c, l, s, o, i, n, f)) && (old_assertValidReturnValue(o, p), 0 === o ? b = p : 1 === o ? (b = old_getInit(p), v = p.get || f.get, y = p.set || f.set, f = {
get: v,
set: y
}) : f = p, void 0 !== b && (void 0 === d ? d = b : "function" == typeof d ? d = [d, b] : d.push(b)));
}
if (0 === o || 1 === o) {
if (void 0 === d) d = function d(e, t) {
return t;
};else if ("function" != typeof d) {
var g = d;
d = function d(e, t) {
for (var a = t, r = 0; r < g.length; r++) a = g[r].call(e, a);
return a;
};
} else {
var _ = d;
d = function d(e, t) {
return _.call(e, t);
};
}
e.push(d);
}
0 !== o && (1 === o ? (c.get = f.get, c.set = f.set) : 2 === o ? c.value = f : 3 === o ? c.get = f : 4 === o && (c.set = f), n ? 1 === o ? (e.push(function (e, t) {
return f.get.call(e, t);
}), e.push(function (e, t) {
return f.set.call(e, t);
})) : 2 === o ? e.push(f) : e.push(function (e, t) {
return f.call(e, t);
}) : Object.defineProperty(t, r, c));
}
function old_applyMemberDecs(e, t, a, r, o) {
for (var i, n, l = new Map(), s = new Map(), c = 0; c < o.length; c++) {
var d = o[c];
if (Array.isArray(d)) {
var u,
f,
p,
v = d[1],
y = d[2],
h = d.length > 3,
m = v >= 5;
if (m ? (u = t, f = r, 0 != (v -= 5) && (p = n = n || [])) : (u = t.prototype, f = a, 0 !== v && (p = i = i || [])), 0 !== v && !h) {
var b = m ? s : l,
g = b.get(y) || 0;
if (!0 === g || 3 === g && 4 !== v || 4 === g && 3 !== v) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + y);
!g && v > 2 ? b.set(y, v) : b.set(y, !0);
}
old_applyMemberDec(e, u, d, y, v, m, h, f, p);
}
}
old_pushInitializers(e, i), old_pushInitializers(e, n);
}
function old_pushInitializers(e, t) {
t && e.push(function (e) {
for (var a = 0; a < t.length; a++) t[a].call(e);
return e;
});
}
function old_applyClassDecs(e, t, a, r) {
if (r.length > 0) {
for (var o = [], i = t, n = t.name, l = r.length - 1; l >= 0; l--) {
var s = {
v: !1
};
try {
var c = Object.assign({
kind: "class",
name: n,
addInitializer: old_createAddInitializerMethod(o, s)
}, old_createMetadataMethodsForProperty(a, 0, n, s)),
d = r[l](i, c);
} finally {
s.v = !0;
}
void 0 !== d && (old_assertValidReturnValue(10, d), i = d);
}
e.push(i, function () {
for (var e = 0; e < o.length; e++) o[e].call(i);
});
}
}
function applyDecs(e, t, a) {
var r = [],
o = {},
i = {};
return old_applyMemberDecs(r, e, i, o, t), old_convertMetadataMapToFinal(e.prototype, i), old_applyClassDecs(r, e, o, a), old_convertMetadataMapToFinal(e, o), r;
}
module.exports = applyDecs, module.exports.__esModule = true, module.exports["default"] = module.exports;

184
node_modules/@babel/runtime/helpers/applyDecs2203.js generated vendored Normal file
View File

@ -0,0 +1,184 @@
var _typeof = require("./typeof.js")["default"];
function applyDecs2203Factory() {
function createAddInitializerMethod(e, t) {
return function (r) {
!function (e, t) {
if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
}(t), assertCallable(r, "An initializer"), e.push(r);
};
}
function memberDec(e, t, r, a, n, i, s, o) {
var c;
switch (n) {
case 1:
c = "accessor";
break;
case 2:
c = "method";
break;
case 3:
c = "getter";
break;
case 4:
c = "setter";
break;
default:
c = "field";
}
var l,
u,
f = {
kind: c,
name: s ? "#" + t : t,
"static": i,
"private": s
},
p = {
v: !1
};
0 !== n && (f.addInitializer = createAddInitializerMethod(a, p)), 0 === n ? s ? (l = r.get, u = r.set) : (l = function l() {
return this[t];
}, u = function u(e) {
this[t] = e;
}) : 2 === n ? l = function l() {
return r.value;
} : (1 !== n && 3 !== n || (l = function l() {
return r.get.call(this);
}), 1 !== n && 4 !== n || (u = function u(e) {
r.set.call(this, e);
})), f.access = l && u ? {
get: l,
set: u
} : l ? {
get: l
} : {
set: u
};
try {
return e(o, f);
} finally {
p.v = !0;
}
}
function assertCallable(e, t) {
if ("function" != typeof e) throw new TypeError(t + " must be a function");
}
function assertValidReturnValue(e, t) {
var r = _typeof(t);
if (1 === e) {
if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
} else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
}
function applyMemberDec(e, t, r, a, n, i, s, o) {
var c,
l,
u,
f,
p,
d,
h = r[0];
if (s ? c = 0 === n || 1 === n ? {
get: r[3],
set: r[4]
} : 3 === n ? {
get: r[3]
} : 4 === n ? {
set: r[3]
} : {
value: r[3]
} : 0 !== n && (c = Object.getOwnPropertyDescriptor(t, a)), 1 === n ? u = {
get: c.get,
set: c.set
} : 2 === n ? u = c.value : 3 === n ? u = c.get : 4 === n && (u = c.set), "function" == typeof h) void 0 !== (f = memberDec(h, a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? l = f : 1 === n ? (l = f.init, p = f.get || u.get, d = f.set || u.set, u = {
get: p,
set: d
}) : u = f);else for (var v = h.length - 1; v >= 0; v--) {
var g;
void 0 !== (f = memberDec(h[v], a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? g = f : 1 === n ? (g = f.init, p = f.get || u.get, d = f.set || u.set, u = {
get: p,
set: d
}) : u = f, void 0 !== g && (void 0 === l ? l = g : "function" == typeof l ? l = [l, g] : l.push(g)));
}
if (0 === n || 1 === n) {
if (void 0 === l) l = function l(e, t) {
return t;
};else if ("function" != typeof l) {
var y = l;
l = function l(e, t) {
for (var r = t, a = 0; a < y.length; a++) r = y[a].call(e, r);
return r;
};
} else {
var m = l;
l = function l(e, t) {
return m.call(e, t);
};
}
e.push(l);
}
0 !== n && (1 === n ? (c.get = u.get, c.set = u.set) : 2 === n ? c.value = u : 3 === n ? c.get = u : 4 === n && (c.set = u), s ? 1 === n ? (e.push(function (e, t) {
return u.get.call(e, t);
}), e.push(function (e, t) {
return u.set.call(e, t);
})) : 2 === n ? e.push(u) : e.push(function (e, t) {
return u.call(e, t);
}) : Object.defineProperty(t, a, c));
}
function pushInitializers(e, t) {
t && e.push(function (e) {
for (var r = 0; r < t.length; r++) t[r].call(e);
return e;
});
}
return function (e, t, r) {
var a = [];
return function (e, t, r) {
for (var a, n, i = new Map(), s = new Map(), o = 0; o < r.length; o++) {
var c = r[o];
if (Array.isArray(c)) {
var l,
u,
f = c[1],
p = c[2],
d = c.length > 3,
h = f >= 5;
if (h ? (l = t, 0 != (f -= 5) && (u = n = n || [])) : (l = t.prototype, 0 !== f && (u = a = a || [])), 0 !== f && !d) {
var v = h ? s : i,
g = v.get(p) || 0;
if (!0 === g || 3 === g && 4 !== f || 4 === g && 3 !== f) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + p);
!g && f > 2 ? v.set(p, f) : v.set(p, !0);
}
applyMemberDec(e, l, c, p, f, h, d, u);
}
}
pushInitializers(e, a), pushInitializers(e, n);
}(a, e, t), function (e, t, r) {
if (r.length > 0) {
for (var a = [], n = t, i = t.name, s = r.length - 1; s >= 0; s--) {
var o = {
v: !1
};
try {
var c = r[s](n, {
kind: "class",
name: i,
addInitializer: createAddInitializerMethod(a, o)
});
} finally {
o.v = !0;
}
void 0 !== c && (assertValidReturnValue(10, c), n = c);
}
e.push(n, function () {
for (var e = 0; e < a.length; e++) a[e].call(n);
});
}
}(a, e, r), a;
};
}
var applyDecs2203Impl;
function applyDecs2203(e, t, r) {
return (applyDecs2203Impl = applyDecs2203Impl || applyDecs2203Factory())(e, t, r);
}
module.exports = applyDecs2203, module.exports.__esModule = true, module.exports["default"] = module.exports;

191
node_modules/@babel/runtime/helpers/applyDecs2203R.js generated vendored Normal file
View File

@ -0,0 +1,191 @@
var _typeof = require("./typeof.js")["default"];
var setFunctionName = require("./setFunctionName.js");
var toPropertyKey = require("./toPropertyKey.js");
function applyDecs2203RFactory() {
function createAddInitializerMethod(e, t) {
return function (r) {
!function (e, t) {
if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
}(t), assertCallable(r, "An initializer"), e.push(r);
};
}
function memberDec(e, t, r, n, a, i, o, s) {
var c;
switch (a) {
case 1:
c = "accessor";
break;
case 2:
c = "method";
break;
case 3:
c = "getter";
break;
case 4:
c = "setter";
break;
default:
c = "field";
}
var l,
u,
f = {
kind: c,
name: o ? "#" + t : toPropertyKey(t),
"static": i,
"private": o
},
p = {
v: !1
};
0 !== a && (f.addInitializer = createAddInitializerMethod(n, p)), 0 === a ? o ? (l = r.get, u = r.set) : (l = function l() {
return this[t];
}, u = function u(e) {
this[t] = e;
}) : 2 === a ? l = function l() {
return r.value;
} : (1 !== a && 3 !== a || (l = function l() {
return r.get.call(this);
}), 1 !== a && 4 !== a || (u = function u(e) {
r.set.call(this, e);
})), f.access = l && u ? {
get: l,
set: u
} : l ? {
get: l
} : {
set: u
};
try {
return e(s, f);
} finally {
p.v = !0;
}
}
function assertCallable(e, t) {
if ("function" != typeof e) throw new TypeError(t + " must be a function");
}
function assertValidReturnValue(e, t) {
var r = _typeof(t);
if (1 === e) {
if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
} else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
}
function applyMemberDec(e, t, r, n, a, i, o, s) {
var c,
l,
u,
f,
p,
d,
h,
v = r[0];
if (o ? (0 === a || 1 === a ? (c = {
get: r[3],
set: r[4]
}, u = "get") : 3 === a ? (c = {
get: r[3]
}, u = "get") : 4 === a ? (c = {
set: r[3]
}, u = "set") : c = {
value: r[3]
}, 0 !== a && (1 === a && setFunctionName(r[4], "#" + n, "set"), setFunctionName(r[3], "#" + n, u))) : 0 !== a && (c = Object.getOwnPropertyDescriptor(t, n)), 1 === a ? f = {
get: c.get,
set: c.set
} : 2 === a ? f = c.value : 3 === a ? f = c.get : 4 === a && (f = c.set), "function" == typeof v) void 0 !== (p = memberDec(v, n, c, s, a, i, o, f)) && (assertValidReturnValue(a, p), 0 === a ? l = p : 1 === a ? (l = p.init, d = p.get || f.get, h = p.set || f.set, f = {
get: d,
set: h
}) : f = p);else for (var g = v.length - 1; g >= 0; g--) {
var y;
void 0 !== (p = memberDec(v[g], n, c, s, a, i, o, f)) && (assertValidReturnValue(a, p), 0 === a ? y = p : 1 === a ? (y = p.init, d = p.get || f.get, h = p.set || f.set, f = {
get: d,
set: h
}) : f = p, void 0 !== y && (void 0 === l ? l = y : "function" == typeof l ? l = [l, y] : l.push(y)));
}
if (0 === a || 1 === a) {
if (void 0 === l) l = function l(e, t) {
return t;
};else if ("function" != typeof l) {
var m = l;
l = function l(e, t) {
for (var r = t, n = 0; n < m.length; n++) r = m[n].call(e, r);
return r;
};
} else {
var b = l;
l = function l(e, t) {
return b.call(e, t);
};
}
e.push(l);
}
0 !== a && (1 === a ? (c.get = f.get, c.set = f.set) : 2 === a ? c.value = f : 3 === a ? c.get = f : 4 === a && (c.set = f), o ? 1 === a ? (e.push(function (e, t) {
return f.get.call(e, t);
}), e.push(function (e, t) {
return f.set.call(e, t);
})) : 2 === a ? e.push(f) : e.push(function (e, t) {
return f.call(e, t);
}) : Object.defineProperty(t, n, c));
}
function applyMemberDecs(e, t) {
for (var r, n, a = [], i = new Map(), o = new Map(), s = 0; s < t.length; s++) {
var c = t[s];
if (Array.isArray(c)) {
var l,
u,
f = c[1],
p = c[2],
d = c.length > 3,
h = f >= 5;
if (h ? (l = e, 0 != (f -= 5) && (u = n = n || [])) : (l = e.prototype, 0 !== f && (u = r = r || [])), 0 !== f && !d) {
var v = h ? o : i,
g = v.get(p) || 0;
if (!0 === g || 3 === g && 4 !== f || 4 === g && 3 !== f) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + p);
!g && f > 2 ? v.set(p, f) : v.set(p, !0);
}
applyMemberDec(a, l, c, p, f, h, d, u);
}
}
return pushInitializers(a, r), pushInitializers(a, n), a;
}
function pushInitializers(e, t) {
t && e.push(function (e) {
for (var r = 0; r < t.length; r++) t[r].call(e);
return e;
});
}
return function (e, t, r) {
return {
e: applyMemberDecs(e, t),
get c() {
return function (e, t) {
if (t.length > 0) {
for (var r = [], n = e, a = e.name, i = t.length - 1; i >= 0; i--) {
var o = {
v: !1
};
try {
var s = t[i](n, {
kind: "class",
name: a,
addInitializer: createAddInitializerMethod(r, o)
});
} finally {
o.v = !0;
}
void 0 !== s && (assertValidReturnValue(10, s), n = s);
}
return [n, function () {
for (var e = 0; e < r.length; e++) r[e].call(n);
}];
}
}(e, r);
}
};
};
}
function applyDecs2203R(e, t, r) {
return (module.exports = applyDecs2203R = applyDecs2203RFactory(), module.exports.__esModule = true, module.exports["default"] = module.exports)(e, t, r);
}
module.exports = applyDecs2203R, module.exports.__esModule = true, module.exports["default"] = module.exports;

222
node_modules/@babel/runtime/helpers/applyDecs2301.js generated vendored Normal file
View File

@ -0,0 +1,222 @@
var _typeof = require("./typeof.js")["default"];
var checkInRHS = require("./checkInRHS.js");
var setFunctionName = require("./setFunctionName.js");
var toPropertyKey = require("./toPropertyKey.js");
function applyDecs2301Factory() {
function createAddInitializerMethod(e, t) {
return function (r) {
!function (e, t) {
if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
}(t), assertCallable(r, "An initializer"), e.push(r);
};
}
function assertInstanceIfPrivate(e, t) {
if (!e(t)) throw new TypeError("Attempted to access private element on non-instance");
}
function memberDec(e, t, r, n, a, i, s, o, c) {
var u;
switch (a) {
case 1:
u = "accessor";
break;
case 2:
u = "method";
break;
case 3:
u = "getter";
break;
case 4:
u = "setter";
break;
default:
u = "field";
}
var l,
f,
p = {
kind: u,
name: s ? "#" + t : toPropertyKey(t),
"static": i,
"private": s
},
d = {
v: !1
};
if (0 !== a && (p.addInitializer = createAddInitializerMethod(n, d)), s || 0 !== a && 2 !== a) {
if (2 === a) l = function l(e) {
return assertInstanceIfPrivate(c, e), r.value;
};else {
var h = 0 === a || 1 === a;
(h || 3 === a) && (l = s ? function (e) {
return assertInstanceIfPrivate(c, e), r.get.call(e);
} : function (e) {
return r.get.call(e);
}), (h || 4 === a) && (f = s ? function (e, t) {
assertInstanceIfPrivate(c, e), r.set.call(e, t);
} : function (e, t) {
r.set.call(e, t);
});
}
} else l = function l(e) {
return e[t];
}, 0 === a && (f = function f(e, r) {
e[t] = r;
});
var v = s ? c.bind() : function (e) {
return t in e;
};
p.access = l && f ? {
get: l,
set: f,
has: v
} : l ? {
get: l,
has: v
} : {
set: f,
has: v
};
try {
return e(o, p);
} finally {
d.v = !0;
}
}
function assertCallable(e, t) {
if ("function" != typeof e) throw new TypeError(t + " must be a function");
}
function assertValidReturnValue(e, t) {
var r = _typeof(t);
if (1 === e) {
if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
} else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
}
function curryThis2(e) {
return function (t) {
e(this, t);
};
}
function applyMemberDec(e, t, r, n, a, i, s, o, c) {
var u,
l,
f,
p,
d,
h,
v,
y,
g = r[0];
if (s ? (0 === a || 1 === a ? (u = {
get: (d = r[3], function () {
return d(this);
}),
set: curryThis2(r[4])
}, f = "get") : 3 === a ? (u = {
get: r[3]
}, f = "get") : 4 === a ? (u = {
set: r[3]
}, f = "set") : u = {
value: r[3]
}, 0 !== a && (1 === a && setFunctionName(u.set, "#" + n, "set"), setFunctionName(u[f || "value"], "#" + n, f))) : 0 !== a && (u = Object.getOwnPropertyDescriptor(t, n)), 1 === a ? p = {
get: u.get,
set: u.set
} : 2 === a ? p = u.value : 3 === a ? p = u.get : 4 === a && (p = u.set), "function" == typeof g) void 0 !== (h = memberDec(g, n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? l = h : 1 === a ? (l = h.init, v = h.get || p.get, y = h.set || p.set, p = {
get: v,
set: y
}) : p = h);else for (var m = g.length - 1; m >= 0; m--) {
var b;
void 0 !== (h = memberDec(g[m], n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? b = h : 1 === a ? (b = h.init, v = h.get || p.get, y = h.set || p.set, p = {
get: v,
set: y
}) : p = h, void 0 !== b && (void 0 === l ? l = b : "function" == typeof l ? l = [l, b] : l.push(b)));
}
if (0 === a || 1 === a) {
if (void 0 === l) l = function l(e, t) {
return t;
};else if ("function" != typeof l) {
var I = l;
l = function l(e, t) {
for (var r = t, n = 0; n < I.length; n++) r = I[n].call(e, r);
return r;
};
} else {
var w = l;
l = function l(e, t) {
return w.call(e, t);
};
}
e.push(l);
}
0 !== a && (1 === a ? (u.get = p.get, u.set = p.set) : 2 === a ? u.value = p : 3 === a ? u.get = p : 4 === a && (u.set = p), s ? 1 === a ? (e.push(function (e, t) {
return p.get.call(e, t);
}), e.push(function (e, t) {
return p.set.call(e, t);
})) : 2 === a ? e.push(p) : e.push(function (e, t) {
return p.call(e, t);
}) : Object.defineProperty(t, n, u));
}
function applyMemberDecs(e, t, r) {
for (var n, a, i, s = [], o = new Map(), c = new Map(), u = 0; u < t.length; u++) {
var l = t[u];
if (Array.isArray(l)) {
var f,
p,
d = l[1],
h = l[2],
v = l.length > 3,
y = d >= 5,
g = r;
if (y ? (f = e, 0 != (d -= 5) && (p = a = a || []), v && !i && (i = function i(t) {
return checkInRHS(t) === e;
}), g = i) : (f = e.prototype, 0 !== d && (p = n = n || [])), 0 !== d && !v) {
var m = y ? c : o,
b = m.get(h) || 0;
if (!0 === b || 3 === b && 4 !== d || 4 === b && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h);
!b && d > 2 ? m.set(h, d) : m.set(h, !0);
}
applyMemberDec(s, f, l, h, d, y, v, p, g);
}
}
return pushInitializers(s, n), pushInitializers(s, a), s;
}
function pushInitializers(e, t) {
t && e.push(function (e) {
for (var r = 0; r < t.length; r++) t[r].call(e);
return e;
});
}
return function (e, t, r, n) {
return {
e: applyMemberDecs(e, t, n),
get c() {
return function (e, t) {
if (t.length > 0) {
for (var r = [], n = e, a = e.name, i = t.length - 1; i >= 0; i--) {
var s = {
v: !1
};
try {
var o = t[i](n, {
kind: "class",
name: a,
addInitializer: createAddInitializerMethod(r, s)
});
} finally {
s.v = !0;
}
void 0 !== o && (assertValidReturnValue(10, o), n = o);
}
return [n, function () {
for (var e = 0; e < r.length; e++) r[e].call(n);
}];
}
}(e, r);
}
};
};
}
function applyDecs2301(e, t, r, n) {
return (module.exports = applyDecs2301 = applyDecs2301Factory(), module.exports.__esModule = true, module.exports["default"] = module.exports)(e, t, r, n);
}
module.exports = applyDecs2301, module.exports.__esModule = true, module.exports["default"] = module.exports;

Some files were not shown because too many files have changed in this diff Show More