添加:总平台添加商品

This commit is contained in:
wuhui_zzw 2024-04-09 13:33:26 +08:00
parent 79c7068c44
commit ca198a4c11
18 changed files with 6655 additions and 96 deletions

View File

@ -1,4 +1,3 @@
import request from './request'
/**
@ -37,3 +36,47 @@ export function expressStatuseApi(id, is_show) {
export function syncExpressApi() {
return request.get('store/express/sync')
}
/**
* @description 运费模板 -- 城市
*/
export function cityList() {
return request.get('system/city/lst')
}
export function cityListV2(pid) {
return request.get('v2/system/city/lst/' + pid)
}
/**
* @description 运费模板 -- 列表
*/
export function templateListApi(data) {
return request.get('store/shipping/lst', data)
}
/**
* @description 运费模板 -- 新增
*/
export function templateCreateApi(data) {
return request.post('store/shipping/create', data)
}
/**
* @description 运费模板 -- 编辑
*/
export function templateUpdateApi(id, data) {
return request.post(`store/shipping/update/${id}`, data)
}
/**
* @description 运费模板 -- 详情
*/
export function templateDetailApi(id) {
return request.get(`/store/shipping/detail/${id}`)
}
/**
* @description 运费模板 -- 删除
*/
export function templateDeleteApi(id) {
return request.delete(`store/shipping/delete/${id}`)
}

View File

