Browse Source

上传

master
前端-胡立永 1 month ago
parent
commit
60f5f14a0f
15 changed files with 783 additions and 41 deletions
  1. +2
    -1
      api/api.js
  2. +9
    -4
      api/http.js
  3. +15
    -0
      api/model/order.js
  4. +215
    -0
      components/list/activity/active-itemV2.vue
  5. +1
    -1
      manifest.json
  6. +28
    -1
      mixins/product.js
  7. +3
    -0
      pages.json
  8. +25
    -20
      pages/index/product.vue
  9. +89
    -2
      pages_order/components/list/gourmet/productSelectList.vue
  10. +2
    -2
      pages_order/components/product/submit.vue
  11. +3
    -2
      pages_order/gourmet/gourmetDetail.vue
  12. +5
    -3
      pages_order/gourmet/gourmetList.vue
  13. +375
    -0
      pages_order/product/addProduct.vue
  14. +5
    -5
      pages_order/product/productDetail.vue
  15. +6
    -0
      utils/utils.js

+ 2
- 1
api/api.js View File

@ -424,7 +424,8 @@ export function api(key, data, callback, loadingTitle) {
}
http.http(req.url, data, callback, req.method,
loadingTitle || req.showLoading, loadingTitle || req.loadingTitle)
loadingTitle || req.showLoading, loadingTitle || req.loadingTitle,
req)
}


+ 9
- 4
api/http.js View File

