Merge branch 'master' of https://gitea.zianxin.com/zax/biz-mobile-react-cloud
This commit is contained in:
commit
20b5569412
31 files changed
+1382
-258
No files matched your search
@@ -20,15 +20,15 @@ VITE_OAUTH2_APP_CLIENT='mini:mini'
|
||||
# VITE_APP_DEV_SERVICE = https://stgl.pj.gov.cn/api # 域名线上
|
||||
#VITE_APP_DEV_SERVICE = http://59.202.170.152:81/api # 信创线上
|
||||
# VITE_APP_DEV_SERVICE = http://192.168.101.174:9999 # 邓-本地
|
||||
VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地
|
||||
; VITE_APP_DEV_SERVICE = http://123.157.250.162:8089/api # 测试线上
|
||||
# VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地
|
||||
VITE_APP_DEV_SERVICE = http://123.157.250.162:8089/api # 测试线上
|
||||
|
||||
# --------------------------- 开发环境 图片访问基础地址 ---------------------------
|
||||
# VITE_IMAGE_DEV_PATH = https://stgl.pj.gov.cn/api # 域名线上
|
||||
#VITE_IMAGE_DEV_PATH = http://59.202.170.152:81/api # 信创线上
|
||||
# VITE_IMAGE_DEV_PATH = http://192.168.101.174:9999 # 邓-本地
|
||||
VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
|
||||
; VITE_IMAGE_DEV_PATH = http://123.157.250.162:8089/api # 测试线上
|
||||
# VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
|
||||
VITE_IMAGE_DEV_PATH = http://123.157.250.162:8089/api # 测试线上
|
||||
|
||||
# --------------------------- 生产环境 api地址 ----------------------------------
|
||||
VITE_APP_PROD_SERVICE = https://stgl.pj.gov.cn/api # 域名线上
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
<template>
|
||||
<view class="plate-number-keyboard-box" v-if="showKeyboard" @tap.stop>
|
||||
<view class="pnk-main" :animation="animationData">
|
||||
<view class="pnk-main-title">
|
||||
<text>请点击选择车牌号</text>
|
||||
<view class="xiala" @tap="_closeKeyboard"></view>
|
||||
</view>
|
||||
<view class="pnk-content">
|
||||
<!-- 省份面板 -->
|
||||
<view class="province-plane" v-if="showProvince">
|
||||
<block v-for="(item, index) in provinceList" :key="index">
|
||||
<view class="line">
|
||||
<view v-if="index === 'line4'" class='number-item handle-btn' @tap='_clickChangePlane'>ABC
|
||||
</view>
|
||||
<view class="number-item"
|
||||
:class="(cursor === 0 && index === 'line4' && ind >= 2) || (cursor >= 6 && (index !== 'line4' || (index === 'line4' && ind < 2))) ? 'disabled' : ''"
|
||||
v-if="!((cursor === 0 && index === 'line4' && ind > 7) || (cursor >= 6 && index === 'line4' && ind < 2))"
|
||||
v-for="(it, ind) in item" :key="ind" :data-text='it'
|
||||
:data-disabled="(cursor === 0 && index === 'line4' && ind >= 2) || (cursor >= 6 && (index !== 'line4' || (index === 'line4' && ind < 2)))"
|
||||
@tap='_handleClick'>{{ it }}</view>
|
||||
<view v-if="index === 'line4'" class='number-item handle-btn delete-btn'
|
||||
@tap='_handleDelete'></view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<!-- 字母数字面板 -->
|
||||
<view class='letter-number-plane' v-if="!showProvince">
|
||||
<block v-for="(item, index) in letterNumberList" :key="index">
|
||||
<view class='line'>
|
||||
<view v-if="index === 'line4' && cursor === 0" class='number-item handle-btn'
|
||||
@tap='_clickChangePlane'>省</view>
|
||||
<view v-if="index === 'line4' && cursor > 0" class="number-item handle-btn"
|
||||
:class="cursor < 6 ? 'disabled' : ''" :data-disabled="cursor < 6"
|
||||
@tap='_clickChangePlane'>字</view>
|
||||
<view class="number-item"
|
||||
:class="index === 'line2' && (it === 'I' || it === 'O') ? 'disabled' : ''"
|
||||
:data-disabled="index === 'line2' && (it === 'I' || it === 'O')"
|
||||
v-for="(it, ind) in item" :key="ind" :data-text='it' @tap='_handleClick'>{{ it }}</view>
|
||||
<view v-if="index === 'line4'" class='number-item handle-btn delete-btn'
|
||||
@tap='_handleDelete'></view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
cursor: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showKeyboard: true, // 是否显示键盘
|
||||
provinceList: {
|
||||
line1: ['京', '津', '渝', '沪', '冀', '晋', '辽', '吉', '黑', '苏'],
|
||||
line2: ['浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '粤', '琼'],
|
||||
line3: ['川', '贵', '云', '陕', '甘', '青', '蒙', '桂', '宁', '新'],
|
||||
line4: ['藏', '使', '领', '警', '学', '挂', '港', '澳', '试', '超', '军']
|
||||
},
|
||||
letterNumberList: {
|
||||
line1: [1, 2, 3, 4, 5, 6, 7, 8, 9, '0'],
|
||||
line2: ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
|
||||
line3: ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
|
||||
line4: ['Z', 'X', 'C', 'V', 'B', 'N', 'M'],
|
||||
// line5: ['领', '警', '学', '挂', '港', '澳', '试', '超', '军']
|
||||
},
|
||||
showProvince: true, // 是否显示省份面板,控制省份面板和字符面板显示
|
||||
animationData: {} // 键盘动画
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
cursor(val) {
|
||||
this.showProvince = (val === 0);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.showProvince = (this.cursor === 0);
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.showKeyboard = true;
|
||||
|
||||
const animation = uni.createAnimation({
|
||||
duration: 200,
|
||||
});
|
||||
// 立即执行无效,延迟一段时间执行弹出动画
|
||||
setTimeout(() => {
|
||||
animation.translateY(0).step();
|
||||
this.animationData = animation.export();
|
||||
this.$emit('onShow');
|
||||
}, 100);
|
||||
},
|
||||
hide() {
|
||||
const animation = uni.createAnimation({
|
||||
duration: 200
|
||||
})
|
||||
setTimeout(() => {
|
||||
animation.translateY(300).step();
|
||||
this.animationData = animation.export();
|
||||
setTimeout(() => {
|
||||
this.showKeyboard = false;
|
||||
}, 300);
|
||||
this.$emit('onHide');
|
||||
}, 100);
|
||||
},
|
||||
/**
|
||||
* 键盘面板切换操作,控制省份内容和字符内容显示
|
||||
*/
|
||||
_clickChangePlane: function (e) {
|
||||
if (e.currentTarget.dataset.disabled) {
|
||||
return;
|
||||
}
|
||||
this.showProvince = !this.showProvince
|
||||
},
|
||||
/**
|
||||
* 关闭键盘,将键盘隐藏
|
||||
*/
|
||||
_closeKeyboard: function (e) {
|
||||
// 创建动画,执行键盘面板退出动画,动画结束后隐藏整个键盘组件
|
||||
this.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* 键盘主要键点击事件,将点击内容更新到plateNumber
|
||||
*/
|
||||
_handleClick: function (e) {
|
||||
// 如果当前显示的省份面板,当即任意省份后,自动切换到字符面板,同时将结果值的第一个字符修改
|
||||
if (e.currentTarget.dataset.disabled) {
|
||||
return;
|
||||
}
|
||||
if (this.showProvince) {
|
||||
this.showProvince = false;
|
||||
}
|
||||
if (this.cursor === 7) {
|
||||
this.hide();
|
||||
}
|
||||
this.$emit('onInput', e.currentTarget.dataset.text);
|
||||
},
|
||||
_handleCursor: function (e) {
|
||||
console.log(e.currentTarget.dataset.index)
|
||||
this.cursor = e.currentTarget.dataset.index;
|
||||
},
|
||||
/**
|
||||
* 删除回退点击事件
|
||||
*/
|
||||
_handleDelete: function () {
|
||||
this.$emit('onDel');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
button {
|
||||
padding: 0rpx;
|
||||
}
|
||||
|
||||
.plate-number-keyboard-box {
|
||||
position: fixed;
|
||||
bottom: 0rpx;
|
||||
left: 0rpx;
|
||||
width: 100%;
|
||||
height: 432rpx;
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.pnk-main {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0rpx;
|
||||
height: 432rpx;
|
||||
width: 100%;
|
||||
background: #d0d5d9;
|
||||
transform: translateY(432rpx);
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.pnk-main .pnk-main-title {
|
||||
font-size: 24rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #ddd;
|
||||
padding: 0rpx 10rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pnk-main-title text {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.pnk-main-title .xiala {
|
||||
position: relative;
|
||||
float: right;
|
||||
width: 70rpx;
|
||||
height: 50rpx;
|
||||
font-size: 40rpx;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.pnk-content {
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.line:last-of-type {
|
||||
margin-bottom: 0rpx;
|
||||
}
|
||||
|
||||
.line .number-item {
|
||||
width: 60rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 12rpx;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
background: #fff;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.line .number-item.disabled {
|
||||
background: #ccc !important;
|
||||
color: #999 !important;
|
||||
}
|
||||
|
||||
.line .number-item:active {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.line .handle-btn {
|
||||
width: 80rpx;
|
||||
background: #acb3bb;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.xiala::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: calc(50% - 14rpx);
|
||||
top: calc(50% - 8rpx);
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAsCAMAAADFL88lAAAAclBMVEUAAAADGyYDGyYAADUDGyYAKjMAKysAIiIDGyYDGyYDGyYDGiYDGyYDGyYDGiYDGiUCGiYDGyYDGyYDGyUEGyYDGyYDGiUCGyYDGyUEGyUCGiUAGCYDGyYDGyYCGiUAGCQDHCYDGiUCHCcDHCcDGyYDHSnHUSRaAAAAJHRSTlMA/fsD+AUGB7yzubatqaSdf6+XkYvcwczGhHoK8udqDmVLb1ulZTqDAAACG0lEQVRIx6XV6WLCIAwA4AAF6rGtHvWaO9zg/V9xIVaMomuh+VWRfhBIAUA17bHdW9AwIjSYfVu1DSK69s45v/0CW+5Z+NoRUyto/FE6WfntO4ml3tZXyBx9A62TDqNYJO8dvaAI9wH0QOLOgi30dsEjUUCLLD1WfmPA5HuGvDMicYaHiFdhSXX+/troYZoHgBp/losazIYBU2xSscFRg87z9OY2RWxSNRNnACZn/dSdp0Kj5uIkQ7Q0Ge4ZaiYxVs8CxaEeTNmLUwWWDSTjQC+D1pGGncXUJHnxLy5K/zpApC4T7t0kpmP1kPgGoAZ48+srSXmoVMzwsDjiC0ycZojovTBvknSneuTi8onIPcc8/bCoZqnY7z0vNBvKQEZxdRVT75V1XNCrz8WuDoRfo9jnOe6lYfgchd9zkXtvfH7/Fq1ixS87MfWWzJtTl8Fi86i8VmdP4H50Xo84ScTEY599/yd1Lyp1463RyztGbBRFEA8kMk9grvEQMQADRXm5xkjknnQuz6NuXPxBsdyj0LfiJ4p3nkAv2Y/eveZiIPdedPUio5chLpj4DUZBc/FkPN6KRHEW4XDJV1Y5Ht+ZORN/P4Mn4vGrITtsEOVFxOg8gV4YbrQY93cZvaKshegg5mkoDBXneNauV0OxyC43+rSv3niR6m9V5KUXnOQX18gwdCVVQlTk0X6MFtfeO+dTr3wdT5vjR30alO8fxlZei+kmmyYAAAAASUVORK5CYII=);
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.delete-btn::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: calc(50% - 18rpx);
|
||||
top: calc(50% - 15rpx);
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAAvCAMAAACIYFl1AAAAk1BMVEUAAAADGyYAHCsAHh8DGyUDHCYDGyYAHykDGycDGyYDGyYAHSYEGiUAHCcDGyYCGyYEGyYAFCoCGyYDGyYCGiYDGyYDGyYEGSYFGyUDGyYDGyUDGiYCGycCGyYCGiYDGiYDGiUAHCgDGyYDGiYEGyQFGiUDGyYDGyYEGyUDGyUAHSQDGyYAGiUDGyUDGyYDGyYDHCi5/q4pAAAAL3RSTlMA+gQI/En3GeFj8RFFItl8QgzN49S+Wjs06LKSd3JrV00q3rg5L8aah1IX6x2splBDDs0AAAJiSURBVEjHrZaNdvIgDIYDxTptrbbz/3/qpvPbRu7/6j4Sh7Ht2VnpGdtRAzzkBQIEHosG2GTKNin94wgqrD4i2mYFcVOBzxgbo/jfFyW/lPJVylhlMAUpEaTsFpsUa2M8lkSP0TjWWPfnfvgvSx/++7uRq/qPji/oGnE123d+KfvRdEF+Hth5jMZgAU2KPqASWANMyLYnSKJbyaOfSgKDZ4HJ8caJVniByA+na+703VP3iWHPvvxDpTDToO8dK7TURB729Z/OUpgKO1x7yhPDIbfW4SlaE+MZtK/oIfbIEtbXCOzncMBY4SLxjuHdosUdaGF3VPMOugyTvcLYid7d2ZGlwWwqs0wNKoM4Al2FUxb9CXe4W/ASmJnXOe9zRXatwBqigvz0ByB7kYxdq8F4DtrvhWMPSVk2WUMWvS0tLYcBjxhpbyw+mC3Br5ZET3R5cV9vQp+6QDJo9PilslUclyRascBH+hQzneX6jVlFC1CFt9x0qUZUDh3L835bcgdZeoFhEJPoIhfWd6HIId/EWpxKB4GXJBo79wNRCSpjFQ+wBV2HeyxtJaJLR2H9fZWYNVk1OEOlaDvzOku+CurktoII+EPPMud9qznDB6/2OAla7fb7XI8wcwqKMIlt0za25VRtQk+VnGcaOPQ8+1uHhC9b3CRyh/Va3GHOvmZ8EV3Db09uQhL+5eGAe5uqvnhO+6AXQ7ZmQXN6zoPfKra3TriiByf4lSTkSDaOgt5niUfODLKwzEAWhHOS8ykkJxHhRXg2JK5nNjgPE5qi9JbgBWSAksZN2uSekvWOG2a9yxnAf+zPn543ZzPrAAAAAElFTkSuQmCC);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,312 @@
|
||||
<template>
|
||||
<view class="plate-number">
|
||||
<view class="plate-number-box" :class="plate[7] && 'green'" @tap.stop>
|
||||
<template v-for="(item, index) in 8" :key="`plate-${index}`">
|
||||
<text v-if="index == 2" class="fz-000000 fz-weight fz-32">·</text>
|
||||
<label :id="'input' + index"
|
||||
:class="[(index == cursor && focus ? 'focus' : '') + (index === 7 && !plate[index] ? ' xinnengyuan' : ''), 'bglabel']"
|
||||
:data-index="index" @tap='_handleCursor'>
|
||||
{{ plate[index] || '' }}
|
||||
</label>
|
||||
</template>
|
||||
</view>
|
||||
<plate-keyboard ref='plateKeyboard' :cursor="cursor" @onInput="_keyboardInput" @onDel="_keyboardDel"
|
||||
@onShow="plateKeyboardOnShow" @onHide="plateKeyboardOnHide" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PlateKeyboard from './plate-keyboard.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PlateKeyboard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
plate: new Array(8),
|
||||
cursor: 0,
|
||||
focus: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 根据IP获取到当前省份
|
||||
this.getLocationByIP();
|
||||
},
|
||||
methods: {
|
||||
setPlate: function (plateNumber) {
|
||||
const plate = plateNumber.split('');
|
||||
while (plate.length < 8) {
|
||||
plate.push('');
|
||||
}
|
||||
this.plate = plate;
|
||||
this.cursor = plateNumber.length;
|
||||
this.focus = false;
|
||||
},
|
||||
getPlate: function () {
|
||||
return this.plate.join('');
|
||||
},
|
||||
onInput: function (text) {
|
||||
// 车牌号最多8位,大多数7位,新能源8位,控制不能超过8位数
|
||||
if (this.cursor < 8) {
|
||||
this.plate.splice(this.cursor++, 1, text);
|
||||
}
|
||||
},
|
||||
onDel: function () {
|
||||
if (this.plate[this.cursor]) {
|
||||
this.plate.splice(this.cursor, 1, '');
|
||||
} else if (this.cursor > 0) {
|
||||
this.plate.splice(--this.cursor, 1, '');
|
||||
}
|
||||
},
|
||||
_handleCursor: function (e) {
|
||||
let index = parseInt(e.currentTarget.dataset.index);
|
||||
for (; index > 0 && !this.plate[index] && !this.plate[index - 1]; index--);
|
||||
|
||||
this.cursor = index;
|
||||
this.focus = true;
|
||||
|
||||
this.$refs.plateKeyboard.show();
|
||||
},
|
||||
|
||||
hidePlateKeyboard() {
|
||||
this.$refs.plateKeyboard.hide();
|
||||
},
|
||||
_keyboardInput(val) {
|
||||
console.log('===input:' + val);
|
||||
this.onInput(val);
|
||||
},
|
||||
_keyboardDel() {
|
||||
console.log('===del')
|
||||
this.onDel();
|
||||
},
|
||||
plateKeyboardOnShow() {
|
||||
this.$emit('plateKeyboardOnShow');
|
||||
},
|
||||
plateKeyboardOnHide() {
|
||||
this.focus = false;
|
||||
this.$emit('plateKeyboardOnHide');
|
||||
},
|
||||
|
||||
async getLocationByIP() {
|
||||
if (getApp().globalData.provinceShort) {
|
||||
this.setPlate(getApp().globalData.provinceShort);
|
||||
} else {
|
||||
if (!this.$Request) {
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await this.$Request(this.$Api.general.park.getLocationByIP, {});
|
||||
if (res.success) {
|
||||
var prov = res.data.province;
|
||||
if (prov) {
|
||||
let provShort = this.provinceForShort(prov);
|
||||
if (provShort) {
|
||||
getApp().globalData.provinceShort = provShort;
|
||||
if (!this.getPlate()) {
|
||||
this.setPlate(provShort);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
provinceForShort(province) {
|
||||
if (province == "北京市")
|
||||
return "京";
|
||||
else if (province == "天津市")
|
||||
return "津";
|
||||
else if (province == "重庆市")
|
||||
return "渝";
|
||||
else if (province == "上海市")
|
||||
return "沪";
|
||||
else if (province == "河北省")
|
||||
return "冀";
|
||||
else if (province == "山西省")
|
||||
return "晋";
|
||||
else if (province == "辽宁省")
|
||||
return "辽";
|
||||
else if (province == "吉林省")
|
||||
return "吉";
|
||||
else if (province == "黑龙江省")
|
||||
return "黑";
|
||||
else if (province == "江苏省")
|
||||
return "苏";
|
||||
else if (province == "浙江省")
|
||||
return "浙";
|
||||
else if (province == "安徽省")
|
||||
return "皖";
|
||||
else if (province == "福建省")
|
||||
return "闽";
|
||||
else if (province == "江西省")
|
||||
return "赣";
|
||||
else if (province == "山东省")
|
||||
return "鲁";
|
||||
else if (province == "河南省")
|
||||
return "豫";
|
||||
else if (province == "湖北省")
|
||||
return "鄂";
|
||||
else if (province == "湖南省")
|
||||
return "湘";
|
||||
else if (province == "广东省")
|
||||
return "粤";
|
||||
else if (province == "海南省")
|
||||
return "琼";
|
||||
else if (province == "四川省")
|
||||
return "川";
|
||||
else if (province == "贵州省")
|
||||
return "贵";
|
||||
else if (province == "云南省")
|
||||
return "云";
|
||||
else if (province == "陕西省")
|
||||
return "陕";
|
||||
else if (province == "甘肃省")
|
||||
return "甘";
|
||||
else if (province == "青海省")
|
||||
return "青";
|
||||
else if (province == "台湾省")
|
||||
return "台";
|
||||
else if (province == "内蒙古自治区")
|
||||
return "蒙";
|
||||
else if (province == "广西壮族自治区")
|
||||
return "桂";
|
||||
else if (province == "宁夏回族自治区")
|
||||
return "宁";
|
||||
else if (province == "新疆维吾尔自治区 ")
|
||||
return "新";
|
||||
else if (province == "西藏自治区")
|
||||
return "藏";
|
||||
else if (province == "香港特别行政区")
|
||||
return "港";
|
||||
else if (province == "澳门特别行政区")
|
||||
return "澳";
|
||||
else return '';
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.plate-number {
|
||||
/* display: flex; */
|
||||
/* justify-content: spa; */
|
||||
}
|
||||
|
||||
.plate-number-box {
|
||||
position: relative;
|
||||
/* height: 50rpx; */
|
||||
padding: 24rpx 0;
|
||||
box-sizing: content-box;
|
||||
margin: auto;
|
||||
border-radius: 10rpx;
|
||||
transition: all 1s;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* .plate-number-box::before {
|
||||
content: '';
|
||||
border: 2rpx solid #fff;
|
||||
position: absolute;
|
||||
top: 5rpx;
|
||||
left: 5rpx;
|
||||
border-radius: 10rpx;
|
||||
height: 86rpx;
|
||||
} */
|
||||
.bglabel {
|
||||
background-color: #F2F5FA;
|
||||
}
|
||||
|
||||
/* .plate-number-box::after {
|
||||
content: '·';
|
||||
position: absolute;
|
||||
left: 122rpx;
|
||||
top: 30rpx;
|
||||
color: #fff;
|
||||
font-size: 50rpx;
|
||||
line-height: 40rpx;
|
||||
} */
|
||||
|
||||
.plate-number-box.green {
|
||||
/* background: linear-gradient(#f8f8f8 20%, #16b235); */
|
||||
box-shadow: 0 0 4rpx 0 #ebebeb;
|
||||
}
|
||||
|
||||
/* .plate-number-box.green::before {
|
||||
border: 2rpx solid #000;
|
||||
} */
|
||||
|
||||
/* .plate-number-box.green::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 120rpx;
|
||||
top: 36rpx;
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAF6UExURUdwTH3EyJfLtffOk9mwguW7jHvftPvQofnPoVlKOYzOo4jMs5HPp5fIvqbYnOhFQfrCkJG6pIbLw4vUzYjKv5vjs9q8JvLPn4bJpJHqtYrNqnStopDh3oLJwViHcIjLv3q2qozMvmRYSYfLpovMqm6ggum9j+PMnqDSuqTQuOjOpKPOoGaZfnGqi+DCKXooHt20hqWvqW9fEMt9bKG7p8LDXnuSiKS4o////zqp4Deo4jCuMS2tLfTz8+vr7OUUW9rZ22JbUvv8/Uuy2zGxMUO2SiaZJ9DhLjdEOkpPTckubzSj2lu62VO+YDJERD9NR/f290JFQbe1tV3BbuLg4d/c3bXXLzIxJ1dVUj1OVnHF0W3IhMXCwSlMXhlAGiZOJ8zhL0ZiUVdfW7mGmU1aVqakpZiWlyNGV2mnp4KBgkpybhg9UTKh2bbWKmlnZLDcfbrcMWeofoOMGaa3IzpLVFx3GcngQ9wzaa/chHoJLK0NRGEiRWppaD1PV9NqRZ0AAAA4dFJOUwATR/X49w/6+v3hs3ByFPT09uNHzUf0+Swpy+YuL+Xw1f398P3c9/f98Pu6yMb0+vjc+vi5+NyxP0I0ygAAAWxJREFUKM910ldXwjAYBuC0KgqlVeZhKEPAhXuGKYIIKKscNsjGvff87yZNOdYLn8v3bZKTLwWAoGjGardbGQ0FpChWXU1GkOSZjZVUU9pqxOvxeL0e72X8Qjs5yDXqJMqI4/p52qwRv1dHBjEq8jCXNgtrKG1SyI+wq9MChPW0TYYKtnuIfaa/K5XKUyIIITzpsWjB2usu8v4VDGBZlMNsYpsDdBfnH3wgLICCfocGmxvjyEpJTpTxVjCU2QHzs0PYiEgewkWgpwJzC2PYqGg6RA75pwiXVWirCWRmdZggWwXRCveWXq9fXi/tETfi4W5Av8VardgjH4QS/bYOcIqXGPJQllwQdlwcAMrb62KxePdcimPCSHIZJZqVzJTy+3y+/QNBAw0xn1nEQwQGRVRoMF8zDwsJi5E8CK1I+XGF+JuhPm/RDZ7QYKpF/USDby8Zfx9dplTUUlEkde9Syv78JxzNOJxOB6PjxOAHI6di/dhTK/cAAAAASUVORK5CYII=);
|
||||
} */
|
||||
|
||||
.plate-number-box.green label {
|
||||
color: #222;
|
||||
text-shadow: 0 0 2rpx #fff;
|
||||
}
|
||||
|
||||
.plate-number-box label {
|
||||
width: 60rpx;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
/* width: 8%; */
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-size: 50rpx;
|
||||
height: 86rpx;
|
||||
line-height: 86rpx;
|
||||
text-shadow: 0rpx 0rpx 2rpx #000;
|
||||
/* margin: 0 10rpx; */
|
||||
}
|
||||
|
||||
.plate-number-box label:nth-child(2) {
|
||||
/* margin-right: 20rpx; */
|
||||
}
|
||||
|
||||
.plate-number-box label:last-child {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
/* .plate-number-box label.focus::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -6rpx;
|
||||
left: 5%;
|
||||
width: 90%;
|
||||
height: 4rpx;
|
||||
background: #fff;
|
||||
animation: cursor 1s ease-in infinite;
|
||||
} */
|
||||
|
||||
/* .plate-number-box label.xinnengyuan::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 12%;
|
||||
top: 12%;
|
||||
width: 76%;
|
||||
height: 76%;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
} */
|
||||
|
||||
@keyframes cursor {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -198,6 +198,13 @@
|
||||
"navigationBarTitleText": "商品分类管理",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "settlement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "结算",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -55,7 +55,7 @@ const getDetail = async () => {
|
||||
|
||||
// 获取购物车信息
|
||||
const getFoodCart = async () => {
|
||||
const { data } = await foodApi.getShopCar({ merchantId: state.detailId, hardType: "CANTEEN" })
|
||||
const { data } = await orderApi.getShopCar({ merchantId: state.detailId, hardType: "CANTEEN" })
|
||||
state.cartList = data ?? []
|
||||
if (isEmpty(state.cartList)) {
|
||||
state.foodList.forEach((v: any) => {
|
||||
@@ -154,7 +154,7 @@ const updateFoodCart = async () => {
|
||||
})
|
||||
if (isEmpty(list)) return
|
||||
const _pa = { merchantId: state.detailId, list: list, hardType: "CANTEEN" }
|
||||
const { data, code }: any = await foodApi.updateShopCar(_pa)
|
||||
const { data, code }: any = await orderApi.updateShopCar(_pa)
|
||||
if (code == 0) await getFoodCart()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import PlateNum from '@/components/tongtong-plate/plate-number.vue';
|
||||
|
||||
import { hooks, router } from "@@/index"
|
||||
import { userCarApi } from "@@/api"
|
||||
@@ -9,6 +10,7 @@ import { serviceEnum } from "@/sheep/constant"
|
||||
const { carTypeEnum } = serviceEnum
|
||||
|
||||
const applyFormRef = ref<any>(null)
|
||||
const plateNumRef = ref<any>(null)
|
||||
|
||||
const visitorReasonList = ref<Array<{ title: string; id: string }>>(Object.keys(carTypeEnum).map((key) => ({
|
||||
title: carTypeEnum[key],
|
||||
@@ -49,6 +51,14 @@ const carNumberPickerConfirm = (e) => {
|
||||
}
|
||||
|
||||
const doSubmit = async () => {
|
||||
// 车牌号
|
||||
const carNumber = plateNumRef.value.getPlate()
|
||||
if (!carNumber) {
|
||||
uni.showToast({ title: "请输入车牌号", icon: "none" })
|
||||
return
|
||||
}
|
||||
applyForm.carNumber = carNumber
|
||||
// 校验
|
||||
applyFormRef.value.submit()
|
||||
const { isPass } = applyFormRef.value.validate()
|
||||
if (!isPass) return
|
||||
@@ -81,7 +91,7 @@ const doSubmit = async () => {
|
||||
</tm-picker>
|
||||
</tm-form-item>
|
||||
<tm-form-item name="carNumber" label="车牌号" :showBottom="false">
|
||||
<tm-input v-model="applyForm.carNumber" placeholder="请输入" show-char-count></tm-input>
|
||||
<PlateNum ref="plateNumRef" />
|
||||
</tm-form-item>
|
||||
</tm-form>
|
||||
</view>
|
||||
|
||||
@@ -4,15 +4,9 @@
|
||||
<tm-sheet :margin="[0]">
|
||||
<tm-alert :border="['2']" :borderColor="['#89c0ff']" :darkBorderColor="['#3b5066']">访客邀约请填写以下信息</tm-alert>
|
||||
<tm-form @submit="onsubmit" v-model="form" :rules="rules" direction="vertical">
|
||||
<!-- <tm-form-item name="name" label="访客姓名">
|
||||
<tm-input color="transparent" v-model.trim="form.name" placeholder="请输入真实姓名" />
|
||||
</tm-form-item> -->
|
||||
<tm-form-item name="mobile" label="访客手机号">
|
||||
<tm-input color="transparent" v-model.trim="form.mobile" placeholder="请输入访客手机号" />
|
||||
</tm-form-item>
|
||||
<!-- <tm-form-item name="companyName" label="来访公司名称">
|
||||
<tm-input color="transparent" v-model.trim="form.companyName" placeholder="来访公司名称" />
|
||||
</tm-form-item> -->
|
||||
<tm-form-item name="vStartDate" label="拜访开始时间 >" @click="startDatePicker('vStartDate')">
|
||||
<template #label>
|
||||
<span>拜访开始时间 </span>
|
||||
@@ -39,30 +33,6 @@
|
||||
color="transparent"
|
||||
/>
|
||||
</tm-form-item>
|
||||
|
||||
<!-- <tm-form-item name="deptId" label="拜访部门">
|
||||
<tm-drawer :show-close="true" :show-footer="true" size="auto" title="请选择拜访部门">
|
||||
<template #trigger>
|
||||
<tm-input :modelValue="form.deptId" placeholder="请选择拜访部门" style="pointer-events: none" disabled color="transparent">
|
||||
<template v-slot:rightIcon>
|
||||
<tm-icon name="arrow-right-s-line"></tm-icon>
|
||||
</template>
|
||||
</tm-input>
|
||||
</template>
|
||||
<tm-text color="#999999"></tm-text>
|
||||
</tm-drawer>
|
||||
</tm-form-item> -->
|
||||
|
||||
<!-- <tm-form-item name="reasonValue" label="拜访原因">
|
||||
<tm-picker @confirm="reasonPickerConfirm" :list="visitorReasonList">
|
||||
<tm-input :modelValue="form.reasonText" placeholder="请选择拜访原因" style="pointer-events: none" disabled color="transparent">
|
||||
<template #rightIcon>
|
||||
<tm-icon name="arrow-right-s-line"></tm-icon>
|
||||
</template>
|
||||
</tm-input>
|
||||
</tm-picker>
|
||||
</tm-form-item> -->
|
||||
|
||||
<tm-form-item name="isOtherPeople" label="是否可随行人员" direction="horizontal" labelWidth="500">
|
||||
<tm-switch v-model="form.isOtherPeople" />
|
||||
</tm-form-item>
|
||||
@@ -133,49 +103,20 @@ interface FormData {
|
||||
}
|
||||
|
||||
const form = reactive<FormData>({
|
||||
// name: "",
|
||||
mobile: "",
|
||||
// companyName: "",
|
||||
vStartDate: "",
|
||||
vEndDate: "",
|
||||
// reasonValue: "",
|
||||
// reasonText: "",
|
||||
isOtherPeople: true,
|
||||
isDrive: true,
|
||||
})
|
||||
const showDatePicker = ref(false)
|
||||
const curDateType = ref("")
|
||||
const confirmModalShow = ref(false)
|
||||
// const visitorReasonList = ref<{ title: string; id: string }[]>([])
|
||||
|
||||
// onLoad(() => {
|
||||
// getVisitorReasonList()
|
||||
// })
|
||||
|
||||
// 获取拜访原因列表
|
||||
// const getVisitorReasonList = async () => {
|
||||
// const { code, data } = await invitationApi.getDictListByType("1")
|
||||
// if (code == 0 && data) {
|
||||
// visitorReasonList.value = data.map((item: any) => ({ title: item.label, id: item.value }))
|
||||
// return
|
||||
// }
|
||||
// visitorReasonList.value = []
|
||||
// }
|
||||
|
||||
// 来访原因选择器确认
|
||||
// const reasonPickerConfirm = (ids: string) => {
|
||||
// const reason = visitorReasonList.value.find((item) => item.id === ids[0])
|
||||
// form.reasonText = reason?.title || ""
|
||||
// form.reasonValue = reason?.id || ""
|
||||
// }
|
||||
|
||||
const rules: Record<string, TM.FORM_RULE[]> = {
|
||||
// name: [{ required: true, message: "姓名2到5个字符", rule: /^.{2,5}$/ }],
|
||||
mobile: [{ required: true, message: "请输入正确的手机号", rule: /^(?:(?:\+|00)86)?1\d{10}$/ }],
|
||||
// companyName: [{ required: true, message: "请输入来访公司名称" }],
|
||||
vStartDate: [{ required: true, message: "请选择拜访开始时间" }],
|
||||
vEndDate: [{ required: true, message: "请选择拜访离开时间" }],
|
||||
// reasonValue: [{ required: true, message: "请选择拜访原因" }],
|
||||
}
|
||||
|
||||
// 开始日期选择
|
||||
@@ -237,13 +178,9 @@ const confirmSubmit = async () => {
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(form, {
|
||||
// name: "",
|
||||
mobile: "",
|
||||
// companyName: "",
|
||||
vstartDate: "",
|
||||
vendDate: "",
|
||||
// reasonValue: "",
|
||||
// reasonText: "",
|
||||
isOtherPeople: true,
|
||||
isDrive: true,
|
||||
})
|
||||
|
||||
@@ -138,7 +138,7 @@ import { reactive, nextTick } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { isEmpty } from "radash"
|
||||
import { hooks, router } from "@@/index"
|
||||
import { foodApi, merchantApi, payApi, shopApi } from "@@/api"
|
||||
import { foodApi, merchantApi, orderApi, payApi, shopApi } from "@@/api"
|
||||
import { filePath } from "@@/utils/file"
|
||||
// import ProductRow from "./components/product-row.vue"
|
||||
// import ProductCart from "./components/product-cart.vue"
|
||||
@@ -196,7 +196,7 @@ const getDetail = async () => {
|
||||
}
|
||||
|
||||
const getShopCart = async () => {
|
||||
const { data } = await foodApi.getShopCar({ merchantId: state.merchantId, hardType: "SUPERMARKET" })
|
||||
const { data } = await orderApi.getShopCar({ merchantId: state.merchantId, hardType: "SUPERMARKET" })
|
||||
state.cartList = data ?? []
|
||||
state.totPrice = state.cartList.map((v) => Number(v.totalPrice)).reduce((pre, next) => pre + next, 0)
|
||||
state.totCount = state.cartList.map((v) => v.productCount).reduce((pre, next) => pre + next, 0)
|
||||
@@ -293,7 +293,7 @@ const updateShopCart = async () => {
|
||||
productId: v.productId,
|
||||
}
|
||||
})
|
||||
const { code }: any = await foodApi.updateShopCar({ merchantId: state.merchantId, list, hardType: "SUPERMARKET" })
|
||||
const { code }: any = await orderApi.updateShopCar({ merchantId: state.merchantId, list, hardType: "SUPERMARKET" })
|
||||
if (code == 0) await getShopCart()
|
||||
}
|
||||
|
||||
|
||||
@@ -44,15 +44,17 @@
|
||||
<script setup lang="ts">
|
||||
import ProductTotal from "./components/product-total.vue"
|
||||
import { isEmpty } from "radash"
|
||||
import { useCartStore } from "@/sheep/stores/cart"
|
||||
import { useOnlineCartStore } from "@/sheep/stores/online-cart"
|
||||
import { payApi } from "@/sheep/api"
|
||||
import { hooks, router } from "@/sheep"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
|
||||
const cartStore = useCartStore()
|
||||
const cartStore = useOnlineCartStore()
|
||||
|
||||
// 点击提交订单
|
||||
const doBuy = async () => {
|
||||
if (isEmpty(cartStore.cart)) return uni.showToast({ title: "请至少购买一件商品", icon: "none" })
|
||||
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "是否确定购买",
|
||||
@@ -67,8 +69,6 @@ const doBuy = async () => {
|
||||
// 提交订单
|
||||
const submitPay = async () => {
|
||||
try {
|
||||
if (isEmpty(cartStore.cart)) return uni.showToast({ title: "请至少购买一件商品", icon: "none" })
|
||||
|
||||
uni.showLoading({ title: "支付中...", mask: false })
|
||||
const { code, msg }: any = await payApi.createSupermarketOrder({ carParentId: cartStore.cart[0].parentCarId, hardType: "SUPERMARKET" })
|
||||
if (code != 0) throw new Error(msg)
|
||||
|
||||
@@ -4,11 +4,11 @@ import { onLoad } from "@dcloudio/uni-app"
|
||||
import { onlineShopApi } from "@@/api"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
import ProductSku from "./components/product-sku.vue"
|
||||
import { useCartStore } from "@/sheep/stores/cart"
|
||||
import { useOnlineCartStore } from "@/sheep/stores/online-cart"
|
||||
import { hooks, router } from "@/sheep"
|
||||
import { displayPrice } from "@/sheep/utils/formatMoney"
|
||||
|
||||
const cartStore = useCartStore()
|
||||
const cartStore = useOnlineCartStore()
|
||||
|
||||
const state = reactive<any>({
|
||||
detailId: null,
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<tm-drawer z-index="800" v-model:show="modelValue" showClose title="购物车" size="80%" bgColor="#ECF4F9" @close="doClose">
|
||||
<view v-if="totPrice > 0" class="flex-row card px-15rpx py-25rpx mb-20rpx" v-for="(v, i) in cartList" :key="i">
|
||||
<image class="size-160rpx rounded-12rpx mr-20rpx bg-#eeeeee" :src="filePath(v.productPic)" mode="aspectFill" />
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="sub-text-30 truncate">{{ v.productName }}</view>
|
||||
<view class="second-text-26 show-line">单位 {{ v.unit }}</view>
|
||||
<view class="flex-row justify-between items-center">
|
||||
<view class="second-text-30"> ¥{{ hooks.useMoney(v.productPrice) }} </view>
|
||||
<view class="second-text-30">x {{ v.productCount }}</view>
|
||||
</view>
|
||||
<view class="flex-row justify-between items-center">
|
||||
<view class="second-text-32 c-red!">¥{{ hooks.useMoney(v.totalPrice) }}</view>
|
||||
<view class="flex-row justify-between items-center">
|
||||
<view
|
||||
class="flex-row-center size-40rpx rounded-full border-1px border-solid border-color-#0094ff"
|
||||
@tap.stop="removeProductCount(v.productId, merchantId)"
|
||||
>
|
||||
<view class="iconfont icon-a--" />
|
||||
</view>
|
||||
<view class="sub-text-28 m-x-20rpx">{{ v.productCount }}</view>
|
||||
<view class="flex-row-center size-40rpx rounded-full bg-#0094ff" @tap.stop="addProductCount(v.productId, merchantId)">
|
||||
<view class="font-size-40rpx color-white iconfont icon-a-" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="flex-col justify-center items-center pt-300rpx">
|
||||
<image src="@/static/page/cart_empty.png" class="size-350rpx" />
|
||||
<text class="sub-text-32 font-bold">购物车空空如也</text>
|
||||
</view>
|
||||
|
||||
<view class="h-100rpx"></view>
|
||||
</tm-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
import useCartBuy from "../use-cart-buy"
|
||||
import { hooks } from "@/sheep"
|
||||
|
||||
const modelValue = defineModel("modelValue", { default: false })
|
||||
const props = defineProps({
|
||||
merchantId: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
})
|
||||
const { totPrice, cartList, addProductCount, removeProductCount } = useCartBuy()
|
||||
|
||||
// 关闭
|
||||
const doClose = () => {
|
||||
modelValue.value = false
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<tm-drawer z-index="2000" v-model:show="modelValue" showFooter showClose title="加入购物车" size="70%" bgColor="#ECF4F9" @close="doClose">
|
||||
<view class="flex-col card py-20rpx px-30rpx mb-20rpx">
|
||||
<view class="prefix_title mb-15rpx">商品信息</view>
|
||||
<view class="flex items-center">
|
||||
<image
|
||||
class="size-160rpx bg-#eeeeee rounded-1 mr-2"
|
||||
:src="filePath(goodsInfo.coverImage)"
|
||||
mode="aspectFill"
|
||||
@tap.stop="goodsInfo.coverImage && usePreviewImage(filePath(goodsInfo.coverImage))"
|
||||
/>
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="sub-text-32 truncate">{{ goodsInfo.title }}</view>
|
||||
<view class="second-text-32 c-red!">
|
||||
<text>¥{{ displayPrice(state.selectedSku.price, "") || 0 }}</text>
|
||||
<!-- <text class="m-l-20rpx second-text-28 line-through">¥{{ displayPrice(state.selectedSku.retailPrice, "") || 0 }}</text> -->
|
||||
</view>
|
||||
<view class="second-text-26">库存 {{ state.selectedSku.stock || 0 }}</view>
|
||||
<view class="second-text-26">
|
||||
已选择
|
||||
{{
|
||||
`${state.selectedSku.skuName || "未选择"} / ${
|
||||
state.selectedSku.weightG ? state.selectedSku.weightG + "克" : "未选择"
|
||||
},数量 ${state.goodsCount}`
|
||||
}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 规格 -->
|
||||
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
|
||||
<view class="prefix_title mb-15rpx">规格</view>
|
||||
<view class="flex flex-wrap">
|
||||
<view
|
||||
class="text-center rounded-2 mr-4 mb-2 py-2 px-3 text-28 bg-#F2F2F2 c-black border border-solid border-#E5E5E5"
|
||||
:class="{ 'bg-#0094ff! c-white!': state.selectedSku.id === v.id }"
|
||||
v-for="v in goodsInfo.skuList"
|
||||
:key="v.id"
|
||||
@click="onSelectSku(v)"
|
||||
>
|
||||
{{ (v.skuName || "") + " / " + (v.skuWeight || "") + "克" }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 购买数量 -->
|
||||
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
|
||||
<view class="prefix_title mb-15rpx">购买数量</view>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="second-text-28">库存 {{ state.selectedSku.stock }}</view>
|
||||
<view class="flex">
|
||||
<view class="flex-row-center size-40rpx rounded-full border-1px border-solid border-color-#0094ff" @tap.stop="handleNumRemove">
|
||||
<view class="iconfont icon-a--" />
|
||||
</view>
|
||||
<view class="sub-text-28 m-x-20rpx">{{ String(state.goodsCount).padStart(2, "0") }}</view>
|
||||
<view class="flex-row-center size-40rpx rounded-full bg-#0094ff" @tap.stop="handleNumAdd">
|
||||
<view class="font-size-40rpx color-white iconfont icon-a-" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<template #footer>
|
||||
<button
|
||||
class="mx-12 rounded-3 bg-#0094ff sub-text-30 py-2 c-white! active:bg-#0094ff99"
|
||||
:class="{ 'bg-#0094ff77!': Object.keys(state.selectedSku).length === 0 }"
|
||||
@tap="handleSkuAddToCart"
|
||||
>
|
||||
加入购物车
|
||||
</button>
|
||||
</template>
|
||||
</tm-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, watch } from "vue"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
import { usePreviewImage } from "@/sheep/hooks/use-img"
|
||||
import { isEmpty } from "radash"
|
||||
import { displayPrice } from "@/sheep/utils/formatMoney"
|
||||
|
||||
const modelValue = defineModel("modelValue", { default: false })
|
||||
const emit = defineEmits<{ (e: "onSkuAddToCart", val: object): void }>()
|
||||
const props = defineProps({
|
||||
goodsInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const state = reactive<any>({
|
||||
selectedSku: {},
|
||||
goodsCount: 1,
|
||||
})
|
||||
|
||||
watch(modelValue, (newValue) => {
|
||||
if (newValue && !isEmpty(props.goodsInfo)) {
|
||||
state.selectedSku = props.goodsInfo.skuList[0]
|
||||
}
|
||||
})
|
||||
|
||||
// 选择规格/取消选择规格
|
||||
const onSelectSku = (skuItem: any) => {
|
||||
if (state.selectedSku.id == skuItem.id) {
|
||||
state.selectedSku = {}
|
||||
return
|
||||
}
|
||||
state.selectedSku = skuItem
|
||||
}
|
||||
|
||||
// 加数量
|
||||
const handleNumAdd = () => {
|
||||
if (state.goodsCount >= state.selectedSku.stock) return uni.showToast({ title: "库存不足", icon: "none" })
|
||||
state.goodsCount += 1
|
||||
}
|
||||
|
||||
// 减数量
|
||||
const handleNumRemove = () => {
|
||||
if (state.goodsCount <= 1) return
|
||||
state.goodsCount -= 1
|
||||
}
|
||||
|
||||
// 点击sku加入到购物车
|
||||
const handleSkuAddToCart = async () => {
|
||||
if (!state.selectedSku.id) return uni.showToast({ title: "请选择包装单位", icon: "none" })
|
||||
|
||||
// 检查库存
|
||||
// try {
|
||||
// uni.showLoading({ title: "加载中", mask: true })
|
||||
// const { code }: any = await shopApi.checkSpuStock({ spuId: props.goodsInfo.id, incrCount: state.goodsCount })
|
||||
// if (code != 0) return uni.showToast({ title: "库存不足", icon: "none" })
|
||||
// } catch (e) {
|
||||
// console.error(e)
|
||||
// } finally {
|
||||
// uni.hideLoading()
|
||||
// }
|
||||
|
||||
// 检查库存
|
||||
if (props.goodsInfo.stock === 0 || Number(state.goodsCount) > Number(state.selectedSku.stock))
|
||||
return uni.showToast({ title: "库存不足", icon: "none" })
|
||||
|
||||
emit("onSkuAddToCart", {
|
||||
spuId: props.goodsInfo.id,
|
||||
skuId: state.selectedSku.id,
|
||||
productCount: state.goodsCount,
|
||||
...state.selectedSku,
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭
|
||||
const doClose = () => {
|
||||
modelValue.value = false
|
||||
state.selectedSku = {}
|
||||
state.goodsCount = 1
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<view class="flex-row items-center justify-between" @tap="doContainer">
|
||||
<view class="flex-row-center">
|
||||
<tm-badge bg-color="red" :label="totalCount" :offset="[8, 8]">
|
||||
<image class="size-100rpx" src="/static/icon/cart.png" />
|
||||
</tm-badge>
|
||||
<view class="flex-col m-l-30rpx">
|
||||
<view class="second-text-36 color-#f63a36!">¥ {{ hooks.useMoney(props.totPrice) }}</view>
|
||||
<view class="sub-text-28">共{{ props.totCount }}件</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-#0094ff p-x-60rpx p-y-20rpx text-center rounded-40rpx sub-text-30 color-white!" @tap.stop="goSettlement">去结算</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { hooks } from "@@/index"
|
||||
import useCartBuy from "../use-cart-buy"
|
||||
|
||||
const emit = defineEmits(["submit", "doContainer"])
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
totPrice: number
|
||||
totCount: number
|
||||
}>(),
|
||||
{
|
||||
totPrice: 0,
|
||||
totCount: 0,
|
||||
},
|
||||
)
|
||||
|
||||
const { totalCount } = useCartBuy()
|
||||
|
||||
const goSettlement = () => emit("submit")
|
||||
|
||||
const doContainer = () => emit("doContainer")
|
||||
</script>
|
||||
@@ -1,41 +1,45 @@
|
||||
<template>
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<image :src="filePath(state.detail.coverImage)" class="w-full h-500rpx bg-#eeeeee" mode="aspectFill" />
|
||||
<view v-if="state.detail.id" class="card p-20rpx mt-10rpx mx-20rpx bg-gradient-to-b from-#0094ff33 to-#fff">
|
||||
<view v-if="state.detail.priceType == '2'" class="w-full flex justify-between items-center">
|
||||
<image :src="filePath(goodsDetail.coverImage)" class="w-full h-500rpx bg-#eeeeee" mode="aspectFill" />
|
||||
<view v-if="goodsDetail.id" class="card p-20rpx mt-10rpx mx-20rpx bg-gradient-to-b from-#0094ff33 to-#fff">
|
||||
<view v-if="goodsDetail.priceType == '2'" class="w-full flex justify-between items-center">
|
||||
<view class="flex items-center">
|
||||
<text class="second-text-34 line-through">¥</text>
|
||||
<text class="font-bold second-text-40 line-through mr-2">{{ displayPrice(state.detail.originalPrice, "") }}</text>
|
||||
<text class="font-bold second-text-40 line-through mr-2">{{ displayPrice(goodsDetail.originalPrice, "") }}</text>
|
||||
<text class="text-34rpx color-red!">¥</text>
|
||||
<text class="text-46rpx font-bold color-red!">{{ displayPrice(state.detail.spuPrice, "") }}</text>
|
||||
<text class="text-46rpx font-bold color-red!">{{ displayPrice(goodsDetail.spuPrice, "") }}</text>
|
||||
<text class="view-clip px-2 text-22rpx c-white bg-red ml-2 rounded-r-1 rounded-lt-1">到手价</text>
|
||||
</view>
|
||||
<view class="main-text-32 c-red! font-italic">
|
||||
<text>约省</text>
|
||||
<text class="text-44rpx mx-1">{{ displayPrice(Number(state.detail.originalPrice) - Number(state.detail.spuPrice), "") }}</text>
|
||||
<text class="text-44rpx mx-1">{{ displayPrice(Number(goodsDetail.originalPrice) - Number(goodsDetail.spuPrice), "") }}</text>
|
||||
<text>元</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="w-full flex justify-start items-center">
|
||||
<text class="text-34rpx color-red!">¥</text>
|
||||
<text class="text-46rpx font-bold color-red!">{{ displayPrice(state.detail.skuList[0].price, "") }}</text>
|
||||
<text class="text-46rpx font-bold color-red!">{{ displayPrice(goodsDetail.skuList[0].price, "") }}</text>
|
||||
<text class="view-clip px-2 text-22rpx c-white bg-red ml-2 rounded-r-1 rounded-lt-1">到手价</text>
|
||||
</view>
|
||||
<view class="w-full sub-text-36 flex items-center mt-1">
|
||||
<text class="c-#0094ff! sub-text-24 px-2 bg-#0094ff22 rounded-1 mr-2 whitespace-nowrap">
|
||||
{{ state.detail.status == "0" ? "在售" : "未售" }}
|
||||
{{ goodsDetail.status == "0" ? "在售" : "未售" }}
|
||||
</text>
|
||||
<text class="truncate">{{ state.detail.title }}</text>
|
||||
<text class="truncate">{{ goodsDetail.title }}</text>
|
||||
</view>
|
||||
<view class="second-text-26 mt-1">售卖时间 {{ state.detail.saleStartTime }} ~ {{ state.detail.saleEndTime }}</view>
|
||||
<view class="second-text-26 truncate mt-1">
|
||||
<text class="mr-20rpx">售卖单位 {{ state.detail.unit }}</text>
|
||||
<text class="mr-20rpx">剩余库存 {{ state.detail.totalStock }}</text>
|
||||
<view class="second-text-26 mt-1">售卖时间 {{ goodsDetail.saleStartTime }} ~ {{ goodsDetail.saleEndTime }}</view>
|
||||
<view class="second-text-26 truncate mt-1 flex justify-between items-center">
|
||||
<view>
|
||||
<text class="mr-20rpx">售卖单位 {{ goodsDetail.unit }}</text>
|
||||
<text class="mr-20rpx">剩余库存 {{ goodsDetail.totalStock }}</text>
|
||||
</view>
|
||||
<view class="second-text-24 px-2 py-8rpx bg-#0094ff c-white! border-rd-8" @tap.stop="state.showSkuDialog = true">加入购物车</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="state.detail.priceType == '1'" class="mt-20rpx card p-20rpx mx-20rpx">
|
||||
<view class="prefix_title">包装单位</view>
|
||||
<view class="bg-#1879ff09 rounded-1 my-2 p-3" v-for="(item, index) in state.detail.skuList" :key="index">
|
||||
|
||||
<view v-if="goodsDetail.priceType == '1'" class="mt-20rpx card p-20rpx mx-20rpx">
|
||||
<view class="prefix_title">规格</view>
|
||||
<view class="bg-#1879ff09 rounded-1 my-2 p-3" v-for="(item, index) in goodsDetail.skuList" :key="index">
|
||||
<view class="sub-text-30">{{ item.skuName }}</view>
|
||||
<view class="second-text-28 mt-1 flex justify-between items-center">
|
||||
<text>售价 {{ displayPrice(item.price) }}</text>
|
||||
@@ -44,37 +48,72 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mt-20rpx card p-20rpx mx-20rpx">
|
||||
<view class="prefix_title">商品描述</view>
|
||||
<view class="mt-20rpx overflow-auto text-26rpx!" v-html="state.detail.description"></view>
|
||||
<view class="mt-20rpx overflow-auto text-26rpx!" v-html="goodsDetail.description"></view>
|
||||
</view>
|
||||
<view class="h-30rpx" />
|
||||
|
||||
<template #main-bottom>
|
||||
<view class="z-200 p-x-30rpx p-y-30rpx bg-white">
|
||||
<product-total :totPrice="totPrice" :totCount="totalCount" @doContainer="doCart" @submit="goSettlement" />
|
||||
</view>
|
||||
</template>
|
||||
</crud-layout>
|
||||
<product-sku v-model="state.showSkuDialog" :goodsInfo="state.goodsDetail" @onSkuAddToCart="onSkuAddToCart" />
|
||||
<product-cart v-model="state.showCartDialog" :merchantId="state.mchId" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { reactive } from "vue"
|
||||
import { computed, reactive } from "vue"
|
||||
import { prosperityShopApi } from "@/sheep/api"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
import { displayPrice } from "@/sheep/utils/formatMoney"
|
||||
import ProductTotal from "./components/product-total.vue"
|
||||
import ProductSku from "./components/product-sku.vue"
|
||||
import ProductCart from "./components/product-cart.vue"
|
||||
import useCartBuy from "./use-cart-buy"
|
||||
|
||||
const { totPrice, totalCount, skuAddToCart, getShopCart, goSettlement } = useCartBuy()
|
||||
|
||||
const state = reactive<any>({
|
||||
id: "",
|
||||
detail: {},
|
||||
mchId: "",
|
||||
goodsDetail: {},
|
||||
showSkuDialog: false,
|
||||
showCartDialog: false,
|
||||
})
|
||||
const goodsDetail = computed(() => state.goodsDetail)
|
||||
|
||||
onLoad(async (option: any) => {
|
||||
if (!option.id) return uni.showToast({ title: "参数错误", icon: "error" })
|
||||
uni.showLoading({ title: "加载中..." })
|
||||
const { id, mchId } = option
|
||||
if (!id || !mchId) return uni.showToast({ title: "参数错误", icon: "error" })
|
||||
state.id = option.id
|
||||
await getGoodsDetail(option.id)
|
||||
state.mchId = option.mchId
|
||||
uni.showLoading({ title: "加载中..." })
|
||||
await getGoodsDetail(id)
|
||||
await getShopCart(mchId)
|
||||
uni.hideLoading()
|
||||
})
|
||||
|
||||
// 获取商品详情
|
||||
const getGoodsDetail = async (id: string) => {
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsDetail(id)
|
||||
if (code != 0) return uni.showToast({ title: msg || "商品详情获取失败", icon: "none" })
|
||||
state.detail = data
|
||||
state.goodsDetail = data
|
||||
}
|
||||
|
||||
// 选择sku加入到购物车
|
||||
const onSkuAddToCart = (sku: any) => {
|
||||
skuAddToCart({ ...state.goodsDetail, ...sku, productId: sku.skuId }, state.mchId)
|
||||
state.showSkuDialog = false
|
||||
}
|
||||
|
||||
// 查看购物车
|
||||
const doCart = () => {
|
||||
state.showCartDialog = true
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ const search = () => {
|
||||
const doGoodsDetail = (id: string) => {
|
||||
if (!id) return uni.showToast({ title: "商品id不存在", icon: "none" })
|
||||
uni.navigateTo({
|
||||
url: `/pages/prosperity-shop/goods-detail?id=${id}`,
|
||||
url: `/pages/prosperity-shop/goods-detail?id=${id}&merchantId=${state.params.merchantId}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<crud-layout title="结算" mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<view class="h-20rpx" />
|
||||
<view class="bg-#FFA61Ecc color-#fff px-2 py-1 text-28rpx rounded-2">温馨提示:当天的订单预计明天开始配送</view>
|
||||
|
||||
<tm-sticky-header>
|
||||
<view class="h-20rpx" />
|
||||
<view class="card p-20rpx">
|
||||
<view class="text-36rpx">请选择自提点</view>
|
||||
<!-- <tm-picker rang-key="title" rang-text="title" v-model="state.curPickUp" v-model:model-str="state.curPickUp" :list="state.pickUpList"> -->
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="sub-text-28">请选择自提点</view>
|
||||
<view class="flex-row items-center second-text-24">
|
||||
<text>{{ 0 || "请选择自提点" }} </text>
|
||||
<text class="ml-10rpx color-#b1b1b1 iconfont icon-xiangxiajiantouxiao" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- </tm-picker> -->
|
||||
<view class="c-#0089ff text-24rpx">配送订单较多时,配送时间可能波动</view>
|
||||
</view>
|
||||
<view class="h-20rpx" />
|
||||
</tm-sticky-header>
|
||||
|
||||
<view class="card p-20rpx mb-20rpx mx-1">
|
||||
<view v-if="totalCount > 0" class="flex-row px-15rpx mb-20rpx" v-for="(v, i) in cartList" :key="i">
|
||||
<image class="size-125rpx rounded-12rpx mr-20rpx bg-#eeeeee" :src="filePath(v.productPic)" mode="aspectFill" />
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="sub-text-30 truncate">{{ v.productName }}</view>
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="flex-col">
|
||||
<view class="second-text-30">¥{{ hooks.useMoney(v.productPrice) }}</view>
|
||||
<view class="second-text-30">x {{ v.productCount }}</view>
|
||||
</view>
|
||||
<view class="second-text-32 c-red!">¥{{ hooks.useMoney(v.totalPrice) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="text-center second-text-28">你尚未选择任何商品</view>
|
||||
</view>
|
||||
<view class="h-20rpx" />
|
||||
|
||||
<template #main-bottom>
|
||||
<view class="flex justify-end items-center p-4">
|
||||
<view class="flex-col mr-4">
|
||||
<view class="second-text-36 color-#f63a36!">¥ {{ hooks.useMoney(totPrice) }}</view>
|
||||
<view class="sub-text-28">共{{ totalCount }}件</view>
|
||||
</view>
|
||||
<view class="bg-#0094ff px-60rpx py-20rpx text-center rounded-full sub-text-32 color-white!" @tap.stop="doBuy">提交订单</view>
|
||||
</view>
|
||||
</template>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue"
|
||||
import { hooks } from "@/sheep"
|
||||
import useCartBuy from "./use-cart-buy"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
|
||||
const { cartList, totPrice, totalCount, doBuy } = useCartBuy()
|
||||
|
||||
const state = reactive({
|
||||
pickUpList: [],
|
||||
curPickUp: {},
|
||||
})
|
||||
</script>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png" @scroll="onScroll">
|
||||
<view class="w-full h-400rpx relative">
|
||||
<image :src="filePath(state.detail.images)" class="w-full h-full bg-#eeeeee" mode="aspectFill" />
|
||||
<image :src="filePath(mchDetail.images)" class="w-full h-full bg-#eeeeee" mode="aspectFill" />
|
||||
<view class="absolute w-full h-full top-0 left-0" :style="filterStyle"></view>
|
||||
</view>
|
||||
<view
|
||||
@@ -12,25 +12,20 @@
|
||||
<image class="w-36rpx h-36rpx" src="@/static/page/shop-goods-search.png" />
|
||||
<text v-if="scrollDetail.scrollTop > 30" class="bg-#eeeeee44 whitespace-nowrap overflow-hidden second-text-26 ml-2">搜索商品</text>
|
||||
</view>
|
||||
<view v-if="state.detail.id" class="card p-20rpx mt-10rpx mx-20rpx">
|
||||
<view class="w-full sub-text-32 truncate">{{ state.detail.name }}</view>
|
||||
<view class="sub-text-24 mt-1">
|
||||
<text class="c-#0094ff! mr-20rpx px-2 bg-#0094ff22 rounded-2">{{ state.detail.status == "0" ? "开业中" : "未开业" }}</text>
|
||||
<text class="rounded-2 c-#0094ff px-2 bg-#0094ff22 rounded-2">{{ state.detail.businessHours }}</text>
|
||||
</view>
|
||||
<view class="second-text-24 truncate mt-1">
|
||||
<text class="mr-20rpx">营业人 {{ state.detail.contactName }}·{{ state.detail.contactPhone }}</text>
|
||||
<text class="mr-20rpx">许可 {{ state.detail.licenseNo }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="mchDetail.id" class="card p-20rpx mt-10rpx mx-20rpx">
|
||||
<view class="w-full sub-text-32 truncate">{{ mchDetail.name }}</view>
|
||||
<text class="sub-text-24 c-#0094ff! px-2 bg-#0094ff22 rounded-2 mr-4">营业</text>
|
||||
<text class="second-text-24 truncate mt-1">营业人 {{ mchDetail.contactName }}·{{ mchDetail.contactPhone }}</text>
|
||||
<view class="second-text-26 mt-1">
|
||||
<image class="w-24rpx h-24rpx mr-1" src="@/static/page/address.svg" />
|
||||
<text>{{ state.detail.address }}</text>
|
||||
<text>{{ mchDetail.address }}</text>
|
||||
</view>
|
||||
<marquee class="second-text-24 mt-1">{{ state.detail.remark }}</marquee>
|
||||
<marquee class="second-text-24 mt-1">{{ mchDetail.remark }}</marquee>
|
||||
</view>
|
||||
|
||||
<view class="flex mt-2">
|
||||
<scroll-view scroll-y class="menu w-200rpx mb-20rpx bg-#f6f6f6 pl-20rpx" style="height: calc(100vh - 420rpx)">
|
||||
<scroll-view scroll-y class="menu w-200rpx mb-20rpx bg-#f6f6f6 pl-20rpx" style="height: calc(100vh - 300rpx)">
|
||||
<view
|
||||
class="menu_item flex-row-center"
|
||||
v-for="(v, i) in state.category"
|
||||
@@ -48,7 +43,7 @@
|
||||
style="height: calc(100vh - 420rpx)"
|
||||
>
|
||||
<view v-for="v in state.goodsList" :key="v.id" class="card flex mx-15rpx mb-2 p-2" @click="doGoodsDetail(v.id)">
|
||||
<image :src="filePath(v.coverImage)" class="size-160rpx rounded-12rpx bg-#eeeeee" mode="aspectFill" />
|
||||
<image :src="filePath(v.coverImage)" class="size-170rpx rounded-12rpx bg-#eeeeee" mode="aspectFill" />
|
||||
<view class="flex-1 ml-2 overflow-hidden">
|
||||
<view class="truncate sub-text-30">{{ v.title }}</view>
|
||||
<view>
|
||||
@@ -58,80 +53,106 @@
|
||||
<text class="second-text-26 mr-2">单位 {{ v.unit }}</text>
|
||||
<text class="second-text-26">库存 {{ v.totalStock }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<template v-if="v.priceType == '2'">
|
||||
<text class="second-text-28 line-through mr-1">
|
||||
<text class="text-26rpx">¥</text>
|
||||
<text class="font-bold">{{ displayPrice(v.originalPrice, "") }}</text>
|
||||
</text>
|
||||
<text class="color-red">
|
||||
<text class="text-26rpx">¥</text>
|
||||
<text class="text-32rpx font-bold">{{ displayPrice(v.spuPrice, "").split(".")[0] }}.</text>
|
||||
<text class="text-30rpx font-bold">{{ displayPrice(v.spuPrice, "").split(".")[1] }}</text>
|
||||
</text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text class="color-red">
|
||||
<text class="text-26rpx">¥</text>
|
||||
<text class="text-32rpx font-bold">{{ displayPrice(v.minPrice, "").split(".")[0] }}.</text>
|
||||
<text class="text-30rpx font-bold">{{ displayPrice(v.minPrice, "").split(".")[1] }}</text>
|
||||
</text>
|
||||
</template>
|
||||
<text class="view-clip px-1 text-18rpx c-white bg-red ml-1 rounded-r-1 rounded-lt-1">到手价</text>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="flex items-center">
|
||||
<template v-if="v.priceType == '2'">
|
||||
<text class="second-text-28 line-through mr-1">
|
||||
<text class="text-26rpx">¥</text>
|
||||
<text>{{ displayPrice(v.originalPrice, "") }}</text>
|
||||
</text>
|
||||
<text class="color-red">
|
||||
<text class="text-26rpx">¥</text>
|
||||
<text class="text-32rpx">{{ displayPrice(v.spuPrice, "").split(".")[0] }}.</text>
|
||||
<text class="text-30rpx">{{ displayPrice(v.spuPrice, "").split(".")[1] }}</text>
|
||||
</text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text class="color-red">
|
||||
<text class="text-26rpx">¥</text>
|
||||
<text class="text-32rpx">{{ displayPrice(v.minPrice, "").split(".")[0] }}.</text>
|
||||
<text class="text-30rpx">{{ displayPrice(v.minPrice, "").split(".")[1] }}</text>
|
||||
</text>
|
||||
</template>
|
||||
<text class="view-clip px-1 text-20rpx c-white bg-red ml-1 rounded-r-1 rounded-lt-1">到手价</text>
|
||||
</view>
|
||||
<view class="second-text-24 px-2 py-2rpx bg-#0094ff c-white! border-rd-8" @tap.stop="doSelectSku(v.id)">选规格</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view v-else class="mx-auto mt-10 second-text-28">暂无商品</view>
|
||||
</view>
|
||||
|
||||
<template #main-bottom>
|
||||
<view class="z-200 p-x-30rpx p-y-30rpx bg-white">
|
||||
<product-total :totPrice="totPrice" :totCount="totalCount" @doContainer="doCart" @submit="goSettlement" />
|
||||
</view>
|
||||
</template>
|
||||
</crud-layout>
|
||||
<product-sku v-model="state.showSkuDialog" :goodsInfo="state.goodsDetail" @onSkuAddToCart="onSkuAddToCart" />
|
||||
<product-cart v-model="state.showCartDialog" :merchantId="state.mchId" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue"
|
||||
import { prosperityShopApi } from "@/sheep/api"
|
||||
import { computed, reactive } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { prosperityShopApi } from "@/sheep/api"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
import treeToList from "@/sheep/utils/tree-to-list"
|
||||
import { displayPrice } from "@/sheep/utils/formatMoney"
|
||||
import { useShopDetailScroll } from "./use-shop-detail-scroll"
|
||||
import useShopDetailScroll from "./use-shop-detail-scroll"
|
||||
import useCartBuy from "./use-cart-buy"
|
||||
import ProductTotal from "./components/product-total.vue"
|
||||
import ProductSku from "./components/product-sku.vue"
|
||||
import ProductCart from "./components/product-cart.vue"
|
||||
|
||||
const state = reactive<any>({
|
||||
id: "",
|
||||
detail: {},
|
||||
mchId: "",
|
||||
mchDetail: {},
|
||||
category: [],
|
||||
curCategoryIndex: 0,
|
||||
goodsList: [],
|
||||
goodsDetail: {},
|
||||
showSkuDialog: false,
|
||||
showCartDialog: false,
|
||||
})
|
||||
const mchDetail = computed(() => state.mchDetail)
|
||||
|
||||
const { scrollDetail, onScroll, filterStyle, searchStyle } = useShopDetailScroll()
|
||||
const { totPrice, totalCount, skuAddToCart, getShopCart, goSettlement } = useCartBuy()
|
||||
|
||||
onLoad(async (option: any) => {
|
||||
if (!option.id) return uni.showToast({ title: "参数错误", icon: "error" })
|
||||
const { id } = option
|
||||
if (!id) return uni.showToast({ title: "参数错误", icon: "error" })
|
||||
state.mchId = id
|
||||
uni.showLoading({ title: "加载中..." })
|
||||
state.id = option.id
|
||||
await getShopDetail(option.id)
|
||||
await getGoodsCategoryTree(option.id)
|
||||
await getMchDetail(id)
|
||||
await getGoodsCategoryTree(id)
|
||||
await getGoodsList()
|
||||
await getShopCart(id)
|
||||
uni.hideLoading()
|
||||
})
|
||||
|
||||
const getShopDetail = async (id: string) => {
|
||||
// 获取商户详情
|
||||
const getMchDetail = async (id: string) => {
|
||||
const { code, data, msg } = await prosperityShopApi.getShopDetail(id)
|
||||
if (code != 0) return uni.showToast({ title: msg || "超市详情获取失败", icon: "none" })
|
||||
state.detail = data
|
||||
state.mchDetail = data
|
||||
}
|
||||
|
||||
// 获取商品分类
|
||||
const getGoodsCategoryTree = async (id: string) => {
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsCategoryTree({ merchantId: id })
|
||||
if (code != 0) return uni.showToast({ title: msg || "商品分类获取失败", icon: "none" })
|
||||
state.category = treeToList(data) ?? []
|
||||
}
|
||||
|
||||
// 获取商品列表
|
||||
const getGoodsList = async () => {
|
||||
const params = {
|
||||
current: 1,
|
||||
size: 99999,
|
||||
merchantId: state.id,
|
||||
merchantId: state.mchId,
|
||||
categoryId: state.category[state.curCategoryIndex].id,
|
||||
}
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsList(params)
|
||||
@@ -139,6 +160,7 @@ const getGoodsList = async () => {
|
||||
state.goodsList = data?.records ?? []
|
||||
}
|
||||
|
||||
// 切换分类
|
||||
const doCategory = async (index: number) => {
|
||||
if (state.curCategoryIndex == index) return
|
||||
state.curCategoryIndex = index
|
||||
@@ -147,16 +169,40 @@ const doCategory = async (index: number) => {
|
||||
uni.hideLoading()
|
||||
}
|
||||
|
||||
// 去查看商品详情
|
||||
const doGoodsDetail = (id: string) => {
|
||||
if (!id) return uni.showToast({ title: "商品id不存在", icon: "none" })
|
||||
if (!id || !state.mchId) return uni.showToast({ title: "id错误", icon: "none" })
|
||||
uni.navigateTo({
|
||||
url: `/pages/prosperity-shop/goods-detail?id=${id}`,
|
||||
url: `/pages/prosperity-shop/goods-detail?id=${id}&mchId=${state.mchId}`,
|
||||
})
|
||||
}
|
||||
|
||||
// 去搜索商品
|
||||
const goSearch = () => {
|
||||
if (!state.detail.id) return uni.showToast({ title: "超市id不存在", icon: "none" })
|
||||
uni.navigateTo({ url: `/pages/prosperity-shop/goods-search?merchantId=${state.detail.id}` })
|
||||
if (!state.mchDetail.id) return uni.showToast({ title: "超市id不存在", icon: "none" })
|
||||
uni.navigateTo({ url: `/pages/prosperity-shop/goods-search?merchantId=${state.mchDetail.id}` })
|
||||
}
|
||||
|
||||
// 选规格
|
||||
const doSelectSku = async (id: string) => {
|
||||
if (!id) return uni.showToast({ title: "商品id不存在", icon: "none" })
|
||||
uni.showLoading({ title: "加载中..." })
|
||||
const { code, data, msg } = await prosperityShopApi.getGoodsDetail(id)
|
||||
if (code != 0) return uni.showToast({ title: msg || "商品详情获取失败", icon: "none" })
|
||||
uni.hideLoading()
|
||||
state.goodsDetail = data
|
||||
state.showSkuDialog = true
|
||||
}
|
||||
|
||||
// 选择sku加入到购物车
|
||||
const onSkuAddToCart = (sku: any) => {
|
||||
skuAddToCart({ ...state.goodsDetail, ...sku, productId: sku.skuId }, state.mchId)
|
||||
state.showSkuDialog = false
|
||||
}
|
||||
|
||||
// 查看购物车
|
||||
const doCart = () => {
|
||||
state.showCartDialog = true
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { router } from "@/sheep"
|
||||
import { orderApi } from "@/sheep/api"
|
||||
import { useProsperityCartStore } from "@/sheep/stores/prosperity-cart"
|
||||
import { isEmpty } from "radash"
|
||||
import { computed } from "vue"
|
||||
|
||||
export default function useCartBuy() {
|
||||
const cartStore = useProsperityCartStore()
|
||||
|
||||
// 购物车商品总金额
|
||||
const totPrice = computed(() => {
|
||||
return cartStore.totPrice
|
||||
})
|
||||
|
||||
// 购物车商品总数量
|
||||
const totalCount = computed(() => {
|
||||
return cartStore.totalCount
|
||||
})
|
||||
|
||||
// 购物车商品列表
|
||||
const cartList = computed(() => {
|
||||
return cartStore.cartList
|
||||
})
|
||||
|
||||
// 选择sku确认加入到购物车
|
||||
const skuAddToCart = (sku: any, merchantId: string) => {
|
||||
cartStore.addGoodsItemToCart(sku)
|
||||
cartStore.updateShopCart(merchantId)
|
||||
}
|
||||
|
||||
// 获取购物车列表
|
||||
const getShopCart = async (merchantId: string) => {
|
||||
await cartStore.getShopCart(merchantId)
|
||||
}
|
||||
|
||||
// 添加一个商品数量
|
||||
const addProductCount = async (productId: string, merchantId: string) => {
|
||||
if (!merchantId) return
|
||||
await cartStore.addProductCount(productId, merchantId)
|
||||
}
|
||||
|
||||
// 减少一个商品数量
|
||||
const removeProductCount = async (productId: string, merchantId: string) => {
|
||||
if (!merchantId) return
|
||||
await cartStore.removeProductCount(productId, merchantId)
|
||||
}
|
||||
|
||||
const goSettlement = () => {
|
||||
uni.navigateTo({ url: "/pages/prosperity-shop/settlement" })
|
||||
}
|
||||
|
||||
// 点击提交订单
|
||||
const doBuy = async () => {
|
||||
if (isEmpty(cartList.value)) return uni.showToast({ title: "请至少购买一件商品", icon: "none" })
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "是否确定购买",
|
||||
confirmColor: "#0094ff",
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
submitPay()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 确认提交订单
|
||||
const submitPay = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: "支付中...", mask: false })
|
||||
const { code, msg }: any = await orderApi.appCreateFarmerReserveOrder({
|
||||
carParentId: cartStore.cartList[0].parentCarId,
|
||||
hardType: "FARMER",
|
||||
})
|
||||
if (code != 0) throw new Error(msg)
|
||||
uni.showToast({ title: "支付成功", icon: "none" })
|
||||
router.jump("/pages/tabbar/order")
|
||||
} catch (error: any) {
|
||||
uni.showToast({ title: error.message, icon: "none" })
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totPrice,
|
||||
totalCount,
|
||||
cartList,
|
||||
getShopCart,
|
||||
skuAddToCart,
|
||||
addProductCount,
|
||||
removeProductCount,
|
||||
goSettlement,
|
||||
doBuy,
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ interface scrollDetail {
|
||||
scrollWidth: number
|
||||
}
|
||||
|
||||
export function useShopDetailScroll() {
|
||||
export default function useShopDetailScroll() {
|
||||
const scrollDetail = ref<scrollDetail>({} as scrollDetail)
|
||||
|
||||
const onScroll = (e: any) => {
|
||||
@@ -31,7 +31,7 @@ export function useShopDetailScroll() {
|
||||
const scrollY = scrollDetail.value.scrollTop
|
||||
const scrollHeight = scrollDetail.value.scrollHeight
|
||||
const scrollWidth = scrollDetail.value.scrollWidth
|
||||
const calcWidth = Math.min((scrollY / scrollHeight) * scrollWidth, scrollWidth)
|
||||
const calcWidth = Math.min(((scrollY / scrollHeight) * scrollWidth) / 2, scrollWidth)
|
||||
if (isNaN(calcWidth)) return { width: `${minWidth}%` }
|
||||
if (calcWidth < 2) return { width: `${calcWidth + minWidth}%` }
|
||||
return {
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
<template>
|
||||
<crud-layout title="喜好分析" bg="/static/page/blue-bg.png">
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
height="100%"
|
||||
:fixed="false"
|
||||
safe-area-inset-bottom
|
||||
:loading-more-enabled="true"
|
||||
:show-scrollbar="false"
|
||||
@query="query"
|
||||
:auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false"
|
||||
hide-empty-view
|
||||
>
|
||||
<z-paging ref="pageRef" height="100%" :fixed="false" safe-area-inset-bottom :loading-more-enabled="true"
|
||||
:show-scrollbar="false" @query="query" :auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false" hide-empty-view>
|
||||
<tm-sheet :margin="[0, 20]">
|
||||
<view class="prefix_title mb-15rpx">菜品分类购买数量占比图</view>
|
||||
<view class="w-full h-600rpx">
|
||||
<qiun-data-charts type="pie" :opts="pieChartOpts" :chartData="pieChartData" tooltipFormat="canteenPieTooltip" />
|
||||
<qiun-data-charts type="pie" :opts="pieChartOpts" :chartData="pieChartData"
|
||||
tooltipFormat="canteenPieTooltip" />
|
||||
</view>
|
||||
</tm-sheet>
|
||||
|
||||
@@ -30,40 +22,37 @@
|
||||
<tm-sheet :margin="[0, 20]">
|
||||
<view class="prefix_title mb-15rpx">个人菜品喜好排行</view>
|
||||
<view v-if="productLikeTopList.length > 0" class="rounded-16rpx bg-white overflow-hidden card">
|
||||
<view class="bg-gradient-to-r from-blue-100 to-blue-100 px-20rpx py-16rpx flex items-center border-b border-gray-100">
|
||||
<view
|
||||
class="bg-gradient-to-r from-blue-100 to-blue-100 px-20rpx py-16rpx flex items-center border-b border-gray-100">
|
||||
<view class="w-80rpx text-center text-24rpx font-bold text-gray-600">排名</view>
|
||||
<view class="flex-1 px-16rpx text-24rpx font-bold text-gray-600">菜品名称</view>
|
||||
<view class="w-120rpx text-center text-24rpx font-bold text-gray-600">分类</view>
|
||||
<view class="w-160rpx text-center text-24rpx font-bold text-gray-600">购买数量</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="(item, index) in productLikeTopList"
|
||||
:key="item.productId"
|
||||
<view v-for="(item, index) in productLikeTopList" :key="item.productId"
|
||||
class="flex items-center px-20rpx py-16rpx border-b border-gray-50 hover:bg-gray-50 transition-colors"
|
||||
:class="{
|
||||
'bg-gradient-to-r from-yellow-50 to-orange-50': index === 0,
|
||||
'bg-gradient-to-r from-gray-50 to-gray-100': index === 1,
|
||||
'bg-gradient-to-r from-orange-50 to-red-50': index === 2,
|
||||
}"
|
||||
>
|
||||
}">
|
||||
<view class="w-80rpx flex justify-center items-center">
|
||||
<view
|
||||
v-if="index < 3"
|
||||
<view v-if="index < 3"
|
||||
class="w-40rpx h-40rpx rounded-1 flex items-center justify-center text-20rpx font-bold text-white"
|
||||
:class="{
|
||||
'bg-gradient-to-r from-yellow-400 to-yellow-500': index === 0,
|
||||
'bg-gradient-to-r from-gray-400 to-gray-500': index === 1,
|
||||
'bg-gradient-to-r from-orange-400 to-orange-500': index === 2,
|
||||
}"
|
||||
>
|
||||
}">
|
||||
{{ index + 1 }}
|
||||
</view>
|
||||
<view v-else class="text-24rpx font-medium text-gray-500">{{ index + 1 }}</view>
|
||||
</view>
|
||||
|
||||
<view class="flex-1 px-16rpx">
|
||||
<view class="text-26rpx font-medium text-gray-800 truncate">{{ item.productName || "未知菜品" }}</view>
|
||||
<view class="text-26rpx font-medium text-gray-800 truncate">{{ item.productName || "未知菜品" }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="w-120rpx text-center">
|
||||
@@ -71,7 +60,9 @@
|
||||
</view>
|
||||
|
||||
<view class="w-160rpx text-center">
|
||||
<view class="px-12rpx py-6rpx bg-blue-100 text-blue-600 text-22rpx rounded-1 whitespace-nowrap">{{ item.payCount }}次</view>
|
||||
<view
|
||||
class="px-12rpx py-6rpx bg-blue-100 text-blue-600 text-22rpx rounded-1 whitespace-nowrap">
|
||||
{{ item.payCount }}次</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,35 +1,17 @@
|
||||
<template>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
:fixed="false"
|
||||
height="100%"
|
||||
v-model="pageHook.list"
|
||||
:default-page-size="10"
|
||||
safe-area-inset-bottom
|
||||
:loading-more-enabled="false"
|
||||
:show-scrollbar="false"
|
||||
@query="query"
|
||||
:auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false"
|
||||
@scroll="pageHook.scroll"
|
||||
>
|
||||
<z-paging ref="pageRef" :fixed="false" height="100%" v-model="pageHook.list" :default-page-size="10"
|
||||
safe-area-inset-bottom :loading-more-enabled="false" :show-scrollbar="false" @query="query"
|
||||
:auto-clean-list-when-reload="false" :auto-scroll-to-top-when-reload="false" @scroll="pageHook.scroll">
|
||||
<template #top>
|
||||
<view class="flex items-center justify-between my-2">
|
||||
<view class="flex-1 bg-white rounded-12rpx p-20rpx flex justify-between items-center">
|
||||
<text class="text-30 font-600">流水统计</text>
|
||||
<tm-text color="#999999" font-size="26">{{ formatVal }}</tm-text>
|
||||
<view class="flex items-center cursor-pointer">
|
||||
<tm-between-time
|
||||
start="2020-1-1"
|
||||
end="2050-1-1"
|
||||
v-model="state.date"
|
||||
v-model:model-str="state.formatVal"
|
||||
@confirm="datePickerConfirm"
|
||||
format="YYYY-MM-DD"
|
||||
:quickDate="[]"
|
||||
drawerSize="900"
|
||||
>
|
||||
<tm-between-time start="2020-1-1" end="2050-1-1" v-model="state.date"
|
||||
v-model:model-str="state.formatVal" @confirm="datePickerConfirm" format="YYYY-MM-DD"
|
||||
:quickDate="[]" drawerSize="900">
|
||||
<image class="w-[30rpx] h-[30rpx]" src="@/static/page/filter.svg" />
|
||||
<text class="ml-1 text-30">筛选</text>
|
||||
</tm-between-time>
|
||||
@@ -50,7 +32,8 @@
|
||||
<view class="flex justify-between mb-2">
|
||||
<view class="flex-1 flex items-center p-2 bg-white rounded-8rpx">
|
||||
<text class="flex-1 text-sm text-center text-gray-600">流水金额</text>
|
||||
<text class="flex-1 text-sm text-center text-gray-800">¥ {{ hooks.useMoney(v.totalPayPrice) }}</text>
|
||||
<text class="flex-1 text-sm text-center text-gray-800">¥ {{ hooks.useMoney(v.totalPayPrice)
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="flex-1 flex items-center p-2 bg-white rounded-8rpx ml-2">
|
||||
<text class="flex-1 text-sm text-center text-gray-600">流水次数</text>
|
||||
@@ -60,7 +43,9 @@
|
||||
<view class="flex justify-between mb-2">
|
||||
<view class="flex-1 flex items-center p-2 bg-white rounded-8rpx">
|
||||
<text class="flex-1 text-sm text-center text-gray-600">盈利金额</text>
|
||||
<text class="flex-1 text-sm text-center text-green-500">¥ {{ hooks.useMoney(v.totalProfitPrice) }}</text>
|
||||
<text class="flex-1 text-sm text-center text-green-500">¥ {{
|
||||
hooks.useMoney(v.totalProfitPrice)
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="flex-1 flex items-center p-2 bg-white rounded-8rpx ml-2">
|
||||
<text class="flex-1 text-sm text-center text-gray-600">盈利次数</text>
|
||||
@@ -70,7 +55,8 @@
|
||||
<view class="flex justify-between mb-0">
|
||||
<view class="flex-1 flex items-center p-2 bg-white rounded-8rpx">
|
||||
<text class="flex-1 text-sm text-center text-gray-600">退款金额</text>
|
||||
<text class="flex-1 text-sm text-center text-red-500">¥ {{ hooks.useMoney(v.totalRefundPrice) }}</text>
|
||||
<text class="flex-1 text-sm text-center text-red-500">¥ {{
|
||||
hooks.useMoney(v.totalRefundPrice) }}</text>
|
||||
</view>
|
||||
<view class="flex-1 flex items-center p-2 bg-white rounded-8rpx ml-2">
|
||||
<text class="flex-1 text-sm text-center text-gray-600">退款次数</text>
|
||||
@@ -80,7 +66,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="fixed bottom-120rpx right-40rpx">
|
||||
<view class="fixed bottom-200rpx right-40rpx">
|
||||
<tm-button size="m" class="px-1 ml-1" @click="doWaterTotal">每月流水合计</tm-button>
|
||||
</view>
|
||||
</z-paging>
|
||||
@@ -126,7 +112,9 @@ const query = (page: number, pagesize: number) => {
|
||||
// 时间范围选择器确认
|
||||
const datePickerConfirm = (date: any) => {
|
||||
const list = formatVal.value.split("~")
|
||||
state.pa.createTimeList = [list[0] + " 00:00:00", list[1] + " 23:59:59"]
|
||||
if (list && list.length == 2) {
|
||||
state.pa.createTimeList = [list[0] + " 00:00:00", list[1] + " 23:59:59"]
|
||||
}
|
||||
pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -2,13 +2,10 @@
|
||||
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<template #main-top>
|
||||
<view class="flex items-center py-3 px-5">
|
||||
<image
|
||||
v-if="state.userInfo?.sysUser?.avatar"
|
||||
class="size-100rpx rounded-full"
|
||||
:src="filePath(state.userInfo.sysUser.avatar)"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<image v-else class="w-100rpx h-100rpx rounded-full" src="/static/icon/default-avatar.png" mode="aspectFill" />
|
||||
<image v-if="state.userInfo?.sysUser?.avatar" class="size-100rpx rounded-full"
|
||||
:src="filePath(state.userInfo.sysUser.avatar)" mode="aspectFill" />
|
||||
<image v-else class="w-100rpx h-100rpx rounded-full" src="/static/icon/default-avatar.png"
|
||||
mode="aspectFill" />
|
||||
<view class="ml-30rpx" v-if="state.userInfo?.sysUser?.userId">
|
||||
<view class="sub-text-30">{{ state.userInfo?.sysUser?.name }}</view>
|
||||
<view class="sub-text-26">ID {{ state.userInfo?.sysUser?.userId }}</view>
|
||||
@@ -21,7 +18,8 @@
|
||||
</template>
|
||||
|
||||
<view class="mt-10rpx rounded-20rpx shadow-main p-30rpx pb-40rpx bg-white">
|
||||
<view class="service_item flex items-center justify-between" v-for="(v, i) in state.menuList" :key="i" @tap="onTabMenu(v)">
|
||||
<view class="service_item flex items-center justify-between" v-for="(v, i) in state.menuList" :key="i"
|
||||
@tap="onTabMenu(v)">
|
||||
<view class="flex-row-center">
|
||||
<image class="size-40rpx" :src="v.icon" mode="aspectFill" />
|
||||
<text class="sub-text-28 m-l-20rpx">{{ v.text }}</text>
|
||||
@@ -31,13 +29,15 @@
|
||||
</view>
|
||||
|
||||
<view v-if="isDevEnv()" class="flex-col-center mt-40rpx mx-30rpx">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff" @tap="doLogout">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff"
|
||||
@tap="doLogout">
|
||||
退出登录
|
||||
</view>
|
||||
</view>
|
||||
<view class="h-30rpx" />
|
||||
<view v-if="state.appInfo == APPENV.SH" class="flex-col-center mt-40rpx mx-30rpx">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff" @tap="doChangeRole">
|
||||
<view class="w-full text-center sub-text-28 p-y-20rpx rounded-40rpx border-solid border border-#0094ff"
|
||||
@tap="doChangeRole">
|
||||
切换角色
|
||||
</view>
|
||||
</view>
|
||||
@@ -50,7 +50,8 @@
|
||||
</view>
|
||||
</crud-layout>
|
||||
|
||||
<tm-modal :show="state.actModalShow" :showCancel="false" title="核销活动兑换券" zIndex="999" @confirm="" @cancel="" @close="">
|
||||
<tm-modal :show="state.actModalShow" :showCancel="false" title="核销活动兑换券" zIndex="999" @confirm="" @cancel=""
|
||||
@close="">
|
||||
<view class="text-center text-28">是否核销该活动兑换券?</view>
|
||||
<view class="text-center text-28">确认核销将会对用户的 消费钱包 扣除 1元 钱</view>
|
||||
<template #footer>
|
||||
@@ -80,7 +81,7 @@ const state = reactive<any>({
|
||||
{ text: "扫一扫", icon: "/static/icon/scan.png", path: "" },
|
||||
{ text: "我的钱包", icon: "/static/icon/service_3.png", path: "/pages/wallet/list" },
|
||||
{ text: "我的人脸", icon: "/static/icon/service_5.png", path: "/pages/human-face/list" },
|
||||
// { text: "车辆管理", icon: "/static/icon/service_6.png", path: "/pages/car/userCar/list" },
|
||||
{ text: "车辆管理", icon: "/static/icon/service_6.png", path: "/pages/car/userCar/list" },
|
||||
{ text: "清除缓存", icon: "/static/icon/clear-storage.png", path: "" },
|
||||
],
|
||||
appInfo: "",
|
||||
|
||||
@@ -143,10 +143,10 @@ import { isEmpty } from "radash"
|
||||
import { filePath } from "@@/utils/file"
|
||||
import { merchantApi, onlineShopApi } from "@@/api"
|
||||
import { hooks, router } from "@@/index"
|
||||
import { useCartStore } from "@/sheep/stores/cart"
|
||||
import { useOnlineCartStore } from "@/sheep/stores/online-cart"
|
||||
import treeToList from "@/sheep/utils/tree-to-list"
|
||||
|
||||
const cartStore = useCartStore()
|
||||
const cartStore = useOnlineCartStore()
|
||||
|
||||
const state = reactive<any>({
|
||||
params: {
|
||||
|
||||
@@ -57,20 +57,15 @@
|
||||
|
||||
<view class="card p-20rpx mb-20rpx" v-for="(v, i) in pageHook.list" :key="i" @tap="toDetail(v)">
|
||||
<view class="flex">
|
||||
<image class="w-150rpx h-150rpx bg-#eeeeee rounded-12rpx" :src="filePath(v.images)" mode="aspectFill" />
|
||||
<image class="w-160rpx h-160rpx bg-#eeeeee rounded-12rpx" :src="filePath(v.images)" mode="aspectFill" />
|
||||
<view class="ml-20rpx flex-1 overflow-hidden">
|
||||
<view class="sub-text-30 truncate">{{ v.name }}</view>
|
||||
<view class="second-text-26 truncate">
|
||||
<text class="mr-20rpx">{{ v.contactName }}</text>
|
||||
<text class="mr-20rpx">
|
||||
<view class="sub-text-32 truncate">{{ v.name }}222222222222222222222222 </view>
|
||||
<view class="second-text-26 flex justify-between my-6rpx">
|
||||
<view>
|
||||
<image class="w-24rpx h-24rpx mr-1" src="@/static/page/phone.svg" />
|
||||
<text @tap.stop="doPhone(v.contactPhone)">{{ v.contactPhone }}</text>
|
||||
</text>
|
||||
<text>{{ v.email }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text class="c-#0094ff! sub-text-26 px-2 bg-#0094ff22 rounded-2 mr-2">营业</text>
|
||||
<text class="c-#0094ff! sub-text-26 px-2 bg-#0094ff22 rounded-2">{{ v.businessHours }}</text>
|
||||
</view>
|
||||
<text class="c-#0094ff! sub-text-26 px-2 bg-#0094ff22 rounded-2">营业</text>
|
||||
</view>
|
||||
<view class="second-text-26">
|
||||
<image class="w-24rpx h-24rpx mr-1" src="@/static/page/address.svg" />
|
||||
@@ -83,21 +78,21 @@
|
||||
<view class="w-160rpx flex-col items-center mr-20rpx" v-for="(pV, pI) in v.featuredProducts" :key="pI">
|
||||
<image class="w-160rpx h-160rpx rounded-12rpx bg-#eeeeee" :src="filePath(pV.coverImage)" mode="aspectFill" />
|
||||
<view class="w-full mt-4rpx sub-text-24 truncate">{{ pV.title }}</view>
|
||||
<view class="w-full flex justify-between pr-1">
|
||||
<view class="w-full flex justify-between">
|
||||
<text class="main-text-26 color-red!">
|
||||
<text class="text-22rpx">¥</text>
|
||||
<text>{{ pV.priceType == "1" ? displayPrice(pV.minPrice, "") : displayPrice(pV.spuPrice, "") }}</text>
|
||||
</text>
|
||||
<text class="sub-text-24">{{ pV.unit || "" }}</text>
|
||||
</view>
|
||||
<view class="w-full flex justify-between pr-1">
|
||||
<text class="second-text-24 line-through">
|
||||
<template v-if="pV.priceType == '2'">
|
||||
<text class="text-22rpx">¥</text>
|
||||
<text>{{ displayPrice(pV.originalPrice, "") }}</text>
|
||||
</template>
|
||||
</text>
|
||||
<text class="second-text-24">库存{{ pV.totalStock }}</text>
|
||||
</view>
|
||||
<view class="w-full flex justify-between second-text-24">
|
||||
<text>{{ pV.unit || "" }}</text>
|
||||
<text>库存{{ pV.totalStock }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -23,18 +23,6 @@ export default {
|
||||
method: "GET",
|
||||
params,
|
||||
}),
|
||||
getShopCar: (params: any) =>
|
||||
request({
|
||||
url: `/hard/hard-car/app/mch-detail`,
|
||||
method: "GET",
|
||||
params,
|
||||
}),
|
||||
updateShopCar: (data: any) =>
|
||||
request({
|
||||
url: `/hard/hard-car/app/save-or-upload`,
|
||||
method: "POST",
|
||||
data,
|
||||
}),
|
||||
checkSpuStock: (params) => {
|
||||
return request({
|
||||
url: "/canteen/canteenOnlineSpu/app/checkSpuStock",
|
||||
|
||||
@@ -25,6 +25,18 @@ export default {
|
||||
method: "GET",
|
||||
params,
|
||||
}),
|
||||
getShopCar: (params: any) =>
|
||||
request({
|
||||
url: `/hard/hard-car/app/mch-detail`,
|
||||
method: "GET",
|
||||
params,
|
||||
}),
|
||||
updateShopCar: (data: any) =>
|
||||
request({
|
||||
url: `/hard/hard-car/app/save-or-upload`,
|
||||
method: "POST",
|
||||
data,
|
||||
}),
|
||||
/**
|
||||
* 预约时间列表
|
||||
*/
|
||||
@@ -44,4 +56,16 @@ export default {
|
||||
method: "POST",
|
||||
data,
|
||||
}),
|
||||
/**
|
||||
* 创建共富商城预约订单
|
||||
* @body body.carParentId 购物车id
|
||||
* @body body.walletTypeId 钱包类型id
|
||||
* @body body.pickUpId 自提点id
|
||||
*/
|
||||
appCreateFarmerReserveOrder: (data: any) =>
|
||||
request({
|
||||
url: "/hard/hard-order/app/create-farmer-order",
|
||||
method: "POST",
|
||||
data,
|
||||
}),
|
||||
}
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
data,
|
||||
}),
|
||||
/**
|
||||
* 个人菜品喜好排行
|
||||
*
|
||||
*/
|
||||
productLikeTop: (data: any): any =>
|
||||
request({
|
||||
|
||||
@@ -69,4 +69,26 @@ export default {
|
||||
method: "GET",
|
||||
data: {},
|
||||
}),
|
||||
/**
|
||||
* 自提点分页
|
||||
* @param params.pageNum 页码
|
||||
* @param params.pageSize 每页数量
|
||||
* @param params.mchIds 商户ID列表
|
||||
*/
|
||||
pickUpPage: (params: any): Promise<any> =>
|
||||
request({
|
||||
url: "wallet/mch-pick-up/app/page",
|
||||
method: "GET",
|
||||
params: params,
|
||||
}),
|
||||
/**
|
||||
* 自提点详情
|
||||
* @param params.id 自提点id
|
||||
*/
|
||||
pickUpDetail: (params: any): Promise<any> =>
|
||||
request({
|
||||
url: "wallet/mch-pick-up/app/detail",
|
||||
method: "GET",
|
||||
params: params,
|
||||
}),
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { foodApi } from "../api"
|
||||
import { orderApi } from "../api"
|
||||
|
||||
export const useCartStore = defineStore("cartStore", {
|
||||
export const useOnlineCartStore = defineStore("onlineCartStore", {
|
||||
state: () => ({
|
||||
cart: JSON.parse(uni.getStorageSync("onlineShopCart") || "[]"),
|
||||
shopMerchantId: uni.getStorageSync("onlineShopMerchantId") || "",
|
||||
}),
|
||||
getters: {
|
||||
totalCount(state) {
|
||||
return state.cart.reduce((prev: string, cur: any) => {
|
||||
return state.cart.reduce((prev: number, cur: { productCount: number }) => {
|
||||
return prev + cur.productCount
|
||||
}, 0)
|
||||
},
|
||||
@@ -58,7 +58,7 @@ export const useCartStore = defineStore("cartStore", {
|
||||
await this.getShopCart()
|
||||
},
|
||||
async getShopCart() {
|
||||
const { data } = await foodApi.getShopCar({ merchantId: this.shopMerchantId, hardType: "SUPERMARKET" })
|
||||
const { data } = await orderApi.getShopCar({ merchantId: this.shopMerchantId, hardType: "SUPERMARKET" })
|
||||
this.saveShopCart(data ?? [])
|
||||
},
|
||||
async updateShopCart() {
|
||||
@@ -70,7 +70,7 @@ export const useCartStore = defineStore("cartStore", {
|
||||
productId: v.productId,
|
||||
}
|
||||
})
|
||||
const { code }: any = await foodApi.updateShopCar({ merchantId: this.shopMerchantId, list, hardType: "SUPERMARKET" })
|
||||
const { code }: any = await orderApi.updateShopCar({ merchantId: this.shopMerchantId, list, hardType: "SUPERMARKET" })
|
||||
if (code == 0) return await this.getShopCart()
|
||||
uni.showToast({ title: "更新购物车失败", icon: "none" })
|
||||
},
|
||||
@@ -0,0 +1,74 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { orderApi } from "../api"
|
||||
|
||||
// 共富商城购物车
|
||||
export const useProsperityCartStore = defineStore("prosperityCartStore", {
|
||||
state: (): any => ({
|
||||
cartList: [],
|
||||
}),
|
||||
getters: {
|
||||
totalCount(state) {
|
||||
return state.cartList.reduce((prev: number, cur: { productCount: number }) => {
|
||||
return prev + cur.productCount
|
||||
}, 0)
|
||||
},
|
||||
totPrice(state) {
|
||||
return state.cartList
|
||||
.map((item: any) => Number(item.totalPrice))
|
||||
.reduce((prev: number, cur: number) => prev + cur, 0)
|
||||
.toFixed(2)
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 购物车添加商品项
|
||||
addGoodsItemToCart(goodsItem: any) {
|
||||
const findResult = this.cartList.find((item: any) => {
|
||||
return item.productId === goodsItem.productId
|
||||
})
|
||||
if (!findResult) {
|
||||
this.cartList.unshift(goodsItem)
|
||||
} else {
|
||||
findResult.productCount++
|
||||
}
|
||||
},
|
||||
// 购物车商品项数量减一
|
||||
async removeProductCount(productId: string, merchantId: string) {
|
||||
this.cartList.forEach((item: any) => {
|
||||
if (item.productId === productId) {
|
||||
item.productCount--
|
||||
}
|
||||
})
|
||||
await this.updateShopCart(merchantId)
|
||||
await this.getShopCart(merchantId)
|
||||
},
|
||||
// 购物车商品项数量加一
|
||||
async addProductCount(productId: string, merchantId: string) {
|
||||
this.cartList.forEach((item: any) => {
|
||||
if (item.productId === productId) {
|
||||
item.productCount++
|
||||
}
|
||||
})
|
||||
await this.updateShopCart(merchantId)
|
||||
await this.getShopCart(merchantId)
|
||||
},
|
||||
// 获取购物车商品列表
|
||||
async getShopCart(merchantId: string) {
|
||||
const { data } = await orderApi.getShopCar({ merchantId, hardType: "FARMER" })
|
||||
this.cartList = data ?? []
|
||||
},
|
||||
// 更新购物车商品列表
|
||||
async updateShopCart(merchantId: string) {
|
||||
const list = this.cartList
|
||||
.filter((v) => v.productCount && v.productCount > 0)
|
||||
.map((v) => {
|
||||
return {
|
||||
productCount: v.productCount,
|
||||
productId: v.productId,
|
||||
}
|
||||
})
|
||||
const { code }: any = await orderApi.updateShopCar({ merchantId, list, hardType: "FARMER" })
|
||||
if (code == 0) return await this.getShopCart(merchantId)
|
||||
uni.showToast({ title: "更新购物车失败", icon: "none" })
|
||||
},
|
||||
},
|
||||
})
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Reference in new issue
Block a user