标品迁移

This commit is contained in:
liuye
2023-11-17 09:34:34 +08:00
parent 22023aa887
commit df464eae89
28 changed files with 8925 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
<template>
<ai-list v-if="!isShowDetail">
<template slot="title">
<ai-title title="积分超市" :isShowBottomBorder="false">
</ai-title>
</template>
<template slot="tabs">
<el-tabs v-model="currIndex">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
<component :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/>
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<AddGoods v-else-if="componentName === 'AddGoods'" :params="params" :instance="instance" :dict="dict" @change="onChange"></AddGoods>
<AddStore v-else-if="componentName === 'AddStore'" :params="params" :instance="instance" :dict="dict" @change="onChange"></AddStore>
</template>
<script>
import AddGoods from './components/addGoods'
import AddStore from './components/AddStore'
import StoreList from './components/StoreList'
import GoodsList from './components/GoodsList'
import { mapState } from 'vuex'
export default {
name: 'AppIntegratingSupermarket',
label: '积分超市',
components: {
GoodsList,
StoreList,
AddGoods,
AddStore
},
props: {
instance: Function,
dict: Object,
permissions: Function
},
computed: {
...mapState(['user']),
tabs () {
const tabList = [
{label: '商品信息', name: 'GoodsList', comp: GoodsList, permission: ''},
{label: '店铺管理', name: 'StoreList', comp: StoreList, permission: ''}
].filter(item => {
return true
})
return tabList
}
},
data () {
return {
activeName: 'GoodsList',
currIndex: '0',
componentName: '',
params: {},
isShowDetail: false
}
},
methods: {
onAreaChange () {
if (this.currIndex === '0') {
this.$nextTick(() => {
this.$refs[this.currIndex][0].getList()
})
}
},
onChange (data) {
if (data.type === 'GoodsList') {
this.componentName = 'GoodsList'
this.isShowDetail = false
this.params = data.params
}
if (data.type === 'StoreList') {
this.componentName = 'StoreList'
this.isShowDetail = false
this.params = data.params
}
if (data.type === 'AddGoods') {
this.componentName = 'AddGoods'
this.isShowDetail = true
this.params = data.params
}
if (data.type === 'AddStore') {
this.componentName = 'AddStore'
this.isShowDetail = true
this.params = data.params
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,629 @@
<template>
<ai-detail class="appgoods">
<template slot="title">
<ai-title :title="id ? '编辑店铺' : '添加店铺'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</ai-title>
</template>
<template slot="content">
<ai-card title="基本信息">
<template #content>
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
<el-form-item style="width: 100%" label="店铺名称" prop="title" :rules="[{required: true, message: '请输入店铺名称', trigger: 'blur'}]">
<el-input type="input" size="small" v-model="form.title" clearable placeholder="请输入店铺名称" :maxlength="50" show-word-limit></el-input>
</el-form-item>
<el-form-item style="width: 100%" label="店铺类型" prop="type" :rules="[{required: true, message: '请选择店铺类型', trigger: 'change'}]">
<ai-select
v-model="form.type"
placeholder="请选择店铺类型"
:selectList="dict.getDict('integralSSType')">
</ai-select>
</el-form-item>
<el-form-item label="可见范围" label-width="120px" prop="serviceType" :rules="[{required: true, message: '请选择可见范围', trigger: 'change'}]">
<el-radio-group v-model="form.serviceType" @change="form.girdList = [], girdList = [], form.visibleNames = ''">
<el-radio label="0">不限</el-radio>
<el-radio label="1">仅指定网格可见</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="选择网格" v-if="form.serviceType === '1'" style="width: 100%;" label-width="120px" prop="visibleNames" :rules="[{ required: true, message: '请选择网格', trigger: 'change' }]">
<ai-picker
:instance="instance"
multiple
dialogTitle="选择网格"
:ops="{label: 'girdName', id: 'girdCode'}"
pageTitle="网格"
:action="'/app/appgirdinfo/girdList?idType=1'"
v-model="form.girdList"
@pick="onPick"
@change="onSelcetChange">
<div class="AppAnnounceDetail-select">
<el-input size="small" class="AppAnnounceDetail-select__input" placeholder="请选择..." disabled v-model="form.visibleNames"></el-input>
<div class="select-left" v-if="form.girdList.length">
<span v-for="(item, index) in girdList" :key="index" v-if="index < 9">{{ item.girdName }}</span>
<em v-if="girdList.length > 9">{{ girdList.length }}</em>
</div>
<i v-if="!form.girdList.length">请选择</i>
<div class="select-right">{{ form.girdList.length ? '重新选择' : '选择' }}</div>
</div>
</ai-picker>
</el-form-item>
<el-form-item label="店铺地点" style="width: 100%;" prop="address" :rules="[{required: true, message: '请选择店铺地点', trigger: 'change'}]">
<el-input v-model="form.address" disabled size="small">
<template slot="append">
<el-button @click="showMap = true">选择位置</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
</template>
</ai-card>
<ai-card title="商品列表">
<template #right>
<el-button type="primary" icon="iconfont iconAdd" @click="showList">选择商品</el-button>
</template>
<template #content>
<ai-table
:tableData="form.goodsList"
:isShowPagination="false"
:col-configs="chooseColConfigs"
@getList="() => {}">
<el-table-column
label="商品"
slot="goods"
align="left"
width="300">
<template v-slot="{ row }">
<div class="goods">
<ai-uploader
:disabled="true"
:instance="instance"
:value="[{url: row.goods.picUrl}]"
:limit="1">
</ai-uploader>
<p>{{ row.goods.title }}</p>
</div>
</template>
</el-table-column>
<el-table-column
label="兑换所需积分"
slot="integralPrice"
align="center"
width="140">
<template v-slot="{ row }">
<el-input-number style="width: 120px;" :precision="2" size="small" type="input" v-model="row.integralPrice" :min="0" placeholder="请输入"></el-input-number>
</template>
</el-table-column>
<el-table-column
label="兑换后补差价金额"
slot="payMoney"
align="center"
width="150">
<template v-slot="{ row }">
<el-input-number style="width: 120px;" :precision="2" size="small" type="input" v-if="row.goods.type !== '0'" :min="0" v-model="row.payMoney" clearable placeholder="请输入"></el-input-number>
</template>
</el-table-column>
<el-table-column
label="库存"
slot="stock"
align="center"
width="140">
<template v-slot="{ row }">
<el-input-number style="width: 120px;" :precision="0" size="small" type="input" v-model="row.stock" :min="0" clearable placeholder="请输入"></el-input-number>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center" width="180" fixed="right">
<template v-slot="{ row, $index }">
<div class="table-options">
<el-button v-if="row.id" type="text" :title="row.status === '0' ? '上架' : '下架'" @click="changeStatus(row.status, $index)">{{ row.status === '0' ? '上架' : '下架' }}</el-button>
<el-button type="text" title="删除" @click="remove($index)">删除</el-button>
<el-button type="text" title="复制链接" v-if="row.goods.type === '1'" @click="copy(row.goods.jdUrl)">复制链接</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</template>
</ai-card>
<ai-dialog
title="选择商品"
:visible.sync="isShow"
:destroyOnClose="true"
@confirm="onConfirm"
width="1080px">
<ai-search-bar>
<template slot="left">
<ai-select
v-model="search.type"
@change="(search.current = 1), getList()"
placeholder="请选择商品类型"
:selectList="dict.getDict('integralSGType')">
</ai-select>
<ai-select
v-model="search.status"
@change="(search.current = 1), getList()"
placeholder="请选择状态"
:selectList="dict.getDict('integralSGStatus')">
</ai-select>
</template>
<template slot="right">
<el-input
v-model="search.title"
class="search-input"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="请输入商品名称/商品类型说明"
clearable
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
ref="aiTable"
style="margin-top: 8px;"
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:current.sync="search.current"
:size.sync="search.size"
@selection-change="handleSelectionChange"
@getList="getList">
<el-table-column
label="商品"
slot="goods"
align="left"
width="300">
<template v-slot="{ row }">
<div class="goods">
<ai-uploader
:disabled="true"
:instance="instance"
:value="[{url: row.picUrl}]"
:limit="1">
</ai-uploader>
<p>{{ row.title }}</p>
</div>
</template>
</el-table-column>
</ai-table>
</ai-dialog>
<ai-dialog title="地图" :visible.sync="showMap" @opened="initMap" :destroyOnclose="false" width="800px" class="mapDialog" @onConfirm="selectMap">
<div id="map"></div>
<el-form label-width="80px" style="padding: 10px 20px 0 20px;">
<el-row type="flex" justify="space-between">
<el-form-item label="经度">
<el-input disabled size="small" v-model="placeDetail.lng"></el-input>
</el-form-item>
<el-form-item label="纬度">
<el-input disabled size="small" v-model="placeDetail.lat"></el-input>
</el-form-item>
</el-row>
</el-form>
<el-input id="searchPlaceInput" size="medium" class="searchPlaceInput" clearable v-model="searchPlace" autocomplete="on" @change="placeSearch.search(searchPlace)" placeholder="请输入关键字">
<el-button type="primary" slot="append" @click="placeSearch.search(searchPlace)">搜索</el-button>
</el-input>
<div id="searchPlaceOutput" />
</ai-dialog>
</template>
<template #footer>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="confirm">提交</el-button>
</template>
</ai-detail>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader'
export default {
name: 'AddStore',
props: {
instance: Function,
dict: Object,
params: Object
},
data () {
return {
isShow: false,
form: {
title: '',
type: '',
serviceType: '0',
visibleNames: '',
girdList: [],
goodsList: [],
address: ''
},
girdList: [],
id: '',
search: {
type: '',
title: '',
current: 1,
status: '',
size: 10
},
total: 0,
tableData: [],
chooseColConfigs: [
{ slot: 'goods' },
{ prop: 'goods', label: '商品类型', align: 'center', format: v => this.dict.getLabel('integralSGType', v.type) },
{ prop: 'typeExplain', label: '商品类型说明'},
{ slot: 'integralPrice' },
{ slot: 'payMoney' },
// { prop: 'goods', label: '商品链接', align: 'center', format: v => v.jdUrl },
{ slot: 'stock' },
{ prop: 'status', width: 90, label: '状态', align: 'center', format: v => this.dict.getLabel('integralSGStatus', v) || '已上架' }
],
colConfigs: [
{ type: 'selection', label: '', align: 'left' },
{ prop: 'serialNumber', label: '商品ID', align: 'center' },
{ slot: 'goods', align: 'center' },
{ prop: 'type', label: '商品类型', align: 'center', format: v => this.dict.getLabel('integralSGType', v) },
{ prop: 'typeExplain', label: '商品类型说明'},
{ prop: 'onlineTime', label: '上架时间', align: 'center' },
{ prop: 'status', width: 90, label: '状态', align: 'center', format: v => this.dict.getLabel('integralSGStatus', v) }
],
chooseList: [],
mapDetail: null,
map: null,
placeSearch: null,
placeDetail: {
lng: '',
lat: '',
address: ''
},
lng: '',
lat: '',
showMap: false,
searchPlace: '',
}
},
created () {
this.dict.load('integralSGType', 'integralSGStatus').then(() => {
this.getList()
})
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
},
methods: {
selectMap() {
this.form.lng = this.placeDetail.lng
this.form.lat = this.placeDetail.lat
this.form.address = this.placeDetail.address
this.showMap = false
},
initMap() {
if (this.map) return
AMapLoader.load({
key: '54a02a43d9828a8f9cd4f26fe281e74e',
version: '2.0',
plugins: ['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'],
}).then((AMap) => {
this.map = new AMap.Map('map', {
resizeEnable: true,
zooms: [6, 20],
center: this.form.lng ? [this.form.lng, this.form.lat] : undefined,
zoom: 11,
})
this.placeSearch = new AMap.PlaceSearch({ map: this.map })
new AMap.AutoComplete({
input: 'searchPlaceInput',
output: 'searchPlaceOutput',
}).on('select', (e) => {
if (e?.poi) {
this.placeSearch.setCity(e.poi.adcode)
this.movePosition(e.poi.location)
}
})
this.map.on('click', (e) => {
new AMap.Geocoder().getAddress(e.lnglat, (sta, res) => {
if (res?.regeocode) {
this.placeDetail = {
lng: e.lnglat?.lng,
lat: e.lnglat?.lat,
address: res.regeocode.formattedAddress,
}
}
})
this.movePosition(e.lnglat)
})
})
},
movePosition(center) {
if (this.map) {
this.map.clearMap()
this.map.panTo(center)
this.map.add([
new AMap.Marker({
position: center,
clickable: true,
}),
])
this.map.setFitView()
}
},
getMap(lng,lat,address) {
AMapLoader.load({
key: '54a02a43d9828a8f9cd4f26fe281e74e',
version: '2.0',
plugins: ['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'],
}).then((AMap) => {
this.mapDetail = new AMap.Map(document.getElementById("mapDetail"), {
resizeEnable: true,
zooms: [6, 20],
zoom: 11,
center:[lng,lat],
})
let marker = new AMap.Marker({
position: new AMap.LngLat(lng,lat),
title: address
})
this.mapDetail.add(marker);
})
},
getList () {
this.instance.post(`/app/appintegralsupermarketgoods/list`, null, {
params: {
...this.search
}
}).then((res) => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
copy (url) {
let oInput = document.createElement('input')
oInput.value = url
document.body.appendChild(oInput)
oInput.select()
document.execCommand('Copy')
this.$message({
message: '已复制',
type: 'success'
})
oInput.remove()
},
changeStatus (status, index) {
this.$confirm(`确定${status === '0' ? '上架' : '下架'}该商品?`).then(() => {
this.$set(this.form.goodsList[index], 'status', status === '0' ? '1' : '0')
this.$message.success(`${status === '0' ? '上架' : '下架'}成功`)
})
},
handleSelectionChange (e) {
this.chooseList = e
},
remove (index) {
this.$confirm('确定删除该商品吗?').then(() => {
this.form.goodsList.splice(index, 1)
this.$message.success('删除成功!')
})
},
showList () {
this.isShow = true
// this.$nextTick(() => {
// if (this.form.goodsList.length) {
// this.form.goodsList.map(v => v.goods).forEach(v => {
// if (this.tableData.filter(e => e.id === v.id).length) {
// this.$refs.aiTable.toggleRowSelection(this.tableData.filter(e => e.id === v.id)[0], true)
// }
// })
// }
// })
},
onConfirm () {
this.isShow = false
let list = this.chooseList.filter(v => {
return this.form.goodsList.map(e => e.goodsId).indexOf(v.id) === -1
}).map(v => {
return {
goods: {
...v
},
goodsId: v.id,
integralPrice: undefined,
payMoney: undefined,
stock: undefined,
status: v.status
}
})
this.form.goodsList = [
...this.form.goodsList ,
...list
]
},
getInfo (id) {
this.instance.post(`/app/appintegralsupermarketshop/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
res.data.goodsList.map((item) => {
item.typeExplain = item.goods.typeExplain
})
this.form = {
...res.data,
visibleNames: '1',
girdList: res.data.serviceType === '1' ? res.data.visibleConfig.map(v => v.visibleId) : []
}
this.girdList = res.data.visibleConfig.map(v => {
return {
girdCode: v.visibleId,
girdName: v.visibleName
}
})
this.placeDetail.lng = res.data.lng
this.placeDetail.lat = res.data.lat
this.getMap(this.info.lng,this.info.lat,this.info.address)
}
})
},
onPick (e) {
this.girdList = e
},
onSelcetChange (e) {
if (e.length) {
this.form.visibleNames = '1'
} else {
this.form.visibleNames = ''
this.form.girdList = []
}
},
confirm () {
this.$refs.form.validate((valid) => {
if (valid) {
if (!this.form.goodsList.length) {
return this.$message.error('请选择商品')
}
for (let i = 0; i < this.form.goodsList.length; i++) {
// if (!this.form.goodsList[i].integralPrice) {
// return this.$message.error('请输入兑换所需积分')
// }
// if (!this.form.goodsList[i].payMoney && this.form.goodsList[i].goods.type === '1') {
// return this.$message.error('请输入兑换后补差价金额')
// }
if (!this.form.goodsList[i].stock) {
return this.$message.error('请输入库存')
}
}
this.instance.post(`/app/appintegralsupermarketshop/addOrUpdate`, {
...this.form,
id: this.params.id || '',
visibleConfig: this.form.serviceType === '1' ? this.girdList.map(v => {
return {
visibleId: v.girdCode,
visibleName: v.girdName
}
}) : []
}).then(res => {
if (res.code == 0) {
this.$message.success('提交成功')
setTimeout(() => {
this.cancel(true)
}, 600)
}
})
}
})
},
cancel (isRefresh) {
this.$emit('change', {
type: 'GoodsList',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
.appgoods {
.goods {
display: flex;
align-items: center;
width: 250px;
height: 120px;
}
.AppAnnounceDetail-select {
display: flex;
align-items: center;
min-height: 32px;
line-height: 1;
background: #F5F5F5;
border-radius: 4px;
border: 1px solid #D0D4DC;
cursor: pointer;
overflow: hidden;
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
&:hover {
border-color: #26f;
}
& > i {
flex: 1;
height: 100%;
line-height: 32px;
padding: 0 12px;
color: #888888;
font-size: 14px;
font-style: normal;
border-right: 1px solid #D0D4DC;
background: #fff;
}
.AppAnnounceDetail-select__input {
position: absolute;
left: 0;
top: 0;
z-index: -1;
opacity: 0;
height: 100%;
}
.select-right {
height: 100%;
padding: 0 12px;
color: #222222;
font-size: 12px;
cursor: pointer;
transition: all ease 0.3s;
&:hover {
opacity: 0.5;
}
}
.select-left {
display: flex;
flex-wrap: wrap;
flex: 1;
padding: 5px 0 0px 12px;
border-right: 1px solid #D0D4DC;
border-radius: 4px 0 0 4px;
background: #fff;
em {
height: 22px;
line-height: 22px;
margin: 0 4px 5px 0;
color: #222222;
font-size: 12px;
font-style: normal;
}
span {
height: 22px;
line-height: 22px;
margin: 0 4px 5px 0;
padding: 0 8px;
font-size: 12px;
color: #222222;
background: #F3F4F7;
border-radius: 2px;
border: 1px solid #D0D4DC;
}
}
}
}
</style>

View File

@@ -0,0 +1,229 @@
<template>
<ai-list isTabs class="GoodsList">
<template slot="content">
<ai-search-bar>
<template slot="left">
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
<ai-select
v-model="search.type"
@change="(search.current = 1), getList()"
placeholder="请选择商品类型"
:selectList="dict.getDict('integralSGType')">
</ai-select>
<ai-select
v-model="search.status"
@change="(search.current = 1), getList()"
placeholder="请选择类型"
:selectList="dict.getDict('integralSGStatus')">
</ai-select>
</template>
<template slot="right">
<el-input
v-model="search.title"
class="search-input"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="请输入商品名称"
clearable
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
style="margin-top: 8px;"
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column
label="商品"
slot="goods"
align="left"
width="450">
<template v-slot="{ row }">
<div class="goods">
<!-- <ai-uploader class="upload"
:disabled="true"
:instance="instance"
:value="[{url: row.picUrl}]"
:limit="1">
<span class="type" :class="`type`+row.type">{{$dict.getLabel('integralSGType', row.type)}}</span>
</ai-uploader> -->
<div class="img-content">
<img :src="row.picUrl" alt="" v-viewer>
<!-- <span class="type type0" v-if="row.type === '0'">积分兑换</span>
<span class="type type1" v-else>京东低价商品</span> -->
<span class="type" :class="`type${row.typeText}`">{{dict.getLabel('integralSGTypeText', row.typeText)}}</span>
</div>
<p>{{ row.title }}</p>
</div>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center" width="210" fixed="right">
<template v-slot="{ row }">
<div class="table-options">
<el-button type="text" title="编辑" @click="toAdd(row.id)">编辑</el-button>
<el-button type="text" :title="row.status === '0' ? '上架' : '下架'" @click="changeStatus(row)">{{ row.status === '0' ? '上架' : '下架' }}</el-button>
<el-button type="text" title="删除" @click="remove(row.id)">删除</el-button>
<el-button type="text" title="复制链接" v-if="row.type === '1'" @click="copy(row.jdUrl)">复制链接</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
import Viewer from 'v-viewer'
import Vue from 'vue'
Vue.use(Viewer)
export default {
name: 'GoodsList',
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
search: {
type: '',
title: '',
current: 1,
status: '',
size: 10,
},
total: 0,
tableData: [],
colConfigs: [
{ prop: 'serialNumber', label: '商品ID', align: 'left' },
{ slot: 'goods', align: 'center' },
{ prop: 'type', label: '商品类型', align: 'center', format: v => this.dict.getLabel('integralSGType', v) },
{ prop: 'onlineTime', label: '上架时间', align: 'center' },
{ prop: 'status', label: '状态', align: 'center', format: v => this.dict.getLabel('integralSGStatus', v) }
],
userList: []
}
},
computed: {
},
created () {
this.dict.load('integralSGType', 'integralSGStatus', 'integralSGTypeText').then(() => {
this.getList()
})
},
methods: {
getList () {
this.instance.post(`/app/appintegralsupermarketgoods/list`, null, {
params: {
...this.search
}
}).then((res) => {
if (res.code == 0) {
res.data.records.map((item) => {
item.typeText = item.type == 0 ? 0 : 1
})
this.tableData = res.data.records
this.total = res.data.total
}
})
},
onAreaChange () {
this.search.current = 1
this.$nextTick(() => {
this.getTableData()
})
},
toAdd (id) {
this.$emit('change', {
type: 'AddGoods',
params: {
id: id || ''
}
})
},
copy (url) {
let oInput = document.createElement('input')
oInput.value = url
document.body.appendChild(oInput)
oInput.select()
document.execCommand('Copy')
this.$message({
message: '已复制',
type: 'success'
})
oInput.remove()
},
remove (id) {
this.$confirm('确定删除该商品吗?').then(() => {
this.instance.post(`/app/appintegralsupermarketgoods/delete?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
changeStatus (row) {
this.$confirm(`确定${row.status === '0' ? '上架' : '下架'}该商品?`).then(() => {
this.instance.post(`/app/appintegralsupermarketgoods/online?id=${row.id}`).then(res => {
if (res.code == 0) {
this.$message.success(`${row.status === '0' ? '上架' : '下架'}成功`)
this.getList()
}
})
})
}
}
}
</script>
<style lang="scss" scoped>
.GoodsList {
.goods {
display: flex;
align-items: center;
}
.img-content {
position: relative;
margin-right: 8px;
img {
width: 120px;
height: 120px;
cursor: pointer;
}
}
.type {
position: absolute;
top: 0;
left: 0;
width: 120px;
text-align: center;
color: #fff;
z-index: 999;
font-size: 12px;
}
.type1 {
background-color: #E64E39;
}
.type0 {
background-color: #FF6900;
}
}
</style>

View File

@@ -0,0 +1,227 @@
<template>
<ai-list isTabs class="order_management">
<template slot="content">
<ai-search-bar>
<template slot="left">
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
<ai-select
v-model="search.type"
@change="(search.current = 1), getList()"
placeholder="请选择店铺类型"
:selectList="dict.getDict('integralSSType')">
</ai-select>
<ai-select
v-model="search.status"
@change="(search.current = 1), getList()"
placeholder="请选择状态"
:selectList="dict.getDict('integralSSStatus')">
</ai-select>
<ai-picker
:instance="instance"
:multiple="false"
dialogTitle="请选择服务地区"
:ops="{ label: 'girdName' }"
pageTitle="网格"
action="/app/appgirdinfo/girdList"
v-model="userList"
@pick="onGridChange">
<div class="userSelcet">
<span style="color: #606266;" v-if="search.visibleId">{{ search.girdName }}</span>
<span v-else>请选择服务地区</span>
<i class="el-icon-arrow-up" v-if="!search.visibleId"></i>
<i class="el-icon-circle-close" v-if="search.visibleId" @click.stop="search.visibleId = '', search.girdName = '', search.current = 1, getList()"></i>
</div>
</ai-picker>
</template>
<template slot="right">
<el-input
v-model="search.title"
class="search-input"
size="small"
v-throttle="() => {search.current = 1, getList()}"
placeholder="请输入店铺名称"
clearable
@clear="search.current = 1, search.title = '', getList()"
suffix-icon="iconfont iconSearch">
</el-input>
</template>
</ai-search-bar>
<ai-table
style="margin-top: 8px;"
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
:current.sync="search.current"
:size.sync="search.size"
@getList="getList">
<el-table-column label="网格店铺服务网格" slot="grid" align="center">
<template v-slot="{ row }">
<span>{{ row.type === '0' ? (row.visibleNames ? row.visibleNames : row.serviceType === '0' ? '不限' : '-') : '-' }}</span>
</template>
</el-table-column>
<el-table-column label="居民店铺服务地区" slot="area" align="center">
<template v-slot="{ row }">
<span>{{ row.type === '1' ? (row.visibleNames ? row.visibleNames : row.serviceType === '0' ? '不限' : '-') : '-' }}</span>
</template>
</el-table-column>
<el-table-column label="操作" slot="options" align="center" width="160" fixed="right">
<template v-slot="{ row }">
<div class="table-options">
<el-button type="text" title="编辑" @click="toAdd(row.id)">编辑</el-button>
<el-button type="text" :title="row.status === '0' ? '启用' : '停用'" @click="changeStatus(row)">{{ row.status === '0' ? '启用' : '停用' }}</el-button>
<el-button type="text" title="删除" @click="remove(row.id)">删除</el-button>
</div>
</template>
</el-table-column>
</ai-table>
</template>
</ai-list>
</template>
<script>
export default {
name: 'GoodsList',
props: {
instance: Function,
dict: Object,
permissions: Function
},
data() {
return {
search: {
type: '',
title: '',
current: 1,
status: '',
size: 10,
visibleId: '',
girdName: ''
},
total: 0,
tableData: [],
shopList: [],
colConfigs: [
{ prop: 'serialNumber', label: '店铺ID', align: 'left' },
{ prop: 'title', label: '店铺名称', align: 'center' },
{ prop: 'type', label: '店铺类型', align: 'center', format: v => this.dict.getLabel('integralSSType', v) },
{ slot: 'grid', label: '网格店铺服务网格', align: 'center' },
{ slot: 'area', label: '居民店铺服务地区', align: 'center' },
{ prop: 'goodsCount', label: '店铺商品数', align: 'center' },
{ prop: 'status', label: '状态', align: 'center', format: v => this.dict.getLabel('integralSSStatus', v) }
]
}
},
computed: {
},
created () {
this.dict.load('integralSSType', 'integralSSStatus', 'integralSSSType').then(() => {
this.getList()
})
},
methods: {
onGridChange (e) {
if (e.length) {
this.search.visibleId = e[0].girdCode
this.search.girdName = e[0].girdName
this.search.current = 1
this.getList()
}
},
getList () {
this.instance.post(`/app/appintegralsupermarketshop/list`, null, {
params: {
...this.search
}
}).then((res) => {
if (res.code == 0) {
this.tableData = res.data.records
this.total = res.data.total
}
})
},
toAdd (id) {
this.$emit('change', {
type: 'AddStore',
params: {
id: id || ''
}
})
},
remove (id) {
this.$confirm('确定删除该商品吗?').then(() => {
this.instance.post(`/app/appintegralsupermarketshop/delete?id=${id}`).then(res => {
if (res.code == 0) {
this.$message.success('删除成功!')
this.getList()
}
})
})
},
changeStatus (row) {
this.$confirm(`确定${row.status === '0' ? '启用' : '停用'}该商铺?`).then(() => {
this.instance.post(`/app/appintegralsupermarketshop/enable?id=${row.id}`).then(res => {
if (res.code == 0) {
this.$message.success(`${row.status === '0' ? '启用' : '停用'}成功`)
this.getList()
}
})
})
}
}
}
</script>
<style lang="scss" scoped>
.order_management {
.userSelcet {
display: flex;
align-items: center;
justify-content: space-between;
width: 215px;
height: 32px;
line-height: 32px;
border-radius: 4px;
border: 1px solid #d0d4dc;
overflow: hidden;
cursor: pointer;
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
&:hover {
border-color: $placeholderColor;
}
i {
display: flex;
position: relative;
align-items: center;
justify-content: center;
width: 30px;
height: 100%;
line-height: 32px;
font-size: 14px;
text-align: center;
color: #d0d4dc;
transform: rotateZ(180deg);
}
.el-icon-circle-close:hover {
opacity: 0.6;
}
span {
flex: 1;
padding: 0 15px;
font-size: 12px;
color: $placeholderColor;
}
}
}
</style>

View File

@@ -0,0 +1,237 @@
<template>
<ai-detail class="appgoods">
<template slot="title">
<ai-title :title="id ? '编辑商品' : '添加商品'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
</ai-title>
</template>
<template slot="content">
<ai-card title="基本信息">
<template #content>
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
<el-form-item style="width: 100%" label="商品名称" prop="title" :rules="[{required: true, message: '请输入商品名称', trigger: 'blur'}]">
<el-input type="input" size="small" v-model="form.title" clearable placeholder="请输入商品名称" :maxlength="50" show-word-limit></el-input>
</el-form-item>
<el-form-item style="width: 100%" label="商品类型" prop="type" :rules="[{required: true, message: '请选择商品类型', trigger: 'change'}]">
<ai-select
v-model="form.type"
placeholder="请选择商品类型"
:selectList="dict.getDict('integralSGType')"
@change="onChange">
</ai-select>
</el-form-item>
<el-form-item style="width: 100%" label="商品类型说明" prop="typeExplain">
<el-input type="input" size="small" v-model="form.typeExplain" clearable placeholder="请输入商品类型说明" maxlength="50" show-word-limit></el-input>
</el-form-item>
<el-form-item style="width: 100%" label="商品图片" prop="picUrl" :rules="[{required: true, message: '请选择商品图片', trigger: 'change'}]">
<ai-uploader
:instance="instance"
isShowTip
isCrop
:cropOps="{
fixedNumber: [1, 1]
}"
v-model="form.picUrl"
:limit="1">
<template slot="tips">
<p>建议尺寸400*400支持上传jpg/png格式图片最多上传一张单个图片大小不超过10M</p>
</template>
</ai-uploader>
</el-form-item>
<el-form-item label="零售价格" prop="retailPrice" :rules="[{required: true, message: '请输入零售价格', trigger: 'change'}]">
<el-input-number style="width: 200px;" size="small" :precision="2" type="input" v-model="form.retailPrice" clearable placeholder="请输入零售价格" :min="0"></el-input-number>
</el-form-item>
<el-form-item v-if="form.type === '2'" label="小程序appid" prop="jdAppid" :rules="[{required: true, message: '请输入京东小程序appid', trigger: 'blur'}]">
<el-input type="input" size="small" v-model="form.jdAppid" clearable placeholder="请输入京东小程序appid"></el-input>
</el-form-item>
<el-form-item v-if="form.type === '2'" style="width: 100%" label="小程序路径" prop="jdUrl" :rules="[{required: true, message: '请输入小程序路径', trigger: 'blur'}]">
<el-input type="input" size="small" v-model="form.jdUrl" clearable placeholder="请输入小程序路径"></el-input>
</el-form-item>
<el-form-item v-if="form.type === '1'" label="商品链接" prop="jdUrl" :rules="[{required: true, message: '请输入商品链接', trigger: 'blur'}]">
<el-input type="input" size="small" v-model="form.jdUrl" clearable placeholder="请输入商品链接"></el-input>
</el-form-item>
<el-form-item style="width: 100%" label="商品描述" prop="description">
<el-input type="textarea" :rows="4" size="small" v-model="form.description" clearable placeholder="请输入商品描述"></el-input>
</el-form-item>
</el-form>
</template>
</ai-card>
</template>
<template #footer>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="confirm">提交</el-button>
</template>
</ai-detail>
</template>
<script>
export default {
name: 'Add',
props: {
instance: Function,
dict: Object,
params: Object
},
data () {
return {
form: {
typeExplain: '',
title: '',
description: '',
type: '',
jdUrl: '',
jdAppid: 'wx91d27dbf599dff74',
retailPrice: undefined,
picUrl: []
},
girdList: [],
cropOps: {
width: '800px',
height: '800px'
},
id: ''
}
},
created () {
if (this.params && this.params.id) {
this.id = this.params.id
this.getInfo(this.params.id)
}
},
methods: {
getInfo (id) {
this.instance.post(`/app/appintegralsupermarketgoods/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.form = res.data
this.form.picUrl = [{
url: res.data.picUrl
}]
}
})
},
onChange () {
if (this.form.type === '2') {
this.form.jdUrl = 'pages/gold/item/pages/detail/index?sku=60626768856&sourceType=wx-zhongwei&ea_ptag=17078.27.755'
} else {
this.form.jdUrl = ''
}
},
confirm () {
this.$refs.form.validate((valid) => {
if (valid) {
this.instance.post(`/app/appintegralsupermarketgoods/addOrUpdate`, {
...this.form,
picUrl: this.form.picUrl[0].url,
id: this.params.id || ''
}).then(res => {
if (res.code == 0) {
this.$message.success('提交成功')
setTimeout(() => {
this.cancel(true)
}, 600)
}
})
}
})
},
cancel (isRefresh) {
this.$emit('change', {
type: 'GoodsList',
isRefresh: !!isRefresh
})
}
}
}
</script>
<style scoped lang="scss">
.appgoods {
.AppAnnounceDetail-select {
display: flex;
align-items: center;
min-height: 32px;
line-height: 1;
background: #F5F5F5;
border-radius: 4px;
border: 1px solid #D0D4DC;
cursor: pointer;
overflow: hidden;
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
&:hover {
border-color: #26f;
}
& > i {
flex: 1;
height: 100%;
line-height: 32px;
padding: 0 12px;
color: #888888;
font-size: 14px;
font-style: normal;
border-right: 1px solid #D0D4DC;
background: #fff;
}
.AppAnnounceDetail-select__input {
position: absolute;
left: 0;
top: 0;
z-index: -1;
opacity: 0;
height: 100%;
}
.select-right {
height: 100%;
padding: 0 12px;
color: #222222;
font-size: 12px;
cursor: pointer;
transition: all ease 0.3s;
&:hover {
opacity: 0.5;
}
}
.select-left {
display: flex;
flex-wrap: wrap;
flex: 1;
padding: 5px 0 0px 12px;
border-right: 1px solid #D0D4DC;
border-radius: 4px 0 0 4px;
background: #fff;
em {
height: 22px;
line-height: 22px;
margin: 0 4px 5px 0;
color: #222222;
font-size: 12px;
font-style: normal;
}
span {
height: 22px;
line-height: 22px;
margin: 0 4px 5px 0;
padding: 0 8px;
font-size: 12px;
color: #222222;
background: #F3F4F7;
border-radius: 2px;
border: 1px solid #D0D4DC;
}
}
}
}
</style>