第一次提交
This commit is contained in:
122
package/user/account/index.vue
Normal file
122
package/user/account/index.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<view class="partner">
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper" v-if="shopInfo">
|
||||
<u-form :model="form" ref="uForm" label-width="240rpx">
|
||||
<u-form-item label="商户名称" prop="name">
|
||||
{{shopInfo.shopName}}
|
||||
</u-form-item>
|
||||
<u-form-item label="联系人" prop="name">
|
||||
{{shopInfo.linkman}}
|
||||
</u-form-item>
|
||||
<u-form-item label="联系方式" prop="name">
|
||||
{{shopInfo.phone}}
|
||||
</u-form-item>
|
||||
<u-form-item label="站点地址" prop="name">
|
||||
{{shopInfo.address}}
|
||||
</u-form-item>
|
||||
<u-form-item label="法定代表人身份" prop="name">
|
||||
<image :src="applyInfo.sfz_image1" mode="widthFix" class="shipin"></image>
|
||||
<image :src="applyInfo.sfz_image2" mode="widthFix" class="shipin"></image>
|
||||
</u-form-item>
|
||||
<u-form-item label="门脸照" prop="name">
|
||||
<image :src="applyInfo.shop_image" mode="widthFix" class="shipin"></image>
|
||||
</u-form-item>
|
||||
<u-form-item label="微信号" prop="name">
|
||||
{{applyInfo.weixin}}
|
||||
</u-form-item>
|
||||
<u-form-item label="食品经营许可证" prop="name">
|
||||
<image :src="applyInfo.shipin_card_image" mode="widthFix" class="shipin"></image>
|
||||
</u-form-item>
|
||||
<u-form-item label="支付宝姓名" prop="name" v-if="shopInfo.alipayName">
|
||||
{{shopInfo.alipayName}}
|
||||
</u-form-item>
|
||||
<u-form-item label="支付宝账号" prop="name" v-if="shopInfo.alipayAccount">
|
||||
{{shopInfo.alipayAccount}}
|
||||
</u-form-item>
|
||||
|
||||
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<!-- <view class="footer">
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle">更新资料</u-button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
// 入驻类型 (合伙人10001,配送员10002,社区门店10003,省代10004)
|
||||
gradeId: 10004,
|
||||
company: '',
|
||||
realName: '',
|
||||
phone: '',
|
||||
mobile: '',
|
||||
region: [],
|
||||
detail: '',
|
||||
}
|
||||
|
||||
import * as UserApi from '@/api/user'
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
disabled: false,
|
||||
imageList: [],
|
||||
shopInfo: null,
|
||||
applyInfo: null
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getUserInfo()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前用户信息
|
||||
getUserInfo() {
|
||||
const app = this
|
||||
UserApi.info().then(result => {
|
||||
app.shopInfo = result.data.shopInfo
|
||||
app.applyInfo = result.data.applyInfo
|
||||
})
|
||||
},
|
||||
groupChange(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.partner {
|
||||
|
||||
.banner {
|
||||
width: 100%;
|
||||
}
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
.logo{
|
||||
width: 100rpx;
|
||||
}
|
||||
.shipin{
|
||||
width: 200rpx;
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
width: 500rpx;
|
||||
margin: 20rpx auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
206
package/user/address/create.vue
Executable file
206
package/user/address/create.vue
Executable file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<!-- 标题 -->
|
||||
<view class="page-title">收货地址</view>
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper">
|
||||
<u-form :model="form" ref="uForm" label-width="140rpx">
|
||||
<u-form-item label="姓名" prop="name">
|
||||
<u-input v-model="form.name" placeholder="请输入收货人姓名" />
|
||||
</u-form-item>
|
||||
<u-form-item label="电话" prop="phone">
|
||||
<u-input v-model="form.phone" placeholder="请输入收货人手机号" />
|
||||
</u-form-item>
|
||||
<u-form-item label="地区" prop="region">
|
||||
<select-region ref="sRegion" v-model="form.region" />
|
||||
</u-form-item>
|
||||
<u-form-item label="详细地址" prop="detail" :border-bottom="false">
|
||||
<u-input v-model="form.detail" placeholder="街道门牌、楼层等信息" />
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="footer">
|
||||
<view class="btn-wrapper">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="btn-item btn-item-wechat" @click="chooseAddress()">选择微信收货地址</view>
|
||||
<!-- #endif -->
|
||||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
import { isMobile } from '@/utils/verify'
|
||||
import * as AddressApi from '@/api/address'
|
||||
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
name: '',
|
||||
phone: '',
|
||||
region: [],
|
||||
detail: ''
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
name: [{
|
||||
required: true,
|
||||
message: '请输入姓名',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
phone: [{
|
||||
required: true,
|
||||
message: '请输入手机号',
|
||||
trigger: ['blur', 'change']
|
||||
}, {
|
||||
// 自定义验证函数
|
||||
validator: (rule, value, callback) => {
|
||||
// 返回true表示校验通过,返回false表示不通过
|
||||
return isMobile(value)
|
||||
},
|
||||
message: '手机号码不正确',
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ['blur'],
|
||||
}],
|
||||
region: [{
|
||||
required: true,
|
||||
message: '请选择省市区',
|
||||
trigger: ['blur', 'change'],
|
||||
type: 'array'
|
||||
}],
|
||||
detail: [{
|
||||
required: true,
|
||||
message: '请输入详细地址',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
rules,
|
||||
// 按钮禁用
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {},
|
||||
|
||||
// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
|
||||
onReady() {
|
||||
this.$refs.uForm.setRules(this.rules)
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 选择微信地址
|
||||
// #ifdef MP-WEIXIN
|
||||
chooseAddress() {
|
||||
const { form, $refs } = this
|
||||
uni.chooseAddress({
|
||||
success(res) {
|
||||
const names = $refs.sRegion.getOptionItemByNames(res)
|
||||
form.name = res.userName
|
||||
form.phone = res.telNumber
|
||||
form.detail = res.detailInfo
|
||||
form.region = names.length > 0 ? names : []
|
||||
}
|
||||
})
|
||||
},
|
||||
// #endif
|
||||
|
||||
// 表单提交
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
if (app.disabled) {
|
||||
return false
|
||||
}
|
||||
app.$refs.uForm.validate(valid => {
|
||||
if (valid) {
|
||||
app.disabled = true
|
||||
AddressApi.add(app.form)
|
||||
.then(result => {
|
||||
app.$toast(result.message)
|
||||
uni.navigateBack()
|
||||
})
|
||||
.finally(() => app.disabled = false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: #f7f8fa;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.page-title {
|
||||
width: 94%;
|
||||
margin: 0 auto;
|
||||
padding-top: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: rgba(69, 90, 100, 0.6);
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
|
||||
.footer {
|
||||
margin-top: 80rpx;
|
||||
|
||||
.btn-wrapper {
|
||||
height: 100%;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-item-wechat {
|
||||
background: #0ba90b;
|
||||
margin-bottom: 26rpx;
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
|
||||
// 禁用按钮
|
||||
&.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
305
package/user/address/index.vue
Executable file
305
package/user/address/index.vue
Executable file
@@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<view class="addres-list">
|
||||
<view class="address-item" v-for="(item, index) in list" :key="index">
|
||||
<view class="contacts">
|
||||
<text class="name">{{ item.name }}</text>
|
||||
<text class="phone">{{ item.phone }}</text>
|
||||
</view>
|
||||
<view class="address">
|
||||
<text class="region" v-for="(region, idx) in item.region" :key="idx">{{ region }}</text>
|
||||
<text class="detail">{{ item.detail }}</text>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="item-option">
|
||||
<view class="_left">
|
||||
<label class="item-radio" @click.stop="handleSetDefault(item.address_id)">
|
||||
<radio class="radio" :color="appTheme.mainBg" :checked="item.address_id == defaultId"></radio>
|
||||
<text class="text">{{ item.address_id == defaultId ? '默认' : '选择' }}</text>
|
||||
</label>
|
||||
</view>
|
||||
<view class="_right">
|
||||
<view class="events">
|
||||
<view class="event-item" @click="handleUpdate(item.address_id)">
|
||||
<text class="iconfont icon-edit"></text>
|
||||
<text class="title">编辑</text>
|
||||
</view>
|
||||
<view class="event-item" @click="handleRemove(item.address_id)">
|
||||
<text class="iconfont icon-delete"></text>
|
||||
<text class="title">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<empty v-if="!list.length" :isLoading="isLoading" tips="亲,暂无收货地址" />
|
||||
<!-- 底部操作按钮 -->
|
||||
<view class="footer-fixed">
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn-item btn-item-main" @click="handleCreate()">添加新地址</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as AddressApi from '@/api/address'
|
||||
import Empty from '@/components/empty'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Empty
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//当前页面参数
|
||||
options: {},
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 收货地址列表
|
||||
list: [],
|
||||
// 默认收货地址
|
||||
defaultId: null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 当前页面参数
|
||||
this.options = options
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
// 获取页面数据
|
||||
this.getPageData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取页面数据
|
||||
getPageData() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
Promise.all([app.getDefaultId(), app.getAddressList()])
|
||||
.then(() => {
|
||||
// 列表排序把默认收货地址放到最前
|
||||
app.onReorder()
|
||||
})
|
||||
.finally(() => app.isLoading = false)
|
||||
},
|
||||
|
||||
// 获取收货地址列表
|
||||
getAddressList() {
|
||||
const app = this
|
||||
return new Promise((resolve, reject) => {
|
||||
AddressApi.list()
|
||||
.then(result => {
|
||||
app.list = result.data.list
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取默认的收货地址
|
||||
getDefaultId() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const app = this
|
||||
AddressApi.defaultId()
|
||||
.then(result => {
|
||||
app.defaultId = result.data.defaultId
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 列表排序把默认收货地址放到最前
|
||||
onReorder() {
|
||||
const app = this
|
||||
app.list.sort(item => {
|
||||
return item.address_id == app.defaultId ? -1 : 1
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 添加新地址
|
||||
*/
|
||||
handleCreate() {
|
||||
this.$navTo('pages/address/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleUpdate(addressId) {
|
||||
this.$navTo('pages/address/update', { addressId })
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleRemove(addressId) {
|
||||
const app = this
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "您确定要删除当前收货地址吗?",
|
||||
success({ confirm }) {
|
||||
confirm && app.onRemove(addressId)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
onRemove(addressId) {
|
||||
const app = this
|
||||
AddressApi.remove(addressId)
|
||||
.then(result => {
|
||||
app.getPageData()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置为默认地址
|
||||
* @param {Object} addressId
|
||||
*/
|
||||
handleSetDefault(addressId) {
|
||||
const app = this
|
||||
AddressApi.setDefault(addressId)
|
||||
.then(result => {
|
||||
app.defaultId = addressId
|
||||
app.options.from === 'checkout' && uni.navigateBack()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.addres-list {
|
||||
padding-bottom: calc(constant(safe-area-inset-bottom) + 140rpx);
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
// 项目内容
|
||||
.address-item {
|
||||
margin: 0 auto 20rpx auto;
|
||||
padding: 30rpx 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.contacts {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.name {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
font-size: 28rpx;
|
||||
|
||||
.region {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f3f3f3;
|
||||
}
|
||||
|
||||
.item-option {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 48rpx;
|
||||
|
||||
// 单选框
|
||||
.item-radio {
|
||||
font-size: 28rpx;
|
||||
|
||||
.radio {
|
||||
vertical-align: middle;
|
||||
transform: scale(0.76)
|
||||
}
|
||||
|
||||
.text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
// 操作
|
||||
.events {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 48rpx;
|
||||
|
||||
.event-item {
|
||||
font-size: 28rpx;
|
||||
margin-right: 26rpx;
|
||||
color: #4c4c4c;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 底部操作栏
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
bottom: var(--window-bottom);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 11;
|
||||
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.btn-wrapper {
|
||||
height: 120rpx;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
244
package/user/address/update.vue
Executable file
244
package/user/address/update.vue
Executable file
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<!-- 标题 -->
|
||||
<view class="page-title">收货地址</view>
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper">
|
||||
<u-form :model="form" ref="uForm" label-width="140rpx">
|
||||
<u-form-item label="姓名" prop="name">
|
||||
<u-input v-model="form.name" placeholder="请输入收货人姓名" />
|
||||
</u-form-item>
|
||||
<u-form-item label="电话" prop="phone">
|
||||
<u-input v-model="form.phone" placeholder="请输入收货人手机号" />
|
||||
</u-form-item>
|
||||
<u-form-item label="地区" prop="region">
|
||||
<select-region ref="sRegion" v-model="form.region" />
|
||||
</u-form-item>
|
||||
<u-form-item label="详细地址" prop="detail" :border-bottom="false">
|
||||
<u-input v-model="form.detail" placeholder="街道门牌、楼层等信息" />
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="footer">
|
||||
<view class="btn-wrapper">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="btn-item btn-item-wechat" @click="chooseAddress()">选择微信收货地址</view>
|
||||
<!-- #endif -->
|
||||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
import { isMobile } from '@/utils/verify'
|
||||
import * as AddressApi from '@/api/address'
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
name: [{
|
||||
required: true,
|
||||
message: '请输入姓名',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
phone: [{
|
||||
required: true,
|
||||
message: '请输入手机号',
|
||||
trigger: ['blur', 'change']
|
||||
}, {
|
||||
// 自定义验证函数
|
||||
validator: (rule, value, callback) => {
|
||||
// 返回true表示校验通过,返回false表示不通过
|
||||
return isMobile(value)
|
||||
},
|
||||
message: '手机号码不正确',
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ['blur'],
|
||||
}],
|
||||
region: [{
|
||||
required: true,
|
||||
message: '请选择省市区',
|
||||
trigger: ['blur', 'change'],
|
||||
type: 'array'
|
||||
}],
|
||||
detail: [{
|
||||
required: true,
|
||||
message: '请输入详细地址',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
name: '',
|
||||
phone: '',
|
||||
region: [],
|
||||
detail: ''
|
||||
},
|
||||
rules,
|
||||
// 加载中
|
||||
isLoading: true,
|
||||
// 按钮禁用
|
||||
disabled: false,
|
||||
// 当前收货地址ID
|
||||
addressId: null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad({ addressId }) {
|
||||
// 当前收货地址ID
|
||||
this.addressId = addressId
|
||||
// 获取当前记录详情
|
||||
this.getDetail()
|
||||
},
|
||||
|
||||
// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
|
||||
onReady() {
|
||||
this.$refs.uForm.setRules(this.rules)
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取当前记录详情
|
||||
getDetail() {
|
||||
const app = this
|
||||
AddressApi.detail(app.addressId)
|
||||
.then(result => {
|
||||
const detail = result.data.detail
|
||||
app.createFormData(detail)
|
||||
})
|
||||
},
|
||||
|
||||
// 选择微信地址
|
||||
// #ifdef MP-WEIXIN
|
||||
chooseAddress() {
|
||||
const { form, $refs } = this
|
||||
uni.chooseAddress({
|
||||
success(res) {
|
||||
const names = $refs.sRegion.getOptionItemByNames(res)
|
||||
form.name = res.userName
|
||||
form.phone = res.telNumber
|
||||
form.detail = res.detailInfo
|
||||
form.region = names.length > 0 ? names : []
|
||||
}
|
||||
})
|
||||
},
|
||||
// #endif
|
||||
|
||||
// 生成默认的表单数据
|
||||
createFormData(detail) {
|
||||
const { form } = this
|
||||
form.name = detail.name
|
||||
form.phone = detail.phone
|
||||
form.detail = detail.detail
|
||||
form.region = this.createRegion(detail)
|
||||
},
|
||||
|
||||
createRegion(detail) {
|
||||
return [{
|
||||
label: detail.region.province,
|
||||
value: detail.province_id
|
||||
}, {
|
||||
label: detail.region.city,
|
||||
value: detail.city_id
|
||||
}, {
|
||||
label: detail.region.region,
|
||||
value: detail.region_id
|
||||
}]
|
||||
},
|
||||
|
||||
// 表单提交
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
if (app.disabled) {
|
||||
return false
|
||||
}
|
||||
app.$refs.uForm.validate(valid => {
|
||||
if (valid) {
|
||||
app.disabled = true
|
||||
AddressApi.edit(app.addressId, app.form)
|
||||
.then(result => {
|
||||
app.$toast(result.message)
|
||||
uni.navigateBack()
|
||||
})
|
||||
.finally(() => app.disabled = false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: #f7f8fa;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.page-title {
|
||||
width: 94%;
|
||||
margin: 0 auto;
|
||||
padding-top: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: rgba(69, 90, 100, 0.6);
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
|
||||
.footer {
|
||||
margin-top: 80rpx;
|
||||
|
||||
.btn-wrapper {
|
||||
height: 100%;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-item-wechat {
|
||||
background: #0ba90b;
|
||||
margin-bottom: 26rpx;
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
|
||||
// 禁用按钮
|
||||
&.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
109
package/user/admin/index.vue
Normal file
109
package/user/admin/index.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<view class="partner">
|
||||
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper" v-if="shopInfo">
|
||||
<u-form :model="form" ref="uForm" label-width="240rpx">
|
||||
<u-form-item>
|
||||
<view class="shop-box">
|
||||
<text class="shop-name">后台管理</text>
|
||||
<text>地址:https://dev.gxwebsoft.com/ylx-admin/</text>
|
||||
<text>账号:{{applyInfo.phone}}</text>
|
||||
<text>密码:默认为手机号码后6位</text>
|
||||
</view>
|
||||
</u-form-item>
|
||||
|
||||
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<!-- <view class="footer">
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle">更新资料</u-button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
// 入驻类型 (合伙人10001,配送员10002,社区门店10003,省代10004)
|
||||
grade_id: 10004,
|
||||
company: '',
|
||||
real_name: '',
|
||||
phone: '',
|
||||
mobile: '',
|
||||
region: [],
|
||||
detail: '',
|
||||
}
|
||||
|
||||
import * as UserApi from '@/api/user'
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
disabled: false,
|
||||
imageList: [],
|
||||
shopInfo: {},
|
||||
applyInfo: {}
|
||||
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getUserInfo()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前用户信息
|
||||
getUserInfo() {
|
||||
const app = this
|
||||
UserApi.info().then(result => {
|
||||
app.shopInfo = result.data.shopInfo
|
||||
app.applyInfo = result.data.applyInfo
|
||||
})
|
||||
},
|
||||
groupChange(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.partner {
|
||||
.banner {
|
||||
padding-top: 20rpx;
|
||||
width: 100%;
|
||||
}
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
.shop-box{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.shop-name{
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
.logo{
|
||||
width: 100rpx;
|
||||
}
|
||||
.shipin{
|
||||
width: 400rpx;
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
width: 500rpx;
|
||||
margin: 20rpx auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
206
package/user/equipment/create.vue
Executable file
206
package/user/equipment/create.vue
Executable file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<!-- 标题 -->
|
||||
<view class="page-title">收货地址</view>
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper">
|
||||
<u-form :model="form" ref="uForm" label-width="140rpx">
|
||||
<u-form-item label="姓名" prop="name">
|
||||
<u-input v-model="form.name" placeholder="请输入收货人姓名" />
|
||||
</u-form-item>
|
||||
<u-form-item label="电话" prop="phone">
|
||||
<u-input v-model="form.phone" placeholder="请输入收货人手机号" />
|
||||
</u-form-item>
|
||||
<u-form-item label="地区" prop="region">
|
||||
<select-region ref="sRegion" v-model="form.region" />
|
||||
</u-form-item>
|
||||
<u-form-item label="详细地址" prop="detail" :border-bottom="false">
|
||||
<u-input v-model="form.detail" placeholder="街道门牌、楼层等信息" />
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="footer">
|
||||
<view class="btn-wrapper">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="btn-item btn-item-wechat" @click="chooseAddress()">选择微信收货地址</view>
|
||||
<!-- #endif -->
|
||||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
import { isMobile } from '@/utils/verify'
|
||||
import * as AddressApi from '@/api/address'
|
||||
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
name: '',
|
||||
phone: '',
|
||||
region: [],
|
||||
detail: ''
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
name: [{
|
||||
required: true,
|
||||
message: '请输入姓名',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
phone: [{
|
||||
required: true,
|
||||
message: '请输入手机号',
|
||||
trigger: ['blur', 'change']
|
||||
}, {
|
||||
// 自定义验证函数
|
||||
validator: (rule, value, callback) => {
|
||||
// 返回true表示校验通过,返回false表示不通过
|
||||
return isMobile(value)
|
||||
},
|
||||
message: '手机号码不正确',
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ['blur'],
|
||||
}],
|
||||
region: [{
|
||||
required: true,
|
||||
message: '请选择省市区',
|
||||
trigger: ['blur', 'change'],
|
||||
type: 'array'
|
||||
}],
|
||||
detail: [{
|
||||
required: true,
|
||||
message: '请输入详细地址',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
rules,
|
||||
// 按钮禁用
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {},
|
||||
|
||||
// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
|
||||
onReady() {
|
||||
this.$refs.uForm.setRules(this.rules)
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 选择微信地址
|
||||
// #ifdef MP-WEIXIN
|
||||
chooseAddress() {
|
||||
const { form, $refs } = this
|
||||
uni.chooseAddress({
|
||||
success(res) {
|
||||
const names = $refs.sRegion.getOptionItemByNames(res)
|
||||
form.name = res.userName
|
||||
form.phone = res.telNumber
|
||||
form.detail = res.detailInfo
|
||||
form.region = names.length > 0 ? names : []
|
||||
}
|
||||
})
|
||||
},
|
||||
// #endif
|
||||
|
||||
// 表单提交
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
if (app.disabled) {
|
||||
return false
|
||||
}
|
||||
app.$refs.uForm.validate(valid => {
|
||||
if (valid) {
|
||||
app.disabled = true
|
||||
AddressApi.add(app.form)
|
||||
.then(result => {
|
||||
app.$toast(result.message)
|
||||
uni.navigateBack()
|
||||
})
|
||||
.finally(() => app.disabled = false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: #f7f8fa;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.page-title {
|
||||
width: 94%;
|
||||
margin: 0 auto;
|
||||
padding-top: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: rgba(69, 90, 100, 0.6);
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
|
||||
.footer {
|
||||
margin-top: 80rpx;
|
||||
|
||||
.btn-wrapper {
|
||||
height: 100%;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-item-wechat {
|
||||
background: #0ba90b;
|
||||
margin-bottom: 26rpx;
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
|
||||
// 禁用按钮
|
||||
&.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
441
package/user/equipment/detail.vue
Executable file
441
package/user/equipment/detail.vue
Executable file
@@ -0,0 +1,441 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<view class="addres-list">
|
||||
<view class="address-item">
|
||||
<view class="head-info">
|
||||
<view class="title">{{ title }}</view>
|
||||
<view class="description">{{ description }}</view>
|
||||
|
||||
</view>
|
||||
<u-form :label-width="200" :model="form" ref="uForm">
|
||||
<u-form-item left-icon="info-circle" label="剩余电量">
|
||||
<view class="item-right">{{ form.surplusPower }}</view>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="info-circle" label="设备电压">
|
||||
<view class="item-right">{{ form.equipmentVoltage }}</view>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="info-circle" label="GPS信号">
|
||||
<view class="item-right">{{ form.gps }}</view>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="info-circle" label="GSM信号">
|
||||
<view class="item-right">{{ form.gsm }}</view>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="info-circle" label="设备电流">
|
||||
<view class="item-right">{{ form.equipmentCurrent }}</view>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="info-circle" label="标称容量">
|
||||
<view class="item-right">{{ form.nominalCapacity }}</view>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="info-circle" label="设备温度">
|
||||
<view class="item-right">{{ form.equipmentTemperature }}</view>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="info-circle" label="电池温度">
|
||||
<view class="item-right">{{ form.batteryTemperature }}</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
<view class="address-item">
|
||||
<u-row gutter="16" justify="center">
|
||||
<u-col span="4">
|
||||
<view class="demo-layout bg-purple">
|
||||
<text class="desc">最高电压</text>
|
||||
<text class="value1">3.168V</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="4">
|
||||
<view class="demo-layout bg-purple-light">
|
||||
<text class="desc">最低电压</text>
|
||||
<text class="value2">3.166V</text>
|
||||
</view>
|
||||
</u-col>
|
||||
<u-col span="4">
|
||||
<view class="demo-layout bg-purple-dark">
|
||||
<text class="desc">相差压值</text>
|
||||
<text class="value3">0.002V</text>
|
||||
</view>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
<view class="address-item">
|
||||
<view class="head-info">
|
||||
<view class="title">电芯电压</view>
|
||||
</view>
|
||||
<view class="content">
|
||||
<image class="image" src="/static/battery.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as AddressApi from '@/api/address'
|
||||
import Empty from '@/components/empty'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Empty
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//当前页面参数
|
||||
options: {},
|
||||
form: {
|
||||
surplusPower: '98%',
|
||||
equipmentVoltage: '82.6V',
|
||||
gps: '',
|
||||
gsm: '',
|
||||
equipmentCurrent: '12AH',
|
||||
nominalCapacity: '50AH',
|
||||
equipmentTemperature: '2℃',
|
||||
batteryTemperature: '35℃'
|
||||
},
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 收货地址列表
|
||||
list: [],
|
||||
// 默认收货地址
|
||||
defaultId: null,
|
||||
title: '设备信息',
|
||||
description: '要查看设备的相关参数信息'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 当前页面参数
|
||||
this.options = options
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
// 获取页面数据
|
||||
this.getPageData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取页面数据
|
||||
getPageData() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
Promise.all([app.getDefaultId(), app.getAddressList()])
|
||||
.then(() => {
|
||||
// 列表排序把默认收货地址放到最前
|
||||
app.onReorder()
|
||||
})
|
||||
.finally(() => app.isLoading = false)
|
||||
},
|
||||
|
||||
// 获取收货地址列表
|
||||
getAddressList() {
|
||||
const app = this
|
||||
return new Promise((resolve, reject) => {
|
||||
AddressApi.list()
|
||||
.then(result => {
|
||||
app.list = result.data.list
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取默认的收货地址
|
||||
getDefaultId() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const app = this
|
||||
AddressApi.defaultId()
|
||||
.then(result => {
|
||||
app.defaultId = result.data.defaultId
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 列表排序把默认收货地址放到最前
|
||||
onReorder() {
|
||||
const app = this
|
||||
app.list.sort(item => {
|
||||
return item.address_id == app.defaultId ? -1 : 1
|
||||
})
|
||||
},
|
||||
|
||||
navTo(url) {
|
||||
this.$navTo(url)
|
||||
},
|
||||
|
||||
/**
|
||||
* 添加新地址
|
||||
*/
|
||||
handleCreate() {
|
||||
this.$navTo('pages/address/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleUpdate(addressId) {
|
||||
this.$navTo('pages/address/update', {
|
||||
addressId
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleRemove(addressId) {
|
||||
const app = this
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "您确定要删除当前收货地址吗?",
|
||||
success({
|
||||
confirm
|
||||
}) {
|
||||
confirm && app.onRemove(addressId)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
onRemove(addressId) {
|
||||
const app = this
|
||||
AddressApi.remove(addressId)
|
||||
.then(result => {
|
||||
app.getPageData()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置为默认地址
|
||||
* @param {Object} addressId
|
||||
*/
|
||||
handleSetDefault(addressId) {
|
||||
const app = this
|
||||
AddressApi.setDefault(addressId)
|
||||
.then(result => {
|
||||
app.defaultId = addressId
|
||||
app.options.from === 'checkout' && uni.navigateBack()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.addres-list {
|
||||
padding-bottom: calc(constant(safe-area-inset-bottom) + 140rpx);
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
|
||||
padding-top: 20rpx;
|
||||
|
||||
.head-info {
|
||||
width: 750rpx;
|
||||
margin: auto;
|
||||
display: felx;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 34rpx;
|
||||
}
|
||||
|
||||
.description {
|
||||
padding: 10rpx 0;
|
||||
font-size: 30rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 项目内容
|
||||
.address-item {
|
||||
margin: 0 auto 20rpx auto;
|
||||
padding: 30rpx 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.demo-layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.value1 {
|
||||
color: #de4e02;
|
||||
}
|
||||
|
||||
.value2 {
|
||||
color: #ff0089;
|
||||
}
|
||||
|
||||
.value3 {
|
||||
color: #0c10f5;
|
||||
}
|
||||
}
|
||||
|
||||
.image{
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.contacts {
|
||||
margin-bottom: 16rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.bms-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.item {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.bms-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 120rpx;
|
||||
|
||||
.bms-image-box {
|
||||
display: flex;
|
||||
font-size: 22rpx;
|
||||
margin-bottom: 18rpx;
|
||||
color: #00af00;
|
||||
|
||||
.bms-image-fbf {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 50rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
font-size: 28rpx;
|
||||
|
||||
.region {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f3f3f3;
|
||||
}
|
||||
|
||||
.line-align {
|
||||
width: 6rpx;
|
||||
height: 48rpx;
|
||||
border-right: 1rpx solid #f3f3f3;
|
||||
}
|
||||
|
||||
.item-option {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 48rpx;
|
||||
|
||||
// 单选框
|
||||
.item-radio {
|
||||
font-size: 28rpx;
|
||||
|
||||
.radio {
|
||||
vertical-align: middle;
|
||||
transform: scale(0.76)
|
||||
}
|
||||
|
||||
.text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
// 操作
|
||||
.events {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 48rpx;
|
||||
|
||||
.event-item {
|
||||
font-size: 28rpx;
|
||||
margin-right: 26rpx;
|
||||
color: #4c4c4c;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 底部操作栏
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
bottom: var(--window-bottom);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 11;
|
||||
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.btn-wrapper {
|
||||
height: 120rpx;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
358
package/user/equipment/index.vue
Executable file
358
package/user/equipment/index.vue
Executable file
@@ -0,0 +1,358 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<view class="addres-list">
|
||||
<view class="address-item" v-for="(item, index) in list" :key="index">
|
||||
<view class="title">
|
||||
<text>设备编号:{{ item.phone }}</text>
|
||||
<u-tag text="已激活" plain size="mini" type="success"></u-tag>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="contacts">
|
||||
<view class="bms-info">
|
||||
<text class="item">电池型号:</text>
|
||||
<text class="item">BMS模块:硬件版</text>
|
||||
<text class="item">工作状态:正常</text>
|
||||
<text class="item">电池状态:健康</text>
|
||||
</view>
|
||||
<view class="bms-image">
|
||||
<view class="bms-image-box">
|
||||
<image class="image" src="../../../static/battery.png"></image>
|
||||
<text class="bms-image-fbf">67%</text>
|
||||
</view>
|
||||
<u-tag text="离线" plain size="mini" type="info"></u-tag>
|
||||
</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="item-option">
|
||||
<view class="_left">
|
||||
<u-icon label="操作" size="40" name="map" @click="navTo('package/user/equipment/operation')"></u-icon>
|
||||
</view>
|
||||
<view class="line-align"></view>
|
||||
<view class="_right">
|
||||
<view class="events">
|
||||
<u-icon label="详情" size="40" name="file-text" @click="navTo('package/user/equipment/detail')"></u-icon>
|
||||
<!-- <view class="event-item" @click="handleUpdate(item.address_id)">
|
||||
<text class="iconfont icon-edit"></text>
|
||||
<text class="title">编辑</text>
|
||||
</view>
|
||||
<view class="event-item" @click="handleRemove(item.address_id)">
|
||||
<text class="iconfont icon-delete"></text>
|
||||
<text class="title">删除</text>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<empty v-if="!list.length" :isLoading="isLoading" tips="亲,暂无取货地址" />
|
||||
<!-- 底部操作按钮 -->
|
||||
<view class="footer-fixed">
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn-item btn-item-main" @click="handleCreate()">添加新地址</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as AddressApi from '@/api/address'
|
||||
import Empty from '@/components/empty'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Empty
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//当前页面参数
|
||||
options: {},
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 收货地址列表
|
||||
list: [],
|
||||
// 默认收货地址
|
||||
defaultId: null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 当前页面参数
|
||||
this.options = options
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
// 获取页面数据
|
||||
this.getPageData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取页面数据
|
||||
getPageData() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
Promise.all([app.getDefaultId(), app.getAddressList()])
|
||||
.then(() => {
|
||||
// 列表排序把默认收货地址放到最前
|
||||
app.onReorder()
|
||||
})
|
||||
.finally(() => app.isLoading = false)
|
||||
},
|
||||
|
||||
// 获取收货地址列表
|
||||
getAddressList() {
|
||||
const app = this
|
||||
return new Promise((resolve, reject) => {
|
||||
AddressApi.list()
|
||||
.then(result => {
|
||||
app.list = result.data.list
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取默认的收货地址
|
||||
getDefaultId() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const app = this
|
||||
AddressApi.defaultId()
|
||||
.then(result => {
|
||||
app.defaultId = result.data.defaultId
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 列表排序把默认收货地址放到最前
|
||||
onReorder() {
|
||||
const app = this
|
||||
app.list.sort(item => {
|
||||
return item.address_id == app.defaultId ? -1 : 1
|
||||
})
|
||||
},
|
||||
|
||||
navTo(url){
|
||||
this.$navTo(url)
|
||||
},
|
||||
|
||||
/**
|
||||
* 添加新地址
|
||||
*/
|
||||
handleCreate() {
|
||||
this.$navTo('pages/address/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleUpdate(addressId) {
|
||||
this.$navTo('pages/address/update', { addressId })
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleRemove(addressId) {
|
||||
const app = this
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "您确定要删除当前收货地址吗?",
|
||||
success({ confirm }) {
|
||||
confirm && app.onRemove(addressId)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
onRemove(addressId) {
|
||||
const app = this
|
||||
AddressApi.remove(addressId)
|
||||
.then(result => {
|
||||
app.getPageData()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置为默认地址
|
||||
* @param {Object} addressId
|
||||
*/
|
||||
handleSetDefault(addressId) {
|
||||
const app = this
|
||||
AddressApi.setDefault(addressId)
|
||||
.then(result => {
|
||||
app.defaultId = addressId
|
||||
app.options.from === 'checkout' && uni.navigateBack()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.addres-list {
|
||||
padding-bottom: calc(constant(safe-area-inset-bottom) + 140rpx);
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
// 项目内容
|
||||
.address-item {
|
||||
margin: 0 auto 20rpx auto;
|
||||
padding: 30rpx 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
.title{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.contacts {
|
||||
margin-bottom: 16rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.bms-info{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #666666;
|
||||
.item{
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
.name {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
.bms-image{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 120rpx;
|
||||
.bms-image-box{
|
||||
display: flex;
|
||||
font-size: 22rpx;
|
||||
margin-bottom: 18rpx;
|
||||
color: #00af00;
|
||||
.bms-image-fbf{
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
}
|
||||
.image{
|
||||
width: 50rpx; height: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
font-size: 28rpx;
|
||||
|
||||
.region {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f3f3f3;
|
||||
}
|
||||
|
||||
.line-align{
|
||||
width: 6rpx;
|
||||
height: 48rpx;
|
||||
border-right: 1rpx solid #f3f3f3;
|
||||
}
|
||||
|
||||
.item-option {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 48rpx;
|
||||
|
||||
// 单选框
|
||||
.item-radio {
|
||||
font-size: 28rpx;
|
||||
|
||||
.radio {
|
||||
vertical-align: middle;
|
||||
transform: scale(0.76)
|
||||
}
|
||||
|
||||
.text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
// 操作
|
||||
.events {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 48rpx;
|
||||
|
||||
.event-item {
|
||||
font-size: 28rpx;
|
||||
margin-right: 26rpx;
|
||||
color: #4c4c4c;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 底部操作栏
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
bottom: var(--window-bottom);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 11;
|
||||
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.btn-wrapper {
|
||||
height: 120rpx;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
440
package/user/equipment/operation.vue
Executable file
440
package/user/equipment/operation.vue
Executable file
@@ -0,0 +1,440 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<view class="addres-list">
|
||||
<view class="address-item">
|
||||
<view class="head-info">
|
||||
<view class="title">{{ title }}</view>
|
||||
<view class="description">{{ description }}</view>
|
||||
</view>
|
||||
<u-form :label-width="200" :model="form" ref="uForm">
|
||||
<u-form-item left-icon="pause-circle" label="放电开关">
|
||||
<u-switch slot="right" v-model="form.switchVal1"></u-switch>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="lock-open" label="放电开关">
|
||||
<u-switch slot="right" v-model="form.switchVal2"></u-switch>
|
||||
</u-form-item>
|
||||
<u-form-item left-icon="reload" label="更换电池">
|
||||
<u-tag text="更换" slot="right" plain type="error" @click="handleChangeEquipment"></u-tag>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 换电 -->
|
||||
<u-popup v-model="showQRCodeBind" mode="center" border-radius="26" :closeable="true">
|
||||
<view class="qrcode-bind">
|
||||
<view class="title">请输入更换的新电池编号</view>
|
||||
<view class="bind-content">
|
||||
<input v-model="bindValue" class="input" @confirm="onSearch" focus="true" placeholder="请输入设备编号"
|
||||
type="text"></input>
|
||||
</view>
|
||||
<view class="submit">
|
||||
<u-button type="error" @click="doEquipment(true)">确定更换电池</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as AddressApi from '@/api/address'
|
||||
import Empty from '@/components/empty'
|
||||
import * as EquipmentApi from '@/websoft/api/equipment.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Empty
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//当前页面参数
|
||||
options: {},
|
||||
equipmentId: {},
|
||||
equipment: {},
|
||||
form: {
|
||||
switchVal1: false,
|
||||
switchVal2: false,
|
||||
},
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 收货地址列表
|
||||
list: [],
|
||||
// 默认收货地址
|
||||
defaultId: null,
|
||||
title: '设备操作',
|
||||
showQRCodeBind: false,
|
||||
bindValue: '',
|
||||
orderId: null,
|
||||
description: '用户可控制设备的控制开关'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 当前页面参数
|
||||
this.options = options
|
||||
this.equipmentId = options.equipmentId
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
// 获取页面数据
|
||||
this.getPageData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取页面数据
|
||||
getPageData() {
|
||||
const app = this
|
||||
EquipmentApi.getEquipment(app.equipmentId).then(result => {
|
||||
app.equipment = result.data
|
||||
app.orderId = result.data.orderId
|
||||
})
|
||||
// app.isLoading = true
|
||||
// Promise.all([app.getDefaultId(), app.getAddressList()])
|
||||
// .then(() => {
|
||||
// // 列表排序把默认收货地址放到最前
|
||||
// app.onReorder()
|
||||
// })
|
||||
// .finally(() => app.isLoading = false)
|
||||
},
|
||||
|
||||
// 获取收货地址列表
|
||||
getAddressList() {
|
||||
const app = this
|
||||
return new Promise((resolve, reject) => {
|
||||
AddressApi.list()
|
||||
.then(result => {
|
||||
app.list = result.data.list
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
handleChangeEquipment() {
|
||||
const app = this
|
||||
app.showQRCodeBind = true
|
||||
},
|
||||
doEquipment(canReset = false) {
|
||||
const app = this
|
||||
const {
|
||||
equipmentId,
|
||||
bindValue,
|
||||
orderId
|
||||
} = this
|
||||
EquipmentApi.changeEquipment({
|
||||
equipmentCode: bindValue,
|
||||
equipmentId,
|
||||
orderId
|
||||
}).then(result => {
|
||||
app.$success(result.message)
|
||||
app.showQRCodeBind = false
|
||||
app.getPageData()
|
||||
}).catch(err => {
|
||||
app.$error(err.message)
|
||||
})
|
||||
console.log("this.bindValue: ", this.bindValue);
|
||||
},
|
||||
|
||||
// 获取默认的收货地址
|
||||
getDefaultId() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const app = this
|
||||
AddressApi.defaultId()
|
||||
.then(result => {
|
||||
app.defaultId = result.data.defaultId
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 列表排序把默认收货地址放到最前
|
||||
onReorder() {
|
||||
const app = this
|
||||
app.list.sort(item => {
|
||||
return item.address_id == app.defaultId ? -1 : 1
|
||||
})
|
||||
},
|
||||
|
||||
navTo(url) {
|
||||
this.$navTo(url)
|
||||
},
|
||||
|
||||
/**
|
||||
* 添加新地址
|
||||
*/
|
||||
handleCreate() {
|
||||
this.$navTo('pages/address/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleUpdate(addressId) {
|
||||
this.$navTo('pages/address/update', {
|
||||
addressId
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
handleRemove(addressId) {
|
||||
const app = this
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "您确定要删除当前收货地址吗?",
|
||||
success({
|
||||
confirm
|
||||
}) {
|
||||
confirm && app.onRemove(addressId)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认删除收货地址
|
||||
* @param {int} addressId 收货地址ID
|
||||
*/
|
||||
onRemove(addressId) {
|
||||
const app = this
|
||||
AddressApi.remove(addressId)
|
||||
.then(result => {
|
||||
app.getPageData()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置为默认地址
|
||||
* @param {Object} addressId
|
||||
*/
|
||||
handleSetDefault(addressId) {
|
||||
const app = this
|
||||
AddressApi.setDefault(addressId)
|
||||
.then(result => {
|
||||
app.defaultId = addressId
|
||||
app.options.from === 'checkout' && uni.navigateBack()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.addres-list {
|
||||
padding-bottom: calc(constant(safe-area-inset-bottom) + 140rpx);
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
|
||||
padding-top: 20rpx;
|
||||
|
||||
.head-info {
|
||||
width: 750rpx;
|
||||
margin: auto;
|
||||
display: felx;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 34rpx;
|
||||
}
|
||||
|
||||
.description {
|
||||
padding: 10rpx 0;
|
||||
font-size: 30rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 项目内容
|
||||
.address-item {
|
||||
margin: 0 auto 20rpx auto;
|
||||
padding: 30rpx 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.contacts {
|
||||
margin-bottom: 16rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.bms-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.item {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.bms-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 120rpx;
|
||||
|
||||
.bms-image-box {
|
||||
display: flex;
|
||||
font-size: 22rpx;
|
||||
margin-bottom: 18rpx;
|
||||
color: #00af00;
|
||||
|
||||
.bms-image-fbf {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 50rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
font-size: 28rpx;
|
||||
|
||||
.region {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
margin: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f3f3f3;
|
||||
}
|
||||
|
||||
.line-align {
|
||||
width: 6rpx;
|
||||
height: 48rpx;
|
||||
border-right: 1rpx solid #f3f3f3;
|
||||
}
|
||||
|
||||
.item-option {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 48rpx;
|
||||
|
||||
// 单选框
|
||||
.item-radio {
|
||||
font-size: 28rpx;
|
||||
|
||||
.radio {
|
||||
vertical-align: middle;
|
||||
transform: scale(0.76)
|
||||
}
|
||||
|
||||
.text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
// 操作
|
||||
.events {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 48rpx;
|
||||
|
||||
.event-item {
|
||||
font-size: 28rpx;
|
||||
margin-right: 26rpx;
|
||||
color: #4c4c4c;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 底部操作栏
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
bottom: var(--window-bottom);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 11;
|
||||
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.btn-wrapper {
|
||||
height: 120rpx;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 1rpx 5rpx 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
}
|
||||
|
||||
}
|
||||
// 弹出层 - 绑定设备码
|
||||
.qrcode-bind{
|
||||
width: 550rpx;
|
||||
height: 300rpx;
|
||||
padding: 36rpx 30rpx;
|
||||
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 26rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bind-content {
|
||||
padding: 0 10rpx;
|
||||
border: 1rpx solid #eee;
|
||||
font-size: 24rpx;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 510rpx;
|
||||
height: 510rpx;
|
||||
}
|
||||
|
||||
}
|
||||
.submit{
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
244
package/user/equipment/update.vue
Executable file
244
package/user/equipment/update.vue
Executable file
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<!-- 标题 -->
|
||||
<view class="page-title">收货地址</view>
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper">
|
||||
<u-form :model="form" ref="uForm" label-width="140rpx">
|
||||
<u-form-item label="姓名" prop="name">
|
||||
<u-input v-model="form.name" placeholder="请输入收货人姓名" />
|
||||
</u-form-item>
|
||||
<u-form-item label="电话" prop="phone">
|
||||
<u-input v-model="form.phone" placeholder="请输入收货人手机号" />
|
||||
</u-form-item>
|
||||
<u-form-item label="地区" prop="region">
|
||||
<select-region ref="sRegion" v-model="form.region" />
|
||||
</u-form-item>
|
||||
<u-form-item label="详细地址" prop="detail" :border-bottom="false">
|
||||
<u-input v-model="form.detail" placeholder="街道门牌、楼层等信息" />
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="footer">
|
||||
<view class="btn-wrapper">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="btn-item btn-item-wechat" @click="chooseAddress()">选择微信收货地址</view>
|
||||
<!-- #endif -->
|
||||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
import { isMobile } from '@/utils/verify'
|
||||
import * as AddressApi from '@/api/address'
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
name: [{
|
||||
required: true,
|
||||
message: '请输入姓名',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
phone: [{
|
||||
required: true,
|
||||
message: '请输入手机号',
|
||||
trigger: ['blur', 'change']
|
||||
}, {
|
||||
// 自定义验证函数
|
||||
validator: (rule, value, callback) => {
|
||||
// 返回true表示校验通过,返回false表示不通过
|
||||
return isMobile(value)
|
||||
},
|
||||
message: '手机号码不正确',
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ['blur'],
|
||||
}],
|
||||
region: [{
|
||||
required: true,
|
||||
message: '请选择省市区',
|
||||
trigger: ['blur', 'change'],
|
||||
type: 'array'
|
||||
}],
|
||||
detail: [{
|
||||
required: true,
|
||||
message: '请输入详细地址',
|
||||
trigger: ['blur', 'change']
|
||||
}],
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
name: '',
|
||||
phone: '',
|
||||
region: [],
|
||||
detail: ''
|
||||
},
|
||||
rules,
|
||||
// 加载中
|
||||
isLoading: true,
|
||||
// 按钮禁用
|
||||
disabled: false,
|
||||
// 当前收货地址ID
|
||||
addressId: null
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad({ addressId }) {
|
||||
// 当前收货地址ID
|
||||
this.addressId = addressId
|
||||
// 获取当前记录详情
|
||||
this.getDetail()
|
||||
},
|
||||
|
||||
// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
|
||||
onReady() {
|
||||
this.$refs.uForm.setRules(this.rules)
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取当前记录详情
|
||||
getDetail() {
|
||||
const app = this
|
||||
AddressApi.detail(app.addressId)
|
||||
.then(result => {
|
||||
const detail = result.data.detail
|
||||
app.createFormData(detail)
|
||||
})
|
||||
},
|
||||
|
||||
// 选择微信地址
|
||||
// #ifdef MP-WEIXIN
|
||||
chooseAddress() {
|
||||
const { form, $refs } = this
|
||||
uni.chooseAddress({
|
||||
success(res) {
|
||||
const names = $refs.sRegion.getOptionItemByNames(res)
|
||||
form.name = res.userName
|
||||
form.phone = res.telNumber
|
||||
form.detail = res.detailInfo
|
||||
form.region = names.length > 0 ? names : []
|
||||
}
|
||||
})
|
||||
},
|
||||
// #endif
|
||||
|
||||
// 生成默认的表单数据
|
||||
createFormData(detail) {
|
||||
const { form } = this
|
||||
form.name = detail.name
|
||||
form.phone = detail.phone
|
||||
form.detail = detail.detail
|
||||
form.region = this.createRegion(detail)
|
||||
},
|
||||
|
||||
createRegion(detail) {
|
||||
return [{
|
||||
label: detail.region.province,
|
||||
value: detail.province_id
|
||||
}, {
|
||||
label: detail.region.city,
|
||||
value: detail.city_id
|
||||
}, {
|
||||
label: detail.region.region,
|
||||
value: detail.region_id
|
||||
}]
|
||||
},
|
||||
|
||||
// 表单提交
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
if (app.disabled) {
|
||||
return false
|
||||
}
|
||||
app.$refs.uForm.validate(valid => {
|
||||
if (valid) {
|
||||
app.disabled = true
|
||||
AddressApi.edit(app.addressId, app.form)
|
||||
.then(result => {
|
||||
app.$toast(result.message)
|
||||
uni.navigateBack()
|
||||
})
|
||||
.finally(() => app.disabled = false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: #f7f8fa;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.page-title {
|
||||
width: 94%;
|
||||
margin: 0 auto;
|
||||
padding-top: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: rgba(69, 90, 100, 0.6);
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
|
||||
.footer {
|
||||
margin-top: 80rpx;
|
||||
|
||||
.btn-wrapper {
|
||||
height: 100%;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 86rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-item-wechat {
|
||||
background: #0ba90b;
|
||||
margin-bottom: 26rpx;
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
|
||||
// 禁用按钮
|
||||
&.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
618
package/user/goods/cashier.vue
Executable file
618
package/user/goods/cashier.vue
Executable file
@@ -0,0 +1,618 @@
|
||||
<template>
|
||||
<view v-if="!isLoading" class="container" :style="appThemeStyle">
|
||||
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-info">
|
||||
<!-- 支付剩余时间 -->
|
||||
<view class="order-countdown">
|
||||
<text class="m-r-6">剩余时间</text>
|
||||
<count-down :date="order.expirationTime" separator="zh" theme="text" />
|
||||
</view>
|
||||
<!-- 付款金额 -->
|
||||
<view class="order-amount">
|
||||
<text class="unit">¥</text>
|
||||
<text class="amount">{{ order.pay_price }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 购买时长 -->
|
||||
<u-card title="订单信息">
|
||||
<view class="duration-method" slot="body">
|
||||
<view class="pay-item dis-flex flex-x-between">
|
||||
<view class="item-left dis-flex flex-y-center">
|
||||
<view class="item-left_text">
|
||||
<text>购买时长</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-right col-m" @click="onShowDuration">
|
||||
<text class="duration-title">{{ duration[planId].label }}</text>
|
||||
<text class="iconfont icon-arrow-down"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pay-item dis-flex flex-x-between">
|
||||
<view class="item-left dis-flex flex-y-center">
|
||||
<view class="item-left_text">
|
||||
<text>购买数量</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-right col-m">
|
||||
<text>{{ length }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<u-select v-model="showDuration" :list="duration" @confirm="onConfirm"></u-select>
|
||||
</view>
|
||||
</u-card>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<u-card title="付款方式">
|
||||
<view class="payment-method" slot="body">
|
||||
<view v-for="(item, index) in methods" :key="index" class="pay-item dis-flex flex-x-between"
|
||||
@click="handleSelectPayType(index)">
|
||||
<view class="item-left dis-flex flex-y-center">
|
||||
<view class="item-left_icon" :class="[item.method]">
|
||||
<text class="iconfont" :class="[PayMethodIconEnum[item.method]]"></text>
|
||||
</view>
|
||||
<view class="item-left_text">
|
||||
<text>{{ PayMethodEnum[item.method].name }}</text>
|
||||
</view>
|
||||
<view v-if="item.method === PayMethodEnum.BALANCE.value" class="user-balance">
|
||||
<text>(可用¥{{ personal.balance }}元)</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-right col-m" v-if="curPaymentItem && curPaymentItem.method == item.method">
|
||||
<text class="iconfont icon-check"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-card>
|
||||
|
||||
<!-- 确认按钮 -->
|
||||
<view class="footer-fixed">
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn-item btn-item-main" :class="{ disabled }" @click="handleSubmit()">确认支付</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付确认弹窗 -->
|
||||
<!-- #ifdef H5 -->
|
||||
<u-modal v-if="tempUnifyData" v-model="showConfirmModal" title="支付确认" show-cancel-button confirm-text="已完成支付"
|
||||
:confirm-color="appTheme.mainBg" negative-top="100" :asyncClose="true"
|
||||
@confirm="onTradeQuery(tempUnifyData.outTradeNo, tempUnifyData.method)">
|
||||
<view class="modal-content">
|
||||
<text>请在{{ PayMethodClientNameEnum[tempUnifyData.method] }}内完成支付,如果您已经支付成功,请点击“已完成支付”按钮</text>
|
||||
</view>
|
||||
</u-modal>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import storage from '@/utils/storage'
|
||||
import {
|
||||
inArray,
|
||||
urlEncode
|
||||
} from '@/utils/util'
|
||||
import {
|
||||
Alipay,
|
||||
Wechat
|
||||
} from '@/core/payment'
|
||||
import CountDown from '@/components/countdown'
|
||||
import {
|
||||
PayMethodEnum
|
||||
} from '@/common/enum/payment'
|
||||
import {
|
||||
PayStatusEnum
|
||||
} from '@/common/enum/order'
|
||||
import * as Api from '@/api/order/popularize.js'
|
||||
|
||||
// 支付方式对应的图标
|
||||
const PayMethodIconEnum = {
|
||||
[PayMethodEnum.WECHAT.value]: 'icon-wechat-pay',
|
||||
[PayMethodEnum.ALIPAY.value]: 'icon-alipay',
|
||||
[PayMethodEnum.BALANCE.value]: 'icon-balance-pay'
|
||||
}
|
||||
|
||||
// 支付方式的终端名称
|
||||
const PayMethodClientNameEnum = {
|
||||
[PayMethodEnum.WECHAT.value]: '微信',
|
||||
[PayMethodEnum.ALIPAY.value]: '支付宝'
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CountDown
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 加载中
|
||||
isLoading: true,
|
||||
// 确认按钮禁用
|
||||
disabled: false,
|
||||
// 枚举类
|
||||
PayMethodEnum,
|
||||
PayMethodIconEnum,
|
||||
PayMethodClientNameEnum,
|
||||
// 当前选中的支付方式
|
||||
curPaymentItem: null,
|
||||
// 当前订单ID
|
||||
orderId: null,
|
||||
// 当前结算订单信息
|
||||
order: {},
|
||||
// 个人信息
|
||||
personal: {
|
||||
balance: '0.00'
|
||||
},
|
||||
// 当前客户端的支付方式列表(后端根据platform判断)
|
||||
methods: [],
|
||||
// 支付确认弹窗
|
||||
showConfirmModal: false,
|
||||
// #ifdef H5
|
||||
// 当前微信支付信息 (临时数据, 仅用于H5端)
|
||||
tempUnifyData: {
|
||||
outTradeNo: '',
|
||||
method: ''
|
||||
},
|
||||
// #endif
|
||||
// 购买商品数量
|
||||
length: 0,
|
||||
// 购买的商品ID
|
||||
goodsIds: [],
|
||||
|
||||
// 购买时长
|
||||
duration: [],
|
||||
// 套餐ID
|
||||
planId: 0,
|
||||
showDuration: false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 读取缓存数据
|
||||
const goodsIds = storage.get('selectGoodsIdsByPopularize')
|
||||
this.goodsIds = goodsIds
|
||||
// 购买数量
|
||||
this.length = goodsIds.length
|
||||
// 获取收银台信息
|
||||
this.getCashierInfo()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取收银台信息
|
||||
getCashierInfo() {
|
||||
const app = this
|
||||
const { goodsIds, planId, length } = this
|
||||
app.isLoading = true
|
||||
// 读取缓存数据
|
||||
Api.orderInfo({form: {planId,goodsIds,length}})
|
||||
.then(result => {
|
||||
app.order = result.data.order
|
||||
app.personal = result.data.personal
|
||||
app.methods = result.data.paymentMethods
|
||||
app.duration = result.data.planList.map((d,index) => {
|
||||
return {
|
||||
value: index,
|
||||
label: d.plan_name + '¥(' + d.money + ')'
|
||||
}
|
||||
})
|
||||
app.isLoading = false
|
||||
app.setDefaultPayType()
|
||||
app.checkOrderPayStatus()
|
||||
// #ifdef H5
|
||||
// 判断当前页面来源于浏览器返回
|
||||
this.performance()
|
||||
// #endif
|
||||
})
|
||||
},
|
||||
|
||||
// 设置默认的支付方式
|
||||
setDefaultPayType() {
|
||||
const app = this
|
||||
if (app.disabled) return
|
||||
const defaultIndex = app.methods.findIndex(item => item.is_default == true)
|
||||
defaultIndex > -1 && app.handleSelectPayType(defaultIndex)
|
||||
},
|
||||
|
||||
// 判断当前订单是否为已支付
|
||||
checkOrderPayStatus() {
|
||||
const app = this
|
||||
if (app.order.pay_status == PayStatusEnum.SUCCESS.value) {
|
||||
app.$toast('恭喜您,订单已付款成功')
|
||||
app.onSuccessNav()
|
||||
}
|
||||
},
|
||||
|
||||
onShowDuration(index){
|
||||
this.showDuration = true
|
||||
},
|
||||
|
||||
onConfirm(item){
|
||||
this.planId = item[0].value
|
||||
this.getCashierInfo()
|
||||
},
|
||||
|
||||
bindPickerChange: function(e) {
|
||||
console.log('picker发送选择改变,携带值为', e.detail.value)
|
||||
this.index = e.detail.value
|
||||
},
|
||||
// 选择支付方式
|
||||
handleSelectPayType(index) {
|
||||
this.curPaymentItem = this.methods[index]
|
||||
},
|
||||
|
||||
// 选择时长类型
|
||||
handleSelectDurationType(key){
|
||||
this.selectDuration = key
|
||||
},
|
||||
|
||||
// 判断当前页面来源于浏览器返回
|
||||
// #ifdef H5
|
||||
performance() {
|
||||
const app = this
|
||||
// 判断订单状态, 异步回调会将订单状态变为已支付, 那么就不需要让用户手动查单了
|
||||
if (app.order.pay_status == PayStatusEnum.PENDING.value) {
|
||||
app.alipayPerformance()
|
||||
app.wechatPerformance()
|
||||
}
|
||||
},
|
||||
|
||||
// H5端支付宝支付完成跳转回当前页面时触发
|
||||
alipayPerformance() {
|
||||
const app = this
|
||||
app.tempUnifyData = Alipay.performance()
|
||||
if (app.tempUnifyData) {
|
||||
app.onTradeQuery(app.tempUnifyData.outTradeNo, app.tempUnifyData.method)
|
||||
}
|
||||
},
|
||||
|
||||
// H5端微信支付完成或返回时触发
|
||||
wechatPerformance() {
|
||||
const app = this
|
||||
app.tempUnifyData = Wechat.performance(app.orderId)
|
||||
if (app.tempUnifyData) {
|
||||
app.showConfirmModal = true
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
|
||||
// 确认支付
|
||||
handleSubmit() {
|
||||
const app = this
|
||||
const { goodsIds, planId, length } = this
|
||||
// 判断是否选择了支付方式
|
||||
if (!app.curPaymentItem) {
|
||||
app.$toast('您还没有选择支付方式')
|
||||
return
|
||||
}
|
||||
// 按钮禁用
|
||||
if (app.disabled) return
|
||||
app.disabled = true
|
||||
// 提交到后端API
|
||||
Api.orderPay({
|
||||
form: {
|
||||
method: app.curPaymentItem.method,
|
||||
client: app.platform,
|
||||
extra: app.getExtraAsUnify(app.curPaymentItem.method),
|
||||
goodsIds,
|
||||
planId,
|
||||
length
|
||||
}
|
||||
})
|
||||
.then(result => app.onSubmitCallback(result))
|
||||
.finally(err => {
|
||||
setTimeout(() => app.disabled = false, 10)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取第三方支付的扩展参数
|
||||
getExtraAsUnify(method) {
|
||||
if (method === PayMethodEnum.ALIPAY.value) {
|
||||
return Alipay.extraAsUnify()
|
||||
}
|
||||
if (method === PayMethodEnum.WECHAT.value) {
|
||||
return Wechat.extraAsUnify()
|
||||
}
|
||||
return {}
|
||||
},
|
||||
|
||||
// 订单提交成功后回调
|
||||
onSubmitCallback(result) {
|
||||
const app = this
|
||||
const method = app.curPaymentItem.method
|
||||
const paymentData = result.data.payment
|
||||
// 余额支付
|
||||
if (method === PayMethodEnum.BALANCE.value) {
|
||||
app.onShowSuccess(result)
|
||||
}
|
||||
// 发起支付宝支付
|
||||
if (method === PayMethodEnum.ALIPAY.value) {
|
||||
console.log('paymentData', paymentData)
|
||||
Alipay.payment(paymentData)
|
||||
.then(res => app.onPaySuccess(res))
|
||||
.catch(err => app.onPayFail(err))
|
||||
}
|
||||
// 发起微信支付
|
||||
if (method === PayMethodEnum.WECHAT.value) {
|
||||
console.log('paymentData', paymentData)
|
||||
Wechat.payment({
|
||||
orderKey: app.orderId,
|
||||
...paymentData
|
||||
})
|
||||
.then(res => app.onPaySuccess(res))
|
||||
.catch(err => app.onPayFail(err))
|
||||
}
|
||||
},
|
||||
|
||||
// 订单支付成功的回调方法
|
||||
// 这里只是前端支付api返回结果success,实际订单是否支付成功 以后端的查单和异步通知为准
|
||||
onPaySuccess({
|
||||
res,
|
||||
option: {
|
||||
isRequireQuery,
|
||||
outTradeNo,
|
||||
method
|
||||
}
|
||||
}) {
|
||||
const app = this
|
||||
// 判断是否需要主动查单
|
||||
// isRequireQuery为true代表需要主动查单
|
||||
if (isRequireQuery) {
|
||||
app.onTradeQuery(outTradeNo, method)
|
||||
return true
|
||||
}
|
||||
this.onShowSuccess(res)
|
||||
},
|
||||
|
||||
// 显示支付成功信息并页面跳转
|
||||
onShowSuccess({
|
||||
message
|
||||
}) {
|
||||
this.$toast(message || '订单支付成功')
|
||||
this.onSuccessNav()
|
||||
},
|
||||
|
||||
// 订单支付失败
|
||||
onPayFail(err) {
|
||||
console.log('onPayFail', err)
|
||||
const errMsg = err.message || '订单未支付'
|
||||
this.$error(errMsg)
|
||||
},
|
||||
|
||||
// 已完成支付按钮事件: 请求后端查单
|
||||
onTradeQuery(outTradeNo, method) {
|
||||
const app = this
|
||||
// 交易查询
|
||||
// 查询第三方支付订单是否付款成功
|
||||
Api.tradeQuery({
|
||||
outTradeNo,
|
||||
method,
|
||||
client: app.platform
|
||||
})
|
||||
.then(result => result.data.isPay ? app.onShowSuccess(result) : app.onPayFail(result))
|
||||
.finally(() => app.showConfirmModal = false)
|
||||
},
|
||||
|
||||
// 支付成功后的跳转
|
||||
onSuccessNav() {
|
||||
const pages = getCurrentPages()
|
||||
const lastPage = pages.length < 2 ? null : pages[pages.length - 2]
|
||||
const backRoutes = [
|
||||
'package/solution/index',
|
||||
'package/solution/detail'
|
||||
]
|
||||
if (lastPage && inArray(lastPage.route, backRoutes)) {
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1000)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.$navTo('package/user/goods/list', {}, 'redirectTo')
|
||||
}, 1200)
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: #F4F4F4;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
// 订单信息
|
||||
.order-info {
|
||||
padding: 80rpx 0;
|
||||
text-align: center;
|
||||
|
||||
.order-countdown {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.order-amount {
|
||||
margin: 0 auto;
|
||||
max-width: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #111111;
|
||||
|
||||
.unit {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: -18rpx;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 56rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.duration-title {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.duration-method {
|
||||
width: 94%;
|
||||
background-color: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.pay-item {
|
||||
padding: 26rpx 0;
|
||||
font-size: 28rpx;
|
||||
border-bottom: 1rpx solid rgb(248, 248, 248);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-left_icon {
|
||||
margin-right: 20rpx;
|
||||
font-size: 44rpx;
|
||||
|
||||
&.wechat {
|
||||
color: #00c800;
|
||||
}
|
||||
|
||||
&.alipay {
|
||||
color: #009fe8;
|
||||
}
|
||||
|
||||
&.balance {
|
||||
color: #ff9700;
|
||||
}
|
||||
}
|
||||
|
||||
.item-left_text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.user-balance {
|
||||
margin-left: 20rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 支付方式
|
||||
.payment-method {
|
||||
width: 94%;
|
||||
background-color: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.pay-item {
|
||||
padding: 26rpx 0;
|
||||
font-size: 28rpx;
|
||||
border-bottom: 1rpx solid rgb(248, 248, 248);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-left_icon {
|
||||
margin-right: 20rpx;
|
||||
font-size: 44rpx;
|
||||
|
||||
&.wechat {
|
||||
color: #00c800;
|
||||
}
|
||||
|
||||
&.alipay {
|
||||
color: #009fe8;
|
||||
}
|
||||
|
||||
&.balance {
|
||||
color: #ff9700;
|
||||
}
|
||||
}
|
||||
|
||||
.item-left_text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.user-balance {
|
||||
margin-left: 20rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 支付确认弹窗
|
||||
.modal-content {
|
||||
padding: 40rpx 48rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 50rpx;
|
||||
text-align: left;
|
||||
color: #606266;
|
||||
// height: 620rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
// 底部操作栏
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
bottom: var(--window-bottom);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 11;
|
||||
box-shadow: 0 -4rpx 40rpx 0 rgba(151, 151, 151, 0.24);
|
||||
background: #fff;
|
||||
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.btn-wrapper {
|
||||
height: 120rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 80rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
|
||||
// 禁用按钮
|
||||
&.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
159
package/user/goods/components/Comment.vue
Executable file
159
package/user/goods/components/Comment.vue
Executable file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<!-- 商品评价 -->
|
||||
<view v-if="!isLoading && list.length" class="goods-comment m-top20">
|
||||
<view class="item-title dis-flex">
|
||||
<view class="block-left flex-box">
|
||||
商品评价 (<text class="total">{{ total }}条</text>)
|
||||
</view>
|
||||
<view class="block-right">
|
||||
<text @click="onTargetToComment" class="show-more col-9">查看更多</text>
|
||||
<text class="iconfont icon-arrow-right col-9"></text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 评论列表 -->
|
||||
<view class="comment-list">
|
||||
<view class="comment-item" v-for="(item, index) in list" :key="index">
|
||||
<view class="comment-item_row dis-flex flex-y-center">
|
||||
<view class="user-info dis-flex flex-y-center">
|
||||
<avatar-image class="user-avatar" :url="item.user.avatar_url" :width="50" />
|
||||
<text class="user-name">{{ item.user.nick_name }}</text>
|
||||
</view>
|
||||
<!-- 评星 -->
|
||||
<view class="star-rating">
|
||||
<u-rate active-color="#f4a213" :current="rates[item.score]" :disabled="true" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-content m-top20">
|
||||
<text class="f-26 twoline-hide">{{ item.content }}</text>
|
||||
</view>
|
||||
<view class="comment-time">{{ item.create_time }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AvatarImage from '@/components/avatar-image'
|
||||
import * as CommentApi from '@/api/comment'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AvatarImage
|
||||
},
|
||||
props: {
|
||||
// 商品ID
|
||||
goodsId: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
// 加载多少条记录 默认2条
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 2
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 评星数据转换
|
||||
rates: { 10: 5, 20: 3, 30: 1 },
|
||||
// 评价列表数据
|
||||
list: [],
|
||||
// 评价总数量
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
// 加载评价列表数据
|
||||
this.getCommentList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 加载评价列表数据
|
||||
getCommentList() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
CommentApi.listRows(app.goodsId, app.limit)
|
||||
.then(result => {
|
||||
app.list = result.data.list
|
||||
app.total = result.data.total
|
||||
})
|
||||
.catch(err => err)
|
||||
.finally(() => app.isLoading = false)
|
||||
},
|
||||
|
||||
// 跳转到评论列表页
|
||||
onTargetToComment() {
|
||||
const app = this
|
||||
app.$navTo('pages/comment/index', { goodsId: app.goodsId })
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.goods-comment {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 25rpx;
|
||||
|
||||
.total {
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
|
||||
.show-more {
|
||||
margin-right: 8rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
padding: 15rpx 5rpx;
|
||||
margin-bottom: 10rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.comment-item_row {
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.user-info {
|
||||
margin-right: 15rpx;
|
||||
|
||||
.user-avatar {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.item-content {
|
||||
color: #333;
|
||||
margin: 16rpx 0;
|
||||
max-height: 76rpx;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
|
||||
.comment-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
</style>
|
||||
158
package/user/goods/components/Service.vue
Executable file
158
package/user/goods/components/Service.vue
Executable file
@@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<view v-if="list.length" class="service-wrapper" :style="appThemeStyle">
|
||||
<!-- 服务简述 -->
|
||||
<view class="service-simple" @click="handlePopup">
|
||||
<view class="s-list">
|
||||
<view class="s-item" v-for="(item, index) in list" :key="index">
|
||||
<text class="item-icon iconfont icon-fuwu"></text>
|
||||
<text class="item-val">{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 扩展箭头 -->
|
||||
<view class="s-arrow f-26 col-9 t-r">
|
||||
<text class="iconfont icon-arrow-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 详情内容弹窗 -->
|
||||
<u-popup v-model="showPopup" mode="bottom" :closeable="true" :border-radius="26">
|
||||
<view class="service-content">
|
||||
<view class="title">服务</view>
|
||||
<scroll-view class="content-scroll" :scroll-y="true">
|
||||
<view class="s-list clearfix">
|
||||
<view class="s-item" v-for="(item, index) in list" :key="index">
|
||||
<text class="item-icon iconfont icon-fuwu"></text>
|
||||
<view class="item-val">{{ item.name }}</view>
|
||||
<view class="item-summary">{{ item.summary }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as ServiceApi from '@/api/goods/service'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 商品ID
|
||||
goodsId: {
|
||||
type: Number,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 显示详情内容弹窗
|
||||
showPopup: false,
|
||||
// 服务列表数据
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
// 获取商品服务列表
|
||||
this.getServiceList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 获取商品服务列表
|
||||
getServiceList() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
ServiceApi.list(app.goodsId)
|
||||
.then(result => app.list = result.data.list)
|
||||
.finally(() => app.isLoading = false)
|
||||
},
|
||||
|
||||
// 显示弹窗
|
||||
handlePopup() {
|
||||
this.showPopup = !this.showPopup
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.service-wrapper {
|
||||
min-height: 24rpx;
|
||||
margin-bottom: -24rpx;
|
||||
}
|
||||
|
||||
// 服务简述
|
||||
.service-simple {
|
||||
padding: 24rpx 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.s-list {
|
||||
flex: 1;
|
||||
margin-left: -15rpx;
|
||||
}
|
||||
|
||||
.s-item {
|
||||
float: left;
|
||||
font-size: 26rpx;
|
||||
margin: 8rpx 15rpx;
|
||||
|
||||
.item-icon {
|
||||
color: $main-bg;
|
||||
}
|
||||
|
||||
.item-val {
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 服务详细内容
|
||||
.service-content {
|
||||
padding: 24rpx;
|
||||
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 50rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-scroll {
|
||||
min-height: 400rpx;
|
||||
max-height: 760rpx;
|
||||
}
|
||||
|
||||
.s-list {
|
||||
padding: 0 30rpx 0 80rpx;
|
||||
}
|
||||
|
||||
.s-item {
|
||||
position: relative;
|
||||
margin-bottom: 60rpx;
|
||||
|
||||
.item-icon {
|
||||
position: absolute;
|
||||
top: 6rpx;
|
||||
left: -50rpx;
|
||||
color: $main-bg;
|
||||
}
|
||||
|
||||
.item-val {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.item-summary {
|
||||
font-size: 26rpx;
|
||||
margin-top: 20rpx;
|
||||
color: #6d6d6d;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
179
package/user/goods/components/SkuPopup.vue
Executable file
179
package/user/goods/components/SkuPopup.vue
Executable file
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<goods-sku-popup :value="value" @input="onChangeValue" border-radius="20" :localdata="goodsInfo" :mode="skuMode" :maskCloseAble="true"
|
||||
:priceColor="appTheme.mainBg" :buyNowBackgroundColor="appTheme.mainBg" :addCartColor="appTheme.viceText" :addCartBackgroundColor="appTheme.viceBg"
|
||||
:activedStyle="{ color: appTheme.mainBg, borderColor: appTheme.mainBg, backgroundColor: activedBtnBackgroundColor }"
|
||||
@open="openSkuPopup" @close="closeSkuPopup" @add-cart="addCart" @buy-now="buyNow" buyNowText="立即购买" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { setCartTotalNum } from '@/core/app'
|
||||
import { hex2rgba } from '@/utils/color'
|
||||
import * as CartApi from '@/api/cart'
|
||||
import GoodsSkuPopup from '@/components/goods-sku-popup'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GoodsSkuPopup
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'input'
|
||||
},
|
||||
props: {
|
||||
// true 组件显示 false 组件隐藏
|
||||
value: {
|
||||
Type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 模式 1:都显示 2:只显示购物车 3:只显示立即购买
|
||||
skuMode: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
// 商品详情信息
|
||||
goods: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
goodsInfo: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 规格按钮选中时的背景色
|
||||
activedBtnBackgroundColor() {
|
||||
return hex2rgba(this.appTheme.mainBg, 0.1)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const app = this
|
||||
const { goods } = app
|
||||
app.goodsInfo = {
|
||||
_id: goods.goods_id,
|
||||
name: goods.goods_name,
|
||||
goods_thumb: goods.goods_image,
|
||||
sku_list: app.getSkuList(),
|
||||
spec_list: app.getSpecList()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 监听组件显示隐藏
|
||||
onChangeValue(val) {
|
||||
this.$emit('input', val)
|
||||
},
|
||||
|
||||
// 整理商品SKU列表
|
||||
getSkuList() {
|
||||
const app = this
|
||||
const { goods: { goods_name, goods_image, skuList } } = app
|
||||
const skuData = []
|
||||
skuList.forEach(item => {
|
||||
skuData.push({
|
||||
_id: item.id,
|
||||
goods_sku_id: item.goods_sku_id,
|
||||
goods_id: item.goods_id,
|
||||
goods_name: goods_name,
|
||||
image: item.image_url ? item.image_url : goods_image,
|
||||
price: item.goods_price * 100,
|
||||
stock: item.stock_num,
|
||||
spec_value_ids: item.spec_value_ids,
|
||||
sku_name_arr: app.getSkuNameArr(item.spec_value_ids)
|
||||
})
|
||||
})
|
||||
return skuData
|
||||
},
|
||||
|
||||
// 获取sku记录的规格值列表
|
||||
getSkuNameArr(specValueIds) {
|
||||
const app = this
|
||||
const defaultData = ['默认']
|
||||
const skuNameArr = []
|
||||
if (specValueIds) {
|
||||
specValueIds.forEach((valueId, groupIndex) => {
|
||||
const specValueName = app.getSpecValueName(valueId, groupIndex)
|
||||
skuNameArr.push(specValueName)
|
||||
})
|
||||
}
|
||||
return skuNameArr.length ? skuNameArr : defaultData
|
||||
},
|
||||
|
||||
// 获取指定的规格值名称
|
||||
getSpecValueName(valueId, groupIndex) {
|
||||
const app = this
|
||||
const { goods: { specList } } = app
|
||||
const res = specList[groupIndex].valueList.find(specValue => {
|
||||
return specValue.spec_value_id == valueId
|
||||
})
|
||||
return res.spec_value
|
||||
},
|
||||
|
||||
// 整理规格数据
|
||||
getSpecList() {
|
||||
const { goods: { specList } } = this
|
||||
const defaultData = [{ name: '默认', list: [{ name: '默认' }] }]
|
||||
const specData = []
|
||||
specList.forEach(group => {
|
||||
const children = []
|
||||
group.valueList.forEach(specValue => {
|
||||
children.push({ name: specValue.spec_value })
|
||||
})
|
||||
specData.push({
|
||||
name: group.spec_name,
|
||||
list: children
|
||||
})
|
||||
})
|
||||
return specData.length ? specData : defaultData
|
||||
},
|
||||
|
||||
// sku组件 开始-----------------------------------------------------------
|
||||
openSkuPopup() {
|
||||
// console.log("监听 - 打开sku组件")
|
||||
},
|
||||
|
||||
closeSkuPopup() {
|
||||
// console.log("监听 - 关闭sku组件")
|
||||
},
|
||||
|
||||
// 加入购物车按钮
|
||||
addCart(selectShop) {
|
||||
const app = this
|
||||
const { goods_id, goods_sku_id, buy_num } = selectShop
|
||||
CartApi.add(goods_id, goods_sku_id, buy_num)
|
||||
.then(result => {
|
||||
// 显示成功
|
||||
app.$toast(result.message)
|
||||
// 隐藏当前弹窗
|
||||
app.onChangeValue(false)
|
||||
// 购物车商品总数量
|
||||
const cartTotal = result.data.cartTotal
|
||||
// 缓存购物车数量
|
||||
setCartTotalNum(cartTotal)
|
||||
// 传递给父级
|
||||
app.$emit('addCart', cartTotal)
|
||||
})
|
||||
},
|
||||
|
||||
// 立即购买
|
||||
buyNow(selectShop) {
|
||||
// 跳转到订单结算页
|
||||
this.$navTo('pages/checkout/index', {
|
||||
mode: 'buyNow',
|
||||
goodsId: selectShop.goods_id,
|
||||
goodsSkuId: selectShop.goods_sku_id,
|
||||
goodsNum: selectShop.buy_num
|
||||
})
|
||||
// 隐藏当前弹窗
|
||||
this.onChangeValue(false)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
146
package/user/goods/components/SlideImage.vue
Executable file
146
package/user/goods/components/SlideImage.vue
Executable file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<!-- 商品图片 -->
|
||||
<view class="images-swiper">
|
||||
<swiper class="swiper-box" :autoplay="autoplay" :duration="duration" :indicator-dots="indicatorDots"
|
||||
:interval="interval" :circular="true" @change="setCurrent">
|
||||
<!-- 主图视频 -->
|
||||
<swiper-item v-if="video">
|
||||
<view class="slide-video">
|
||||
<video id="myVideo" class="video" :poster="videoCover.preview_url" :src="video.external_url" controls
|
||||
x5-playsinline playsinline webkit-playsinline webkit-playsinline x5-video-player-type="h5"
|
||||
x5-video-player-fullscreen x5-video-orientation="portrait" :enable-progress-gesture="false"
|
||||
@play="onVideoPlay"></video>
|
||||
</view>
|
||||
</swiper-item>
|
||||
<!-- 轮播图片 -->
|
||||
<swiper-item v-for="(item, index) in images" :key="index" @click="onPreviewImages(index)">
|
||||
<view class="slide-image">
|
||||
<image class="image" :draggable="false" :src="item.preview_url"></image>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="swiper-count">
|
||||
<text>{{ currentIndex }}</text>
|
||||
<text>/</text>
|
||||
<text>{{ images.length + (video ? 1 : 0) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 主图视频
|
||||
video: {
|
||||
type: Object,
|
||||
default () {
|
||||
return null
|
||||
}
|
||||
},
|
||||
// 主图视频封面
|
||||
videoCover: {
|
||||
type: Object,
|
||||
default () {
|
||||
return null
|
||||
}
|
||||
},
|
||||
// 图片轮播
|
||||
images: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
indicatorDots: true, // 是否显示面板指示点
|
||||
autoplay: true, // 是否自动切换
|
||||
interval: 4000, // 自动切换时间间隔
|
||||
duration: 800, // 滑动动画时长
|
||||
currentIndex: 1, // 轮播图指针
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 事件:视频开始播放
|
||||
onVideoPlay(e) {
|
||||
this.autoplay = false
|
||||
},
|
||||
|
||||
// 设置轮播图当前指针 数字
|
||||
setCurrent({ detail }) {
|
||||
const app = this
|
||||
app.currentIndex = detail.current + 1
|
||||
},
|
||||
|
||||
// 浏览商品图片
|
||||
onPreviewImages(index) {
|
||||
const app = this
|
||||
const imageUrls = []
|
||||
app.images.forEach(item => {
|
||||
imageUrls.push(item.preview_url);
|
||||
});
|
||||
uni.previewImage({
|
||||
current: imageUrls[index],
|
||||
urls: imageUrls
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// swiper组件
|
||||
.images-swiper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.swiper-box {
|
||||
width: 100%;
|
||||
height: 100vw;
|
||||
|
||||
/* #ifdef H5 */
|
||||
max-width: 480px;
|
||||
max-height: 480px;
|
||||
margin: 0 auto;
|
||||
/* #endif */
|
||||
|
||||
// 主图视频
|
||||
.slide-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.video {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 图片轮播
|
||||
.slide-image {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// swiper计数
|
||||
.swiper-count {
|
||||
position: absolute;
|
||||
right: 36rpx;
|
||||
bottom: 72rpx;
|
||||
padding: 2rpx 18rpx;
|
||||
background: rgba(0, 0, 0, 0.363);
|
||||
border-radius: 50rpx;
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
</style>
|
||||
69
package/user/goods/components/search.vue
Executable file
69
package/user/goods/components/search.vue
Executable file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-wrapper">
|
||||
<view class="index-search" @click="onClick">
|
||||
<view class="index-cont-search t-c">
|
||||
<text class="search-icon iconfont icon-search"></text>
|
||||
<text class="search-text">{{ tips }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
tips: {
|
||||
type: String,
|
||||
default: '搜索商品'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('event')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search-wrapper {
|
||||
background: #fff;
|
||||
padding: 13rpx;
|
||||
}
|
||||
|
||||
.index-search {
|
||||
border-bottom: 0;
|
||||
background: #fff;
|
||||
border-radius: 50rpx;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
color: #6d6d6d;
|
||||
box-sizing: border-box;
|
||||
line-height: 64rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.index-cont-search {
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.index-cont-search .search-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.index-cont-search .search-text {
|
||||
margin-left: 14rpx;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
228
package/user/goods/detail.scss
Executable file
228
package/user/goods/detail.scss
Executable file
@@ -0,0 +1,228 @@
|
||||
.container {
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
// 110 - 18 + 4
|
||||
padding-bottom: calc(constant(safe-area-inset-bottom) + 106rpx + 6rpx);
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 106rpx + 6rpx);
|
||||
}
|
||||
|
||||
// 商品信息
|
||||
.goods-info {
|
||||
background: #fff;
|
||||
padding: 25rpx 30rpx;
|
||||
}
|
||||
|
||||
.info-item__top {
|
||||
min-height: 40rpx;
|
||||
margin-bottom: 20rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.floor-price__samll {
|
||||
font-size: 26rpx;
|
||||
line-height: 1;
|
||||
color: #ff0000;
|
||||
margin-bottom: -10rpx;
|
||||
}
|
||||
|
||||
// 商品价
|
||||
.floor-price {
|
||||
color: #ff0000;
|
||||
margin-right: 15rpx;
|
||||
font-size: 42rpx;
|
||||
}
|
||||
|
||||
.original-price {
|
||||
font-size: 26rpx;
|
||||
text-decoration: line-through;
|
||||
color: #959595;
|
||||
margin-right: 15rpx;
|
||||
margin-bottom: -6rpx;
|
||||
}
|
||||
|
||||
// 会员价标签
|
||||
.user-grade {
|
||||
background: #3c3c3c;
|
||||
border-radius: 6rpx;
|
||||
padding: 8rpx 14rpx;
|
||||
margin-right: 15rpx;
|
||||
font-size: 24rpx;
|
||||
color: #EEE0C3;
|
||||
}
|
||||
|
||||
.goods-sales {
|
||||
font-size: 24rpx;
|
||||
color: #959595;
|
||||
}
|
||||
|
||||
.info-item__name .goods-name {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
/* 商品分享 */
|
||||
|
||||
.goods-share__line {
|
||||
border-left: 1rpx solid #f4f4f4;
|
||||
height: 60rpx;
|
||||
margin: 0 30rpx;
|
||||
}
|
||||
|
||||
.goods-share .share-btn {
|
||||
line-height: normal;
|
||||
padding: 0;
|
||||
background: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
font-size: 8pt;
|
||||
border: none;
|
||||
color: #191919;
|
||||
}
|
||||
|
||||
.goods-share .share-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.goods-share .share__icon {
|
||||
font-size: 40rpx;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
// 商品卖点
|
||||
.info-item_selling-point {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
// 选择商品规格
|
||||
.goods-choice {
|
||||
padding: 26rpx 30rpx;
|
||||
font-size: 28rpx;
|
||||
|
||||
.spec-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.spec-name {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 商品详情
|
||||
.goods-content .item-title {
|
||||
padding: 26rpx 30rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
// 底部操作栏
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
bottom: var(--window-bottom);
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
z-index: 11;
|
||||
box-shadow: 0 -4rpx 40rpx 0 rgba(151, 151, 151, 0.24);
|
||||
background: #fff;
|
||||
|
||||
// 设置ios刘海屏底部横线安全区域
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.footer-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
height: 106rpx;
|
||||
}
|
||||
|
||||
// 快捷菜单
|
||||
.foo-item-fast {
|
||||
box-sizing: border-box;
|
||||
min-width: 214rpx;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
margin-right: 12rpx;
|
||||
|
||||
.fast-item {
|
||||
position: relative;
|
||||
padding: 4rpx 0;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
width: 84rpx;
|
||||
|
||||
&--cart {
|
||||
margin-left: 6rpx;
|
||||
.fast-icon { margin-left: -12rpx; }
|
||||
}
|
||||
|
||||
// 角标
|
||||
.fast-badge {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
min-width: 16px;
|
||||
padding: 0 3px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
font-family: -apple-system-font, Helvetica Neue, Arial, sans-serif;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
background-color: #ee0a24;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.fast-badge--fixed {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform-origin: 100%
|
||||
}
|
||||
|
||||
.fast-icon {
|
||||
font-size: 44rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.fast-text {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 操作按钮
|
||||
.foo-item-btn {
|
||||
flex: 1;
|
||||
|
||||
.btn-wrapper {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-item {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 72rpx;
|
||||
margin-right: 16rpx;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// 立即购买按钮
|
||||
.btn-item-main {
|
||||
background: linear-gradient(to right, $main-bg, $main-bg2);
|
||||
}
|
||||
|
||||
// 购物车按钮
|
||||
.btn-item-deputy {
|
||||
background: linear-gradient(to right, $vice-bg, $vice-bg2);
|
||||
color: $vice-text;
|
||||
}
|
||||
}
|
||||
347
package/user/goods/detail.vue
Executable file
347
package/user/goods/detail.vue
Executable file
@@ -0,0 +1,347 @@
|
||||
<template>
|
||||
<view v-show="!isLoading" class="container" :style="appThemeStyle">
|
||||
<!-- 商品图片轮播 -->
|
||||
<SlideImage v-if="!isLoading" :video="goods.video" :videoCover="goods.videoCover" :images="goods.goods_images" />
|
||||
|
||||
<!-- 商品信息 -->
|
||||
<view v-if="!isLoading" class="goods-info m-top20">
|
||||
<!-- 价格、销量 -->
|
||||
<view class="info-item info-item__top dis-flex flex-x-between flex-y-end">
|
||||
<view class="block-left dis-flex flex-y-center">
|
||||
<!-- 商品售价 -->
|
||||
<text class="floor-price__samll">¥</text>
|
||||
<text class="floor-price">{{ goods.goods_price_min }}</text>
|
||||
<!-- 会员价标签 -->
|
||||
<view v-if="goods.is_user_grade" class="user-grade">
|
||||
<text>会员价</text>
|
||||
</view>
|
||||
<!-- 划线价 -->
|
||||
<text v-if="goods.line_price_min > 0" class="original-price">¥{{ goods.line_price_min }}</text>
|
||||
</view>
|
||||
<view class="block-right dis-flex">
|
||||
<!-- 销量 -->
|
||||
<view class="goods-sales">
|
||||
<text>已售{{ goods.goods_sales }}件</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 标题、分享 -->
|
||||
<view class="info-item info-item__name dis-flex flex-y-center">
|
||||
<view class="goods-name flex-box">
|
||||
<text class="twoline-hide">{{ goods.goods_name }}</text>
|
||||
</view>
|
||||
<view class="goods-share__line"></view>
|
||||
<view class="goods-share">
|
||||
<button class="share-btn dis-flex flex-dir-column" @click="onShowShareSheet()">
|
||||
<text class="share__icon iconfont icon-fenxiang"></text>
|
||||
<text class="f-24">分享</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 商品卖点 -->
|
||||
<view v-if="goods.selling_point" class="info-item info-item_selling-point">
|
||||
<text>{{ goods.selling_point }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 选择商品规格 -->
|
||||
<view v-if="goods.spec_type == 20" class="goods-choice m-top20 b-f" @click="onShowSkuPopup(1)">
|
||||
<view class="spec-list">
|
||||
<view class="flex-box">
|
||||
<text class="col-8">选择:</text>
|
||||
<text class="spec-name" v-for="(item, index) in goods.specList" :key="index">{{ item.spec_name }}</text>
|
||||
</view>
|
||||
<view class="f-26 col-9 t-r">
|
||||
<text class="iconfont icon-arrow-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品服务 -->
|
||||
<Service v-if="!isLoading" :goods-id="goodsId" />
|
||||
|
||||
<!-- 商品SKU弹窗 -->
|
||||
<SkuPopup v-if="!isLoading" v-model="showSkuPopup" :skuMode="skuMode" :goods="goods" @addCart="onAddCart" />
|
||||
|
||||
<!-- 商品评价 -->
|
||||
<Comment v-if="!isLoading" :goods-id="goodsId" :limit="2" />
|
||||
|
||||
<!-- 商品描述 -->
|
||||
<view v-if="!isLoading" class="goods-content m-top20">
|
||||
<view class="item-title b-f">
|
||||
<text>商品描述</text>
|
||||
</view>
|
||||
<block v-if="goods.content != ''">
|
||||
<view class="goods-content__detail b-f">
|
||||
<mp-html :content="goods.content" />
|
||||
</view>
|
||||
</block>
|
||||
<empty v-else tips="亲,暂无商品描述" />
|
||||
</view>
|
||||
|
||||
<!-- 商品推荐 -->
|
||||
<recommended />
|
||||
|
||||
<!-- 底部选项卡 -->
|
||||
<view class="footer-fixed">
|
||||
<view class="footer-container">
|
||||
<!-- 导航图标 -->
|
||||
<view class="foo-item-fast">
|
||||
<!-- 首页 -->
|
||||
<view class="fast-item fast-item--home" @click="onTargetHome">
|
||||
<view class="fast-icon">
|
||||
<text class="iconfont icon-shouye"></text>
|
||||
</view>
|
||||
<view class="fast-text">
|
||||
<text>站点</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button class="btn-normal" @click="onCollection(goods.goods_id)">
|
||||
<view class="fast-item">
|
||||
<view class="fast-icon">
|
||||
<u-icon name="star-fill" color="#fd8008" v-if="goods.is_collection"></u-icon>
|
||||
<u-icon name="star" v-else></u-icon>
|
||||
</view>
|
||||
<view class="fast-text">
|
||||
<text>收藏</text>
|
||||
</view>
|
||||
</view>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- 客服 (仅微信小程序端显示) -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- <button class="btn-normal" open-type="contact">
|
||||
<view class="fast-item">
|
||||
<view class="fast-icon">
|
||||
<text class="iconfont icon-kefu1"></text>
|
||||
</view>
|
||||
<view class="fast-text">
|
||||
<text>客服</text>
|
||||
</view>
|
||||
</view>
|
||||
</button> -->
|
||||
<!-- #endif -->
|
||||
<!-- 购物车 -->
|
||||
<view class="fast-item fast-item--cart" @click="onTargetCart">
|
||||
<view v-if="cartTotal > 0" class="fast-badge fast-badge--fixed">{{ cartTotal > 99 ? '99+' : cartTotal }}
|
||||
</view>
|
||||
<view class="fast-icon">
|
||||
<text class="iconfont icon-gouwuche"></text>
|
||||
</view>
|
||||
<view class="fast-text">
|
||||
<text>购物车</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="foo-item-btn">
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn-item btn-item-deputy" @click="onShowSkuPopup(2)">
|
||||
<text>加入购物车</text>
|
||||
</view>
|
||||
<view class="btn-item btn-item-main" @click="onShowSkuPopup(3)">
|
||||
<text>立即购买</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快捷导航 -->
|
||||
<!-- <shortcut bottom="120rpx" /> -->
|
||||
|
||||
<!-- 分享菜单 -->
|
||||
<share-sheet v-model="showShareSheet" :shareTitle="goods.goods_name" :shareImageUrl="goods.goods_image"
|
||||
:posterApiCall="posterApiCall" :posterApiParam="{ goodsId }" />
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSceneData } from '@/core/app'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import * as CartApi from '@/api/cart'
|
||||
import Recommended from '@/components/recommended'
|
||||
import ShareSheet from '@/components/share-sheet'
|
||||
import SlideImage from './components/SlideImage'
|
||||
import SkuPopup from './components/SkuPopup'
|
||||
import Comment from './components/Comment'
|
||||
import Service from './components/Service'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Recommended,
|
||||
ShareSheet,
|
||||
SlideImage,
|
||||
SkuPopup,
|
||||
Comment,
|
||||
Service
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 当前商品ID
|
||||
goodsId: null,
|
||||
// 商品详情
|
||||
goods: {},
|
||||
// 购物车总数量
|
||||
cartTotal: 0,
|
||||
// 显示/隐藏SKU弹窗
|
||||
showSkuPopup: false,
|
||||
// 模式 1:都显示 2:只显示购物车 3:只显示立即购买
|
||||
skuMode: 1,
|
||||
// 显示/隐藏分享菜单
|
||||
showShareSheet: false,
|
||||
// 获取商品海报图api方法
|
||||
posterApiCall: GoodsApi.poster
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 记录query参数
|
||||
this.onRecordQuery(options)
|
||||
// 加载页面数据
|
||||
this.onRefreshPage()
|
||||
// 浏览历史
|
||||
this.saveFootMarkList(options.goodsId)
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 浏览历史记录
|
||||
saveFootMarkList(goodsId){
|
||||
const userId = uni.getStorageSync('userId')
|
||||
const arr = uni.getStorageSync(`FOOTMARKLIST_${userId}`) || []
|
||||
arr.unshift(Number(goodsId))
|
||||
return uni.setStorageSync(`FOOTMARKLIST_${userId}`,arr)
|
||||
},
|
||||
// 记录query参数
|
||||
onRecordQuery(query) {
|
||||
const scene = getSceneData(query)
|
||||
this.goodsId = query.goodsId ? parseInt(query.goodsId) : parseInt(scene.gid)
|
||||
},
|
||||
|
||||
// 刷新页面数据
|
||||
onRefreshPage() {
|
||||
const app = this
|
||||
app.isLoading = true
|
||||
Promise.all([app.getGoodsDetail(), app.getCartTotal()])
|
||||
.finally(() => app.isLoading = false)
|
||||
},
|
||||
|
||||
// 获取商品信息
|
||||
getGoodsDetail() {
|
||||
const app = this
|
||||
return new Promise((resolve, reject) => {
|
||||
GoodsApi.detail(app.goodsId)
|
||||
.then(result => {
|
||||
app.goods = result.data.detail
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取购物车总数量
|
||||
getCartTotal() {
|
||||
const app = this
|
||||
return new Promise((resolve, reject) => {
|
||||
CartApi.total()
|
||||
.then(result => {
|
||||
app.cartTotal = result.data.cartTotal
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 更新购物车数量
|
||||
onAddCart(total) {
|
||||
this.cartTotal = total
|
||||
},
|
||||
|
||||
/**
|
||||
* 显示/隐藏SKU弹窗
|
||||
* @param {skuMode} 模式 1:都显示 2:只显示购物车 3:只显示立即购买
|
||||
*/
|
||||
onShowSkuPopup(skuMode = 1) {
|
||||
const shopInfo = uni.getStorageSync('shopInfo')
|
||||
const clerkInfo = uni.getStorageSync('clerkInfo')
|
||||
if(shopInfo || clerkInfo){
|
||||
return this.$error('请使用会员账号购买')
|
||||
}
|
||||
this.skuMode = skuMode
|
||||
this.showSkuPopup = !this.showSkuPopup
|
||||
},
|
||||
|
||||
// 显示隐藏分享菜单
|
||||
onShowShareSheet() {
|
||||
this.showShareSheet = !this.showShareSheet
|
||||
},
|
||||
|
||||
// 跳转到首页
|
||||
onTargetHome(e) {
|
||||
const { goods } = this
|
||||
console.log("this.goods: ",goods);
|
||||
this.$navTo('package/shops/detail/index',goods)
|
||||
},
|
||||
|
||||
// 加入收藏
|
||||
onCollection(goodsId){
|
||||
GoodsApi.collection({goodsId})
|
||||
this.goods.is_collection = !this.goods.is_collection
|
||||
},
|
||||
|
||||
// 跳转到购物车页
|
||||
onTargetCart() {
|
||||
this.$navTo('pages/cart/index')
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享当前页面
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
const app = this
|
||||
// 构建页面参数
|
||||
const params = app.$getShareUrlParams({
|
||||
goodsId: app.goodsId,
|
||||
})
|
||||
return {
|
||||
title: app.goods.goods_name,
|
||||
path: `/pages/goods/detail?${params}`
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享到朋友圈
|
||||
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta)
|
||||
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
|
||||
*/
|
||||
onShareTimeline() {
|
||||
const app = this
|
||||
// 构建页面参数
|
||||
const params = app.$getShareUrlParams({
|
||||
goodsId: app.goodsId,
|
||||
})
|
||||
return {
|
||||
title: app.goods.goods_name,
|
||||
path: `/pages/goods/detail?${params}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
@import "./detail.scss";
|
||||
</style>
|
||||
659
package/user/goods/list.vue
Executable file
659
package/user/goods/list.vue
Executable file
@@ -0,0 +1,659 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ native: true }"
|
||||
@down="downCallback" :up="upOption" @up="upCallback">
|
||||
<!-- 页面头部 -->
|
||||
<view class="header">
|
||||
<view class="search">
|
||||
<input v-model="searchValue" class="input" focus="true" placeholder="请输入您搜索的商品" type="text" @input="onInput" @confirm="onSearch"></input>
|
||||
</view>
|
||||
<u-dropdown>
|
||||
<u-dropdown-item v-model="parentId" :title="parentName" :options="parentList"></u-dropdown-item>
|
||||
<u-dropdown-item v-if="childrenList.length > 0" v-model="categoryId" :title="categoryName" :options="childrenList"></u-dropdown-item>
|
||||
<u-dropdown-item v-if="thirdList.length > 0" v-model="thirdId" :title="thirdName" :options="thirdList"></u-dropdown-item>
|
||||
</u-dropdown>
|
||||
</view>
|
||||
<!-- {{parentId}}
|
||||
{{categoryId}}
|
||||
{{thirdId}}
|
||||
{{JSON.stringify(childrenList)}}
|
||||
{{JSON.stringify(thirdList)}} -->
|
||||
<!-- 排序标签 -->
|
||||
<!-- <view class="store-sort">
|
||||
<view class="sort-item" :class="{ active: sortType === 'all' }" @click="handleSortType('all')">
|
||||
<text>综合</text>
|
||||
</view>
|
||||
<view class="sort-item" :class="{ active: sortType === 'sales' }" @click="handleSortType('sales')">
|
||||
<text>销量</text>
|
||||
</view>
|
||||
<view class="sort-item sort-item-price" :class="{ active: sortType === 'price' }" @click="handleSortType('price')">
|
||||
<text>价格</text>
|
||||
<view class="price-arrow">
|
||||
<view class="icon up" :class="{ active: sortType === 'price' && !sortPrice }">
|
||||
<text class="iconfont icon-arrow-up"></text>
|
||||
</view>
|
||||
<view class="icon down" :class="{ active: sortType === 'price' && sortPrice }">
|
||||
<text class="iconfont icon-arrow-down"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
<!-- 商品列表 -->
|
||||
<view class="goods-list clearfix" :class="['column-' + (showView ? '1' : '2')]">
|
||||
<view class="goods-item" v-for="(item, index) in list.data" :key="index">
|
||||
<!-- 单列显示 -->
|
||||
<view v-if="showView" class="dis-flex">
|
||||
<!-- 商品图片 -->
|
||||
<view class="goods-item_left" @click="onTargetDetail(item.goods_id)">
|
||||
<image class="image" :src="item.goods_image"></image>
|
||||
</view>
|
||||
<view class="goods-item_right">
|
||||
<!-- 商品名称 -->
|
||||
<view class="goods-name">
|
||||
<text class="twoline-hide" @click="onTargetDetail(item.goods_id)">{{ item.goods_name }}</text>
|
||||
</view>
|
||||
<view class="goods-item_desc">
|
||||
<!-- 商品卖点 -->
|
||||
<view class="desc-selling_point dis-flex">
|
||||
<text class="oneline-hide">{{ item.selling_point }}</text>
|
||||
</view>
|
||||
<!-- 商品销量 -->
|
||||
<view class="desc-goods_sales dis-flex">
|
||||
<text>已售{{ item.goods_sales }}件</text>
|
||||
</view>
|
||||
<!-- 商品价格 -->
|
||||
<view class="desc_footer">
|
||||
<text class="price_x">¥{{ item.goods_price_min }}</text>
|
||||
<text class="price_y col-9"
|
||||
v-if="item.line_price_min > 0">¥{{ item.line_price_min }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="buy-gouwuche" v-if="item.top_time == 0">
|
||||
<u-checkbox v-model="item.checked" @change="checkboxChange(item.goods_id)">置顶</u-checkbox>
|
||||
<!-- <u-button size="mini">置顶</u-button> -->
|
||||
</view>
|
||||
<view class="buy-gouwuche" v-else>
|
||||
<u-tag text="投放中"></u-tag>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 多列显示 -->
|
||||
<view v-else class="">
|
||||
<!-- 商品图片 -->
|
||||
<view class="goods-image">
|
||||
<image class="image" mode="aspectFill" :src="item.goods_image"></image>
|
||||
</view>
|
||||
<view class="detail">
|
||||
<!-- 商品名称 -->
|
||||
<view class="goods-name">
|
||||
<text class="twoline-hide">{{ item.goods_name }}</text>
|
||||
</view>
|
||||
<!-- 商品价格 -->
|
||||
<view class="detail-price oneline-hide">
|
||||
<text class="goods-price f-30 col-m">¥{{ item.goods_price_min }}</text>
|
||||
<text v-if="item.line_price_min > 0"
|
||||
class="line-price col-9 f-24">¥{{ item.line_price_min }}</text>
|
||||
</view>
|
||||
<!-- 商品销量 -->
|
||||
<text class="col-9 f-24 u-text-right">已售{{ item.goods_sales }}件</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="gotobuy">
|
||||
<u-button v-if="checked.length > 0" type="primary" @click="goToBuy">去付款</u-button>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
|
||||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import * as CategoryApi from '@/api/category'
|
||||
import {
|
||||
getEmptyPaginateObj,
|
||||
getMoreListData
|
||||
} from '@/core/app'
|
||||
import Search from './components/search.vue'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const pageSize = 15
|
||||
const showViewKey = 'GoodsList-ShowView';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollBody,
|
||||
Search
|
||||
},
|
||||
mixins: [MescrollMixin],
|
||||
data() {
|
||||
return {
|
||||
showView: true, // 列表显示方式 (true列表、false平铺)
|
||||
sortType: 'all', // 排序类型
|
||||
sortPrice: false, // 价格排序 (true高到低 false低到高)
|
||||
options: {}, // 当前页面参数
|
||||
list: getEmptyPaginateObj(), // 商品列表数据
|
||||
searchValue: '',
|
||||
// 上拉加载配置
|
||||
upOption: {
|
||||
// 首次自动执行
|
||||
auto: true,
|
||||
// 每页数据的数量; 默认10
|
||||
page: {
|
||||
size: pageSize
|
||||
},
|
||||
// 数量要大于4条才显示无更多数据
|
||||
noMoreSize: 4,
|
||||
},
|
||||
parentId: 0,
|
||||
parentName: '商品分类',
|
||||
categoryId: 0,
|
||||
categoryName: '请选择',
|
||||
category: [],
|
||||
parentList: [],
|
||||
childrenList: [],
|
||||
// 三级分类
|
||||
thirdId: 0,
|
||||
thirdName: '请选择',
|
||||
thirdList: [],
|
||||
checked: [],
|
||||
time: ''
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 记录options
|
||||
this.options = options
|
||||
// 设置默认列表显示方式
|
||||
this.setShowView()
|
||||
// 加载商品分类
|
||||
this.getCategory()
|
||||
// 检查商品支付状态并设置置顶时间
|
||||
// this.time = this.$u.timeFrom(1665049088);
|
||||
// console.log("this.time: ",this.time);
|
||||
|
||||
},
|
||||
|
||||
watch: {
|
||||
parentId(val) {
|
||||
// 设置一级分类名称
|
||||
this.parentList.map(d => {
|
||||
if(d.value == val){
|
||||
this.parentName = d.label
|
||||
this.parentId = d.value
|
||||
this.categoryId = 0
|
||||
this.categoryName = '请选择'
|
||||
this.thirdId = 0
|
||||
d.children && this.getChildrenList(d.value)
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
categoryId(val){
|
||||
this.childrenList.map(d => {
|
||||
if(d.value == val){
|
||||
this.categoryName = d.label
|
||||
this.categoryId = d.value
|
||||
this.thirdId = 0
|
||||
d.children && this.getThirdList(d.value)
|
||||
}
|
||||
})
|
||||
this.getGoodsList()
|
||||
},
|
||||
thirdId(val){
|
||||
this.thirdList.map(d => {
|
||||
if(d.value == val){
|
||||
this.thirdName = d.label
|
||||
this.thirdId = d.value
|
||||
}
|
||||
})
|
||||
this.getGoodsList()
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 上拉加载的回调 (页面初始化时也会执行一次)
|
||||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
|
||||
* @param {Object} page
|
||||
*/
|
||||
upCallback(page) {
|
||||
const app = this
|
||||
// 设置列表数据
|
||||
app.getGoodsList(page.num)
|
||||
.then(list => {
|
||||
const curPageLen = list.data.length
|
||||
const totalSize = list.data.total
|
||||
app.mescroll.endBySize(curPageLen, totalSize)
|
||||
})
|
||||
.catch(() => app.mescroll.endErr())
|
||||
},
|
||||
// 选择一级分类后刷新左侧菜单
|
||||
getChildrenList(parentId){
|
||||
const app = this
|
||||
app.parentId = parentId
|
||||
app.category.map(d => {
|
||||
if(d.category_id == parentId){
|
||||
app.childrenList = d.children.map(item => {
|
||||
return {
|
||||
value: item.category_id,
|
||||
label: item.name,
|
||||
children: item.children
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 三级分类
|
||||
getThirdList(categoryId){
|
||||
const app = this
|
||||
app.categoryId = categoryId
|
||||
app.childrenList.map(d => {
|
||||
console.log(categoryId + "====",d.value);
|
||||
if(d.value == categoryId){
|
||||
app.thirdList = d.children.map(d => {
|
||||
return {
|
||||
value: d.category_id,
|
||||
label: d.name,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 设置默认列表显示方式
|
||||
setShowView() {
|
||||
this.showView = uni.getStorageSync(showViewKey) || true
|
||||
},
|
||||
|
||||
onInput(e){
|
||||
this.searchValue = e.detail.value
|
||||
this.options.search = e.detail.value
|
||||
},
|
||||
|
||||
onSearch(){
|
||||
this.getGoodsList()
|
||||
},
|
||||
// 收集选中的goodsId
|
||||
checkboxChange(goodsId){
|
||||
const app = this
|
||||
// 查找数组是否含该元素并返回下标位置
|
||||
var index = app.checked.indexOf(goodsId)
|
||||
// 存在则删除不存在则插入
|
||||
if( index > -1){
|
||||
app.checked.splice(index,1)
|
||||
}else{
|
||||
app.checked.push(goodsId)
|
||||
}
|
||||
storage.set('selectGoodsIdsByPopularize', app.checked)
|
||||
},
|
||||
goToBuy(){
|
||||
this.$navTo('package/user/goods/cashier')
|
||||
},
|
||||
|
||||
getCategory(){
|
||||
CategoryApi.list().then(result => {
|
||||
this.category = result.data.list
|
||||
// 抽取一级分类
|
||||
this.parentList = result.data.list.map(d => {
|
||||
if(d.parent_id == 0){
|
||||
return {
|
||||
value: d.category_id,
|
||||
label: d.name,
|
||||
children: d.children
|
||||
}
|
||||
}
|
||||
})
|
||||
// console.log('顶部一级分类:',this.parentList);
|
||||
// 左侧二级分类
|
||||
// result.data.list.map(d => {
|
||||
// if(d.category_id == this.parentId){
|
||||
// this.childrenList = d.children
|
||||
// }
|
||||
// })
|
||||
// console.log(": ",this.childrenList);
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取商品列表
|
||||
* @param {number} pageNo 页码
|
||||
*/
|
||||
getGoodsList(pageNo = 1) {
|
||||
const app = this
|
||||
const { thirdId, categoryId, parentId } = this
|
||||
const { shopId } = uni.getStorageSync('shopInfo')
|
||||
let lastId = 0;
|
||||
if(parentId > 0) {
|
||||
lastId = parentId
|
||||
}
|
||||
if(categoryId > 0) {
|
||||
lastId = categoryId
|
||||
}
|
||||
if(thirdId > 0){
|
||||
lastId = thirdId
|
||||
}
|
||||
const param = {
|
||||
sortType: app.sortType,
|
||||
sortPrice: Number(app.sortPrice),
|
||||
categoryId: lastId || 0,
|
||||
goodsName: app.options.search || '',
|
||||
page: pageNo,
|
||||
shopId,
|
||||
// storeHouseGoods: true,
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
GoodsApi.list(param)
|
||||
.then(result => {
|
||||
// 合并新数据
|
||||
const newList = result.data.list
|
||||
app.list.data = getMoreListData(newList, app.list, pageNo)
|
||||
resolve(newList)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 切换排序方式
|
||||
handleSortType(newSortType) {
|
||||
const app = this
|
||||
const newSortPrice = newSortType === 'price' ? !app.sortPrice : true
|
||||
app.sortType = newSortType
|
||||
app.sortPrice = newSortPrice
|
||||
// 刷新列表数据
|
||||
app.list = getEmptyPaginateObj()
|
||||
app.mescroll.resetUpScroll()
|
||||
},
|
||||
|
||||
// 切换列表显示方式
|
||||
handleShowView() {
|
||||
const app = this
|
||||
app.showView = !app.showView
|
||||
uni.setStorageSync(showViewKey, app.showView)
|
||||
},
|
||||
|
||||
// 跳转商品详情页
|
||||
onTargetDetail(goodsId) {
|
||||
this.$navTo('pages/goods/detail', {
|
||||
goodsId
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 商品搜索
|
||||
*/
|
||||
handleSearch() {
|
||||
const searchPageUrl = 'pages/search/index'
|
||||
// 判断来源页面
|
||||
let pages = getCurrentPages()
|
||||
if (pages.length > 1 &&
|
||||
pages[pages.length - 2].route === searchPageUrl) {
|
||||
uni.navigateBack()
|
||||
return
|
||||
}
|
||||
// 跳转到商品搜索页
|
||||
this.$navTo(searchPageUrl)
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 设置分享内容
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
// 构建分享参数
|
||||
return {
|
||||
title: "全部分类",
|
||||
path: "/pages/category/index?" + this.$getShareUrlParams()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享到朋友圈
|
||||
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta)
|
||||
* https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
|
||||
*/
|
||||
onShareTimeline() {
|
||||
// 构建分享参数
|
||||
return {
|
||||
title: "全部分类",
|
||||
path: "/pages/category/index?" + this.$getShareUrlParams()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 页面头部
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
flex: 1;
|
||||
// 搜索框
|
||||
.search {
|
||||
flex: 1;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
// 切换显示方式
|
||||
.show-view {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
font-size: 36rpx;
|
||||
color: #505050;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
// 排序组件
|
||||
.store-sort {
|
||||
position: sticky;
|
||||
top: var(--window-top);
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 99;
|
||||
|
||||
.sort-item {
|
||||
flex-basis: 33.3333%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50rpx;
|
||||
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-item-price .price-arrow {
|
||||
margin-left: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #000;
|
||||
|
||||
.icon {
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
|
||||
&.up {
|
||||
margin-bottom: -16rpx;
|
||||
}
|
||||
|
||||
&.down {
|
||||
margin-top: -16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 商品列表
|
||||
.goods-list {
|
||||
padding: 4rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// 单列显示
|
||||
.goods-list.column-1 {
|
||||
.goods-item {
|
||||
width: 100%;
|
||||
height: 280rpx;
|
||||
margin-bottom: 12rpx;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
line-height: 1.6;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_left {
|
||||
display: flex;
|
||||
width: 300rpx;
|
||||
background: #fff;
|
||||
align-items: center;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 240rpx;
|
||||
height: 240rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
.goods-name {
|
||||
margin-top: 10rpx;
|
||||
min-height: 68rpx;
|
||||
line-height: 1.3;
|
||||
white-space: normal;
|
||||
color: #484848;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.buy-gouwuche{
|
||||
position: absolute;
|
||||
right: 10rpx;
|
||||
bottom: 10rpx;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_desc {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.desc-selling_point {
|
||||
width: 400rpx;
|
||||
font-size: 24rpx;
|
||||
color: #e49a3d;
|
||||
}
|
||||
|
||||
.desc-goods_sales {
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.desc_footer {
|
||||
font-size: 24rpx;
|
||||
|
||||
.price_x {
|
||||
margin-right: 16rpx;
|
||||
color: $main-bg;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.price_y {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 平铺显示
|
||||
.goods-list.column-2 {
|
||||
.goods-item {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
padding: 6rpx;
|
||||
|
||||
.goods-image {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-bottom: 100%;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
display: block;
|
||||
margin-top: 100%;
|
||||
}
|
||||
|
||||
.image {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
-o-object-fit: cover;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
padding: 8rpx;
|
||||
background: #fff;
|
||||
|
||||
.goods-name {
|
||||
min-height: 68rpx;
|
||||
line-height: 1.3;
|
||||
white-space: normal;
|
||||
color: #484848;
|
||||
font-size: 26rpx;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.detail-price {
|
||||
.goods-price {
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.line-price {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.gotobuy{
|
||||
position: fixed;
|
||||
width: 700rpx;
|
||||
margin-left: 25rpx;
|
||||
bottom: 50rpx;
|
||||
}
|
||||
</style>
|
||||
109
package/user/notice/index.vue
Normal file
109
package/user/notice/index.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<view class="partner">
|
||||
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper" v-if="shopInfo">
|
||||
<!-- <u-form :model="form" ref="uForm" label-width="240rpx">
|
||||
<u-form-item>
|
||||
<view class="shop-box">
|
||||
<text class="shop-name">后台管理</text>
|
||||
<text>地址:https://dev.gxwebsoft.com/ylx-admin/</text>
|
||||
<text>账号:{{applyInfo.phone}}</text>
|
||||
<text>密码:默认为手机号码后6位</text>
|
||||
</view>
|
||||
</u-form-item>
|
||||
|
||||
|
||||
</u-form> -->
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<!-- <view class="footer">
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle">更新资料</u-button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
// 入驻类型 (合伙人10001,配送员10002,社区门店10003,省代10004)
|
||||
grade_id: 10004,
|
||||
company: '',
|
||||
real_name: '',
|
||||
phone: '',
|
||||
mobile: '',
|
||||
region: [],
|
||||
detail: '',
|
||||
}
|
||||
|
||||
import * as UserApi from '@/api/user'
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
disabled: false,
|
||||
imageList: [],
|
||||
shopInfo: {},
|
||||
applyInfo: {}
|
||||
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getUserInfo()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前用户信息
|
||||
getUserInfo() {
|
||||
const app = this
|
||||
UserApi.info().then(result => {
|
||||
app.shopInfo = result.data.shopInfo
|
||||
app.applyInfo = result.data.applyInfo
|
||||
})
|
||||
},
|
||||
groupChange(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.partner {
|
||||
.banner {
|
||||
padding-top: 20rpx;
|
||||
width: 100%;
|
||||
}
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
.shop-box{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.shop-name{
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
.logo{
|
||||
width: 100rpx;
|
||||
}
|
||||
.shipin{
|
||||
width: 400rpx;
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
width: 500rpx;
|
||||
margin: 20rpx auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
521
package/user/order/index.vue
Executable file
521
package/user/order/index.vue
Executable file
@@ -0,0 +1,521 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ native: true }" @down="downCallback" :up="upOption"
|
||||
@up="upCallback">
|
||||
<!-- tab栏 -->
|
||||
<u-tabs :list="tabs" :is-scroll="false" :current="curTab" :active-color="appTheme.mainBg" :duration="0.2" @change="onChangeTab" />
|
||||
<!-- 订单列表 -->
|
||||
<view class="order-list">
|
||||
<view class="order-item" v-for="(item, index) in list.data" :key="index">
|
||||
<view class="item-top">
|
||||
<view class="item-top-left">
|
||||
<text class="order-time">{{ item.create_time }}</text>
|
||||
</view>
|
||||
<view class="item-top-right">
|
||||
<text class="state-text">{{ item.state_text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 商品列表 -->
|
||||
<view class="goods-list">
|
||||
<view class="goods-item" v-for="(goods, idx) in item.goods" :key="idx">
|
||||
<!-- 商品图片 -->
|
||||
<view class="goods-image">
|
||||
<image class="image" :src="goods.goods_image" mode="scaleToFill"></image>
|
||||
</view>
|
||||
<!-- 商品信息 -->
|
||||
<view class="goods-content">
|
||||
<view class="goods-title"><text class="twoline-hide">{{ goods.goods_name }}</text></view>
|
||||
<view class="goods-props clearfix">
|
||||
<view class="goods-props-item" v-for="(props, idx) in goods.goods_props" :key="idx">
|
||||
<text>{{ props.value.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 交易信息 -->
|
||||
<view class="goods-trade">
|
||||
<view class="goods-price">
|
||||
<text class="unit">¥</text>
|
||||
<text class="value">{{ goods.is_user_grade ? goods.grade_goods_price : goods.goods_price }}</text>
|
||||
</view>
|
||||
<view class="goods-num">
|
||||
<text>×{{ goods.total_num }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 订单合计 -->
|
||||
<view class="order-total">
|
||||
<text>共{{ item.total_num }}件商品,总金额</text>
|
||||
<text class="unit">¥</text>
|
||||
<text class="money">{{ item.pay_price }}</text>
|
||||
</view>
|
||||
<!-- 订单操作 -->
|
||||
<view v-if="item.order_status != OrderStatusEnum.CANCELLED.value" class="order-handle">
|
||||
<view class="btn-group clearfix">
|
||||
<!-- 未支付取消订单 -->
|
||||
<!-- <block v-if="item.pay_status == PayStatusEnum.PENDING.value">
|
||||
<view class="btn-item" @click="onCancel(item.order_id)">取消</view>
|
||||
</block> -->
|
||||
<!-- 已支付进行中的订单 -->
|
||||
<!-- <block v-if="item.order_status != OrderStatusEnum.APPLY_CANCEL.value"> -->
|
||||
<!-- <block v-if="item.pay_status == PayStatusEnum.SUCCESS.value && item.delivery_status == DeliveryStatusEnum.NOT_DELIVERED.value">
|
||||
<u-button type="primary" size="mini" class="btn-item" @click="onDelivery(item.order_id)">配送</u-button>
|
||||
</block> -->
|
||||
<!-- 订单核销码 -->
|
||||
<!-- <block v-if="item.pay_status == PayStatusEnum.SUCCESS.value && item.delivery_type == DeliveryTypeEnum.EXTRACT.value
|
||||
&& item.delivery_status == DeliveryStatusEnum.NOT_DELIVERED.value">
|
||||
<view class="btn-item active" @click="onExtractQRCode(item.order_id)">
|
||||
<text class="iconfont icon-qr-extract"></text>
|
||||
<text class="m-l-10">核销码</text>
|
||||
</view>
|
||||
</block> -->
|
||||
<!-- </block> -->
|
||||
<!-- 已申请取消 -->
|
||||
<!-- <view v-else class="f-28 col-8">取消申请中</view> -->
|
||||
<!-- 未支付的订单 -->
|
||||
<!-- <block v-if="item.pay_status == PayStatusEnum.PENDING.value">
|
||||
<view class="btn-item active" @click="onPay(item.order_id)">去支付</view>
|
||||
</block> -->
|
||||
<!-- 确认收货 -->
|
||||
<!-- <block v-if="item.delivery_status == DeliveryStatusEnum.DELIVERED.value && item.receipt_status == ReceiptStatusEnum.NOT_RECEIVED.value">
|
||||
<view class="btn-item active" @click="onReceipt(item.order_id)">确认收货</view>
|
||||
</block> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
<!-- 核销二维码弹窗 -->
|
||||
<u-popup v-model="showQRCodePopup" mode="center" border-radius="26" :closeable="true">
|
||||
<view class="qrcode-popup">
|
||||
<view class="title">自提核销二维码</view>
|
||||
<view class="pop-content">
|
||||
<image v-if="qrcodeImage" class="image" :src="qrcodeImage"></image>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
DeliveryStatusEnum,
|
||||
DeliveryTypeEnum,
|
||||
OrderStatusEnum,
|
||||
PayStatusEnum,
|
||||
PayTypeEnum,
|
||||
ReceiptStatusEnum
|
||||
} from '@/common/enum/order'
|
||||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
|
||||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
|
||||
import { getEmptyPaginateObj, getMoreListData } from '@/core/app'
|
||||
import * as OrderApi from '@/api/order'
|
||||
import * as UserApi from '@/api/user'
|
||||
import { wxPayment } from '@/core/app'
|
||||
|
||||
// 每页记录数量
|
||||
const pageSize = 15
|
||||
|
||||
// tab栏数据
|
||||
const tabs = [{
|
||||
name: `全部`,
|
||||
value: 'all'
|
||||
}, {
|
||||
name: `待支付`,
|
||||
value: 'payment'
|
||||
}, {
|
||||
name: `待发货`,
|
||||
value: 'delivery'
|
||||
}, {
|
||||
name: `待收货`,
|
||||
value: 'received'
|
||||
}, {
|
||||
name: `待评价`,
|
||||
value: 'comment'
|
||||
}]
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollBody
|
||||
},
|
||||
mixins: [MescrollMixin],
|
||||
data() {
|
||||
return {
|
||||
// 枚举类
|
||||
DeliveryStatusEnum,
|
||||
DeliveryTypeEnum,
|
||||
OrderStatusEnum,
|
||||
PayStatusEnum,
|
||||
PayTypeEnum,
|
||||
ReceiptStatusEnum,
|
||||
|
||||
// 当前页面参数
|
||||
options: { dataType: 'all' },
|
||||
// tab栏数据
|
||||
tabs,
|
||||
// 当前标签索引
|
||||
curTab: 0,
|
||||
// 订单列表数据
|
||||
list: getEmptyPaginateObj(),
|
||||
|
||||
// 上拉加载配置
|
||||
upOption: {
|
||||
// 首次自动执行
|
||||
auto: true,
|
||||
// 每页数据的数量; 默认10
|
||||
page: { size: pageSize },
|
||||
// 数量要大于4条才显示无更多数据
|
||||
noMoreSize: 4,
|
||||
// 空布局
|
||||
empty: {
|
||||
tip: '亲,暂无订单记录'
|
||||
}
|
||||
},
|
||||
// 控制首次触发onShow事件时不刷新列表
|
||||
canReset: false,
|
||||
// 核销二维码弹窗
|
||||
showQRCodePopup: false,
|
||||
// 核销二维码图片url (通过后端获取)
|
||||
qrcodeImage: '',
|
||||
shopInfo: {},
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 初始化当前选中的标签
|
||||
this.initCurTab(options)
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow() {
|
||||
this.canReset && this.onRefreshList()
|
||||
this.canReset = true
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 初始化当前选中的标签
|
||||
initCurTab(options) {
|
||||
const app = this
|
||||
if (options.dataType) {
|
||||
const index = app.tabs.findIndex(item => item.value == options.dataType)
|
||||
app.curTab = index > -1 ? index : 0
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 上拉加载的回调 (页面初始化时也会执行一次)
|
||||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
|
||||
* @param {Object} page
|
||||
*/
|
||||
upCallback(page) {
|
||||
const app = this
|
||||
// 设置列表数据
|
||||
app.getOrderList(page.num)
|
||||
.then(list => {
|
||||
const curPageLen = list.data.length
|
||||
const totalSize = list.data.total
|
||||
app.mescroll.endBySize(curPageLen, totalSize)
|
||||
})
|
||||
.catch(() => app.mescroll.endErr())
|
||||
},
|
||||
|
||||
// 获取订单列表
|
||||
getOrderList(pageNo = 1) {
|
||||
const app = this
|
||||
const shopInfo = uni.getStorageSync('shopInfo')
|
||||
return new Promise((resolve, reject) => {
|
||||
OrderApi.list({ dataType: app.getTabValue(), page: pageNo, byShopId: shopInfo.shopId }, { load: false })
|
||||
.then(result => {
|
||||
// 合并新数据
|
||||
const newList = app.initList(result.data.list)
|
||||
app.list.data = getMoreListData(newList, app.list, pageNo)
|
||||
resolve(newList)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 初始化订单列表数据
|
||||
initList(newList) {
|
||||
newList.data.forEach(item => {
|
||||
item.total_num = 0
|
||||
item.goods.forEach(goods => {
|
||||
item.total_num += goods.total_num
|
||||
})
|
||||
})
|
||||
return newList
|
||||
},
|
||||
|
||||
// 获取当前标签项的值
|
||||
getTabValue() {
|
||||
return this.tabs[this.curTab].value
|
||||
},
|
||||
|
||||
// 切换标签项
|
||||
onChangeTab(index) {
|
||||
const app = this
|
||||
// 设置当前选中的标签
|
||||
app.curTab = index
|
||||
// 刷新订单列表
|
||||
app.onRefreshList()
|
||||
},
|
||||
|
||||
// 刷新订单列表
|
||||
onRefreshList() {
|
||||
this.list = getEmptyPaginateObj()
|
||||
setTimeout(() => {
|
||||
this.mescroll.resetUpScroll()
|
||||
}, 120)
|
||||
},
|
||||
|
||||
// 取消订单
|
||||
onCancel(orderId) {
|
||||
const app = this
|
||||
uni.showModal({
|
||||
title: '友情提示',
|
||||
content: '确认要取消该订单吗?',
|
||||
success(o) {
|
||||
if (o.confirm) {
|
||||
OrderApi.cancel(orderId)
|
||||
.then(result => {
|
||||
// 显示成功信息
|
||||
app.$toast(result.message)
|
||||
// 刷新订单列表
|
||||
app.onRefreshList()
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onDelivery(orderId){
|
||||
return this.$navTo('package/dealer/driver', { orderId })
|
||||
console.log(orderId);
|
||||
return false
|
||||
},
|
||||
|
||||
// 确认收货
|
||||
onReceipt(orderId) {
|
||||
const app = this
|
||||
uni.showModal({
|
||||
title: '友情提示',
|
||||
content: '确认收到商品了吗?',
|
||||
success(o) {
|
||||
if (o.confirm) {
|
||||
OrderApi.receipt(orderId)
|
||||
.then(result => {
|
||||
// 显示成功信息
|
||||
app.$success(result.message)
|
||||
// 刷新订单列表
|
||||
app.onRefreshList()
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 获取核销二维码
|
||||
onExtractQRCode(orderId) {
|
||||
const app = this
|
||||
OrderApi.extractQrcode(orderId, { channel: app.platform })
|
||||
.then(result => {
|
||||
app.qrcodeImage = result.data.qrcode
|
||||
app.showQRCodePopup = true
|
||||
})
|
||||
},
|
||||
|
||||
// 点击去支付
|
||||
onPay(orderId) {
|
||||
this.$navTo('pages/checkout/cashier/index', { orderId })
|
||||
},
|
||||
|
||||
// 跳转到订单详情页
|
||||
handleTargetDetail(orderId) {
|
||||
this.$navTo('pages/order/detail', { orderId })
|
||||
},
|
||||
|
||||
// 跳转到订单评价页
|
||||
handleTargetComment(orderId) {
|
||||
this.$navTo('pages/order/comment/index', { orderId })
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 项目内容
|
||||
.order-item {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 30rpx 30rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
// 项目顶部
|
||||
.item-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 26rpx;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.order-time {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.state-text {
|
||||
color: $main-bg;
|
||||
}
|
||||
}
|
||||
|
||||
// 商品列表
|
||||
.goods-list {
|
||||
|
||||
// 商品项
|
||||
.goods-item {
|
||||
display: flex;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
// 商品图片
|
||||
.goods-image {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 商品内容
|
||||
.goods-content {
|
||||
flex: 1;
|
||||
padding-left: 16rpx;
|
||||
padding-top: 16rpx;
|
||||
|
||||
.goods-title {
|
||||
font-size: 26rpx;
|
||||
max-height: 76rpx;
|
||||
}
|
||||
|
||||
.goods-props {
|
||||
margin-top: 14rpx;
|
||||
height: 40rpx;
|
||||
color: #ababab;
|
||||
font-size: 24rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.goods-props-item {
|
||||
display: inline-block;
|
||||
margin-right: 14rpx;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #F5F5F5;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 交易信息
|
||||
.goods-trade {
|
||||
padding-top: 16rpx;
|
||||
width: 150rpx;
|
||||
text-align: right;
|
||||
color: $uni-text-color-grey;
|
||||
font-size: 26rpx;
|
||||
|
||||
.goods-price {
|
||||
vertical-align: bottom;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.unit {
|
||||
margin-right: -2rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 订单合计
|
||||
.order-total {
|
||||
font-size: 26rpx;
|
||||
vertical-align: bottom;
|
||||
text-align: right;
|
||||
height: 40rpx;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.unit {
|
||||
margin-left: 8rpx;
|
||||
margin-right: -2rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.money {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 订单操作
|
||||
.order-handle {
|
||||
.btn-group {
|
||||
|
||||
.btn-item {
|
||||
border-radius: 10rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
margin-left: 15rpx;
|
||||
font-size: 28rpx;
|
||||
float: right;
|
||||
|
||||
&:last-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
border: 1rpx solid $main-bg;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 弹出层 - 核销二维码
|
||||
.qrcode-popup {
|
||||
padding: 36rpx 30rpx;
|
||||
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 26rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pop-content {
|
||||
min-height: 260rpx;
|
||||
padding: 0 10rpx;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 510rpx;
|
||||
height: 510rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
402
package/user/popularize/components/goods.vue
Executable file
402
package/user/popularize/components/goods.vue
Executable file
@@ -0,0 +1,402 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption"
|
||||
:bottombar="false" @up="upCallback">
|
||||
<view class="cate-content">
|
||||
<!-- 商品列表 -->
|
||||
<view class="goods-list">
|
||||
<view class="goods-item--container" v-for="(item, index) in goodsList.data" :key="index">
|
||||
<view class="goods-item" @click="onTargetGoods(item.goods_id)">
|
||||
<!-- 商品图片 -->
|
||||
<view class="goods-item_left">
|
||||
<image class="image" :src="item.goods_image"></image>
|
||||
</view>
|
||||
<view class="goods-item_right">
|
||||
<!-- 商品标题 -->
|
||||
<view class="goods-name">
|
||||
<text class="twoline-hide">{{ item.goods_name }}</text>
|
||||
</view>
|
||||
<view class="item-prices oneline-hide">
|
||||
<text class="goods-sales">已售{{ item.goods_sales }}件</text>
|
||||
</view>
|
||||
<!-- 商品信息 -->
|
||||
<view class="goods-item_desc">
|
||||
<view class="desc_footer">
|
||||
<view class="item-prices oneline-hide">
|
||||
<text class="price_x">¥{{ item.goods_price_min }}</text>
|
||||
<!-- 商品销量 -->
|
||||
<text v-if="item.line_price_min > 0"
|
||||
class="price_y">¥{{ item.line_price_min }}</text>
|
||||
</view>
|
||||
<view class="buy-gouwuche">
|
||||
<u-button size="mini" @click="handleAddCart(item)">取消收藏
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 加入购物车组件 -->
|
||||
<AddCartPopup ref="AddCartPopup" @addCart="onUpdateCartTabBadge" />
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
|
||||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
|
||||
import {
|
||||
getEmptyPaginateObj,
|
||||
getMoreListData,
|
||||
setCartTabBadge
|
||||
} from '@/core/app'
|
||||
import {
|
||||
PageCategoryStyleEnum
|
||||
} from '@/common/enum/store/page/category'
|
||||
import Empty from '@/components/empty'
|
||||
import AddCartBtn from '@/components/add-cart-btn'
|
||||
import AddCartPopup from '@/components/add-cart-popup'
|
||||
import {
|
||||
rpx2px
|
||||
} from '@/utils/util'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
|
||||
const pageSize = 15
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollBody,
|
||||
Empty,
|
||||
AddCartBtn,
|
||||
AddCartPopup
|
||||
},
|
||||
mixins: [MescrollMixin],
|
||||
props: {
|
||||
// 分类列表
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 枚举类
|
||||
PageCategoryStyleEnum,
|
||||
// 列表高度
|
||||
scrollHeight: 0,
|
||||
// 一级分类:指针
|
||||
curIndex: -1,
|
||||
// 商品列表
|
||||
goodsList: getEmptyPaginateObj(),
|
||||
// 上拉加载配置
|
||||
upOption: {
|
||||
// 首次自动执行
|
||||
auto: true,
|
||||
// 每页数据的数量; 默认10
|
||||
page: {
|
||||
size: pageSize
|
||||
},
|
||||
// 数量要大于3条才显示无更多数据
|
||||
noMoreSize: 3,
|
||||
// 返回顶部
|
||||
toTop: {
|
||||
right: 30,
|
||||
bottom: 48,
|
||||
zIndex: 9
|
||||
}
|
||||
},
|
||||
|
||||
sortPrice: false, // 价格排序 (true高到低 false低到高)
|
||||
sortType: 'hot', // 排序类型
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 设置分类列表高度
|
||||
this.setListHeight()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 切换排序方式
|
||||
handleSortType(newSortType) {
|
||||
const app = this
|
||||
const newSortPrice = newSortType === 'price' ? !app.sortPrice : true
|
||||
app.sortType = newSortType
|
||||
app.sortPrice = newSortPrice
|
||||
// 刷新列表数据
|
||||
app.getGoodsList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 上拉加载的回调 (页面初始化时也会执行一次)
|
||||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
|
||||
* @param {Object} page
|
||||
*/
|
||||
upCallback(page) {
|
||||
const app = this
|
||||
// 设置列表数据
|
||||
console.log(page.num);
|
||||
app.getGoodsList(page.num)
|
||||
.then(list => {
|
||||
const curPageLen = list.data.length
|
||||
const totalSize = list.data.total
|
||||
app.mescroll.endBySize(curPageLen, totalSize)
|
||||
})
|
||||
.catch(() => app.mescroll.endErr())
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取商品列表
|
||||
* @param {Number} pageNo 页码
|
||||
*/
|
||||
getGoodsList(pageNo = 1) {
|
||||
const app = this
|
||||
const categoryId = app.curIndex > -1 ? app.list[app.curIndex].category_id : 0
|
||||
return new Promise((resolve, reject) => {
|
||||
GoodsApi.list({
|
||||
categoryId,
|
||||
page: pageNo,
|
||||
collection: true
|
||||
}, {
|
||||
load: false
|
||||
})
|
||||
.then(result => {
|
||||
const newList = result.data.list
|
||||
app.goodsList.data = getMoreListData(newList, app.goodsList, pageNo)
|
||||
app.goodsList.last_page = newList.last_page
|
||||
resolve(newList)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 设置列表内容的高度
|
||||
setListHeight() {
|
||||
const {
|
||||
windowHeight
|
||||
} = uni.getSystemInfoSync()
|
||||
this.scrollHeight = windowHeight - rpx2px(96)
|
||||
},
|
||||
|
||||
// 一级分类:选中分类
|
||||
handleSelectNav(index) {
|
||||
this.curIndex = index
|
||||
this.onRefreshList()
|
||||
},
|
||||
|
||||
// 刷新列表数据
|
||||
onRefreshList() {
|
||||
this.goodsList = getEmptyPaginateObj()
|
||||
setTimeout(() => this.mescroll.resetUpScroll(), 120)
|
||||
},
|
||||
|
||||
// 跳转至商品列表页
|
||||
onTargetGoods(goodsId) {
|
||||
this.$navTo('pages/goods/detail', {
|
||||
goodsId
|
||||
})
|
||||
},
|
||||
|
||||
// 点击加入购物车
|
||||
handleAddCart(item) {
|
||||
GoodsApi.collection({goodsId: item.})
|
||||
this.$emit('addCart')
|
||||
},
|
||||
|
||||
// 更新购物车角标
|
||||
onUpdateCartTabBadge() {
|
||||
console.log('onUpdateCartTabBadge')
|
||||
setCartTabBadge()
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
background-color: #F6F6F6 !important;
|
||||
}
|
||||
|
||||
// 分类内容
|
||||
.cate-content {
|
||||
z-index: 1;
|
||||
background-color: #F6F6F6 !important;
|
||||
padding-top: 0rpx;
|
||||
}
|
||||
|
||||
// 一级分类+二级分类 20
|
||||
.cate-left {
|
||||
width: 173rpx;
|
||||
height: 100%;
|
||||
background: #f8f8f8;
|
||||
color: #444;
|
||||
|
||||
position: fixed;
|
||||
top: calc(286rpx + var(--window-top));
|
||||
left: var(--window-left);
|
||||
bottom: var(--window-bottom);
|
||||
}
|
||||
|
||||
// 左侧一级分类
|
||||
.type-nav {
|
||||
position: relative;
|
||||
height: 90rpx;
|
||||
z-index: 10;
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.selected {
|
||||
background: #fff;
|
||||
border-right: none;
|
||||
font-size: 28rpx;
|
||||
color: $main-bg
|
||||
}
|
||||
}
|
||||
|
||||
// 商品列表
|
||||
.goods-list {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
padding: 28rpx 22rpx;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
padding: 20rpx;
|
||||
border: 1px solid #F6F6F6;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.goods-item_left {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
margin-right: 20rpx;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
.goods-name {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 68rpx;
|
||||
font-size: 34rpx;
|
||||
line-height: 1.3;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_desc {
|
||||
margin-top: 20rpx;
|
||||
|
||||
.people {
|
||||
margin-right: 14rpx;
|
||||
}
|
||||
|
||||
.desc_footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
position: absolute;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
min-height: 44rpx;
|
||||
|
||||
.item-prices {
|
||||
padding-right: 6rpx;
|
||||
|
||||
.price_x {
|
||||
margin-right: 14rpx;
|
||||
font-weight: 600;
|
||||
color: #ff0000;
|
||||
font-size: 38rpx;
|
||||
}
|
||||
|
||||
.price_y {
|
||||
color: #999;
|
||||
text-decoration: line-through;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.goods-sales {
|
||||
padding-top: 8rpx !important;
|
||||
color: #b3b3b3 !important;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background: #fff;
|
||||
border-radius: 14rpx;
|
||||
padding: 20rpx 4rpx;
|
||||
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
// 排序组件
|
||||
.store-sort {
|
||||
margin-top: 24rpx;
|
||||
position: sticky;
|
||||
top: var(--window-top);
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 99;
|
||||
|
||||
.sort-item {
|
||||
flex-basis: 33.3333%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50rpx;
|
||||
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-item-price .price-arrow {
|
||||
margin-left: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #000;
|
||||
|
||||
.icon {
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
|
||||
&.up {
|
||||
margin-bottom: -16rpx;
|
||||
}
|
||||
|
||||
&.down {
|
||||
margin-top: -16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
404
package/user/popularize/components/goods1.vue
Executable file
404
package/user/popularize/components/goods1.vue
Executable file
@@ -0,0 +1,404 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption"
|
||||
:bottombar="false" @up="upCallback">
|
||||
<view class="cate-content">
|
||||
<!-- 商品列表 -->
|
||||
<view class="goods-list">
|
||||
<view class="goods-item--container" v-for="(item, index) in goodsList.data" :key="index">
|
||||
<view class="goods-item" @click="onTargetGoods(item.goods_id)">
|
||||
<!-- 商品图片 -->
|
||||
<view class="goods-item_left">
|
||||
<image class="image" :src="item.goods_image"></image>
|
||||
</view>
|
||||
<view class="goods-item_right">
|
||||
<!-- 商品标题 -->
|
||||
<view class="goods-name">
|
||||
<text class="twoline-hide">{{ item.goods_name }}</text>
|
||||
</view>
|
||||
<view class="item-prices oneline-hide">
|
||||
<text class="goods-sales">已售{{ item.goods_sales }}件</text>
|
||||
</view>
|
||||
<!-- 商品信息 -->
|
||||
<view class="goods-item_desc">
|
||||
<view class="desc_footer">
|
||||
<view class="item-prices oneline-hide">
|
||||
<text class="price_x">¥{{ item.goods_price_min }}</text>
|
||||
<!-- 商品销量 -->
|
||||
<text v-if="item.line_price_min > 0"
|
||||
class="price_y">¥{{ item.line_price_min }}</text>
|
||||
</view>
|
||||
<view class="buy-gouwuche">
|
||||
<u-button type="primary" size="mini">置顶</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 加入购物车组件 -->
|
||||
<AddCartPopup ref="AddCartPopup" @addCart="onUpdateCartTabBadge" />
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
|
||||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
|
||||
import {
|
||||
getEmptyPaginateObj,
|
||||
getMoreListData,
|
||||
setCartTabBadge
|
||||
} from '@/core/app'
|
||||
import {
|
||||
PageCategoryStyleEnum
|
||||
} from '@/common/enum/store/page/category'
|
||||
import Empty from '@/components/empty'
|
||||
import AddCartBtn from '@/components/add-cart-btn'
|
||||
import AddCartPopup from '@/components/add-cart-popup'
|
||||
import {
|
||||
rpx2px
|
||||
} from '@/utils/util'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
|
||||
const pageSize = 15
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollBody,
|
||||
Empty,
|
||||
AddCartBtn,
|
||||
AddCartPopup
|
||||
},
|
||||
mixins: [MescrollMixin],
|
||||
props: {
|
||||
// 分类列表
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 枚举类
|
||||
PageCategoryStyleEnum,
|
||||
// 列表高度
|
||||
scrollHeight: 0,
|
||||
// 一级分类:指针
|
||||
curIndex: -1,
|
||||
// 商品列表
|
||||
goodsList: getEmptyPaginateObj(),
|
||||
// 上拉加载配置
|
||||
upOption: {
|
||||
// 首次自动执行
|
||||
auto: true,
|
||||
// 每页数据的数量; 默认10
|
||||
page: {
|
||||
size: pageSize
|
||||
},
|
||||
// 数量要大于3条才显示无更多数据
|
||||
noMoreSize: 3,
|
||||
// 返回顶部
|
||||
toTop: {
|
||||
right: 30,
|
||||
bottom: 48,
|
||||
zIndex: 9
|
||||
}
|
||||
},
|
||||
|
||||
sortPrice: false, // 价格排序 (true高到低 false低到高)
|
||||
sortType: 'hot', // 排序类型
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 设置分类列表高度
|
||||
this.setListHeight()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 切换排序方式
|
||||
handleSortType(newSortType) {
|
||||
const app = this
|
||||
const newSortPrice = newSortType === 'price' ? !app.sortPrice : true
|
||||
app.sortType = newSortType
|
||||
app.sortPrice = newSortPrice
|
||||
// 刷新列表数据
|
||||
app.getGoodsList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 上拉加载的回调 (页面初始化时也会执行一次)
|
||||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
|
||||
* @param {Object} page
|
||||
*/
|
||||
upCallback(page) {
|
||||
const app = this
|
||||
// 设置列表数据
|
||||
console.log(page.num);
|
||||
app.getGoodsList(page.num)
|
||||
.then(list => {
|
||||
const curPageLen = list.data.length
|
||||
const totalSize = list.data.total
|
||||
app.mescroll.endBySize(curPageLen, totalSize)
|
||||
})
|
||||
.catch(() => app.mescroll.endErr())
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取商品列表
|
||||
* @param {Number} pageNo 页码
|
||||
*/
|
||||
getGoodsList(pageNo = 1) {
|
||||
const app = this
|
||||
const categoryId = app.curIndex > -1 ? app.list[app.curIndex].category_id : 0
|
||||
const { sortType } = this
|
||||
const { shopId } = uni.getStorageSync('shopInfo')
|
||||
return new Promise((resolve, reject) => {
|
||||
GoodsApi.list({
|
||||
categoryId,
|
||||
page: pageNo,
|
||||
sortType,
|
||||
shopId
|
||||
}, {
|
||||
load: false
|
||||
})
|
||||
.then(result => {
|
||||
const newList = result.data.list
|
||||
app.goodsList.data = getMoreListData(newList, app.goodsList, pageNo)
|
||||
app.goodsList.last_page = newList.last_page
|
||||
resolve(newList)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 设置列表内容的高度
|
||||
setListHeight() {
|
||||
const {
|
||||
windowHeight
|
||||
} = uni.getSystemInfoSync()
|
||||
this.scrollHeight = windowHeight - rpx2px(96)
|
||||
},
|
||||
|
||||
// 一级分类:选中分类
|
||||
handleSelectNav(index) {
|
||||
this.curIndex = index
|
||||
this.onRefreshList()
|
||||
},
|
||||
|
||||
// 刷新列表数据
|
||||
onRefreshList() {
|
||||
this.goodsList = getEmptyPaginateObj()
|
||||
setTimeout(() => this.mescroll.resetUpScroll(), 120)
|
||||
},
|
||||
|
||||
// 跳转至商品列表页
|
||||
onTargetGoods(goodsId) {
|
||||
this.$navTo('pages/goods/detail', {
|
||||
goodsId
|
||||
})
|
||||
},
|
||||
|
||||
// 点击加入购物车
|
||||
handleAddCart(item) {
|
||||
this.$refs.AddCartPopup.handle(item)
|
||||
this.$emit('addCart')
|
||||
},
|
||||
|
||||
// 更新购物车角标
|
||||
onUpdateCartTabBadge() {
|
||||
console.log('onUpdateCartTabBadge')
|
||||
setCartTabBadge()
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
background-color: #F6F6F6 !important;
|
||||
}
|
||||
|
||||
// 分类内容
|
||||
.cate-content {
|
||||
z-index: 1;
|
||||
background-color: #F6F6F6 !important;
|
||||
padding-top: 0rpx;
|
||||
}
|
||||
|
||||
// 一级分类+二级分类 20
|
||||
.cate-left {
|
||||
width: 173rpx;
|
||||
height: 100%;
|
||||
background: #f8f8f8;
|
||||
color: #444;
|
||||
|
||||
position: fixed;
|
||||
top: calc(286rpx + var(--window-top));
|
||||
left: var(--window-left);
|
||||
bottom: var(--window-bottom);
|
||||
}
|
||||
|
||||
// 左侧一级分类
|
||||
.type-nav {
|
||||
position: relative;
|
||||
height: 90rpx;
|
||||
z-index: 10;
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.selected {
|
||||
background: #fff;
|
||||
border-right: none;
|
||||
font-size: 28rpx;
|
||||
color: $main-bg
|
||||
}
|
||||
}
|
||||
|
||||
// 商品列表
|
||||
.goods-list {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
padding: 28rpx 22rpx;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
padding: 20rpx;
|
||||
border: 1px solid #F6F6F6;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.goods-item_left {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
margin-right: 20rpx;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
.goods-name {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 68rpx;
|
||||
font-size: 34rpx;
|
||||
line-height: 1.3;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_desc {
|
||||
margin-top: 20rpx;
|
||||
|
||||
.people {
|
||||
margin-right: 14rpx;
|
||||
}
|
||||
|
||||
.desc_footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
position: absolute;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
min-height: 44rpx;
|
||||
|
||||
.item-prices {
|
||||
padding-right: 6rpx;
|
||||
|
||||
.price_x {
|
||||
margin-right: 14rpx;
|
||||
font-weight: 600;
|
||||
color: #ff0000;
|
||||
font-size: 38rpx;
|
||||
}
|
||||
|
||||
.price_y {
|
||||
color: #999;
|
||||
text-decoration: line-through;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.goods-sales {
|
||||
padding-top: 8rpx !important;
|
||||
color: #b3b3b3 !important;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background: #fff;
|
||||
border-radius: 14rpx;
|
||||
padding: 20rpx 4rpx;
|
||||
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
// 排序组件
|
||||
.store-sort {
|
||||
margin-top: 24rpx;
|
||||
position: sticky;
|
||||
top: var(--window-top);
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 99;
|
||||
|
||||
.sort-item {
|
||||
flex-basis: 33.3333%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50rpx;
|
||||
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-item-price .price-arrow {
|
||||
margin-left: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #000;
|
||||
|
||||
.icon {
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
|
||||
&.up {
|
||||
margin-bottom: -16rpx;
|
||||
}
|
||||
|
||||
&.down {
|
||||
margin-top: -16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
395
package/user/popularize/index.vue
Executable file
395
package/user/popularize/index.vue
Executable file
@@ -0,0 +1,395 @@
|
||||
<template>
|
||||
<view class="container" :style="appThemeStyle">
|
||||
<mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{ use: false }" :up="upOption"
|
||||
:bottombar="false" @up="upCallback">
|
||||
<view class="cate-content">
|
||||
<!-- 商品列表 -->
|
||||
<view class="goods-list">
|
||||
<view class="goods-item--container" v-for="(item, index) in goodsList.data" :key="index">
|
||||
<view class="goods-item" @click="onTargetGoods(item.goods_id)">
|
||||
<!-- 商品图片 -->
|
||||
<view class="goods-item_left">
|
||||
<image class="image" :src="item.goods_image"></image>
|
||||
</view>
|
||||
<view class="goods-item_right">
|
||||
<!-- 商品标题 -->
|
||||
<view class="goods-name">
|
||||
<text class="twoline-hide">{{ item.goods_name }}</text>
|
||||
</view>
|
||||
<view class="item-prices oneline-hide">
|
||||
<text class="goods-sales">已售{{ item.goods_sales }}件</text>
|
||||
</view>
|
||||
<!-- 商品信息 -->
|
||||
<view class="goods-item_desc">
|
||||
<view class="desc_footer">
|
||||
<view class="item-prices oneline-hide">
|
||||
<text class="price_x">¥{{ item.goods_price_min }}</text>
|
||||
<!-- 商品销量 -->
|
||||
<text v-if="item.line_price_min > 0"
|
||||
class="price_y">¥{{ item.line_price_min }}</text>
|
||||
</view>
|
||||
<view class="buy-gouwuche">
|
||||
<u-button type="primary" size="mini">置顶</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MescrollBody from '@/components/mescroll-uni/mescroll-body.vue'
|
||||
import MescrollMixin from '@/components/mescroll-uni/mescroll-mixins'
|
||||
import {
|
||||
getEmptyPaginateObj,
|
||||
getMoreListData,
|
||||
setCartTabBadge
|
||||
} from '@/core/app'
|
||||
import {
|
||||
PageCategoryStyleEnum
|
||||
} from '@/common/enum/store/page/category'
|
||||
import Empty from '@/components/empty'
|
||||
import AddCartBtn from '@/components/add-cart-btn'
|
||||
import AddCartPopup from '@/components/add-cart-popup'
|
||||
import {
|
||||
rpx2px
|
||||
} from '@/utils/util'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
|
||||
const pageSize = 15
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollBody,
|
||||
Empty,
|
||||
AddCartBtn,
|
||||
AddCartPopup
|
||||
},
|
||||
mixins: [MescrollMixin],
|
||||
data() {
|
||||
return {
|
||||
// 枚举类
|
||||
PageCategoryStyleEnum,
|
||||
// 列表高度
|
||||
scrollHeight: 0,
|
||||
// 一级分类:指针
|
||||
curIndex: -1,
|
||||
// 商品列表
|
||||
goodsList: getEmptyPaginateObj(),
|
||||
// 上拉加载配置
|
||||
upOption: {
|
||||
// 首次自动执行
|
||||
auto: true,
|
||||
// 每页数据的数量; 默认10
|
||||
page: {
|
||||
size: pageSize
|
||||
},
|
||||
// 数量要大于3条才显示无更多数据
|
||||
noMoreSize: 3,
|
||||
// 返回顶部
|
||||
toTop: {
|
||||
right: 30,
|
||||
bottom: 48,
|
||||
zIndex: 9
|
||||
}
|
||||
},
|
||||
|
||||
sortPrice: false, // 价格排序 (true高到低 false低到高)
|
||||
sortType: 'hot', // 排序类型
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 设置分类列表高度
|
||||
this.setListHeight()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 切换排序方式
|
||||
handleSortType(newSortType) {
|
||||
const app = this
|
||||
const newSortPrice = newSortType === 'price' ? !app.sortPrice : true
|
||||
app.sortType = newSortType
|
||||
app.sortPrice = newSortPrice
|
||||
// 刷新列表数据
|
||||
app.getGoodsList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 上拉加载的回调 (页面初始化时也会执行一次)
|
||||
* 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
|
||||
* @param {Object} page
|
||||
*/
|
||||
upCallback(page) {
|
||||
const app = this
|
||||
// 设置列表数据
|
||||
console.log(page.num);
|
||||
app.getGoodsList(page.num)
|
||||
.then(list => {
|
||||
const curPageLen = list.data.length
|
||||
const totalSize = list.data.total
|
||||
app.mescroll.endBySize(curPageLen, totalSize)
|
||||
})
|
||||
.catch(() => app.mescroll.endErr())
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取商品列表
|
||||
* @param {Number} pageNo 页码
|
||||
*/
|
||||
getGoodsList(pageNo = 1) {
|
||||
const app = this
|
||||
const categoryId = app.curIndex > -1 ? app.list[app.curIndex].category_id : 0
|
||||
const { shopId } = uni.getStorageSync('shopInfo')
|
||||
return new Promise((resolve, reject) => {
|
||||
GoodsApi.list({
|
||||
categoryId,
|
||||
page: pageNo,
|
||||
topGoods: true,
|
||||
shopId
|
||||
}, {
|
||||
load: false
|
||||
})
|
||||
.then(result => {
|
||||
const newList = result.data.list
|
||||
app.goodsList.data = getMoreListData(newList, app.goodsList, pageNo)
|
||||
app.goodsList.last_page = newList.last_page
|
||||
resolve(newList)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
},
|
||||
|
||||
// 设置列表内容的高度
|
||||
setListHeight() {
|
||||
const {
|
||||
windowHeight
|
||||
} = uni.getSystemInfoSync()
|
||||
this.scrollHeight = windowHeight - rpx2px(96)
|
||||
},
|
||||
|
||||
// 一级分类:选中分类
|
||||
handleSelectNav(index) {
|
||||
this.curIndex = index
|
||||
this.onRefreshList()
|
||||
},
|
||||
|
||||
// 刷新列表数据
|
||||
onRefreshList() {
|
||||
this.goodsList = getEmptyPaginateObj()
|
||||
setTimeout(() => this.mescroll.resetUpScroll(), 120)
|
||||
},
|
||||
|
||||
// 跳转至商品列表页
|
||||
onTargetGoods(goodsId) {
|
||||
this.$navTo('pages/goods/detail', {
|
||||
goodsId
|
||||
})
|
||||
},
|
||||
|
||||
// 点击加入购物车
|
||||
handleAddCart(item) {
|
||||
GoodsApi.collection({goodsId: item.goods_id}).then(() => {
|
||||
this.getGoodsList()
|
||||
})
|
||||
},
|
||||
|
||||
// 更新购物车角标
|
||||
onUpdateCartTabBadge() {
|
||||
console.log('onUpdateCartTabBadge')
|
||||
setCartTabBadge()
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
background-color: #F6F6F6 !important;
|
||||
}
|
||||
|
||||
// 分类内容
|
||||
.cate-content {
|
||||
z-index: 1;
|
||||
background-color: #F6F6F6 !important;
|
||||
padding-top: 0rpx;
|
||||
}
|
||||
|
||||
// 一级分类+二级分类 20
|
||||
.cate-left {
|
||||
width: 173rpx;
|
||||
height: 100%;
|
||||
background: #f8f8f8;
|
||||
color: #444;
|
||||
|
||||
position: fixed;
|
||||
top: calc(286rpx + var(--window-top));
|
||||
left: var(--window-left);
|
||||
bottom: var(--window-bottom);
|
||||
}
|
||||
|
||||
// 左侧一级分类
|
||||
.type-nav {
|
||||
position: relative;
|
||||
height: 90rpx;
|
||||
z-index: 10;
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.selected {
|
||||
background: #fff;
|
||||
border-right: none;
|
||||
font-size: 28rpx;
|
||||
color: $main-bg
|
||||
}
|
||||
}
|
||||
|
||||
// 商品列表
|
||||
.goods-list {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
padding: 28rpx 22rpx;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
padding: 20rpx;
|
||||
border: 1px solid #F6F6F6;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.goods-item_left {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
margin-right: 20rpx;
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
.goods-name {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 68rpx;
|
||||
font-size: 34rpx;
|
||||
line-height: 1.3;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-item_desc {
|
||||
margin-top: 20rpx;
|
||||
|
||||
.people {
|
||||
margin-right: 14rpx;
|
||||
}
|
||||
|
||||
.desc_footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
position: absolute;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
min-height: 44rpx;
|
||||
|
||||
.item-prices {
|
||||
padding-right: 6rpx;
|
||||
|
||||
.price_x {
|
||||
margin-right: 14rpx;
|
||||
font-weight: 600;
|
||||
color: #ff0000;
|
||||
font-size: 38rpx;
|
||||
}
|
||||
|
||||
.price_y {
|
||||
color: #999;
|
||||
text-decoration: line-through;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.goods-sales {
|
||||
padding-top: 8rpx !important;
|
||||
color: #b3b3b3 !important;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background: #fff;
|
||||
border-radius: 14rpx;
|
||||
padding: 20rpx 4rpx;
|
||||
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
// 排序组件
|
||||
.store-sort {
|
||||
margin-top: 24rpx;
|
||||
position: sticky;
|
||||
top: var(--window-top);
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 99;
|
||||
|
||||
.sort-item {
|
||||
flex-basis: 33.3333%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50rpx;
|
||||
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-item-price .price-arrow {
|
||||
margin-left: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #000;
|
||||
|
||||
.icon {
|
||||
&.active {
|
||||
color: $main-bg;
|
||||
}
|
||||
|
||||
&.up {
|
||||
margin-bottom: -16rpx;
|
||||
}
|
||||
|
||||
&.down {
|
||||
margin-top: -16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
90
package/user/profile/index.vue
Normal file
90
package/user/profile/index.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<view class="partner">
|
||||
<!-- 表单组件 -->
|
||||
<view v-if="userInfo" class="form-wrapper">
|
||||
<u-form label-width="240rpx">
|
||||
<u-form-item label="会员ID" prop="name">
|
||||
{{userInfo.user_id}}
|
||||
</u-form-item>
|
||||
<u-form-item label="头像" prop="name">
|
||||
<image :src="userInfo.avatar_url" mode="widthFix" class="logo"></image>
|
||||
</u-form-item>
|
||||
<u-form-item label="昵称" prop="name">
|
||||
{{userInfo.nick_name}}
|
||||
</u-form-item>
|
||||
<u-form-item label="手机号码" prop="name">
|
||||
{{userInfo.mobile}}
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<!-- <view class="footer">
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle">更新资料</u-button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as UserApi from '@/api/user'
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disabled: false,
|
||||
userInfo: null,
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getUserInfo()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前用户信息
|
||||
getUserInfo() {
|
||||
const app = this
|
||||
const userInfo = uni.getStorageSync('userInfo')
|
||||
if(userInfo){
|
||||
app.userInfo = userInfo
|
||||
return
|
||||
}
|
||||
UserApi.info().then(result => {
|
||||
app.userInfo = result.data.userInfo
|
||||
})
|
||||
},
|
||||
groupChange(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.partner {
|
||||
|
||||
.banner {
|
||||
width: 100%;
|
||||
}
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
.logo{
|
||||
width: 100rpx;
|
||||
}
|
||||
.shipin{
|
||||
width: 400rpx;
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
width: 500rpx;
|
||||
margin: 20rpx auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
116
package/user/shop/index.vue
Normal file
116
package/user/shop/index.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<view class="partner">
|
||||
|
||||
<!-- 表单组件 -->
|
||||
<view class="form-wrapper" v-if="shopInfo">
|
||||
<u-form :model="form" ref="uForm" label-width="240rpx">
|
||||
<u-form-item>
|
||||
<image :src="shopInfo.backgroundUrl" mode="widthFix" class="banner"></image>
|
||||
</u-form-item>
|
||||
<u-form-item>
|
||||
<view class="shop-box">
|
||||
<text class="shop-name">{{shopInfo.shopName}}</text>
|
||||
<text v-if="shopInfo.region"><u-icon name="map" :size="26"></u-icon>{{shopInfo.region.province}}{{shopInfo.region.city}}{{shopInfo.region.region}}{{shopInfo.address}}</text>
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item>
|
||||
<view class="shop-box">
|
||||
<text class="shop-name">站点简介</text>
|
||||
<text>{{shopInfo.summary}}</text>
|
||||
</view>
|
||||
</u-form-item>
|
||||
|
||||
|
||||
</u-form>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<!-- <view class="footer">
|
||||
<view class="btn">
|
||||
<u-button type="primary" shape="circle">更新资料</u-button>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 表单字段元素
|
||||
const form = {
|
||||
// 入驻类型 (合伙人10001,配送员10002,社区门店10003,省代10004)
|
||||
grade_id: 10004,
|
||||
company: '',
|
||||
real_name: '',
|
||||
phone: '',
|
||||
mobile: '',
|
||||
region: [],
|
||||
detail: '',
|
||||
}
|
||||
|
||||
import * as UserApi from '@/api/user'
|
||||
import SelectRegion from '@/components/select-region/select-region'
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form,
|
||||
disabled: false,
|
||||
imageList: [],
|
||||
shopInfo: {},
|
||||
applyInfo: {}
|
||||
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getUserInfo()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前用户信息
|
||||
getUserInfo() {
|
||||
const app = this
|
||||
UserApi.info().then(result => {
|
||||
app.shopInfo = result.data.shopInfo
|
||||
app.applyInfo = result.data.applyInfo
|
||||
})
|
||||
},
|
||||
groupChange(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.partner {
|
||||
.banner {
|
||||
padding-top: 20rpx;
|
||||
width: 100%;
|
||||
}
|
||||
.form-wrapper {
|
||||
margin: 20rpx auto 20rpx auto;
|
||||
padding: 0 40rpx;
|
||||
width: 94%;
|
||||
box-shadow: 0 1rpx 5rpx 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
.shop-box{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.shop-name{
|
||||
font-weight: bold;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
.logo{
|
||||
width: 100rpx;
|
||||
}
|
||||
.shipin{
|
||||
width: 400rpx;
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
width: 500rpx;
|
||||
margin: 20rpx auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user