@ -3,7 +3,7 @@ import Vue from 'vue'
import utils from '../utils/utils.js'
function http(uri, data, callback, method = 'GET', showLoading, title) {
function http(uri, data, callback, method = 'GET', showLoading, title, req) {
if(showLoading){
uni.showLoading({
@ -11,13 +11,18 @@ function http(uri, data, callback, method = 'GET', showLoading, title) {
});
}
let header = {
'X-Access-Token': uni.getStorageSync('token'),
'Content-Type' : method == 'POST' ? 'application/x-www-form-urlencoded' : 'application/json'
}
uni.request({
url: Vue.prototype.$config.baseUrl + uri,
data: enhanceData(data),
method: method,
header: {
'X-Access-Token': uni.getStorageSync('token'),
'Content-Type' : method == 'POST' ? 'application/x-www-form-urlencoded' : 'application/json'
header : {
...header,
...req.header,
},
success: (res) => {


+ 15
- 0
api/model/order.js View File

@ -62,6 +62,21 @@ const api = {
method: 'GET',
auth : true,
},
// 商城-增加或者修改商品信息
orderSaveOrUpdate : {
url: '/order/saveOrUpdate',
method: 'POST',
auth : true,
header : {
'Content-Type' : 'application/json'
},
},
// 商城-商品下架
orderUpdate : {
url: '/order/update',
method: 'POST',
auth : true,
},
}
export default api

+ 215
- 0
components/list/activity/active-itemV2.vue View File

@ -0,0 +1,215 @@
<template>
<view class="cardList">
<view class="container"
@click="toDetail(item)"
v-for="(item, index) in cardListData" :key="index">
<view class="content" :class="['U','S'].includes(item.state) ? 'content_border' : ''">
<view class="left">
<image :src="item.image && item.image.split(',')[0]" mode="aspectFill">
</view>
<view class="right">
<view class="detailed">
<view class="title">{{item.title}}</view>
<view class="date">{{ $dayjs(item.startTime).format('YYYY-MM-DD') }}</view>
<view class="address">{{item.address}}</view>
</view>
<view class="price">
<view class="num-box">{{item.num || 0}}/{{item.sum || 0}}</view>
<view class="btn-box" v-if="item.state == 0">立即报名</view>
<view class="btn-box btn-box2" v-if="item.state == 1">已结束</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
cardListData: {
type: Array,
default: []
},
},
data() {
return {
};
},
components: {
},
computed: {},
watch: {
},
created() {
},
mounted() {},
methods: {
skip(val) {
uni.navigateTo({
url: '/pages_order/orderDetails'
})
},
toDetail({ id, ntype }) {
if(ntype == 1){
uni.navigateTo({
url:`/pages_order/lvyou-detail?travelId=${id}`
})
return
}
uni.navigateTo({
url:`/pages_order/huodong-detail?activityId=${id}`
})
}
}
};
</script>
<style scoped lang="scss">
.cardList {
position: relative;
z-index: 9;
.container {
margin-top: 31rpx;
padding: 25rpx 0;
border-radius: 20rpx;
background: #1B1713;
.content_border {
border-bottom: 1px solid #2A2A2A;
}
.content {
display: flex;
padding: 24rpx 35rpx;
.left {
width: 228rpx;
height: 228rpx;
border-radius: 20rpx;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.right {
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
margin-left: 26rpx;
color: $uni-text-color-grey;
font-size: 24rpx;
.detailed {
.title {
font-size: 32rpx;
color: #fff;
padding-top: 11rpx;
width: 380rpx;
// overflow:hidden; //
// text-overflow:ellipsis; //
// white-space:nowrap; //
overflow: hidden;
text-overflow: ellipsis;
display:-webkit-box; //
-webkit-box-orient:vertical; //--
-webkit-line-clamp:2; //
}
.date {
padding: 25rpx 0 19rpx;
display: flex;
align-items: center;
&::before {
content: '';
display: block;
background: url('@/static/image/cart/timeIcon.png') no-repeat;
background-size: 100% 100%;
width: 24rpx;
height: 24rpx;
margin-right: 10rpx;
}
}
.address {
display: flex;
align-items: center;
width: 360rpx;
overflow:hidden; //
text-overflow:ellipsis; //
white-space:nowrap; //
&::before {
content: '';
display: block;
background: url('@/static/image/cart/addressIcon.png') no-repeat;
background-size: 100% 100%;
width: 22rpx;
height: 26rpx;
margin-right: 10rpx;
flex-shrink: 0;
}
}
}
.price {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 25rpx;
.num-box {
font-size: 27rpx;
color: #fff;
}
.btn-box {
width: 180rpx;
height: 54rpx;
background: url('@/static/image/member/btn-2.png') no-repeat;
background-size: 100% 100%;
font-weight: 500;
font-size: 23rpx;
color: #FFFFFF;
text-align: center;
line-height: 54rpx;
}
.btn-box2 {
background: #34312E;
color: #AFAFAF;
border-radius: 60rpx;
}
}
}
}
.button-sp-area {
text-align: right;
padding-top: 20rpx;
.mini-btn {
width: 166rpx;
height: 53rpx;
line-height: 53rpx;
font-size: 24rpx;
border-radius: 50rpx;
margin-left: 20rpx;
background-color: #34312E;
color: #AFAFAF;
}
}
}
}
.active {
color: $uni-color-primary !important;
}
</style>

+ 1
- 1
manifest.json View File

@ -1,6 +1,6 @@
{
"name" : "unapp模板",
"appid" : "__UNI__E90DB8C",
"appid" : "__UNI__197A38F",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",


+ 28
- 1
mixins/product.js View File

@ -3,15 +3,42 @@
export default {
data() {
return {
productCategory : [
{
name : '户外',
value : 0,
},
{
name : '美食',
value : 1,
},
{
name : '兑换',
value : 2,
},
{
name : '特产',
value : 3,
},
{
name : '校园',
value : 4,
},
],
}
},
methods : {
// 商品详情->积分兑换
isProductPoint(detail){
return [2].includes(detail.className)
},
// 商品详情->微信支付
isProductPrice(detail){
return [0, 1, 3].includes(detail.className)
},
// 是否跳转到商店
isShopBuy(detail){
return [1, 3, 4].includes(detail.className)
},
}
}

+ 3
- 0
pages.json View File

@ -175,6 +175,9 @@
},
{
"path": "notice/noticeDetail"
},
{
"path": "product/addProduct"
}
]
}],


+ 25
- 20
pages/index/product.vue View File

@ -28,7 +28,7 @@
<!-- 分类 -->
<view class="LabelOptions">
<uv-tabs :list="category"
<uv-tabs :list="productCategory"
:activeStyle="{color : '#000', fontWeight : 900}"
lineColor="#5baaff"
lineHeight="8rpx"
@ -97,11 +97,12 @@
<script>
import mixinsList from '@/mixins/list.js'
import mixinsProduct from '@/mixins/product.js'
import tabber from '@/components/base/tabbar.vue'
import productList from '@/components/user/productList.vue'
import { mapState } from 'vuex'
export default {
mixins: [mixinsList],
mixins: [mixinsList, mixinsProduct],
components : {
tabber,
productList,
@ -130,24 +131,28 @@
// rightGap: 10,
// columnGap: 10,
bannerList : [],
category : [
{
name : '美食商城',
value : 0,
},
{
name : '家乡特产',
value : 1,
},
{
name : '积分商城',
value : 2,
},
{
name : '二手集市',
value : 3,
},
],
// category : [
// {
// name : '',
// value : 0,
// },
// {
// name : '',
// value : 1,
// },
// {
// name : '',
// value : 2,
// },
// {
// name : '',
// value : 3,
// },
// {
// name : '',
// value : 4,
// },
// ],
}
},
onShow() {


+ 89
- 2
pages_order/components/list/gourmet/productSelectList.vue View File

@ -2,7 +2,6 @@
<view class="page">
<view class="box d">
<uv-checkbox-group shape="circle" v-model="checkboxValue">
<view v-for="(item, index) in list"
:key="index"
@ -44,6 +43,22 @@
:max="item.num"
>
</uv-number-box>
<uv-icon
name="edit-pen-fill"
size="50rpx"
@click.stop="toEdit(item)"
v-if="edit"
color="#5baaff"
/>
<uv-icon
name="trash-fill"
size="50rpx"
@click.stop="del(item)"
v-if="edit"
color="#5baaff"
/>
</view>
</view>
</view>
@ -76,6 +91,19 @@
:priceList="priceList"
@submit="submit"
/>
<!-- 添加商品 -->
<view class="createDetail"
v-if="edit">
<view
@click="$utils.
navigateTo(`/pages_order/product/addProduct?shopId=${shopId}`)">
<uv-icon
size="40rpx"
color="#fff"
name="plus"></uv-icon>
</view>
</view>
</view>
</template>
@ -88,7 +116,13 @@
},
props : {
list : {
default : []
default : [],
},
edit : {
default : false,
},
shopId : {
default : ''
},
},
computed : {
@ -137,6 +171,32 @@
};
},
methods : {
//
del(item){
uni.showModal({
title: '您确认要下架吗?',
content: `您正在下架 ${item.name}`,
success : res => {
this.$api('orderUpdate', {
id : item.id,
isOpen : 'N',
}, res => {
if(res.code == 200){
this.$emit('getData')
}
})
}
})
},
//
toEdit(item){
this.$utils.
navigateTo('/pages_order/product/addProduct?id='
+ item.id)
},
getDataThen(list){
list.forEach(n => {
if(!this.selectNumMap[n.id]){
@ -231,6 +291,8 @@
font-size: 24rpx;
padding: 6rpx 20rpx;
color: #717171;
display: flex;
justify-content: space-between;
}
.price-box{
@ -356,5 +418,30 @@
flex-direction: column;
font-size: 20rpx;
}
.createDetail {
position: fixed;
top: 60vh;
right: 50rpx;
z-index: 999;
button{
all : unset;
}
button::after{
all : unset;
}
&>view{
width: 100rpx;
height: 100rpx;
background-color: $uni-color;
border-radius: 50rpx;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 10rpx 10rpx rgba(#000, 0.1);
margin-bottom: 30rpx;
}
}
}
</style>

+ 2
- 2
pages_order/components/product/submit.vue View File

@ -62,9 +62,9 @@
}
},
methods: {
//
//
submit(){
if([0, 3].includes(this.detail.className)){
if(this.isShopBuy(this.detail)){
uni.navigateTo({
url: '/pages_order/gourmet/gourmetDetail?id=' + this.detail.shopId
})


+ 3
- 2
pages_order/gourmet/gourmetDetail.vue View File

@ -56,6 +56,8 @@
<view class="goodList"
v-if="tagIndex == 0">
<productSelectList
:shopId="detail.id"
:edit="detail.shopUser == userInfo.id"
@getData="getData"
:list="list"/>
</view>
@ -107,7 +109,6 @@
:list="list"
:params="params"
/>
</view>
</template>
@ -229,7 +230,7 @@
<style lang="scss" scoped>
.postDetail {
padding-bottom: calc(env(safe-area-inset-bottom) + 100rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 200rpx);
.box {
display: flex;
align-items: center;


+ 5
- 3
pages_order/gourmet/gourmetList.vue View File

@ -14,10 +14,12 @@
</view>
<view class="list">
<gourmetItem :key="index" v-for="(item, index) in list" :item="item"
@click="$utils.navigateTo('/pages_order/gourmet/gourmetDetail?id=' + item.id)" />
<gourmetItem
:key="index" v-for="(item, index) in list"
:item="item"
@click="$utils.navigateTo('/pages_order/gourmet/gourmetDetail?id=' + item.id)" />
</view>
</view>
</template>


+ 375
- 0
pages_order/product/addProduct.vue View File

@ -0,0 +1,375 @@
<template>
<view class="publishPost">
<navbar
leftClick
@leftClick="$utils.navigateBack"
title="编辑商品"/>
<!-- <view class="title-input box">
<input type="text" placeholder="取个吸引人的标题吧" v-model="form.title"/>
</view> -->
<view class="category">
<view class="title">
商品图片
</view>
<uv-upload
:fileList="fileList"
:maxCount="imageMax"
multiple
width="150rpx"
height="150rpx"
name="fileList"
@delete="deleteImage"
@afterRead="afterRead"
:previewFullImage="true"></uv-upload>
</view>
<view class="category">
<view class="title">
选择分类
</view>
<view class="tagList">
<view
:class="{act : t.value == form.className}"
@click="clickCategory(t, i)"
v-for="(t, i) in productCategory"
:key="i">
{{ t.name }}
</view>
</view>
</view>
<view class="title-input box">
<view class="shop-box">
标题
</view>
<input type="text" placeholder="请输入标题" v-model="form.name"/>
</view>
<view class="title-input box">
<view class="shop-box">
副标题
</view>
<input type="text" placeholder="请输入商品副标题" v-model="form.nameSub"/>
</view>
<view class="title-input box">
<view class="shop-box">
价格
</view>
<input type="number" placeholder="请输入商品价格" v-model="form.price"/>
</view>
<view class="title-input box">
<view class="shop-box">
原价
</view>
<input type="number" placeholder="请输入商品原价" v-model="form.oldPrice"/>
</view>
<view class="title-input box">
<view class="shop-box">
积分
</view>
<input type="number" placeholder="请输入积分" v-model="form.points"/>
</view>
<view class="category">
<view class="title">
商品详情图片
</view>
<view class="images box">
<uv-upload
:fileList="imageDetailsList"
:maxCount="imageMax"
multiple
width="150rpx"
height="150rpx"
name="imageDetailsList"
@delete="deleteImage"
@afterRead="afterRead"
:previewFullImage="true"></uv-upload>
</view>
</view>
<!-- <view class="category">
<view class="title">
选择地区
</view>
<view class="tagList">
<view
:class="{act : t.name == form.address}"
@click="clickAddress(t, i)"
v-for="(t, i) in cityList"
:key="i">
{{ t.name }}
</view>
</view>
</view> -->
<!-- <view class="configBtn"
@click="$refs.configPopup.open()">
发布须知
</view> -->
<view class="uni-color-btn"
@click="submit">
发布
</view>
<configPopup
ref="configPopup"
:text="headInfo.save_no && headInfo.save_no.keyDetails"
/>
</view>
</template>
<script>
import { mapState } from 'vuex'
import productMixins from '@/mixins/product.js'
export default {
components : {
},
mixins : [productMixins],
data() {
return {
form : {
name : '',
nameSub : '',
price : '',
num : '',
oldPrice : '',
className : 0,
points : '',
isOpen : 'Y',
shopId : '',
},
id : 0,
fileList : [],
imageDetailsList : [],
codeFileList : [],
imageMax : 9,
};
},
computed : {
...mapState([]),
},
onLoad(args) {
this.id = args.id
this.form.shopId = args.shopId
// this.form.address = this.cityList[0].name
this.imageMax = args.imageMax || 9
this.getDateil()
},
onShow() {
},
methods : {
clickCategory(item, index){
this.form.className = item.value
},
getDateil(){
if(!this.id){
return
}
let self = this
this.$api('getShopPingDetail', {
id : this.id
}, res => {
if (res.code == 200) {
self.form.id = res.result.id
self.form.name = res.result.name
self.form.nameSub = res.result.nameSub
self.form.points = res.result.points
self.form.price = res.result.price
self.form.oldPrice = res.result.oldPrice
self.form.className = res.result.className || self.form.className
if(res.result.image){
res.result.image.split(',')
.forEach(url => {
self.fileList.push({
url
})
})
}
if(res.result.imageDetails){
res.result.imageDetails.split(',')
.forEach(url => {
self.imageDetailsList.push({
url
})
})
}
}
})
},
deleteImage(e){
this[e.name].splice(e.index, 1)
},
afterRead(e){
let self = this
e.file.forEach(file => {
self.$Oss.ossUpload(file.url).then(url => {
self[e.name].push({
url
})
})
})
},
//
submit(){
this.form.image = this.fileList.map((item) => item.url).join(",")
this.form.imageDetails = this.imageDetailsList.map((item) => item.url).join(",")
if (this.$utils.verificationAll(this.form, {
image : '请上传商品图片',
name: '请输入商品标题',
nameSub: '请输入商品副标题',
price: '请输入商品价格',
oldPrice: '请输入商品原价',
points: '请输入积分',
imageDetails : '请上传商品详情图片',
})) {
return
}
delete this.form.shop
this.$api('orderSaveOrUpdate', this.form, res => {
if(res.code == 200){
uni.showToast({
title: '保存成功!',
icon: 'none'
})
setTimeout(uni.navigateBack, 1000, -1)
}
})
},
}
}
</script>
<style lang="scss" scoped>
.publishPost{
background-color: #fff;
min-height: 100vh;
font-size: 28rpx;
padding-bottom: 150rpx;
/deep/ .uv-textarea{
background-color: transparent;
border: none;
}
/deep/ .uv-textarea__count{
background-color: transparent !important;
}
.box{
padding: 0 20rpx;
}
.images{
display: flex;
flex-wrap: wrap;
padding: 20rpx;
}
.title-input{
margin: 10rpx;
border-bottom: 1px solid #00000015;
padding-bottom: 25rpx;
margin-bottom: 15rpx;
display: flex;
align-items: center;
justify-content: space-between;
input{
width: 100%;
}
.shop-box{
font-size: 28rpx;
flex-shrink: 0;
font-weight: 900;
width: 140rpx;
}
}
.content-input{
min-height: 400rpx;
/deep/ .uv-textarea{
min-height: 400rpx;
}
}
.upTop{
.title{
padding-top: 20rpx;
padding-left: 20rpx;
border-top: 1px solid #00000015;
display: flex;
align-items: center;
}
.list{
padding-top: 30rpx;
width: 100%;
.item{
display: flex;
padding: 20rpx;
padding-left: 80rpx;
justify-content: space-between;
width: 600rpx;
border-bottom: 1px solid #00000015;
align-items: center;
}
}
}
.configBtn{
padding: 20rpx;
color: #777;
padding-top: 40rpx;
font-size: 28rpx;
}
.confirmationPopup{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 300rpx;
image{
margin-top: 40rpx;
}
.info{
margin-top: 40rpx;
font-size: 26rpx;
}
}
}
.category{
padding: 20rpx;
.title{
font-weight: 900;
// font-size: 30rpx;
padding-bottom: 20rpx;
}
.tagList{
display: flex;
flex-wrap: wrap;
padding: 10rpx 0;
view{
background: rgba($uni-color, 0.1);
padding: 10rpx 20rpx;
margin: 10rpx;
border-radius: 10rpx;
font-size: 26rpx;
}
.act{
color: #fff;
background: $uni-color;
}
}
}
</style>

+ 5
- 5
pages_order/product/productDetail.vue View File

@ -1,12 +1,12 @@
<template>
<view class="page">
<navbar title="商品详情" leftClick @leftClick="$utils.navigateBack" />
<!-- <navbar title="商品详情" leftClick @leftClick="$utils.navigateBack" /> -->
<view class="swipe">
<uv-swiper
:list="detail.image && detail.image.split(',')"
indicator
height="350rpx"></uv-swiper>
height="550rpx"></uv-swiper>
</view>
<view class="info">
@ -60,14 +60,14 @@
</view> -->
</view>
<view class="info-unit">
<!-- <view class="info-unit">
<uv-cell>
<template #icon>
<text>{{ detail.nameSub }}</text>
<!-- <text>上门取件·送货上门</text> -->
<text>上门取件·送货上门</text>
</template>
</uv-cell>
</view>
</view> -->
<view class="content">
<view class="title">


+ 6
- 0
utils/utils.js View File

@ -172,6 +172,12 @@ export function navigateTo(...args){
}
export function navigateBack(num = -1){
if(getCurrentPages().length == 1){
uni.reLaunch({
url: '/pages/index/index'
})
return
}
uni.navigateBack(num)
}


Loading…
Cancel
Save