@ -42,6 +42,12 @@ export function storeCategoryStatusApi(id, status) {
export function storeCategoryRecommendApi(id, status) {
return request.post(`store/category/is_hot/${id}`, { status })
}
/**
* @description 商品列表 -- 商户分类
*/
export function categorySelectApi() {
return request.get(`store/category/select`)
}
/**
* @description 品牌分类 -- 列表
*/
@ -72,6 +78,12 @@ export function brandCategoryDeleteApi(id) {
export function brandCategoryStatusApi(id, status) {
return request.post(`store/brand/category/status/${id}`, { status })
}
/**
* @description 商品列表 -- 品牌分类
*/
export function categoryBrandListApi() {
return request.get(`store/category/brandlist`)
}
/**
* @description 品牌 -- 列表
*/
@ -420,6 +432,7 @@ export function guaranteeUpdateApi(id) {
export function guaranteeDeleteApi(id) {
return request.delete(`guarantee/delete/${id}`)
}
/**
* @description 商品列表 -- 编辑排序
*/
@ -519,3 +532,67 @@ export function merSpecsList(data) {
export function merProductLstApi(data) {
return request.get(`store/product/list`, data)
}
// 复制商品 -- 剩余次数
export function productCopyCountApi() {
return request.get(`store/productcopy/count`)
}
// 商品列表 -- 运费模板筛选
export function shippingListApi() {
return request.get(`store/shipping/list`)
}
// 商品添加 -- 属性规则
export function templateLsitApi() {
return request.get(`/store/attr/template/list`)
}
// 添加商品 -- 参数筛选
export function specsSelectedApi(data) {
return request.get(`store/params/temp/select`,data)
}
// 配置状态
export function productConfigApi() {
return request.get(`store/product/config`)
}
// 属性规则 -- 添加
export function attrCreatApi(data) {
return request.post('store/attr/template/create', data)
}
// 商品列表 -- 立即生成规格
export function generateAttrApi(id,data) {
return request.post(`store/product/get_attr_value/${id}`, data)
}
// 服务保障 -- 添加
export function guaranteeTemplateAddApi(data) {
return request.post(`guaranteeTemplate/create`, data)
}
// 服务保障 - 搜索
export function guaranteeTemplateSelectApi(data) {
return request.get(`guaranteeTemplate/select`, data)
}
// 服务保障 - 详情
export function guaranteeTemplateDetailApi(id) {
return request.get(`guaranteeTemplate/detail/${id}`)
}
// 添加商品 -- 获取服务保障模板列表
export function guaranteeTemplateListApi() {
return request.get(`guaranteeTemplate/list`)
}
// 添加商品 -- 参数筛选详情
export function productSpecsDetailApi(data) {
return request.get(`store/params/temp/show`, data)
}
// 商品列表 -- 添加
export function productCreateApi(data) {
return request.post(`store/product/create`, data)
}
// 商品列表 -- 编辑
export function productEditApi(id, data) {
return request.post(`store/product/edit/${id}`, data)
}
// 商品列表 -- 商品上下架
export function changeProductStatus(id, status) {
return request.post(`store/product/change_status/${id}`, { status })
}

View File

@ -0,0 +1,278 @@
<template>
<div>
<el-form ref="formDynamic" size="small" :model="formDynamic" :rules="rules" class="attrFrom mb20" label-width="100px" @submit.native.prevent>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="模板名称:" prop="template_name">
<el-input v-model="formDynamic.template_name" placeholder="请输入模板名称" />
</el-form-item>
</el-col>
<el-col v-for="(item, index) in formDynamic.template_value" :key="index" :span="24" class="noForm">
<el-form-item>
<div class="acea-row row-middle"><span class="mr5">{{ item.value }}</span><i class="el-icon-circle-close" @click="handleRemove(index)" /></div>
<div class="rulesBox">
<el-tag
v-for="(j, indexn) in item.detail"
:key="indexn"
closable
size="medium"
:disable-transitions="false"
class="mb5 mr10"
@close="handleClose(item.detail,indexn)"
>
{{ j }}
</el-tag>
<el-input
v-if="item.inputVisible"
ref="saveTagInput"
v-model="item.detail.attrsVal"
class="input-new-tag"
size="small"
maxlength="30"
@keyup.enter.native="createAttr(item.detail.attrsVal,index)"
@blur="createAttr(item.detail.attrsVal,index)"
/>
<el-button v-else class="button-new-tag" size="small" @click="showInput(item)">+ 添加</el-button>
</div>
</el-form-item>
</el-col>
<el-col v-if="isBtn" :span="24" class="mt10" style="padding-left: 0;padding-right: 0;">
<el-col :span="8">
<el-form-item label="规格:">
<el-input v-model="attrsName" maxlength="30" placeholder="请输入规格" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="规格值:">
<el-input v-model="attrsVal" maxlength="30" placeholder="请输入规格值" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-button type="primary" class="mr10" @click="createAttrName">确定</el-button>
<el-button @click="offAttrName">取消</el-button>
</el-col>
</el-col>
<Spin v-if="spinShow" size="large" fix />
</el-row>
<el-form-item>
<el-button v-if="!isBtn" type="primary" icon="md-add" class="mt10" @click="addBtn">添加新规格</el-button>
</el-form-item>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false"> </el-button>
<el-button type="primary" @click="dialogFormVisible = false"> </el-button>
</div>
</el-form>
<span class="footer acea-row">
<el-button @click="resetForm('formDynamic')">取消</el-button>
<el-button :loading="loading" type="primary" @click="handleSubmit('formDynamic')"> </el-button>
</span>
</div>
</template>
<script>
import { attrCreatApi, attrEdittApi } from '@/api/product'
export default {
name: 'CreatAttr',
props: {
currentRow: {
type: Object,
default: null
}
},
data() {
return {
dialogVisible: false,
inputVisible: false,
inputValue: '',
spinShow: false,
loading: false,
grid: {
xl: 3,
lg: 3,
md: 12,
sm: 24,
xs: 24
},
modal: false,
index: 1,
rules: {
template_name: [
{ required: true, message: '请输入模板名称', trigger: 'blur' }
]
},
formDynamic: {
template_name: '',
template_value: []
},
attrsName: '',
attrsVal: '',
formDynamicNameData: [],
isBtn: false,
formDynamicName: [],
results: [],
result: [],
ids: 0
}
},
watch: {
currentRow: {
handler: function(val, oldVal) {
this.formDynamic = val
},
immediate: true
}
},
mounted() {
this.formDynamic.template_value.map(item => {
this.$set(item, 'inputVisible', false)
})
},
methods: {
resetForm(formName) {
this.$msgbox.close()
this.clear()
this.$refs[formName].resetFields()
},
//
addBtn() {
this.isBtn = true
},
handleClose(item, index) {
item.splice(index, 1)
},
//
offAttrName() {
this.isBtn = false
},
//
handleRemove(index) {
this.formDynamic.template_value.splice(index, 1)
},
//
createAttrName() {
if (this.attrsName && this.attrsVal) {
const data = {
value: this.attrsName,
detail: [
this.attrsVal
]
}
this.formDynamic.template_value.push(data)
var hash = {}
this.formDynamic.template_value = this.formDynamic.template_value.reduce(function(item, next) {
/* eslint-disable */
hash[next.value] ? '' : hash[next.value] = true && item.push(next);
return item
}, [])
this.attrsName = '';
this.attrsVal = '';
this.isBtn = false;
} else {
if(!this.attrsName){
this.$message.warning('请输入规格名称!');
return
}
if(!this.attrsVal){
this.$message.warning('请输入规格值!');
return
}
}
},
//
createAttr (num, idx) {
if (num) {
this.formDynamic.template_value[idx].detail.push(num);
var hash = {};
this.formDynamic.template_value[idx].detail = this.formDynamic.template_value[idx].detail.reduce(function (item, next) {
/* eslint-disable */
hash[next] ? '' : hash[next] = true && item.push(next);
return item
}, [])
this.formDynamic.template_value[idx].inputVisible = false
} else {
this.$message.warning('请添加属性');
}
},
showInput(item) {
this.$set(item, 'inputVisible', true)
},
//
handleSubmit (name) {
this.$refs[name].validate((valid) => {
if (valid) {
if (this.formDynamic.template_value.length === 0) {
return this.$message.warning('请至少添加一条属性规格!');
}
this.loading = true;
setTimeout(() => {
this.currentRow.attr_template_id? attrEdittApi(this.currentRow.attr_template_id,this.formDynamic).then(res => {
this.$message.success(res.message);
this.loading = false;
setTimeout(() => {
this.$msgbox.close()
}, 500);
setTimeout(() => {
this.clear();
this.$emit('getList');
}, 600);
}).catch(res => {
this.loading = false;
this.$message.error(res.message);
}):attrCreatApi(this.formDynamic).then(res => {
this.$message.success(res.message);
this.loading = false;
setTimeout(() => {
this.$msgbox.close()
}, 500);
setTimeout(() => {
this.$emit('getList');
this.clear();
}, 600);
}).catch(res => {
this.loading = false;
this.$message.error(res.message);
})
}, 1200);
} else {
return false
}
})
},
clear () {
this.$refs['formDynamic'].resetFields();
this.formDynamic.template_value = [];
this.formDynamic.template_name=''
this.isBtn = false;
this.attrsName = '';
this.attrsVal = '';
},
handleInputConfirm() {
const inputValue = this.inputValue
if (inputValue) {
this.dynamicTags.push(inputValue)
}
this.inputVisible = false
this.inputValue = ''
}
}
}
</script>
<style scoped lang="scss">
.button-new-tag {
height: 28px;
line-height: 26px;
padding-top: 0;
padding-bottom: 0;
}
.input-new-tag {
width: 90px;
margin-left: 10px;
vertical-align: bottom;
}
.footer{
justify-content: flex-end;
}
</style>

View File

@ -0,0 +1,287 @@
<template>
<div class="divBox">
<div class="header clearfix">
<div class="container">
<el-form inline size="small">
<el-form-item label="优惠劵名称:">
<el-input v-model="tableFrom.coupon_name" placeholder="请输入优惠券名称" @keyup.enter.native="getList" class="selWidth" size="small">
<el-button slot="append" icon="el-icon-search" class="el-button-solt" size="small" @click="getList" />
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<el-table
ref="table"
v-loading="listLoading"
:data="tableData.data"
style="width: 100%"
size="mini"
max-height="400"
tooltip-effect="dark"
@selection-change="handleSelectionChange"
>
<el-table-column
v-if="handle==='wu'"
type="selection"
width="55"
/>
<el-table-column
prop="coupon_id"
label="ID"
min-width="50"
/>
<el-table-column
prop="title"
label="优惠券名称"
min-width="120"
/>
<el-table-column
label="优惠劵类型"
min-width="80"
>
<template slot-scope="{ row }">
<span>{{ row.type | couponTypeFilter }}</span>
</template>
</el-table-column>
<el-table-column
prop="coupon_price"
label="优惠券面值"
min-width="90"
/>
<el-table-column
label="最低消费额"
min-width="90"
>
<template slot-scope="scope">
<span>{{ scope.row.use_min_price===0?'不限制':scope.row.use_min_price }}</span>
</template>
</el-table-column>
<el-table-column
label="有效期限"
min-width="250"
>
<template slot-scope="scope">
<span>{{ scope.row.coupon_type===1?scope.row.use_start_time+' 一 '+scope.row.use_end_time:scope.row.coupon_time }}</span>
</template>
</el-table-column>
<el-table-column
label="剩余数量"
min-width="90"
>
<template slot-scope="scope">
<span>{{ scope.row.is_limited===0 ? '不限量' : scope.row.remain_count }}</span>
</template>
</el-table-column>
<el-table-column v-if="handle==='send'" label="操作" min-width="120" fixed="right" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" class="mr10" @click="send(scope.row.id)">发送</el-button>
</template>
</el-table-column>
</el-table>
<div class="block mb20">
<el-pagination
:page-sizes="[10, 20, 40]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
<div>
<el-button size="small" type="primary" class="fr" @click="ok">确定</el-button>
<el-button size="small" class="fr mr20" @click="close">取消</el-button>
</div>
</div>
</template>
<script>
import { couponSelectApi } from '@/api/marketing'
import { roterPre } from '@/settings'
export default {
name: 'CouponList',
props: {
handle: {
type: String,
default: ''
},
couponId: {
type: Array,
default: () => []
},
keyNum: {
type: Number,
default: 0
},
couponData: {
type: Array,
default: () => []
}
},
data() {
return {
roterPre: roterPre,
listLoading: true,
tableData: {
data: [],
total: 0
},
tableFrom: {
page: 1,
limit: 10,
coupon_name: '',
send_type: 3
},
multipleSelection: [],
attr: [],
multipleSelectionAll: [],
idKey: 'coupon_id',
nextPageFlag: false
}
},
watch: {
keyNum: {
deep: true,
handler(val) {
this.getList()
}
}
},
mounted() {
this.tableFrom.page = 1
this.getList()
this.multipleSelectionAll = this.couponData
},
watch:{
couponData: {
deep: true,
handler(val) {
this.multipleSelectionAll = this.couponData
this.getList()
}
},
},
methods: {
close() {
this.$msgbox.close()
this.multipleSelection = []
},
handleSelectionChange(val) {
this.multipleSelection = val
setTimeout(() => {
this.changePageCoreRecordData()
}, 50)
},
//
setSelectRow() {
if (!this.multipleSelectionAll || this.multipleSelectionAll.length <= 0) {
return
}
//
const idKey = this.idKey
const selectAllIds = []
this.multipleSelectionAll.forEach(row => {
selectAllIds.push(row[idKey])
})
this.$refs.table.clearSelection()
for (var i = 0; i < this.tableData.data.length; i++) {
if (selectAllIds.indexOf(this.tableData.data[i][idKey]) >= 0) {
// table使ref="table"
this.$refs.table.toggleRowSelection(this.tableData.data[i], true)
}
}
},
//
changePageCoreRecordData() {
//
const idKey = this.idKey
const that = this
//
if (this.multipleSelectionAll.length <= 0) {
this.multipleSelectionAll = this.multipleSelection
return
}
// key
const selectAllIds = []
this.multipleSelectionAll.forEach(row => {
selectAllIds.push(row[idKey])
})
const selectIds = []
// id
this.multipleSelection.forEach(row => {
selectIds.push(row[idKey])
//
if (selectAllIds.indexOf(row[idKey]) < 0) {
that.multipleSelectionAll.push(row)
}
})
const noSelectIds = []
// id
this.tableData.data.forEach(row => {
if (selectIds.indexOf(row[idKey]) < 0) {
noSelectIds.push(row[idKey])
}
})
noSelectIds.forEach(id => {
if (selectAllIds.indexOf(id) >= 0) {
for (let i = 0; i < that.multipleSelectionAll.length; i++) {
if (that.multipleSelectionAll[i][idKey] == id) {
//
that.multipleSelectionAll.splice(i, 1)
break
}
}
}
})
},
ok() {
if (this.multipleSelection.length > 0) {
this.$emit('getCouponId', this.multipleSelectionAll)
this.close()
} else {
this.$message.warning('请先选择优惠劵')
}
},
//
getList() {
this.listLoading = true
couponSelectApi(this.tableFrom).then(res => {
this.tableData.data = res.data.list
this.tableData.total = res.data.count
this.listLoading = false
this.$nextTick(function() {
this.setSelectRow()//
})
}).catch(res => {
this.listLoading = false
this.$message.error(res.message)
})
},
pageChange(page) {
this.changePageCoreRecordData()
this.tableFrom.page = page
this.getList()
},
handleSizeChange(val) {
this.changePageCoreRecordData()
this.tableFrom.limit = val
this.getList()
}
}
}
</script>
<style scoped lang="scss">
.selWidth{
width: 219px !important;
}
.seachTiele{
line-height: 35px;
}
.fr{
float: right;
}
</style>

View File

@ -0,0 +1,470 @@
<template>
<div class="lazy-cascader" :style="{ width: width }">
<!-- 禁用状态 -->
<div
v-if="disabled"
class="el-input__inner lazy-cascader-input lazy-cascader-input-disabled"
>
<span v-show="placeholderVisible" class="lazy-cascader-placeholder">
{{ placeholder }}
</span>
<div v-if="props.multiple" class="lazy-cascader-tags">
<el-tag
v-for="(item, index) in labelArray"
:key="index"
class="lazy-cascader-tag"
type="info"
disable-transitions
closable
>
<span> {{ item.label.join(separator) }}</span>
</el-tag>
</div>
<div v-else class="lazy-cascader-label">
<el-tooltip
placement="top-start"
:content="labelObject.label.join(separator)"
>
<span>{{ labelObject.label.join(separator) }}</span>
</el-tooltip>
</div>
</div>
<!-- 禁用状态 -->
<!-- 可选状态 -->
<el-popover v-else ref="popover" trigger="click" placement="bottom-start">
<!-- 搜索 -->
<div class="lazy-cascader-search">
<el-autocomplete
v-if="filterable"
v-model="keyword"
:style="{ width: searchWidth || '100%' }"
:popper-class="suggestionsPopperClass"
class="inline-input"
prefix-icon="el-icon-search"
label="name"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
placeholder="请输入"
@select="handleSelect"
@blur="isSearchEmpty = false"
>
<template slot-scope="{ item }">
<div class="name" :class="isChecked(item[props.value])">
{{ item[props.label].join(separator) }}
</div>
</template>
</el-autocomplete>
<div v-show="isSearchEmpty" class="empty">{{ searchEmptyText }}</div>
</div>
<!-- 搜索 -->
<!-- 级联面板 -->
<div class="lazy-cascader-panel">
<el-cascader-panel
ref="panel"
v-model="current"
:options="options"
:props="currentProps"
@change="change"
/>
</div>
<!-- 级联面板 -->
<!--内容区域-->
<div
slot="reference"
class="el-input__inner lazy-cascader-input"
:class="disabled ? 'lazy-cascader-input-disabled' : ''"
>
<span v-show="placeholderVisible" class="lazy-cascader-placeholder">
{{ placeholder }}
</span>
<div v-if="props.multiple" class="lazy-cascader-tags">
<el-tag
v-for="(item, index) in labelArray"
:key="index"
class="lazy-cascader-tag"
type="info"
size="small"
disable-transitions
closable
@close="handleClose(item)"
>
<span> {{ item.label.join(separator) }}</span>
</el-tag>
</div>
<div v-else class="lazy-cascader-label">
<el-tooltip
placement="top-start"
:content="labelObject.label.join(separator)"
>
<span>{{ labelObject.label.join(separator) }}</span>
</el-tooltip>
</div>
<span
v-if="clearable && current.length > 0"
class="lazy-cascader-clear"
@click.stop="clearBtnClick"
>
<i class="el-icon-close" />
</span>
</div>
<!--内容区域-->
</el-popover>
<!-- 可选状态 -->
</div>
</template>
<script>
export default {
props: {
value: {
type: Array,
default: () => {
return []
}
},
separator: {
type: String,
default: '/'
},
placeholder: {
type: String,
default: '请选择'
},
width: {
type: String,
default: '400px'
},
filterable: Boolean,
clearable: Boolean,
disabled: Boolean,
props: {
type: Object,
default: () => {
return {}
}
},
suggestionsPopperClass: {
type: String,
default: 'suggestions-popper-class'
},
searchWidth: {
type: String
},
searchEmptyText: {
type: String,
default: '暂无数据'
}
},
data() {
return {
isSearchEmpty: false,
keyword: '',
options: [],
current: [],
labelObject: { label: [], value: [] },
labelArray: [],
currentProps: {
multiple: this.props.multiple,
checkStrictly: this.props.checkStrictly,
value: this.props.value,
label: this.props.label,
leaf: this.props.leaf,
lazy: true,
lazyLoad: this.lazyLoad
}
}
},
computed: {
placeholderVisible() {
if (this.current) {
return this.current.length == 0
} else {
return true
}
}
},
watch: {
current() {
this.getLabelArray()
},
value(v) {
this.current = v
},
keyword() {
this.isSearchEmpty = false
}
},
created() {
this.initOptions()
},
methods: {
//
isChecked(value) {
//
if (this.props.multiple) {
const index = this.current.findIndex(item => {
return item.join() == value.join()
})
if (index > -1) {
return 'el-link el-link--primary'
} else {
return ''
}
} else {
if (value.join() == this.current.join()) {
return 'el-link el-link--primary'
} else {
return ''
}
}
},
//
querySearch(query, callback) {
this.props.lazySearch(query, list => {
callback(list)
if (!list || !list.length) this.isSearchEmpty = true
})
},
//
handleSelect(item) {
if (this.props.multiple) {
const index = this.current.findIndex(obj => {
return obj.join() == item[this.props.value].join()
})
if (index == -1) {
this.$refs.panel.clearCheckedNodes()
this.current.push(item[this.props.value])
this.$emit('change', this.current)
}
} else {
//
if (
this.current == null ||
item[this.props.value].join() !== this.current.join()
) {
this.$refs.panel.activePath = []
this.current = item[this.props.value]
this.$emit('change', this.current)
}
}
this.keyword = ''
},
//
async initOptions() {
this.props.lazyLoad(0, list => {
this.$set(this, 'options', list)
if (this.props.multiple) {
this.current = [...this.value]
} else {
this.current = this.value
}
})
},
async getLabelArray() {
if (this.props.multiple) {
const array = []
for (let i = 0; i < this.current.length; i++) {
const obj = await this.getObject(this.current[i])
array.push(obj)
}
this.labelArray = array
this.$emit('input', this.current)
if (!this.disabled) {
this.$nextTick(() => {
this.$refs.popover.updatePopper()
})
}
} else {
this.labelObject = await this.getObject(this.current || [])
this.$emit('input', this.current)
}
},
/** 格式化id=>object */
async getObject(id) {
try {
let options = this.options
const nameArray = []
for (let i = 0; i < id.length; i++) {
const index = options.findIndex(item => {
return item[this.props.value] == id[i]
})
if (index < 0) {
continue
}
nameArray.push(options[index][this.props.label])
if (i < id.length - 1 && options[index].children == undefined) {
const list = new Promise(resolve => {
this.props.lazyLoad(id[i], list => {
resolve(list)
})
})
this.$set(options[index], 'children', await list)
options = options[index].children
} else {
options = options[index].children
}
}
return { value: id, label: nameArray }
} catch (e) {
this.current = []
return { value: [], label: [] }
}
},
//
async lazyLoad(node, resolve) {
let current = this.current
if (this.props.multiple) {
current = [...this.current]
}
if (node.root) {
resolve()
} else if (node.data[this.props.leaf]) {
resolve()
} else if (node.data.children) {
if (this.props.multiple) {
this.current = current
}
resolve()
} else {
this.props.lazyLoad(node.value, list => {
node.data.children = list
if (this.props.multiple) {
this.current = current
}
resolve(list)
})
}
},
//
/** 删除**/
handleClose(item) {
const index = this.current.findIndex(obj => {
return obj.join() == item.value.join()
})
if (index > -1) {
this.$refs.panel.clearCheckedNodes()
this.current.splice(index, 1)
this.$emit('change', this.current)
}
},
//
clearBtnClick() {
this.$refs.panel.clearCheckedNodes()
this.current = []
this.$emit('change', this.current)
},
change() {
this.$emit('change', this.current)
}
}
}
</script>
<style lang="scss">
.lazy-cascader {
display: inline-block;
width: 300px;
.lazy-cascader-input {
position: relative;
width: 100%;
background: #fff;
height: auto;
min-height: 36px;
padding: 5px;
line-height: 1;
cursor: pointer;
> .lazy-cascader-placeholder {
padding: 0 2px;
line-height: 28px;
color: #999;
font-size: 14px;
}
> .lazy-cascader-label {
padding: 0 2px;
line-height: 28px;
color: #606266;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
> .lazy-cascader-clear {
position: absolute;
right: 0;
top: 0;
display: inline-block;
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
}
}
.lazy-cascader-input-disabled {
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
cursor: not-allowed;
> .lazy-cascader-label {
color: #c0c4cc;
}
> .lazy-cascader-placeholder {
color: #c0c4cc;
}
}
}
.lazy-cascader-tag {
display: inline-flex;
align-items: center;
max-width: 100%;
margin: 2px;
text-overflow: ellipsis;
background: #f0f2f5;
> span {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
}
> .el-icon-close {
-webkit-box-flex: 0;
-ms-flex: none;
flex: none;
background-color: #c0c4cc;
color: #fff;
}
}
.lazy-cascader-panel {
margin-top: 10px;
display: inline-block;
}
.suggestions-popper-class {
width: auto !important;
min-width: 200px;
}
.lazy-cascader-search {
.empty {
width: calc(100% - 24px);
box-sizing: border-box;
background-color: #fff;
color: #999;
text-align: center;
position: absolute;
z-index: 999;
padding: 12px 0;
margin-top: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
&:before {
content: "";
position: absolute;
top: -12px;
left: 36px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid transparent;
border-bottom: 6px solid #fff;
filter: drop-shadow(0 -1px 2px rgba(0, 0, 0, 0.02));
}
}
}
</style>

View File

@ -0,0 +1,234 @@
<template>
<div>
<el-dialog :title="isEdit ? '编辑服务说明模板' : '添加服务说明模板'" :visible.sync="dialogVisible" width="1000px">
<el-form ref="formValidate" class="formValidate mt20" :model="formValidate" :rules="ruleInline" label-width="100px" label-position="right">
<el-form-item label="模板名称:" prop="template_name">
<el-input v-model="formValidate.template_name" placeholder="请输入模板名称" size="small" />
</el-form-item>
<el-form-item label="服务条款:" prop="template_value">
<div class="acea-row">
<el-tag
v-for="(tag, index) in termsService"
:key="index"
class="mr10"
closable
:disable-transitions="false"
@close="handleCloseItems(tag)"
>{{ tag.guarantee_name }}</el-tag>
</div>
</el-form-item>
<el-form-item>
<el-input v-model="guarantee_name" placeholder="请输入服务条款名称搜索" class="selWidth" size="small" @keyup.enter.native="getServiceTerms">
<el-button slot="append" icon="el-icon-search" size="small" class="el-button-solt" @click="getServiceTerms" />
</el-input>
</el-form-item>
<el-form-item>
<el-checkbox-group v-model="formValidate.template_value" @change="handleCheckedTermsChange">
<el-checkbox v-for="item in termsList" v-show="item.isShow" :key="item.guarantee_id" :label="item.guarantee_id" class="guarantee_checkbox">
<span class="guarantee_name">{{ item.guarantee_name }}</span>
<span class="guarantee_info">{{ item.guarantee_info }}</span></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="排序:">
<el-input-number v-model="formValidate.sort" placeholder="请输入排序" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button v-if="!isEdit" type="primary" :loading="loading" @click="createGuarantee('formValidate')"> </el-button>
<el-button v-else type="primary" :loading="loading" @click="updateGuarantee('formValidate')"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {
guaranteeTemplateAddApi,
guaranteeUpdateApi,
guaranteeTemplateDetailApi,
guaranteeTemplateSelectApi
} from '@/api/product'
export default {
name: 'CreatGuarantee',
data() {
return {
isEdit: false,
dialogVisible: false,
loading: false,
guarantee_id: '',
guarantee_name: '',
termsService: [],
termsList: [],
formValidate: {
template_name: '',
template_value: [],
sort: ''
},
ruleInline: {
template_name: [
{ required: true, message: '请输入模板名称', trigger: 'blur' }
],
template_value: [
{ required: true, message: '请选择服务条款', trigger: 'change' }
]
}
}
},
watch: {
},
mounted() {
this.getServiceTerms()
},
methods: {
/** 获取服务条款 */
getServiceTerms() {
guaranteeTemplateSelectApi({ keyword: this.guarantee_name }).then((res) => {
if (this.guarantee_name) {
this.getSearchItem(res.data)
} else {
this.termsList = res.data
this.termsList.forEach((item, index) => {
item.isShow = true
})
}
})
.catch(({ message }) => {
this.$message.error(message)
})
},
/** 把搜索结果显示出来 */
getSearchItem(arr) {
this.termsList.forEach((item, index) => {
if (arr.length > 0) {
arr.forEach((itemn, indexn) => {
if (itemn.guarantee_id == item.guarantee_id) {
item.isShow = true
} else {
item.isShow = false
}
})
} else {
item.isShow = false
}
this.$set(this.termsList, index, item)
console.log(this.termsList)
})
},
handleCheckedTermsChange(value) {
this.getSelectedItems(value)
},
handleCloseItems(tag) {
this.termsService.splice(this.termsService.indexOf(tag), 1)
this.formValidate.template_value = []
this.termsService.map(item => {
this.formValidate.template_value.push(item.guarantee_id)
})
},
/** 取出选择的服务条款 */
getSelectedItems(arr) {
this.termsService = []
this.termsList.forEach((item, index) => {
arr.forEach((itemn, indexn) => {
if (itemn == item.guarantee_id) {
this.termsService.push(item)
}
})
})
},
//
handleEdit(id) {
this.isEdit = true
this.dialogVisible = true
this.loading = false
this.guarantee_id = id
guaranteeTemplateDetailApi(id).then((res) => {
const data = res.data
this.formValidate = {
template_name: data.template_name,
template_value: data.template_value,
sort: data.sort
}
this.getSelectedItems(data.template_value)
this.$refs['formValidate'].clearValidate()
})
.catch(({ message }) => {
this.$message.error(message)
})
},
add() {
this.isEdit = false
this.dialogVisible = true
this.loading = false
this.guarantee_name = ""
this.formValidate = {
template_name: '',
template_value: [],
sort: ''
}
this.getServiceTerms()
},
/** 添加 */
createGuarantee(name) {
this.$refs[name].validate(valid => {
if (valid) {
this.loading = true
guaranteeTemplateAddApi(this.formValidate)
.then(({ message }) => {
this.$message.success(message)
this.dialogVisible = false
this.loading = false
this.$emit('get-list', '')
})
.catch(({ message }) => {
this.loading = false
this.$message.error(message)
})
}
})
},
/** 编辑 */
updateGuarantee(name) {
this.$refs[name].validate(valid => {
if (valid) {
this.loading = true
guaranteeUpdateApi(this.guarantee_id, this.formValidate)
.then(({ message }) => {
this.$message.success(message)
this.dialogVisible = false
this.loading = false
this.$emit('get-list', '')
})
.catch(({ message }) => {
this.loading = false
this.$message.error(message)
})
}
})
}
}
}
</script>
<style scoped lang="scss">
/deep/.selWidth{
width: 300px!important;
}
.guarantee_info{
display: block;
}
/deep/.el-checkbox__input{
vertical-align: top;
top: 3px;
}
/deep/.el-checkbox__label{
white-space: normal; word-break: break-all;
}
.guarantee_name{
font-weight: bold;
color: #333;
}
</style>

View File

@ -0,0 +1,488 @@
<template>
<div>
<el-form ref="ruleForm" v-loading="loading" :model="ruleForm" label-width="120px" size="mini" :rules="rules">
<el-form-item label="模板名称" prop="name">
<el-input v-model="ruleForm.name" class="withs" placeholder="请输入模板名称" />
</el-form-item>
<el-form-item label="运费说明" prop="info">
<el-input v-model="ruleForm.info" type="textarea" class="withs" placeholder="请输入运费说明" />
</el-form-item>
<el-form-item label="计费方式" prop="type">
<el-radio-group v-model="ruleForm.type" @change="changeRadio(ruleForm.type)">
<el-radio :label="0">按件数</el-radio>
<el-radio :label="1">按重量</el-radio>
<el-radio :label="2">按体积</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="配送区域及运费" prop="region">
<el-table v-loading="listLoading" :data="ruleForm.region" border fit highlight-current-row style="width: 100%" size="mini" class="tempBox">
<el-table-column align="center" label="可配送区域" min-width="260">
<template slot-scope="scope">
<span v-if="scope.$index === 0">默认全国 <span style="font-weight: bold;">(开启指定区域不配送时无效)</span></span>
<LazyCascader
v-else
v-model="scope.row.city_ids"
style="width: 98%"
:props="props"
collapse-tags
clearable
:filterable="false"
/>
</template>
</el-table-column>
<el-table-column min-width="130px" align="center" :label="columns.title">
<template slot-scope="{row}">
<el-input-number v-model="row.first" controls-position="right" :min="0" />
</template>
</el-table-column>
<el-table-column min-width="120px" align="center" label="运费(元)">
<template slot-scope="{row}">
<el-input-number v-model="row.first_price" controls-position="right" :min="0" />
</template>
</el-table-column>
<el-table-column min-width="120px" align="center" :label="columns.title2">
<template slot-scope="{row}">
<el-input-number v-model="row.continue" controls-position="right" :min="0.1" />
</template>
</el-table-column>
<el-table-column class-name="status-col" align="center" label="续费(元)" min-width="120">
<template slot-scope="{row}">
<el-input-number v-model="row.continue_price" controls-position="right" :min="0" />
</template>
</el-table-column>
<el-table-column align="center" label="操作" min-width="80" fixed="right">
<template slot-scope="scope">
<el-button
v-if="scope.$index > 0"
type="text"
size="small"
@click="confirmEdit(ruleForm.region,scope.$index)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item>
<el-button type="primary" size="mini" icon="el-icon-edit" @click="addRegion(ruleForm.region)">
添加配送区域
</el-button>
</el-form-item>
<el-form-item label="指定包邮" prop="appoint">
<el-radio-group v-model="ruleForm.appoint">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="ruleForm.appoint === 1" prop="free">
<el-table v-loading="listLoading" :data="ruleForm.free" border fit highlight-current-row style="width: 100%" size="mini">
<el-table-column align="center" label="选择地区" min-width="220">
<template slot-scope="{row}">
<LazyCascader
v-model="row.city_ids"
style="width: 95%"
:props="props"
collapse-tags
clearable
:filterable="false"
/>
</template>
</el-table-column>
<el-table-column min-width="180px" align="center" :label="columns.title3">
<template slot-scope="{row}">
<el-input-number v-model="row.number" controls-position="right" :min="1" />
</template>
</el-table-column>
<el-table-column min-width="120px" align="center" label="最低购买金额(元)">
<template slot-scope="{row}">
<el-input-number v-model="row.price" controls-position="right" :min="0.01" />
</template>
</el-table-column>
<el-table-column align="center" label="操作" min-width="120" fixed="right">
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click="confirmEdit(ruleForm.free,scope.$index)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item v-if="ruleForm.appoint === 1">
<el-button type="primary" size="mini" icon="el-icon-edit" @click="addFree(ruleForm.free)">
添加指定包邮区域
</el-button>
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="指定区域不配送" prop="undelivery">
<el-radio-group v-model="ruleForm.undelivery">
<el-radio :label="1">自定义</el-radio>
<el-radio :label="2">开启</el-radio>
<el-radio :label="0">关闭</el-radio>
</el-radio-group>
<br>
(说明: 选择"开启", 仅支持上表添加的配送区域)
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="ruleForm.undelivery === 1" class="noBox" prop="city_id3">
<LazyCascader
v-model="ruleForm.city_id3"
placeholder="请选择不配送区域"
style="width: 46%"
:props="props"
collapse-tags
clearable
:filterable="false"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="排序">
<el-input v-model="ruleForm.sort" class="withs" placeholder="请输入排序" />
</el-form-item>
</el-form>
<span class="footer acea-row">
<el-button @click="resetForm('ruleForm')"> </el-button>
<el-button type="primary" @click="onsubmit('ruleForm')"> </el-button>
</span>
</div>
</template>
<script>
import { cityListV2, templateCreateApi, templateDetailApi, templateUpdateApi } from '@/api/freight'
import LazyCascader from '../lazyCascader'
const defaultRole = {
name: '',
type: 0,
appoint: 0,
sort: 0,
info: '',
region: [{
first: 1,
first_price: 0,
continue: 1,
continue_price: 0,
city_id: [],
city_ids: []
}],
undelivery: 0,
free: [],
undelives: {},
city_id3: []
}
const cacheAddress = {}
const kg = '重量kg'
const m = '体积'
const statusMap = [
{
title: '首件',
title2: '续件',
title3: '最低购买件数'
},
{
title: `首件${kg}`,
title2: `续件${kg}`,
title3: `最低购买${kg}`
},
{
title: `首件${m}`,
title2: `续件${m}`,
title3: `最低购买${m}`
}
]
export default {
name: 'CreatTemplates',
components: {
LazyCascader
},
props: {
tempId: {
type: Number,
default: 0
},
componentKey: {
type: Number,
default: 0
}
},
data() {
return {
loading: false,
rules: {
name: [
{ required: true, message: '请输入模板名称', trigger: 'change' }
],
info: [
{ required: true, message: '请输入运费说明', trigger: 'blur' },
{ min: 3, max: 500, message: '长度在 3 到 500 个字符', trigger: 'blur' }
],
free: [
{ type: 'array', required: true, message: '请至少添加一个地区', trigger: 'change' }
],
appoint: [
{ required: true, message: '请选择是否指定包邮', trigger: 'change' }
],
undelivery: [
{ required: true, message: '请选择是否指定区域不配送', trigger: 'change' }
],
type: [
{ required: true, message: '请选择计费方式', trigger: 'change' }
],
region: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
]
// city_id3: [
// { type: 'array', required: true, message: '', trigger: 'remove-tag' }
// ]
},
nodeKey: 'city_id',
props: {
children: 'children',
label: 'name',
value: 'id',
multiple: true,
lazy: true,
lazyLoad: this.lazyLoad,
checkStrictly: true
},
dialogVisible: false,
ruleForm: Object.assign({}, defaultRole),
listLoading: false,
cityList: [],
columns: {
title: '首件',
title2: '续件',
title3: '最低购买件数'
}
}
},
watch: {
componentKey: {
handler: function(val, oldVal) {
if (val) {
this.getInfo()
} else {
this.ruleForm = {
name: '',
type: 0,
appoint: 0,
sort: 0,
region: [{
first: 1,
first_price: 0,
continue: 1,
continue_price: 0,
city_id: [],
city_ids: []
}],
undelivery: 0,
free: [],
undelives: {},
city_id3: []
}
}
}
// immediate: true
}
},
mounted() {
// this.getCityList()
if (this.tempId > 0) this.getInfo()
},
methods: {
resetForm(formName) {
this.$msgbox.close()
this.$refs[formName].resetFields()
},
onClose(formName) {
this.dialogVisible = false
this.$refs[formName].resetFields()
},
confirmEdit(row, index) {
row.splice(index, 1)
},
changeRadio(num) {
this.columns = Object.assign({}, statusMap[num])
},
//
addRegion(region) {
region.push(Object.assign({}, {
first: 1,
first_price: 1,
continue: 1,
continue_price: 0,
city_id: [],
city_ids: []
}))
},
addFree(Free) {
Free.push(Object.assign({}, {
city_id: [],
number: 1,
price: 0.01,
city_ids: []
}))
},
lazyLoad(node, resolve) {
if (cacheAddress[node]) {
cacheAddress[node]().then(res => {
resolve([...res.data])
})
} else {
const p = cityListV2(node)
cacheAddress[node] = () => p
p.then(res => {
res.data.forEach(item => {
item.leaf = item.snum === 0
})
cacheAddress[node] = () => new Promise((resolve1) => {
setTimeout(() => resolve1(res), 300)
})
resolve(res.data)
}).catch(res => {
this.$message.error(res.message)
})
}
},
//
getInfo() {
this.loading = true
templateDetailApi(this.tempId).then(res => {
this.dialogVisible = true
const info = res.data
this.ruleForm = {
name: info.name,
type: info.type,
info: info.info,
appoint: info.appoint,
sort: info.sort,
region: info.region,
undelivery: info.undelivery,
free: info.free,
undelives: info.undelives,
city_id3: info.undelives.city_ids || []
}
this.ruleForm.region.map(item => {
this.$set(item, 'city_id', item.city_ids[0])
this.$set(item, 'city_ids', item.city_ids)
})
this.ruleForm.free.map(item => {
this.$set(item, 'city_id', item.city_ids[0])
this.$set(item, 'city_ids', item.city_ids)
})
this.changeRadio(info.type)
// this.$refs.changeType.click(info.type)
// this.$refs.refid.click();
this.loading = false
}).catch(res => {
this.$message.error(res.message)
this.loading = false
})
},
//
// getCityList() {
// cityListV2(0).then(res => {
// this.cityList = res.data
// }).catch(res => {
// this.$message.error(res.message)
// })
// },
change(idBox) {
idBox.map(item => {
const ids = []
if (item.city_ids.length === 0) return
item.city_ids.map(j => {
// j.splice(0, 1)
ids.push(j[j.length - 1])
})
item.city_id = ids
})
return idBox
},
changeOne(idBox) {
const city_ids = []
if (idBox.length === 0) return
idBox.map(item => {
// item.splice(0, 1)
city_ids.push(item[item.length - 1])
})
return city_ids
},
onsubmit(formName) {
// this.ruleForm.region = this.change(this.ruleForm.region)
// this.ruleForm.free = this.change(this.ruleForm.free)
// this.ruleForm.undelives.city_id = this.changeOne(this.ruleForm.city_id3)
const data = {
name: this.ruleForm.name,
type: this.ruleForm.type,
info: this.ruleForm.info,
appoint: this.ruleForm.appoint,
sort: this.ruleForm.sort,
region: this.change(this.ruleForm.region),
undelivery: this.ruleForm.undelivery,
free: this.change(this.ruleForm.free),
undelives: {
city_id: this.changeOne(this.ruleForm.city_id3)
}
}
this.$refs[formName].validate((valid) => {
if (valid) {
this.tempId === 0 ? templateCreateApi(data).then(res => {
this.$message.success(res.message)
setTimeout(() => {
this.$msgbox.close()
}, 500)
setTimeout(() => {
this.$emit('getList')
this.$refs[formName].resetFields()
}, 600)
}).catch(res => {
this.$message.error(res.message)
}) : templateUpdateApi(this.tempId, data).then(res => {
this.$message.success(res.message)
setTimeout(() => {
this.$msgbox.close()
}, 500)
setTimeout(() => {
this.$emit('getList')
this.$refs[formName].resetFields()
}, 600)
}).catch(res => {
this.$message.error(res.message)
})
} else {
return false
}
})
}
}
}
</script>
<style scoped lang="scss">
.footer{
justify-content: flex-end;
}
.withs{
width: 50%;
}
.noBox{
/deep/.el-form-item__content{
margin-left: 0 !important;
}
}
.tempBox{
/deep/.el-input-number--mini{
width: 100px !important;
}
}
</style>

34
src/libs/modal-attr.js Normal file
View File

@ -0,0 +1,34 @@
export default function modalAttr(val, callback) {
const h = this.$createElement
return new Promise((resolve, reject) => {
this.$msgbox({
title: '属性规格',
customClass: 'upload-form',
closeOnClickModal: false,
showClose: false,
message: h('div', { class: 'common-form-upload' }, [
h('attrFrom', {
props: {
currentRow: val
},
on: {
getList() {
callback()
}
}
})
]),
showCancelButton: false,
showConfirmButton: false
}).then(() => {
resolve()
}).catch(() => {
reject()
this.$message({
type: 'info',
message: '已取消'
})
})
})
}

37
src/libs/modal-coupon.js Normal file
View File

@ -0,0 +1,37 @@
export default function modalCoupon(couponData, handle, couponId, keyNum, callback) {
const h = this.$createElement
return new Promise((resolve, reject) => {
this.$msgbox({
title: '优惠券列表',
customClass: 'upload-form-coupon',
closeOnClickModal: false,
showClose: false,
message: h('div', { class: 'common-form-upload' }, [
h('couponList', {
props: {
couponData: couponData,
handle: handle,
couponId: couponId,
keyNum: keyNum
},
on: {
getCouponId(id) {
callback(id)
}
}
})
]),
showCancelButton: false,
showConfirmButton: false
}).then(() => {
resolve()
}).catch(() => {
reject()
this.$message({
type: 'info',
message: '已取消'
})
})
})
}

View File

@ -0,0 +1,35 @@
export default function modalTemplates(id, callback, componentKey) {
const h = this.$createElement
return new Promise((resolve, reject) => {
this.$msgbox({
title: '运费模板',
customClass: 'upload-form-temp',
closeOnClickModal: false,
showClose: false,
message: h('div', { class: 'common-form-upload' }, [
h('templatesFrom', {
props: {
tempId: id,
componentKey: componentKey
},
on: {
getList() {
callback()
}
}
})
]),
showCancelButton: false,
showConfirmButton: false
}).then(() => {
resolve()
}).catch(() => {
reject()
this.$message({
type: 'info',
message: '已取消'
})
})
})
}

View File

@ -25,6 +25,9 @@ import FormCreate from "@form-create/element-ui";
import uploadPicture from "./components/uploadPicture/uploadFrom";
import VueUeditorWrap from "vue-ueditor-wrap";
import newsCategory from "./components/newsCategory/newsCategoryFrom";
import couponList from './components/couponList'
import attrFrom from './components/attrFrom'
import templatesFrom from './components/templatesFrom'
import { getToken } from "./utils/auth";
import "./icons"; // icon
@ -36,6 +39,9 @@ import { modalSure, deleteSure } from "@/libs/public";
import { modalSureDelete } from "@/libs/public";
import * as filters from "./filters";
import notice from "@/libs/notice";
import modalCoupon from '@/libs/modal-coupon'
import modalAttr from '@/libs/modal-attr'
import modalTemplates from '@/libs/modal-templates'
import guidancePop from "@/components/guidancePop";
// swiper
import VueAwesomeSwiper from "vue-awesome-swiper";
@ -45,6 +51,9 @@ Vue.use(uploadPicture);
Vue.use(FormCreate);
Vue.use(newsCategory);
Vue.component("vue-ueditor-wrap", VueUeditorWrap);
Vue.component('couponList', couponList)
Vue.component('attrFrom', attrFrom)
Vue.component('templatesFrom', templatesFrom)
Vue.use(VueAwesomeSwiper);
Vue.use(Viewer, {
defaultOptions: {
@ -72,6 +81,9 @@ Vue.prototype.$videoCloud = videoCloud;
Vue.prototype.$modalSure = modalSure;
Vue.prototype.$deleteSure = deleteSure;
Vue.prototype.$modalSureDelete = modalSureDelete;
Vue.prototype.$modalCoupon = modalCoupon
Vue.prototype.$modalAttr = modalAttr
Vue.prototype.$modalTemplates = modalTemplates
Vue.prototype.moment = Moment;
Vue.component('guidancePop',guidancePop);

View File

@ -123,7 +123,17 @@ const productRouter =
noCache: true
},
component: () => import('@/views/product/productGuarantee/index.vue')
}
},
{
path: 'addProduct/:id?/:edit?',
component: () => import('@/views/product/addProduct/index'),
name: 'AddProduct',
meta: {
title: '商品添加',
noCache: true
},
hidden: true
},
]
}

View File

@ -438,7 +438,7 @@ table .el-image{
height: 46px!important;
line-height: 46px!important;
font-size: 13px;
padding-left: 0!important;
padding-left: 0!important;
}
.styleTwo .el-submenu__title{
@ -453,7 +453,7 @@ table .el-image{
background: #77777D!important;
.el-submenu__title{
background: #77777D!important;
}
}
}
.styleTwo .router-link-active{
background: #ffffff;
@ -464,3 +464,10 @@ table .el-image{
.el-slider__button-wrapper{
z-index: 100
}
.upload-form-coupon{
min-width: 1100px!important;
max-height:700px!important;
}
.upload-form-temp{
min-width: 1000px!important;
}

View File

@ -0,0 +1,260 @@
<template>
<el-dialog
:visible.sync="carMyShow"
title="添加卡密"
width="600px"
>
<div class="carMywrapper">
<div class="type-radio">
<el-form label-width="80px">
<el-form-item label="卡密类型:">
<el-radio-group v-model="fixedCar.is_type" size="large">
<el-radio :label="0">固定卡密</el-radio>
<!-- <el-radio :label="1">一次性卡密</el-radio> -->
</el-radio-group>
<div v-if="fixedCar.is_type == 0">
<div class="stock-disk">
<el-input
v-model="fixedCar.key"
size="small"
type="textarea"
:rows="4"
placeholder="填写卡密信息"
/>
</div>
<div class="stock-input">
<!-- <el-input
type="number"
size="small"
v-model="fixedCar.stock"
:min="1"
placeholder="填写库存数量"
> -->
<el-input-number v-model="fixedCar.stock" :min="1" label="填写库存数量" />
<!-- </el-input> -->
</div>
</div>
<div class="scroll-virtual" v-if="fixedCar.is_type == 1">
<div
class="acea-row row-middle mb10"
v-for="(item, index) in virtualList"
:key="index"
>
<span class="mr10 virtual-title">卡号{{ index + 1 }}</span>
<el-input
class="mr10 width15"
type="text"
size="small"
v-model.trim="item.key"
placeholder="请输入卡号(非必填)"
></el-input>
<span class="mr10 virtual-title">卡密{{ index + 1 }}</span>
<el-input
class="mr10 width15"
type="text"
v-model.trim="item.pwd"
placeholder="请输入卡密"
size="small"
></el-input>
<span class="deteal-btn" @click="removeVirtual(index)"
>删除</span
>
</div>
</div>
<div v-if="fixedCar.is_type == 1" class="add-more">
<el-button type="primary" size="mini" @click="handleAdd">添加卡密</el-button>
<el-upload
ref="upload"
class="ml10"
style="display: inline-block;"
:action="cardUrl"
:before-upload="beforeUpload"
:headers="header"
:on-success="upFile"
:format="['xlsx']"
:on-format-error="handleFormatError"
>
<!-- <el-button type="success" size="mini">导入卡密</el-button> -->
</el-upload>
<!-- <el-button class="download" type="default" size="small" @click="getCarMyList">下载卡密模板</el-button> -->
</div>
</el-form-item>
</el-form>
</div>
<div class="footer">
<el-button type="primary" class="btns" size="small" @click="cancel">取消</el-button>
<el-button type="primary" class="btns" size="small" @click="subBtn">确定</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import SettingMer from "@/libs/settingMer";
import { getToken } from "@/utils/auth";
import exportExcel from "@/utils/newToExcel.js";
import {
importCard,
exportProductCard
} from "@/api/product";
export default {
name: "addCarMy",
props:{
virtualList: {
type: Array,
default: function () {
return [];
}
}
},
data(){
return {
carMyShow: false,
fixedCar:{
is_type: 0,
key:'',
stock:0
},
cardUrl: SettingMer.https + "/file/upload/1",
header: {} //
}
},
computed: {
// cardUrl() {
// return (
// SettingMer.https +
// `/upload/image/file`
// );
// }
},
created() {
// this.getToken();
},
mounted() {
},
methods:{
//
async getCarMyList() {
let [th, filekey, data, fileName] = [[], [], [], ""];
let lebData = await this.getExcelData();
if (!fileName) fileName = lebData.filename;
if (!filekey.length) {
filekey = lebData.filekey;
}
if (!th.length) th = lebData.header;
data = lebData.export;
exportExcel(th, filekey, fileName, data);
},
getExcelData() {
return new Promise((resolve, reject) => {
exportProductCard().then((res) => {
return resolve(res.data);
});
});
},
removeVirtual(index) {
this.virtualList.splice(index, 1);
},
upFile(res) {
importCard({ file: res.data.src }).then((res) => {
this.$emit('changeVirtual',JSON.parse(JSON.stringify(res.data)))
//this.$refs.upload.clearFiles();
}).catch(err=>{
return this.$Message.error(err.msg);
})
},
handleFormatError(file){
return this.$Message.error('必须上传xlsx格式文件');
},
// token
getToken() {
this.header["Authori-zation"] = "Bearer " + getToken();
},
cancel(){
this.$emit('closeCarMy')
},
handleAdd() {
this.virtualList.push({
key: "",
pwd: "",
});
},
beforeUpload() {
let promise = new Promise((resolve) => {
this.$nextTick(function () {
resolve(true);
});
});
return promise;
},
subBtn(){
if(this.fixedCar.is_type==0){
if(this.fixedCar.key == ''){
return this.$message.error("请填写卡密信息");
}
if(!this.fixedCar.stock){
return this.$message.error("请填写库存数量");
}
this.$emit('fixdBtn',JSON.parse(JSON.stringify(this.fixedCar)))
}else{
let data = {
is_type:1,
list:this.virtualList
}
for (let i = 0; i < this.virtualList.length; i++) {
const element = this.virtualList[i];
if (!element.pwd) {
return this.$message.error("请输入所有卡密");
}
}
this.$emit('fixdBtn',JSON.parse(JSON.stringify(data)))
}
}
}
}
</script>
<style lang="scss" scoped>
.width15{
width: 150px;
}
/deep/.el-radio__label{
font-size: 13px;
}
.carMywrapper{
.download{
margin-left: 10px;
}
.stock-disk{
margin: 10px 0 15px 0;
}
.scroll-virtual {
max-height: 320px;
overflow-y: auto;
margin-top: 10px;
}
.virtual-title {
width: 50px;
}
.deteal-btn {
color: #5179ea;
cursor: pointer;
}
.add-more {
margin-top: 20px;
line-height: 32px;
}
.footer{
display: flex;
justify-content: flex-end;
margin-top: 40px;
button{
margin-left: 10px;
}
}
}
/deep/.el-input-group--append .el-input__inner{
padding-right: 0;
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<el-dialog v-if="showRecord" title="复制记录" :visible.sync="showRecord" width="900px">
<div v-loading="loading">
<el-table
v-loading="loading"
:data="tableData.data"
style="width: 100%"
size="mini"
class="table"
highlight-current-row
>
<el-table-column label="ID" prop="mer_id" min-width="50" />
<el-table-column label="使用次数" prop="num" min-width="80" />
<el-table-column label="复制商品平台名称" prop="type" min-width="120" />
<el-table-column label="剩余次数" prop="number" min-width="80" />
<el-table-column label="商品复制链接" prop="info" min-width="180" />
<el-table-column label="操作时间" prop="create_time" min-width="120" />
</el-table>
<div class="block">
<el-pagination
:page-sizes="[10, 20]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</div>
</el-dialog>
</template>
<script>
import { productCopyRecordApi } from '@/api/product'
export default {
name: 'CopyRecord',
data() {
return {
showRecord: false,
loading: false,
tableData: {
data: [],
total: 0
},
tableFrom: {
page: 1,
limit: 10
}
}
},
methods: {
getRecord() {
this.showRecord = true
this.loading = true
productCopyRecordApi(this.tableFrom)
.then((res) => {
this.tableData.data = res.data.list
this.tableData.total = res.data.count
this.loading = false
})
.catch((res) => {
this.$message.error(res.message)
this.listLoading = false
})
},
pageChange(page) {
this.tableFrom.page = page
this.getRecord()
},
pageChangeLog(page) {
this.tableFromLog.page = page
this.getRecord()
},
handleSizeChange(val) {
this.tableFrom.limit = val
this.getRecord()
}
}
}
</script>
<style scoped lang="scss">
.title {
margin-bottom: 16px;
color: #17233d;
font-weight: 500;
font-size: 14px;
}
.description {
&-term {
display: table-cell;
padding-bottom: 10px;
line-height: 20px;
width: 50%;
font-size: 12px;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,800 @@
<template>
<div class="Box">
<el-dialog
v-if="modals"
:visible.sync="modals"
width="70%"
title="商品采集"
custom-class="dialog-scustom"
>
<el-card>
<div>复制淘宝天猫京东苏宁1688</div>
生成的商品默认是没有上架的请手动上架商品
<span style="color: rgb(237, 64, 20);">商品复制次数剩余{{ count }}</span>
<router-link :to="{path: roterPre + '/setting/sms/sms_pay/index?type=copy'}">
<el-button size="small" type="text">增加采集次数</el-button>
</router-link>
<el-button size="small" type="primary" style="margin-left: 15px;" @click="openRecords">查看商品复制记录</el-button>
</el-card>
<el-form
ref="formValidate"
class="formValidate mt20"
:model="formValidate"
:rules="ruleInline"
label-width="130px"
label-position="right"
@submit.native.prevent
>
<el-form-item label="链接地址:">
<el-input v-model="soure_link" search placeholder="请输入链接地址" class="numPut" />
<el-button :loading="loading" size="small" type="primary" @click="add">确定</el-button>
</el-form-item>
</el-form>
</el-dialog>
<!--商品复制记录-->
<copy-record ref="copyRecord" />
</div>
</template>
<script>
import {
crawlFromApi,
categoryListApi,
shippingListApi,
productCopyApi,
categorySelectApi,
categoryBrandListApi,
productCopyCountApi,
guaranteeTemplateListApi,
productConfigApi,
getProductLabelApi
} from '@/api/product'
import ueditorFrom from '@/components/ueditorFrom'
import copyRecord from './copyRecord'
import SettingMer from '@/libs/settingMer'
import { getToken } from '@/utils/auth'
import { roterPre } from "@/settings";
const defaultObj = {
store_name: '',
cate_id: '',
temp_id: '',
type: 0,
guarantee_template_id: '',
keyword: '',
unit_name: '',
store_info: '',
image: '',
slider_image: [],
content: '',
ficti: 0,
once_count: 0,
give_integral: 0,
is_show: 0,
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
soure_link: '',
attrs: [],
items: [],
delivery_way: [],
mer_labels: [],
delivery_free: 0,
spec_type: 0,
is_copoy: 1,
attrValue: [{
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
bar_code: '',
weight: 0,
volume: 0
}]
}
const objTitle = {
price: {
title: '售价'
},
cost: {
title: '成本价'
},
ot_price: {
title: '市场价'
},
stock: {
title: '库存'
},
bar_code: {
title: '商品编号'
},
weight: {
title: '重量KG'
},
volume: {
title: '体积(m³)'
}
}
export default {
name: 'CopyTaoBao',
components: { ueditorFrom, copyRecord },
data() {
const url = SettingMer.https + '/upload/image/0/file?ueditor=1&token=' + getToken()
return {
roterPre: roterPre,
modals: false,
loading: false,
loading1: false,
BaseURL: SettingMer.https || 'http://localhost:8080',
OneattrValue: [Object.assign({}, defaultObj.attrValue[0])], //
ManyAttrValue: [Object.assign({}, defaultObj.attrValue[0])], //
columnsBatch: [
{
title: '图片',
slot: 'image',
align: 'center',
minWidth: 80
},
{
title: '售价',
slot: 'price',
align: 'center',
minWidth: 95
},
{
title: '成本价',
slot: 'cost',
align: 'center',
minWidth: 95
},
{
title: '市场价',
slot: 'ot_price',
align: 'center',
minWidth: 95
},
{
title: '库存',
slot: 'stock',
align: 'center',
minWidth: 95
},
{
title: '商品编号',
slot: 'bar_code',
align: 'center',
minWidth: 120
},
{
title: '重量KG',
slot: 'weight',
align: 'center',
minWidth: 95
},
{
title: '体积(m³)',
slot: 'volume',
align: 'center',
minWidth: 95
}
],
manyTabDate: {},
count: 0,
modal_loading: false,
images: '',
soure_link: '',
modalPic: false,
isChoice: '',
gridPic: {
xl: 6,
lg: 8,
md: 12,
sm: 12,
xs: 12
},
gridBtn: {
xl: 4,
lg: 8,
md: 8,
sm: 8,
xs: 8
},
columns: [],
virtual: [
{ tit: '普通商品', id: 0, tit2: '物流发货' },
{ tit: '虚拟商品', id: 1, tit2: '虚拟发货' }
],
categoryList: [], //
merCateList: [], //
BrandList: [], //
propsMer: { emitPath: false, multiple: true },
tableFrom: {
mer_cate_id: '',
cate_id: '',
keyword: '',
type: '1',
is_gift_bag: ''
},
ruleInline: {
cate_id: [
{ required: true, message: '请选择商品分类', trigger: 'change' }
],
mer_cate_id: [
{
required: true,
message: '请选择商户分类',
trigger: 'change',
type: 'array',
min: '1'
}
],
temp_id: [
{
required: true,
message: '请选择运费模板',
trigger: 'change',
type: 'number'
}
],
brand_id: [
{ required: true, message: '请选择品牌', trigger: 'change' }
],
store_info: [{ required: true, message: '请输入商品简介', trigger: 'blur' }],
delivery_way: [{ required: true, message: '请选择送货方式', trigger: 'change' }]
},
grid: {
xl: 8,
lg: 8,
md: 12,
sm: 24,
xs: 24
},
grid2: {
xl: 12,
lg: 12,
md: 12,
sm: 24,
xs: 24
},
myConfig: {
autoHeightEnabled: false, //
initialFrameHeight: 500, //
initialFrameWidth: '100%', //
UEDITOR_HOME_URL: '/UEditor/',
'serverUrl': url,
'imageUrl': url,
'imageFieldName': 'file',
imageUrlPrefix: '',
'imageActionName': 'upfile',
'imageMaxSize': 2048000,
'imageAllowFiles': ['.png', '.jpg', '.jpeg', '.gif', '.bmp']
},
formThead: Object.assign({}, objTitle),
formValidate: Object.assign({}, defaultObj),
items: [
{
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
bar_code: '',
weight: 0,
volume: 0
}
],
shippingList: [],
guaranteeList: [], //
isData: false,
artFrom: {
type: 'taobao',
url: ''
},
tableIndex: 0,
labelPosition: 'right',
labelWidth: '120',
isMore: '',
taoBaoStatus: {},
attrInfo: {},
labelList: [],
oneFormBatch: [
{
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
bar_code: '',
weight: 0,
volume: 0
}
]
}
},
computed: {
attrValue() {
const obj = Object.assign({}, defaultObj.attrValue[0])
delete obj.image
return obj
},
// oneFormBatch() {
// const obj = [Object.assign({}, defaultObj.attrValue[0])]
// delete obj[0].bar_code
// return obj
// }
},
watch: {},
created() {
},
mounted() {
this.getCopyCount()
},
methods: {
//
getLabelLst() {
getProductLabelApi().then(res => {
this.labelList = res.data
})
.catch(res => {
this.$message.error(res.message)
})
},
//
getCopyCount() {
productCopyCountApi().then((res) => {
this.count = res.data.count
})
},
//
openRecords() {
this.$refs.copyRecord.getRecord()
},
batchDel() {
this.oneFormBatch = [
{
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
bar_code: '',
weight: 0,
volume: 0
}
]
},
batchAdd() {
for (const val of this.ManyAttrValue) {
this.$set(val, 'image', this.oneFormBatch[0].image)
this.$set(val, 'price', this.oneFormBatch[0].price)
this.$set(val, 'cost', this.oneFormBatch[0].cost)
this.$set(val, 'ot_price', this.oneFormBatch[0].ot_price)
this.$set(val, 'stock', this.oneFormBatch[0].stock)
this.$set(val, 'bar_code', this.oneFormBatch[0].bar_code)
this.$set(val, 'weight', this.oneFormBatch[0].weight)
this.$set(val, 'volume', this.oneFormBatch[0].volume)
this.$set(val, 'extension_one', this.oneFormBatch[0].extension_one)
this.$set(val, 'extension_two', this.oneFormBatch[0].extension_two)
}
},
//
delAttrTable(index) {
this.ManyAttrValue.splice(index, 1)
},
//
productGetTemplate() {
shippingListApi().then((res) => {
this.shippingList = res.data
})
},
//
getGuaranteeList() {
guaranteeTemplateListApi().then(res => {
this.guaranteeList = res.data
})
},
//
handleRemove(i) {
this.formValidate.slider_image.splice(i, 1)
},
//
checked(item, index) {
this.formValidate.image = item
},
//
goodsCategory() {
categoryListApi()
.then((res) => {
this.categoryList = res.data
})
.catch((res) => {
this.$message.error(res.message)
})
},
//
getCategorySelect() {
categorySelectApi()
.then((res) => {
this.merCateList = res.data
})
.catch((res) => {
this.$message.error(res.message)
})
},
//
getBrandListApi() {
categoryBrandListApi()
.then((res) => {
this.BrandList = res.data
})
.catch((res) => {
this.$message.error(res.message)
})
},
virtualbtn(id, type) {
this.formValidate.type = id
this.productCon()
},
watCh(val) {
const tmp = {}
const tmpTab = {}
this.formValidate.attr.forEach((o, i) => {
tmp['value' + i] = { title: o.value }
tmpTab['value' + i] = ''
})
this.ManyAttrValue = this.attrFormat(val)
console.log(this.ManyAttrValue)
this.ManyAttrValue.forEach((val, index) => {
const key = Object.values(val.detail).sort().join('/')
if (this.attrInfo[key]) this.ManyAttrValue[index] = this.attrInfo[key]
val.image = this.formValidate.image
})
this.attrInfo = {}
this.ManyAttrValue.forEach((val) => {
if (val.detail !== 'undefined' && val.detail !== null) {
this.attrInfo[Object.values(val.detail).sort().join('/')] = val
}
})
this.manyTabTit = tmp
this.manyTabDate = tmpTab
this.formThead = Object.assign({}, this.formThead, tmp)
},
attrFormat(arr) {
let data = []
const res = []
return format(arr)
function format(arr) {
if (arr.length > 1) {
arr.forEach((v, i) => {
if (i === 0) data = arr[i]['detail']
const tmp = []
data.forEach(function(vv) {
arr[i + 1] && arr[i + 1]['detail'] && arr[i + 1]['detail'].forEach(g => {
const rep2 = (i !== 0 ? '' : arr[i]['value'] + '_$_') + vv + '-$-' + arr[i + 1]['value'] + '_$_' + g
tmp.push(rep2)
if (i === (arr.length - 2)) {
const rep4 = {
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
bar_code: '',
weight: 0,
volume: 0,
brokerage: 0,
brokerage_two: 0
}
rep2.split('-$-').forEach((h, k) => {
const rep3 = h.split('_$_')
if (!rep4['detail']) rep4['detail'] = {}
rep4['detail'][rep3[0]] = rep3.length > 1 ? rep3[1] : ''
})
Object.values(rep4.detail).forEach((v, i) => {
rep4['value' + i] = v
})
res.push(rep4)
}
})
})
data = tmp.length ? tmp : []
})
} else {
const dataArr = []
arr.forEach((v, k) => {
v['detail'].forEach((vv, kk) => {
dataArr[kk] = v['value'] + '_' + vv
res[kk] = {
image: '',
price: 0,
cost: 0,
ot_price: 0,
stock: 0,
bar_code: '',
weight: 0,
volume: 0,
brokerage: 0,
brokerage_two: 0,
detail: { [v['value']]: vv }
}
Object.values(res[kk].detail).forEach((v, i) => {
res[kk]['value' + i] = v
})
})
})
data.push(dataArr.join('$&'))
}
console.log(res)
return res
}
},
//
add() {
if (this.soure_link) {
var reg = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/
if (!reg.test(this.soure_link)) {
return this.$message.warning('请输入以http开头的地址')
}
this.artFrom.url = this.soure_link
this.loading = true
crawlFromApi(this.artFrom)
.then((res) => {
const info = res.data
this.modals = false
this.$emit('info-data', info);
})
.catch((res) => {
this.$message.error(res.message)
this.loading = false
})
} else {
this.$message.warning('请输入链接地址!')
}
},
//
handleSubmit(name) {
this.$refs[name].validate((valid) => {
if (valid) {
this.modal_loading = true
this.formValidate.cate_id = this.formValidate.cate_id instanceof Array ? this.formValidate.cate_id.pop() : this.formValidate.cate_id
this.formValidate.once_count = this.formValidate.once_count || 0
if (this.formValidate.spec_type == 1) {
this.formValidate.attrValue = this.ManyAttrValue
} else {
this.formValidate.attrValue = this.OneattrValue
this.formValidate.attr = []
}
this.formValidate.is_copoy = 1
// this.formValidate.attrValue = this.items
this.loading1 = true
productCopyApi(this.formValidate)
.then((res) => {
this.$message.success('商品默认为不上架状态请手动上架商品!')
this.loading1 = false
setTimeout(() => {
this.modal_loading = false
}, 500)
setTimeout(() => {
this.modals = false
}, 600)
this.$emit('getSuccess')
})
.catch((res) => {
this.modal_loading = false
this.$message.error(res.message)
this.loading1 = false
})
} else {
if (!this.formValidate.cate_id) {
this.$message.warning('请填写商品分类!')
}
}
})
},
//
modalPicTap(tit, num, index) {
this.tableIndex = index
const _this = this
this.$modalUpload(function(img) {
console.log(_this.formValidate.attr[_this.tableIndex])
if (tit === '1') {
if (index === 'pi') {
_this.oneFormBatch[0].image = img[0]
} else {
_this.OneattrValue[0].image = img[0]
}
}
if (tit === '2') {
_this.ManyAttrValue[_this.tableIndex].image = img[0]
}
_this.modalPic = false
// _this.formValidate.image = img[0];
// _this.OneattrValue[0].image = img[0];
}, tit)
},
//
getPic(pc) {
this.callback(pc)
this.formValidate.attr[this.tableIndex].pic = pc.att_dir
this.modalPic = false
},
handleDragStart(e, item) {
this.dragging = item
},
handleDragEnd(e, item) {
this.dragging = null
},
// divdragenter/dragover
handleDragOver(e) {
// e.dataTransfer.dropEffect="move";//dragenter!
e.dataTransfer.dropEffect = 'move'
},
handleDragEnter(e, item) {
// dragstart
e.dataTransfer.effectAllowed = 'move'
if (item === this.dragging) {
return
}
const newItems = [...this.formValidate.slider_image]
const src = newItems.indexOf(this.dragging)
const dst = newItems.indexOf(item)
newItems.splice(dst, 0, ...newItems.splice(src, 1))
this.formValidate.slider_image = newItems
},
//
addCustomDialog(editorId) {
window.UE.registerUI(
'test-dialog',
function(editor, uiName) {
const dialog = new window.UE.ui.Dialog({
iframeUrl: '/admin/widget.images/index.html?fodder=dialog',
editor: editor,
name: uiName,
title: '上传图片',
cssRules: 'width:1200px;height:500px;padding:20px;'
})
this.dialog = dialog
var btn = new window.UE.ui.Button({
name: 'dialog-button',
title: '上传图片',
cssRules: `background-image: url(../../../assets/images/icons.png);background-position: -726px -77px;`,
onclick: function() {
dialog.render()
dialog.open()
}
})
return btn
},
)
}
}
}
</script>
<style scoped lang="scss">
/deep/.el-cascader {
display: block;
}
.dialog-scustom {
width: 1200px;
height: 600px;
}
.ela-btn {
color: #2d8cf0;
}
.Box .ivu-radio-wrapper {
margin-right: 25px;
}
.Box .numPut {
width: 80% !important;
}
.lunBox {
/* width 80px */
display: flex;
flex-direction: column;
border: 1px solid #0bb20c;
}
.pictrueBox {
display: inline-block;
}
.pictrue {
width: 50px;
height: 50px;
border: 1px dotted rgba(0, 0, 0, 0.1);
display: inline-block;
position: relative;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.pictrueTab {
width: 40px !important;
height: 40px !important;
}
.upLoad {
width: 40px;
height: 40px;
border: 1px dotted rgba(0, 0, 0, 0.1);
border-radius: 4px;
background: rgba(0, 0, 0, 0.02);
cursor: pointer;
}
.ft {
color: red;
}
.buttonGroup {
position: relative;
display: inline-block;
vertical-align: middle;
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.buttonGroup .small-btn {
position: relative;
float: left;
height: 24px;
padding: 0 7px;
font-size: 14px;
border-radius: 3px;
}
.buttonGroup .small-btn:first-child {
margin-left: 0;
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.virtual_boder {
border: 1px solid #1890FF;
}
.virtual_boder2 {
border: 1px solid #E7E7E7;
}
.virtual_san {
position: absolute;
bottom: 0;
right: 0;
width: 0;
height: 0;
border-bottom: 26px solid #1890FF;
border-left: 26px solid transparent;
}
.virtual_dui {
position: absolute;
bottom: -2px;
right: 2px;
color: #FFFFFF;
font-family: system-ui;
}
.virtual {
width: 120px;
height: 60px;
background: #FFFFFF;
border-radius: 3px;
float: left;
text-align: center;
padding-top: 8px;
position: relative;
cursor: pointer;
line-height: 23px;
.virtual_top {
font-size: 14px;
font-weight: 600;
color: rgba(0, 0, 0, 0.85);
}
.virtual_bottom {
font-size: 12px;
font-weight: 400;
color: #999999;
}
}
.virtual:nth-child(2n) {
margin: 0 12px;
}
</style>

View File

@ -1,6 +1,7 @@
<template>
<div class="divBox">
<el-card class="box-card">
<!--顶部内容-->
<div slot="header" class="clearfix">
<el-tabs v-model="tableFrom.type" @tab-click="getList(1),getLstFilterApi()">
<el-tab-pane v-for="(item,index) in headeNum" :key="index" :name="item.type.toString()" :label="item.name +'('+item.count +')' " />
@ -13,6 +14,7 @@
</el-form-item>
<el-form-item label="商户名称:">
<el-select v-model="tableFrom.mer_id" clearable filterable placeholder="请选择" class="selWidth" @change="getList(1)">
<el-option label="平台" :value="0" />
<el-option v-for="item in merSelect" :key="item.mer_id" :label="item.mer_name" :value="item.mer_id" />
</el-select>
</el-form-item>
@ -38,48 +40,49 @@
</el-select>
</el-form-item>
<el-form-item label="会员价设置:">
<el-select v-model="tableFrom.svip_price_type" placeholder="请选择" class="selWidth" clearable @change="getList(1)">
<el-option label="未设置" value="0" />
<el-option label="默认设置" value="1" />
<el-option label="自定义设置" value="2" />
</el-select>
</el-form-item>
<el-form-item label="商品推荐:">
<el-select v-model="tableFrom.hot_type" placeholder="请选择" class="filter-item selWidth" clearable filterable @change="getList(1)">
<el-option v-for="item in recommendList" :key="item.value" :label="item.name" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="商品类型:">
<el-select v-model="tableFrom.is_ficti" placeholder="请选择" class="filter-item selWidth" clearable @change="getList(1)">
<el-option v-for="item in productTypeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="商品搜索:">
<el-input v-model="tableFrom.keyword" @keyup.enter.native="getList(1)" placeholder="请输入商品名称,关键字,产品编号" class="selWidth">
<el-button slot="append" icon="el-icon-search" class="el-button-solt" @click="getList(1)" />
</el-input>
</el-form-item>
</el-form>
<el-select v-model="tableFrom.svip_price_type" placeholder="请选择" class="selWidth" clearable @change="getList(1)">
<el-option label="未设置" value="0" />
<el-option label="默认设置" value="1" />
<el-option label="自定义设置" value="2" />
</el-select>
</el-form-item>
<el-form-item label="商品推荐:">
<el-select v-model="tableFrom.hot_type" placeholder="请选择" class="filter-item selWidth" clearable filterable @change="getList(1)">
<el-option v-for="item in recommendList" :key="item.value" :label="item.name" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="商品类型:">
<el-select v-model="tableFrom.is_ficti" placeholder="请选择" class="filter-item selWidth" clearable @change="getList(1)">
<el-option v-for="item in productTypeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="商品搜索:">
<el-input v-model="tableFrom.keyword" @keyup.enter.native="getList(1)" placeholder="请输入商品名称,关键字,产品编号" class="selWidth">
<el-button slot="append" icon="el-icon-search" class="el-button-solt" @click="getList(1)" />
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<router-link :to="{ path:`${roterPre}` + '/product/addProduct' }">
<el-button size="small" type="primary">添加商品</el-button>
</router-link>
<el-button v-show="tableFrom.type === '6'" size="mini" :disabled="multipleSelection.length==0" @click="batch">批量审核</el-button>
<el-button size="mini" :disabled="multipleSelection.length==0 " @click="batchOff">批量强制下架</el-button>
<el-button size="mini" :disabled="multipleSelection.length==0 " @click="batchShow(0)">批量不显示</el-button>
<el-button size="mini" :disabled="multipleSelection.length==0 " @click="batchShow(1)">批量显示</el-button>
<el-button :disabled="multipleSelection.length==0" size="mini" @click="batchLabel">批量设置标签</el-button>
<el-button :disabled="multipleSelection.length==0" size="mini" @click="batchRecommend">批量设置推荐</el-button>
</div>
<el-button v-show="tableFrom.type === '6'" size="mini" :disabled="multipleSelection.length==0" @click="batch">批量审核</el-button>
<el-button size="mini" :disabled="multipleSelection.length==0 " @click="batchOff">批量强制下架</el-button>
<el-button size="mini" :disabled="multipleSelection.length==0 " @click="batchShow(0)">批量不显示</el-button>
<el-button size="mini" :disabled="multipleSelection.length==0 " @click="batchShow(1)">批量显示</el-button>
<el-button :disabled="multipleSelection.length==0" size="mini" @click="batchLabel">批量设置标签</el-button>
<el-button :disabled="multipleSelection.length==0" size="mini" @click="batchRecommend">批量设置推荐</el-button>
</div>
<!--表格信息-->
<el-table v-loading="listLoading" :data="tableData.data" style="width: 100%" size="mini" @selection-change="handleSelectionChange">
<el-table-column v-if="Number(tableFrom.type)<7" key="2" type="selection" width="55" />
<el-table-column type="expand">
<el-table-column v-if="Number(tableFrom.type)<7" key="2" type="selection" width="30" />
<el-table-column type="expand" align="center" width="50">
<template slot-scope="props">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="平台分类:">
<span>{{ props.row.storeCategory?props.row.storeCategory.cate_name:'-' }}</span>
</el-form-item>
<!-- <el-form-item label="商户类别:">
<span v-if="props.row.merchant" class="spBlock">{{ props.row.merchant .is_trader ? '自营' : '非自营' }}</span>
</el-form-item> -->
<el-form-item label="商品分类:">
<template v-if="props.row.merCateId.length">
<span v-for="(item, index) in props.row.merCateId" :key="index" class="mr10">{{ item.category ? item.category.cate_name : '-' }}</span>
@ -101,71 +104,53 @@
<el-form-item label="已售数量:">
<span>{{ props.row.ficti | filterEmpty }}</span>
</el-form-item>
<!-- <el-form-item label="抵扣积分:">
<span>{{ props.row.integral_total }}</span>
</el-form-item>
<el-form-item label="积分抵扣金额:">
<span>{{ props.row.integral_price_total }}</span>
</el-form-item> -->
</el-form>
</template>
</el-table-column>
<el-table-column prop="product_id" label="ID" min-width="80" />
<el-table-column label="商品图" min-width="70">
<el-table-column prop="product_id" label="ID" min-width="50" align="center"/>
<el-table-column label="商品信息" min-width="230" align="center">
<template slot-scope="scope">
<div class="demo-image__preview">
<el-image style="width: 36px; height: 36px" :src="scope.row.image" :preview-src-list="[scope.row.image]" />
<div class="user-content">
<div class="user-avatar">
<el-image class="logo" :src="scope.row.image" :preview-src-list="[scope.row.image]" />
</div>
<div class="user-info">
<div class="nickname">{{ scope.row.store_name || '-' }}</div>
<div :class="['agent-type-text','tags_name', 'name'+scope.row.spec_type]">{{ scope.row.spec_type==0 ? '[单规格]' : '[多规格]' }}</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="store_name" label="商品名称" min-width="200">
<template slot-scope="scope">
<div><span class="tags_name" :class="'name'+scope.row.spec_type">{{ scope.row.spec_type==0 ? '[单规格]' : '[多规格]' }}</span>{{ scope.row.store_name || '-' }}</div>
</template>
</el-table-column>
<el-table-column label="商户名称" min-width="150">
<el-table-column label="商户名称" min-width="150" align="center">
<template slot-scope="scope">
<span>{{ scope.row.merchant ? scope.row.merchant.mer_name : '' }}</span>
</template>
</el-table-column>
<!-- <el-table-column prop="mer_name" label="商户类别" min-width="90">
<template slot-scope="scope">
<span v-if="scope.row.merchant" class="spBlock">{{ scope.row.merchant .is_trader ? '自营' : '非自营' }}</span>
</template>
</el-table-column> -->
<el-table-column prop="price" label="商品售价" min-width="80" />
<!-- <el-table-column prop="svip_price" label="会员价" min-width="70">
<template slot-scope="scope">
<span>{{ scope.row.svip_price || '-' }}</span>
</template>
</el-table-column> -->
<el-table-column prop="sales" label="销量" min-width="70" />
<!-- <el-table-column prop="integral_total" label="抵扣积分" min-width="90" />
<el-table-column prop="integral_price_total" label="积分抵扣金额" min-width="90" /> -->
<el-table-column prop="stock" label="库存" min-width="70" />
<el-table-column label="推荐级别" min-width="150">
<el-table-column prop="price" label="商品售价" min-width="80" align="center"/>
<el-table-column prop="sales" label="销量" min-width="70" align="center"/>
<el-table-column prop="stock" label="库存" min-width="70" align="center"/>
<el-table-column label="推荐级别" min-width="130" align="center">
<template slot-scope="scope">
<el-rate disabled v-model="scope.row.star" :colors="colors">
</el-rate>
</template>
</el-table-column>
<el-table-column prop="rank" label="排序" min-width="60" />
<el-table-column prop="status" label="是否显示" min-width="80">
<el-table-column prop="rank" label="排序" min-width="50" align="center"/>
<el-table-column prop="status" label="是否显示" min-width="80" align="center">
<template slot-scope="scope">
<el-switch v-model="scope.row.is_used" :active-value="1" :inactive-value="0" active-text="显示" inactive-text="隐藏" @change="onchangeIsShow(scope.row)" />
<div class="switch-content">
<el-switch v-model="scope.row.is_used" :active-value="1" :inactive-value="0" active-text="显示" inactive-text="隐藏" @change="onchangeIsShow(scope.row)" />
</div>
</template>
</el-table-column>
<el-table-column prop="stock" label="商品状态" min-width="90">
<el-table-column prop="stock" label="商品状态" min-width="90" align="center">
<template slot-scope="scope">
<span>{{ scope.row.us_status | productStatusFilter }}</span>
<div class="switch-content" v-if="scope.row.mer_id <= 0">
<el-switch :value="Number(scope.row.us_status) == 1" active-text="上架" inactive-text="下架" @change="changeStatus(scope.row)" />
</div>
<span v-else>{{ scope.row.us_status | productStatusFilter }}</span>
</template>
</el-table-column>
<!-- <el-table-column prop="stock" label="标签" max-height="120" min-width="90" show-overflow-tooltip>
<template slot-scope="scope">
<span v-for="(item,index) in scope.row.sys_labels" :key="index" class="label-list">{{ item.name }}</span>
</template>
</el-table-column>
<el-table-column prop="create_time" label="创建时间" min-width="150" /> -->
<el-table-column v-if="Number(tableFrom.type) < 7" key="8" label="操作" min-width="180" fixed="right" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" @click="onDetails(scope.row.product_id)">详情</el-button>
@ -178,7 +163,7 @@
</span>
<el-dropdown-menu slot="dropdown">
<!-- <el-dropdown-item @click.native="onDetails(scope.row.product_id)">查看详情</el-dropdown-item> -->
<el-dropdown-item v-if="Number(tableFrom.type) < 7" @click.native="onEdit(scope.row.product_id)">编辑商品</el-dropdown-item>
<el-dropdown-item v-if="Number(tableFrom.type) < 7" @click.native="onEdit(scope.row)">编辑商品</el-dropdown-item>
<el-dropdown-item v-if="tableFrom.type != 5">
<router-link :to="{path: roterPre + '/product/comment/?product_id=' + scope.row.product_id}" style="font-size: 14px;">
查看评价
@ -306,7 +291,8 @@ import {
updatetProductLabel,
batchesLabelsApi,
batchesRecommendApi,
batchesOnOffApi
batchesOnOffApi,
changeProductStatus
} from '@/api/product'
import { roterPre } from '@/settings'
import infoFrom from './info'
@ -385,7 +371,7 @@ export default {
store_name: '',
rank: '',
us_status: '',
star: ''
star: 0
},
productStatusList: [
{ label: "上架显示", value: 1 },
@ -454,15 +440,24 @@ export default {
this.getLstFilterApi()
},
onchangeIsShow(row) {
changeApi(row.product_id, row.is_used).then(({
message
}) => {
changeApi(row.product_id, row.is_used).then(({message}) => {
this.$message.success(message)
this.getList('')
this.getLstFilterApi()
}).catch(({
message
}) => {
}).catch(({message}) => {
this.$message.error(message)
})
},
//
changeStatus(row){
//
let status = Number(row.us_status) == 1 ? 0 : 1;
//
changeProductStatus(row.product_id, status).then(({message}) => {
this.$message.success(message)
this.getList('')
this.getLstFilterApi()
}).catch(({message}) => {
this.$message.error(message)
})
},
@ -573,10 +568,16 @@ export default {
this.fullscreenLoading = false
})
},
onEdit(id) {
this.productId = id
this.getInfo(id)
this.dialogVisible = true
onEdit(product) {
let merId = product.mer_id || 0;
// merId 0
if(merId <= 0){
this.$router.push({path: this.roterPre + '/product/addProduct/' + product.product_id});
}else{
this.productId = product.product_id
this.getInfo(product.product_id)
this.dialogVisible = true
}
},
//
toVirtualSales(id) {
@ -752,6 +753,22 @@ export default {
/deep/.el-select-dropdown__item{
max-width: 350px!important;
}
/deep/ .el-table__cell {
.cell{
padding: 0!important;
.el-table__expand-icon{
height: 50px!important;
line-height: 50px!important;
.el-icon.el-icon-arrow-right{
font-size: 30px !important;
height: 50px !important;
line-height: 50px !important;
text-align: center;
position: unset!important;
}
}
}
}
.template{
overflow: hidden;
}
@ -768,7 +785,7 @@ export default {
background: rgba(0, 0, 0, 0.5);
}
.tags_name{
font-size: 10px;
font-size: 13px;
height: 16px;
line-height: 16px;
padding: 0 2px;
@ -812,9 +829,78 @@ table .el-image {
color: #409EFF;
font-size: 12px;
}
.el-icon-arrow-down {
font-size: 12px;
}
.user-content{
--user-content-height-: 80px;
height: var(--user-content-height-);
width: 100%;
display: inline-flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
.user-avatar{
height: var(--user-content-height-);
width: var(--user-content-height-);
display: inline-flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
.logo{
height: 80%!important;
width: 80%!important;
}
}
.user-info{
max-width: calc(100% - var(--user-content-height-));
height: var(--user-content-height-);
display: inline-flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: center;
align-items: flex-start;
.nickname{
width: 100%;
height: 25px;
line-height: 25px;
text-align: left;
font-size: 15px;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
.user-id{
color: #fff;
background-color: #409eff;
border-color: #409eff;
height: 18px;
line-height: 20px;
font-size: 13px;
padding: 0 5px;
border-radius: 5px;
margin-left: 10px;
width: max-content!important;
}
}
.user-id{
width: 100%;
text-align: left;
font-size: 13px;
line-height: calc(var(--user-content-height- * 35%));
}
}
}
.switch-content{
text-align: justify!important;
display: inline-flex;
}
</style>