初始化项目
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
404 page
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: '404'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="用户名称,电话,身份证号">
|
||||
<a-input v-decorator="['search']" placeholder="请输入用户名称,电话,身份证号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="最后使用时间">
|
||||
<a-range-picker format="YYYY-MM-DD" v-decorator="['last_called_at']" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="account_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 公司 -->
|
||||
<span slot="company" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 100px;">{{ item.company.name }}</p>
|
||||
</span>
|
||||
<!-- 最后使用时间 -->
|
||||
<span slot="last_called_at" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 150px;">{{ item.last_called_at | dateFormat }}</p>
|
||||
</span>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/account'
|
||||
import { STable } from '@/components/Table'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'account_id'
|
||||
},
|
||||
{
|
||||
title: '公司信息',
|
||||
dataIndex: 'company',
|
||||
scopedSlots: { customRender: 'company' }
|
||||
},
|
||||
{
|
||||
title: '用户编号',
|
||||
dataIndex: 'userNo'
|
||||
},
|
||||
{
|
||||
title: '用户姓名',
|
||||
dataIndex: 'userName'
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
dataIndex: 'mobile'
|
||||
},
|
||||
{
|
||||
title: '用户角色',
|
||||
dataIndex: 'userType',
|
||||
scopedSlots: { customRender: 'userType' }
|
||||
},
|
||||
{
|
||||
title: '用户身份证号',
|
||||
dataIndex: 'userIdCard'
|
||||
},
|
||||
{
|
||||
title: '最后使用时间',
|
||||
dataIndex: 'last_called_at',
|
||||
scopedSlots: { customRender: 'last_called_at' }
|
||||
},
|
||||
{
|
||||
title: '注册时间',
|
||||
dataIndex: 'create_time'
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="收货人名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入收货人名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="区域" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['province', {rules: [{required: true, message: '请选择省份'}]}]"
|
||||
placeholder="请选择省份"
|
||||
@change="getOptionCity"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.provinces"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['city', {rules: [{required: true, message: '请选择城市'}]}]"
|
||||
placeholder="请选择城市"
|
||||
@change="getOptionArea"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.cities"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['area', {rules: [{required: true, message: '请选择区县'}]}]"
|
||||
placeholder="请选择区县"
|
||||
@change="getOptionStreet"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.districts"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['street', {rules: [{required: true, message: '请选择街道'}]}]"
|
||||
placeholder="请选择街道"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.streets"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="详细地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入详细地址"
|
||||
v-decorator="['detail', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['status', {initialValue: 10, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio
|
||||
v-for="(item, index) in AddressStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value">{{ item.name }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as AddressApi from '@/api/address'
|
||||
import AddressModel from '@/common/model/address/Index'
|
||||
import {
|
||||
AddressStatusEnum
|
||||
} from '@/common/enum/address'
|
||||
import { assignment } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 表单数据
|
||||
formData: AddressModel.formData,
|
||||
addressData: {
|
||||
provinces: [],
|
||||
cities: [],
|
||||
districts: [],
|
||||
streets: []
|
||||
},
|
||||
selectedAddress: {
|
||||
province: '',
|
||||
city: '',
|
||||
area: '',
|
||||
street: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
AddressStatusEnum
|
||||
})
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
this.isLoading = true
|
||||
// 获取form所需的数据
|
||||
AddressModel.getFromData()
|
||||
.then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
this.getRegion()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
// 获取区域下拉框
|
||||
getRegion () {
|
||||
this.isLoading = true
|
||||
AddressApi.getRegion({ form: this.selectedAddress })
|
||||
.then(result => {
|
||||
switch (result.data.field) {
|
||||
case 'city':
|
||||
this.addressData['cities'] = result.data.list
|
||||
break
|
||||
case 'area':
|
||||
this.addressData['districts'] = result.data.list
|
||||
break
|
||||
case 'street':
|
||||
this.addressData['streets'] = result.data.list
|
||||
break
|
||||
default:
|
||||
this.addressData['provinces'] = result.data.list
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
// 获取区域下拉框
|
||||
getOptionCity (val) {
|
||||
this.selectedAddress['province'] = val
|
||||
this.form.setFieldsValue({ 'city': '', 'area': '', 'street': '' })
|
||||
this.getRegion()
|
||||
},
|
||||
getOptionArea (val) {
|
||||
this.selectedAddress['city'] = val
|
||||
this.form.setFieldsValue({ 'area': '', 'street': '' })
|
||||
this.getRegion()
|
||||
},
|
||||
getOptionStreet (val) {
|
||||
this.selectedAddress['area'] = val
|
||||
this.form.setFieldsValue({ 'street': '' })
|
||||
this.getRegion()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
AddressApi.add({ form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,291 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="请选择使用状态">
|
||||
<a-select v-decorator="['status', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in AddressStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入姓名">
|
||||
<a-input v-decorator="['name']" placeholder="请输入姓名" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入省份">
|
||||
<a-input v-decorator="['province']" placeholder="请输入省份" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入城市">
|
||||
<a-input v-decorator="['city']" placeholder="请输入城市" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入地区">
|
||||
<a-input v-decorator="['area']" placeholder="请输入地区" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入街道">
|
||||
<a-input v-decorator="['street']" placeholder="请输入街道" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入详细地址">
|
||||
<a-input v-decorator="['name']" placeholder="请输入详细地址" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<a-button
|
||||
v-if="$auth('/address/create')"
|
||||
class="fl-l"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleCreate"
|
||||
>新增</a-button>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>
|
||||
<a-button
|
||||
icon="arrow-up"
|
||||
@click="handleUpdateState(selectedRowKeys, true)"
|
||||
>未使用</a-button>
|
||||
<a-button
|
||||
icon="arrow-down"
|
||||
@click="handleUpdateState(selectedRowKeys, false)"
|
||||
>已使用</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="address_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 详细地址 -->
|
||||
<span slot="address" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 使用状态 -->
|
||||
<span slot="status" slot-scope="text, item">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text == 10 ? 'green' : 'red'"
|
||||
@click="handleUpdateState([item.address_id], text != 10)"
|
||||
>{{ text == 10 ? '未使用' : '已使用' }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<div class="actions" slot="action" slot-scope="text, item">
|
||||
<router-link :to="{ path: '/address/update', query: { addressId: item.address_id } }">编辑</router-link>
|
||||
<a v-action:delete @click="handleDelete([item.address_id])">删除</a>
|
||||
</div>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as AddressApi from '@/api/address'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import {
|
||||
AddressStatusEnum
|
||||
} from '@/common/enum/address'
|
||||
import { assignment, inArray } from '@/utils/util'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '地址ID',
|
||||
dataIndex: 'address_id'
|
||||
},
|
||||
{
|
||||
title: '收货人名称',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '省份',
|
||||
dataIndex: 'province'
|
||||
},
|
||||
{
|
||||
title: '城市',
|
||||
dataIndex: 'city'
|
||||
},
|
||||
{
|
||||
title: '地区',
|
||||
dataIndex: 'area'
|
||||
},
|
||||
{
|
||||
title: '街道',
|
||||
dataIndex: 'street'
|
||||
},
|
||||
{
|
||||
title: '详细地址',
|
||||
dataIndex: 'detail',
|
||||
width: '307px'
|
||||
},
|
||||
{
|
||||
title: '使用状态',
|
||||
dataIndex: 'status',
|
||||
width: '80px',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '150px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return AddressApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray,
|
||||
AddressStatusEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
/**
|
||||
* 修改使用状态
|
||||
*/
|
||||
handleUpdateState (addressIds, state = true) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要修改地址状态为' + (state ? '未使用' : '已使用') + '?',
|
||||
content: '地址状态修改',
|
||||
onOk () {
|
||||
return AddressApi.changeState({ addressIds, state })
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (addressIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return AddressApi.deleted(addressIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleCreate () {
|
||||
this.$router.push('/address/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="收货人名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入收货人名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="区域" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['province', {rules: [{required: true, message: '请选择省份'}]}]"
|
||||
placeholder="请选择省份"
|
||||
@change="getOptionCity"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.provinces"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['city', {rules: [{required: true, message: '请选择城市'}]}]"
|
||||
placeholder="请选择城市"
|
||||
@change="getOptionArea"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.cities"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['area', {rules: [{required: true, message: '请选择区县'}]}]"
|
||||
placeholder="请选择区县"
|
||||
@change="getOptionStreet"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.districts"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
style="width: 150px"
|
||||
v-decorator="['street', {rules: [{required: true, message: '请选择街道'}]}]"
|
||||
placeholder="请选择街道"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in addressData.streets"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="详细地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入详细地址"
|
||||
v-decorator="['detail', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['status', { rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio
|
||||
v-for="(item, index) in AddressStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value">{{ item.name }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as AddressApi from '@/api/address'
|
||||
import { InputNumberGroup } from '@/components'
|
||||
import AddressModel from '@/common/model/address/Index'
|
||||
import { isEmptyObject, assignment } from '@/utils/util'
|
||||
import {
|
||||
AddressStatusEnum
|
||||
} from '@/common/enum/address'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InputNumberGroup
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 商户ID
|
||||
addressId: null,
|
||||
// 表单数据
|
||||
formData: AddressModel.formData,
|
||||
addressData: {
|
||||
provinces: [],
|
||||
cities: [],
|
||||
districts: [],
|
||||
streets: []
|
||||
},
|
||||
selectedAddress: {
|
||||
province: '',
|
||||
city: '',
|
||||
area: '',
|
||||
street: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
AddressStatusEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
// 初始化数据
|
||||
this.initData()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 销毁商户详情
|
||||
AddressModel.formData.address = {}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 初始化数据
|
||||
initData () {
|
||||
// 记录地址ID
|
||||
this.addressId = this.$route.query.addressId
|
||||
// 获取form所需的数据
|
||||
this.isLoading = true
|
||||
AddressModel.getFromData(this.addressId)
|
||||
.then(() => {
|
||||
// 商户表单数据
|
||||
if (!isEmptyObject(this.form.getFieldsValue())) {
|
||||
this.form.setFieldsValue(AddressModel.getFieldsValue())
|
||||
}
|
||||
this.addressData['provinces'] = this.formData.provinces
|
||||
this.addressData['cities'] = this.formData.cities
|
||||
this.addressData['districts'] = this.formData.districts
|
||||
this.addressData['streets'] = this.formData.streets
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 定位到错误的tab选项卡
|
||||
*/
|
||||
onTargetTabError (errors) {
|
||||
},
|
||||
|
||||
// 获取区域下拉框
|
||||
getRegion () {
|
||||
this.isLoading = true
|
||||
AddressApi.getRegion({ form: this.selectedAddress })
|
||||
.then(result => {
|
||||
switch (result.data.field) {
|
||||
case 'city':
|
||||
this.addressData['cities'] = result.data.list
|
||||
break
|
||||
case 'area':
|
||||
this.addressData['districts'] = result.data.list
|
||||
break
|
||||
case 'street':
|
||||
this.addressData['streets'] = result.data.list
|
||||
break
|
||||
default:
|
||||
this.addressData['provinces'] = result.data.list
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
// 获取区域下拉框
|
||||
getOptionCity (val) {
|
||||
this.selectedAddress['province'] = val
|
||||
this.form.setFieldsValue({ 'city': '', 'area': '', 'street': '' })
|
||||
this.getRegion()
|
||||
},
|
||||
getOptionArea (val) {
|
||||
this.selectedAddress['city'] = val
|
||||
this.form.setFieldsValue({ 'area': '', 'street': '' })
|
||||
this.getRegion()
|
||||
},
|
||||
getOptionStreet (val) {
|
||||
this.selectedAddress['area'] = val
|
||||
this.form.setFieldsValue({ 'street': '' })
|
||||
this.getRegion()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
AddressApi.edit({ addressId: this.addressId, form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
.tabs-content {
|
||||
.tab-pane {
|
||||
animation: fadenum 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 18px;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-number-group {
|
||||
margin: 3px 0;
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="卡号">
|
||||
<a-input v-decorator="['card_number']" placeholder="请输入卡号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="兑换用户ID">
|
||||
<a-input v-decorator="['user_id']" placeholder="请输入兑换用户ID" />
|
||||
</a-form-item>
|
||||
<a-form-item label="批号">
|
||||
<a-input v-decorator="['batch']" placeholder="请输入批号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="使用状态">
|
||||
<a-select v-decorator="['is_used', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in CardStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="打印状态">
|
||||
<a-select v-decorator="['is_print', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in PrintStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<a-button class="fl-l" type="primary" icon="plus" v-action:addCards @click="handleCards()">创建兑换卡</a-button>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<!-- <a-button-->
|
||||
<!-- v-action:pdf-->
|
||||
<!-- @click="handlePDF(selectedRowKeys)"-->
|
||||
<!-- >生成实体卡</a-button>-->
|
||||
<!-- <a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>-->
|
||||
<a-button
|
||||
v-action:status
|
||||
icon="arrow-up"
|
||||
@click="handleUpdateStatus(selectedRowKeys, true)"
|
||||
>已使用</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="card_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="18"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 密钥 -->
|
||||
<span slot="secret_key" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 150px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 密钥一维码 -->
|
||||
<span slot="barcode" slot-scope="item">
|
||||
<img v-if="item.file_path" width="260" :src="publicConfig.BASE_DOMAIN+item.file_path" alt="一维码图片" />
|
||||
</span>
|
||||
<!-- 兑换卡使用状态 -->
|
||||
<span slot="is_used" slot-scope="text">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text === 20 ? 'green' : 'red'"
|
||||
>{{ text === 20 ? '已使用' : '未使用' }}</a-tag>
|
||||
</span>
|
||||
<!-- 兑换卡打印状态 -->
|
||||
<span slot="is_print" slot-scope="text">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text === 1 ? 'green' : 'red'"
|
||||
>{{ text === 1 ? '已打印' : '未打印' }}</a-tag>
|
||||
</span>
|
||||
<!-- 使用人 -->
|
||||
<span slot="user" slot-scope="text, item">
|
||||
<p>{{ item.user ? item.user.mobile : '18281516816' }}</p>
|
||||
</span>
|
||||
<!-- 使用时间 -->
|
||||
<span slot="used_time" slot-scope="text">
|
||||
<p>{{ text | dateFormat }}</p>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<!-- <div class="actions" slot="action" slot-scope="text, item">-->
|
||||
<!-- <a v-action:delete @click="handleDelete([item.card_id])">删除</a>-->
|
||||
<!-- </div>-->
|
||||
</s-table>
|
||||
<AddCardsForm ref="AddCardsForm" :moneyList="moneyList" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CardApi from '@/api/card'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import { CardStatusEnum, PrintStatusEnum, CardMoneyEnum } from '@/common/enum/card'
|
||||
import { AddCardsForm } from './modules'
|
||||
import { assignment, inArray } from '@/utils/util'
|
||||
import store from '@/store'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '兑换卡ID',
|
||||
width: '70px',
|
||||
dataIndex: 'card_id'
|
||||
},
|
||||
{
|
||||
title: '卡号',
|
||||
width: '150px',
|
||||
dataIndex: 'card_number'
|
||||
},
|
||||
{
|
||||
title: '卡密',
|
||||
width: '150px',
|
||||
dataIndex: 'secret_key',
|
||||
scopedSlots: { customRender: 'secret_key' }
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
width: '100px',
|
||||
dataIndex: 'amount'
|
||||
},
|
||||
{
|
||||
title: '批次号',
|
||||
width: '150px',
|
||||
dataIndex: 'batch'
|
||||
},
|
||||
{
|
||||
title: '使用状态',
|
||||
width: '90px',
|
||||
dataIndex: 'is_used',
|
||||
scopedSlots: { customRender: 'is_used' }
|
||||
},
|
||||
// {
|
||||
// title: '打印状态',
|
||||
// width: '90px',
|
||||
// dataIndex: 'is_print',
|
||||
// scopedSlots: { customRender: 'is_print' }
|
||||
// },
|
||||
{
|
||||
title: '使用人',
|
||||
width: '100px',
|
||||
scopedSlots: { customRender: 'user' }
|
||||
},
|
||||
{
|
||||
title: '使用时间',
|
||||
width: '130px',
|
||||
dataIndex: 'used_time',
|
||||
scopedSlots: { customRender: 'used_time' }
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
width: '130px',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '一维码',
|
||||
width: '300px',
|
||||
scopedSlots: { customRender: 'barcode' }
|
||||
}
|
||||
// {
|
||||
// title: '操作',
|
||||
// dataIndex: 'action',
|
||||
// width: '100px',
|
||||
// fixed: 'right',
|
||||
// scopedSlots: { customRender: 'action' }
|
||||
// }
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
AddCardsForm,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
publicConfig: store.getters.publicConfig,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
moneyList: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CardApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray,
|
||||
CardStatusEnum,
|
||||
PrintStatusEnum,
|
||||
CardMoneyEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
this.moneyList = CardMoneyEnum.data
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
// 修改商品状态(上下架)
|
||||
handleUpdateStatus (cardIds, state = true) {
|
||||
if (!this.$auth('/card/changeState')) {
|
||||
return false
|
||||
}
|
||||
if (!state) {
|
||||
this.$message.error('不能改为未使用状态', 1.5)
|
||||
return false
|
||||
}
|
||||
this.isLoading = true
|
||||
CardApi.changeState({ cardIds, state })
|
||||
.then(result => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
this.handleRefresh()
|
||||
})
|
||||
.finally(result => { this.isLoading = false })
|
||||
},
|
||||
// 生成PDF
|
||||
handlePDF (cardIds) {
|
||||
if (!this.$auth('/card/pdf')) {
|
||||
return false
|
||||
}
|
||||
this.isLoading = true
|
||||
CardApi.pdf({ cardIds })
|
||||
.then(result => {
|
||||
this.downLoadFile(result.data.url)
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
this.handleRefresh()
|
||||
})
|
||||
.finally(result => { this.isLoading = false })
|
||||
},
|
||||
// 商户对接参数
|
||||
handleCards () {
|
||||
this.$refs.AddCardsForm.handle()
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (cardIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return CardApi.deleted(cardIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
downLoadFile (url) {
|
||||
const fileName = url.slice(url.lastIndexOf('/') + 1) // 提取文件名
|
||||
|
||||
fetch(url)
|
||||
.then((res) => {
|
||||
if (!res.ok) {
|
||||
throw new Error('Network response was not ok')
|
||||
}
|
||||
return res.blob()
|
||||
})
|
||||
.then((blob) => {
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = fileName // 设置下载文件的文件名
|
||||
document.body.appendChild(link)
|
||||
link.click() // 触发下载
|
||||
window.URL.revokeObjectURL(link.href) // 释放URL对象
|
||||
document.body.removeChild(link) // 清理DOM
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('下载失败:', error) // 错误处理
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="批号">
|
||||
<a-input v-decorator="['batch']" placeholder="请输入批号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="下载状态">
|
||||
<a-select v-decorator="['is_download', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in DownloadStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button
|
||||
v-action:status
|
||||
icon="arrow-down "
|
||||
@click="handleUpdateStatus(selectedRowKeys, true)"
|
||||
>已下载</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="print_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="18"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 兑换卡下载状态 -->
|
||||
<span slot="is_download" slot-scope="text">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text === 1 ? 'green' : 'red'"
|
||||
>{{ text === 1 ? '已下载' : '未下载' }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作 -->
|
||||
<span class="actions" slot="action" slot-scope="text, item">
|
||||
<a
|
||||
v-if="item.is_download === 0"
|
||||
v-action:download
|
||||
:href="item.download_url"
|
||||
target="_blank"
|
||||
>下载</a>
|
||||
</span>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CardPrintApi from '@/api/card/print'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import { DownloadStatusEnum } from '@/common/enum/card'
|
||||
import { AddCardsForm } from './modules'
|
||||
import { assignment, inArray } from '@/utils/util'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '打印记录ID',
|
||||
width: '70px',
|
||||
dataIndex: 'print_id'
|
||||
},
|
||||
{
|
||||
title: '批次号',
|
||||
width: '100px',
|
||||
dataIndex: 'batch'
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
width: '100px',
|
||||
dataIndex: 'amount'
|
||||
},
|
||||
{
|
||||
title: '打印数量',
|
||||
width: '100px',
|
||||
dataIndex: 'num'
|
||||
},
|
||||
{
|
||||
title: '下载状态',
|
||||
width: '90px',
|
||||
dataIndex: 'is_download',
|
||||
scopedSlots: { customRender: 'is_download' }
|
||||
},
|
||||
{
|
||||
title: '下载时间',
|
||||
width: '130px',
|
||||
dataIndex: 'download_time'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
width: '130px',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '100px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
AddCardsForm,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CardPrintApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray,
|
||||
DownloadStatusEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
// 修改下载状态
|
||||
handleUpdateStatus (printIds, state = true) {
|
||||
if (!state) {
|
||||
this.$message.error('不能改为未下载状态', 1.5)
|
||||
return false
|
||||
}
|
||||
this.isLoading = true
|
||||
CardPrintApi.changeState({ printIds, state })
|
||||
.then(result => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
this.handleRefresh()
|
||||
})
|
||||
.finally(result => { this.isLoading = false })
|
||||
},
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<a-modal
|
||||
class="noborder"
|
||||
:title="title"
|
||||
:width="520"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<template>
|
||||
<a-form-item label="兑换卡数量" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
18
|
||||
</a-form-item>
|
||||
<a-form-item label="兑换卡金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select v-decorator="['amount', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in moneyList"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/card'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
// 金额列表
|
||||
moneyList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '创建实体兑换卡',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 显示对话框
|
||||
handle () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.addCards({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-modal-body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,5 @@
|
||||
import AddCardsForm from './AddCardsForm'
|
||||
|
||||
export {
|
||||
AddCardsForm
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
.tabs-content {
|
||||
.tab-pane {
|
||||
animation: fadenum 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 18px;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-number-group {
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.company-textarea{
|
||||
height: 80px;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="下单时间">
|
||||
<a-range-picker format="YYYY-MM-DD" v-decorator="['betweenTime']" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入商户名">
|
||||
<a-input v-decorator="['name']" placeholder="请输入商户名" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="stat-form">
|
||||
<a-form-item class="stat-item" label="总金额">{{ totalMoney }}</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="merchant_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CensusApi from '@/api/census'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import { assignment, inArray } from '@/utils/util'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '商户ID',
|
||||
dataIndex: 'merchant_id'
|
||||
},
|
||||
{
|
||||
title: '商户名称',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '今日分油订单金额',
|
||||
dataIndex: 'today'
|
||||
},
|
||||
{
|
||||
title: '分油总金额',
|
||||
dataIndex: 'amount'
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
totalMoney: 0,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CensusApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray
|
||||
})
|
||||
},
|
||||
created () {
|
||||
this.stat()
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取统计数据
|
||||
stat () {
|
||||
this.isLoading = true
|
||||
const { queryParam } = this
|
||||
return CensusApi.stat({ ...queryParam })
|
||||
.then(response => {
|
||||
this.totalMoney = response.data.totalMoney
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
this.stat()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.stat-form{display: flex;}
|
||||
.stat-item{display: flex;width: 130px;font-size: 20px;}
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
.tabs-content {
|
||||
.tab-pane {
|
||||
animation: fadenum 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 18px;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-number-group {
|
||||
margin: 3px 0;
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="关键字搜索">
|
||||
<a-input v-decorator="['search']" placeholder="结账ID" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<a-button
|
||||
v-if="$auth('/checkout/checkout')"
|
||||
class="fl-l"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleCheckout"
|
||||
>结账</a-button>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="checkout_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 操作项 -->
|
||||
<!-- <div class="actions" slot="action" slot-scope="text, item">
|
||||
<a v-action:delete @click="handleDelete([item.checkout_id])">删除</a>
|
||||
</div> -->
|
||||
</s-table>
|
||||
<CheckoutForm ref="CheckoutForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CheckoutApi from '@/api/checkout'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import { CheckoutForm } from './modules'
|
||||
import { assignment, inArray } from '@/utils/util'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '结账ID',
|
||||
width: '70px',
|
||||
dataIndex: 'checkout_id'
|
||||
},
|
||||
{
|
||||
title: '结账金额',
|
||||
width: '150px',
|
||||
dataIndex: 'amount'
|
||||
},
|
||||
{
|
||||
title: '结账订单数',
|
||||
width: '150px',
|
||||
dataIndex: 'num'
|
||||
},
|
||||
{
|
||||
title: '结账开始时间',
|
||||
dataIndex: 'start_time'
|
||||
},
|
||||
{
|
||||
title: '结账结束时间',
|
||||
dataIndex: 'end_time'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// dataIndex: 'action',
|
||||
// width: '200px',
|
||||
// fixed: 'right',
|
||||
// scopedSlots: { customRender: 'action' }
|
||||
// }
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
CheckoutForm,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CheckoutApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray
|
||||
})
|
||||
},
|
||||
created () {
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
// 结账
|
||||
handleCheckout (item) {
|
||||
this.$refs.CheckoutForm.handle(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (checkoutIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return CheckoutApi.deleted(checkoutIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="560"
|
||||
:visible="visible"
|
||||
:isLoading="isLoading"
|
||||
:confirmLoading="isLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="结账时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-date-picker show-time format="YYYY-MM-DD HH:mm:ss" v-decorator="['end_time', { rules: [{ required: true }] }]" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import * as Api from '@/api/checkout'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '结账',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
handle (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
},
|
||||
|
||||
// 确认按钮
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.checkout({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,5 @@
|
||||
import CheckoutForm from './CheckoutForm'
|
||||
|
||||
export {
|
||||
CheckoutForm
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="默认登录/注册方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['registerMethod', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="10">手机号 + 短信验证码</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<p class="extra">
|
||||
<small>发送短信服务需要先配置</small>
|
||||
<router-link target="_blank" :to="{ path: '/setting/sms' }">短信通知设置</router-link>
|
||||
</p>
|
||||
<p class="extra">使用手机号作为主账户可以实现多种客户端的账户统一,例如H5和微信小程序</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left">微信小程序授权登录</a-divider>
|
||||
|
||||
<a-form-item label="一键授权登录/注册" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['isOauthMpweixin', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">
|
||||
<span>开启</span>
|
||||
<a-tag class="ml-5" color="green">推荐</a-tag>
|
||||
</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>开启后在微信小程序端一键获取用户授权并登录和注册</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-show="form.getFieldValue('isOauthMpweixin') == 1"
|
||||
label="注册时绑定手机号"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-radio-group v-decorator="['isForceBindMpweixin', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">
|
||||
<span>强制绑定</span>
|
||||
<a-tag class="ml-5" color="green">推荐</a-tag>
|
||||
</a-radio>
|
||||
<a-radio :value="0">不绑定</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<p class="extra">开启后在微信小程序端一键授权注册时强制绑定手机号,仅首次注册时弹出</p>
|
||||
<p
|
||||
v-show="form.getFieldValue('isForceBindMpweixin') == 0"
|
||||
class="extra c-red"
|
||||
>如果不强制绑定手机号,会造成多端情况下同一个用户注册多个账户,强烈推荐绑定手机号</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-show="form.getFieldValue('isOauthMpweixin') == 1 && form.getFieldValue('isForceBindMpweixin') == 0"
|
||||
label="手动绑定手机号"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-radio-group v-decorator="['isManualBind', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">不显示</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>用户在个人中心页可以手动操作绑定手机号</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import { isEmpty } from '@/utils/util'
|
||||
import * as Api from '@/api/setting/store'
|
||||
import SettingSmsSceneEnum from '@/common/enum/setting/sms/Scene'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
SettingSmsSceneEnum,
|
||||
// 当前设置项的key
|
||||
key: 'register',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.isLoading = true
|
||||
Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.values
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form } = this
|
||||
!isEmpty(form.getFieldsValue()) && $nextTick(() => {
|
||||
form.setFieldsValue(pick(record, ['registerMethod', 'isManualBind', 'isOauthMpweixin', 'isForceBindMpweixin']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.ant-divider {
|
||||
margin-top: 50px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item class="mt-30" label="是否开启访问" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['enabled', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<p class="extra">
|
||||
<span>注:如关闭,用户则无法通过H5端访问商城</span>
|
||||
</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="H5站点地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['baseUrl', { rules: [{ required: true, message: '请输入H5站点地址' }] }]"
|
||||
/>
|
||||
<div class="form-item-help">
|
||||
<p class="extra">
|
||||
<span>请填写H5端实际的访问地址,以</span>
|
||||
<a-tag class="mlr-5">https://</a-tag>开头; 斜杠
|
||||
<a-tag class="mlr-5">/</a-tag>
|
||||
<span>结尾</span>
|
||||
</p>
|
||||
<p class="extra">
|
||||
<span>例如:https://www.aaa.com/</span>
|
||||
</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import { isEmpty } from '@/utils/util'
|
||||
import * as Api from '@/api/client/h5/setting'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前设置项key
|
||||
key: 'basic',
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.isLoading = true
|
||||
Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.detail
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form } = this
|
||||
!isEmpty(form.getFieldsValue()) && $nextTick(() => {
|
||||
form.setFieldsValue(pick(record, ['enabled', 'baseUrl']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.ant-divider {
|
||||
margin-top: 60px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item class="mt-30" label="小程序 AppID" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['app_id', { rules: [{ required: true, message: '请输入小程序AppID' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="小程序 AppSecret" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['app_secret', { rules: [{ required: true, message: '请输入小程序AppSecret' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-divider orientation="left">微信小程序支付</a-divider>
|
||||
<a-form-item label="微信商户号 MCHID" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['mchid', { rules: [{ required: true, message: '请输入微信商户号mchid' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="微信支付密钥 APIKEY" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['apikey', { rules: [{ required: true, message: '请输入微信支付密钥' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="mt-40" label="证书文件cert" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea :autoSize="{ minRows: 4, maxRows: 6 }" v-decorator="['cert_pem']" />
|
||||
<div class="form-item-help">
|
||||
<small>使用文本编辑器打开apiclient_cert.pem文件,将文件的全部内容复制进来</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="证书文件key" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea :autoSize="{ minRows: 4, maxRows: 6 }" v-decorator="['key_pem']" />
|
||||
<div class="form-item-help">
|
||||
<small>使用文本编辑器打开apiclient_key.pem文件,将文件的全部内容复制进来</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import { isEmpty } from '@/utils/util'
|
||||
import * as Api from '@/api/client/wxapp/setting'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前设置项key
|
||||
key: 'basic',
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.isLoading = true
|
||||
Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.detail
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form } = this
|
||||
!isEmpty(form.getFieldsValue()) && $nextTick(() => {
|
||||
form.setFieldsValue(pick(record, ['app_id', 'app_secret', 'mchid', 'apikey', 'cert_pem', 'key_pem']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.ant-divider {
|
||||
margin-top: 60px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="店铺" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['shop_id', {rules: [{required: true, message: '请选择店铺'}]}]"
|
||||
placeholder="请选择店铺"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.shopList"
|
||||
:key="index"
|
||||
:value="item.shop_id"
|
||||
>{{ item.shop_name }}{{ item.contact_name?'('+item.contact_name+')':'' }}</a-select-option>
|
||||
</a-select>
|
||||
<div class="form-item-help">
|
||||
<router-link
|
||||
target="_blank"
|
||||
:to="{ path: '/shop/create' }"
|
||||
>新增店铺</router-link>
|
||||
<a href="javascript:;" @click="onReloadShopList">刷新</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="微信链接" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入微信链接"
|
||||
v-decorator="['link']"
|
||||
@blur="getOrderNo"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="支付宝链接" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input placeholder="请输入支付宝链接" v-decorator="['alipay']"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="产码账号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入产码账号"
|
||||
v-decorator="['code_account', {rules: [{required: true, min: 2, message: ''}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="订单号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入订单号"
|
||||
v-decorator="['order_no', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="通道编码" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['passageway', {initialValue: 'WX', rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio
|
||||
v-for="(item, index) in PassagewayEnum.data"
|
||||
:key="index"
|
||||
:value="item.value">{{ item.name }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="启停状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['state', {initialValue: 1, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio
|
||||
v-for="(item, index) in StateEnum.data"
|
||||
:key="index"
|
||||
:value="item.value">{{ item.name }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['money', {initialValue: 0, rules:[{ required: true }]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="有限期限(秒) " :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['expiration_time', {initialValue: formData.expiration_time, rules:[{ required: true }]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CodeApi from '@/api/code'
|
||||
import CodeModel from '@/common/model/code/Index'
|
||||
import {
|
||||
PassagewayEnum,
|
||||
StateEnum
|
||||
} from '@/common/enum/code'
|
||||
import { assignment } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 表单数据
|
||||
formData: CodeModel.formData
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
PassagewayEnum,
|
||||
StateEnum
|
||||
})
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
this.isLoading = true
|
||||
// 获取form所需的数据
|
||||
CodeModel.getFromData()
|
||||
.then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
getOrderNo (event) {
|
||||
const url = event.target.value
|
||||
let orderId = url.match(/orderId=([^&]+)/)
|
||||
let custNo = url.match(/custNo=([^&]+)/)
|
||||
orderId = orderId !== null ? orderId[1] : ''
|
||||
custNo = custNo !== null ? custNo[1] : ''
|
||||
this.form.setFieldsValue({ 'code_account': custNo, 'order_no': orderId })
|
||||
},
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
// 刷新店铺列表
|
||||
onReloadShopList () {
|
||||
this.isLoading = true
|
||||
CodeModel.getShopList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
CodeApi.add({ form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="请选择状态">
|
||||
<a-select v-decorator="['status', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in CodeStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="请选择通道">
|
||||
<a-select v-decorator="['passageway', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in PassagewayEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="请选择启停状态">
|
||||
<a-select v-decorator="['state', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in StateEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入产码账号">
|
||||
<a-input v-decorator="['code_account']" placeholder="请输入产码账号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入订单号">
|
||||
<a-input v-decorator="['order_no']" placeholder="请输入订单号" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="stat-form">
|
||||
<a-form-item v-for="(item) in money" class="stat-item" :label="`产码 ${item.money} `">{{ item.num }}</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<a-button
|
||||
v-if="$auth('/code/create')"
|
||||
class="fl-l"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleCreate"
|
||||
>产码</a-button>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>
|
||||
<a-button
|
||||
icon="arrow-up"
|
||||
@click="handleUpdateState(selectedRowKeys, true)"
|
||||
>启用</a-button>
|
||||
<a-button
|
||||
icon="arrow-down"
|
||||
@click="handleUpdateState(selectedRowKeys, false)"
|
||||
>停用</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="code_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 店铺 -->
|
||||
<span slot="shop" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ item.shop.shop_name }}</p>
|
||||
</span>
|
||||
<!-- 支付链接 -->
|
||||
<span slot="link" slot-scope="text, item">
|
||||
<p class="twoline-hide qrcode" @click="qrcode(item)" style="width: 270px;">{{ item.passageway == 'ZFBH5'?item.alipay:item.link }}</p>
|
||||
</span>
|
||||
<!-- 产码状态 -->
|
||||
<span slot="status" slot-scope="text, item">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text == 2 ? 'green' : (text == 3?'red':(text == 4?'orange':'black'))"
|
||||
>{{ CodeStatusEnum[text].name }}</a-tag>
|
||||
</span>
|
||||
<!-- 产码启停状态 -->
|
||||
<span slot="state" slot-scope="text, item">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text == 1 ? 'green' : 'red'"
|
||||
@click="handleUpdateState([item.code_id], text != 1)"
|
||||
>{{ text == 1 ? '启用' : '停用' }}</a-tag>
|
||||
</span>
|
||||
<!-- 管理员 -->
|
||||
<span slot="user" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ item.user.user_name }}</p>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<div class="actions" slot="action" slot-scope="text, item">
|
||||
<router-link :to="{ path: '/code/update', query: { codeId: item.code_id } }">编辑</router-link>
|
||||
<a v-action:delete @click="handleDelete([item.code_id])">删除</a>
|
||||
</div>
|
||||
</s-table>
|
||||
<QrcodeForm ref="QrcodeForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CodeApi from '@/api/code'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import {
|
||||
CodeStatusEnum,
|
||||
PassagewayEnum,
|
||||
StateEnum
|
||||
} from '@/common/enum/code'
|
||||
import { assignment, inArray } from "@/utils/util"
|
||||
import { QrcodeForm } from './modules'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'code_id',
|
||||
width: '50px'
|
||||
},
|
||||
{
|
||||
title: '店铺',
|
||||
dataIndex: 'shop',
|
||||
width: '100px',
|
||||
scopedSlots: { customRender: 'shop' }
|
||||
},
|
||||
{
|
||||
title: '产码账号',
|
||||
dataIndex: 'code_account',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '单号',
|
||||
dataIndex: 'order_no',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '通道',
|
||||
width: '80px',
|
||||
dataIndex: 'passageway'
|
||||
},
|
||||
{
|
||||
title: '支付链接',
|
||||
dataIndex: 'link',
|
||||
width: '307px',
|
||||
scopedSlots: { customRender: 'link' }
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
dataIndex: 'money',
|
||||
width: '80px'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: '80px',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '启停状态',
|
||||
dataIndex: 'state',
|
||||
width: '80px',
|
||||
scopedSlots: { customRender: 'state' }
|
||||
},
|
||||
{
|
||||
title: '调码次数',
|
||||
width: '60px',
|
||||
align: 'center',
|
||||
dataIndex: 'num'
|
||||
},
|
||||
{
|
||||
title: '到期时间',
|
||||
dataIndex: 'expiration_time',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '操作员',
|
||||
dataIndex: 'user',
|
||||
width: '80px',
|
||||
scopedSlots: { customRender: 'user' }
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
dataIndex: 'create_time',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '150px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
STable,
|
||||
QrcodeForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
money: [],
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CodeApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray,
|
||||
CodeStatusEnum,
|
||||
PassagewayEnum,
|
||||
StateEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
this.init()
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取统计数据
|
||||
init () {
|
||||
this.isLoading = true
|
||||
const { queryParam } = this
|
||||
return CodeApi.stat({ ...queryParam })
|
||||
.then(response => {
|
||||
this.money = response.data.money
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改启停状态
|
||||
*/
|
||||
handleUpdateState (codeIds, state = true) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要修改启停状态为' + (state ? '启用' : '停用') + '?',
|
||||
content: '启停状态修改',
|
||||
onOk () {
|
||||
return CodeApi.stateSwitch({ codeIds, state })
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (codeIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return CodeApi.deleted(codeIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
app.init()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleCreate () {
|
||||
this.$router.push('/code/create')
|
||||
},
|
||||
|
||||
// 弹出支付二维码
|
||||
qrcode (record) {
|
||||
this.$refs.QrcodeForm.show(record)
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.stat-form{display: flex;}
|
||||
.stat-item{display: flex;width: 130px;font-size: 20px;}
|
||||
.qrcode{cursor: pointer;}
|
||||
</style>
|
||||
@@ -0,0 +1,353 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="请选择状态">
|
||||
<a-select v-decorator="['pay_status', { initialValue: 1 }]">
|
||||
<a-select-option
|
||||
v-for="(item, index) in PayStatusEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="请选择通道">
|
||||
<a-select v-decorator="['passageway', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in PassagewayEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入产码账号">
|
||||
<a-input v-decorator="['code_account']" placeholder="请输入产码账号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请输入订单号">
|
||||
<a-input v-decorator="['order_no']" placeholder="请输入订单号" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button
|
||||
icon="arrow-down"
|
||||
@click="handleUpdateStatus(selectedRowKeys, false)"
|
||||
>已核销</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="stat-form">
|
||||
<a-form-item class="stat-item" label="产码200">{{ money49 }}</a-form-item>
|
||||
<a-form-item class="stat-item" label="产码200">{{ money99 }}</a-form-item>
|
||||
<a-form-item class="stat-item" label="产码200">{{ money200 }}</a-form-item>
|
||||
<a-form-item class="stat-item" label="产码300">{{ money300 }}</a-form-item>
|
||||
<a-form-item class="stat-item" label="产码500">{{ money500 }}</a-form-item>
|
||||
<a-form-item class="stat-item" label="产码800">{{ money800 }}</a-form-item>
|
||||
<a-form-item class="stat-item" label="产码1000">{{ money1000 }}</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="code_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 店铺 -->
|
||||
<span slot="shop" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ item.shop.shop_name }}</p>
|
||||
</span>
|
||||
<!-- 支付链接 -->
|
||||
<span slot="link" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ item.passageway == 'ZFBH5'?item.alipay:item.link }}</p>
|
||||
</span>
|
||||
<!-- 产码状态 -->
|
||||
<span slot="pay_status" slot-scope="text, item">
|
||||
<a-tag v-if=" text == 1 "
|
||||
class="cur-p"
|
||||
:color="text == 1 ? 'green' : 'blue'"
|
||||
@click="handleUpdateStatus([item.code_id], text != 1)"
|
||||
>{{ text == 1 ? '已支付' : '已核销' }}</a-tag>
|
||||
<a-tag v-else
|
||||
class="cur-p"
|
||||
:color="text == 1 ? 'green' : 'blue'"
|
||||
>{{ text == 1 ? '已支付' : '已核销' }}</a-tag>
|
||||
</span>
|
||||
<!-- 管理员 -->
|
||||
<span slot="user" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ item.user.user_name }}</p>
|
||||
</span>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CodeApi from '@/api/code'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import {
|
||||
CodeStatusEnum,
|
||||
PassagewayEnum,
|
||||
PayStatusEnum
|
||||
} from '@/common/enum/code'
|
||||
import {assignment, inArray} from "@/utils/util"
|
||||
import * as ShopApi from '@/api/shop'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'code_id',
|
||||
width: '50px'
|
||||
},
|
||||
{
|
||||
title: '店铺',
|
||||
dataIndex: 'shop',
|
||||
width: '100px',
|
||||
scopedSlots: { customRender: 'shop' }
|
||||
},
|
||||
{
|
||||
title: '产码账号',
|
||||
dataIndex: 'code_account',
|
||||
width: '150px',
|
||||
},
|
||||
{
|
||||
title: '单号',
|
||||
dataIndex: 'order_no',
|
||||
width: '150px',
|
||||
},
|
||||
{
|
||||
title: '通道',
|
||||
width: '80px',
|
||||
dataIndex: 'passageway'
|
||||
},
|
||||
{
|
||||
title: '支付链接',
|
||||
dataIndex: 'link',
|
||||
width: '307px',
|
||||
scopedSlots: { customRender: 'link' }
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
dataIndex: 'money',
|
||||
width: '80px'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'pay_status',
|
||||
width: '80px',
|
||||
scopedSlots: { customRender: 'pay_status' }
|
||||
},
|
||||
{
|
||||
title: '调码次数',
|
||||
width: '60px',
|
||||
align: 'center',
|
||||
dataIndex: 'num'
|
||||
},
|
||||
{
|
||||
title: '到期时间',
|
||||
dataIndex: 'expiration_time',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '操作员',
|
||||
dataIndex: 'user',
|
||||
width: '80px',
|
||||
scopedSlots: { customRender: 'user' }
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
dataIndex: 'create_time',
|
||||
width: '150px'
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
pay_status: 1,
|
||||
money49: 0,
|
||||
money99: 0,
|
||||
money200: 0,
|
||||
money300: 0,
|
||||
money500: 0,
|
||||
money800: 0,
|
||||
money1000: 0,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {
|
||||
'pay_status': 1
|
||||
},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CodeApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray,
|
||||
CodeStatusEnum,
|
||||
PassagewayEnum,
|
||||
PayStatusEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
this.init()
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取统计数据
|
||||
init () {
|
||||
this.isLoading = true
|
||||
const { queryParam } = this
|
||||
return CodeApi.stat({ ...queryParam })
|
||||
.then(response => {
|
||||
this.money49 = response.data.money49
|
||||
this.money99 = response.data.money99
|
||||
this.money200 = response.data.money200
|
||||
this.money300 = response.data.money300
|
||||
this.money500 = response.data.money500
|
||||
this.money800 = response.data.money800
|
||||
this.money1000 = response.data.money1000
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
/**
|
||||
* 修改核销状态
|
||||
*/
|
||||
handleUpdateStatus (codeIds, state = true) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要修改状态为' + (state ? '已支付' : '已核销') + '?',
|
||||
content: '修改为已核销后不可更改状态',
|
||||
onOk () {
|
||||
return CodeApi.changeState({ codeIds, state })
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (codeIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return CodeApi.deleted(codeIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
app.init()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleCreate () {
|
||||
this.$router.push('/code/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.stat-form{display: flex;}
|
||||
.stat-item{display: flex;width: 130px;font-size: 20px;}
|
||||
</style>
|
||||
@@ -0,0 +1,249 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="店铺" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['shop_id', {rules: [{required: true, message: '请选择店铺'}]}]"
|
||||
placeholder="请选择店铺"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.shopList"
|
||||
:key="index"
|
||||
:value="item.shop_id"
|
||||
>{{ item.shop_name }}{{ item.contact_name?'('+item.contact_name+')':'' }}</a-select-option>
|
||||
</a-select>
|
||||
<div class="form-item-help">
|
||||
<router-link
|
||||
target="_blank"
|
||||
:to="{ path: '/shop/create' }"
|
||||
>新增店铺</router-link>
|
||||
<a href="javascript:;" @click="onReloadShopList">刷新</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="微信链接" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入微信链接"
|
||||
v-decorator="['link']"
|
||||
@blur="getOrderNo"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="支付宝链接" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input placeholder="请输入支付宝链接" v-decorator="['alipay']"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="产码账号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入产码账号"
|
||||
v-decorator="['code_account', {rules: [{required: true, min: 2, message: ''}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="订单号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入订单号"
|
||||
v-decorator="['order_no', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="通道编码" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['passageway', {rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio
|
||||
v-for="(item, index) in PassagewayEnum.data"
|
||||
:key="index"
|
||||
:value="item.value">{{ item.name }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="启停状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['state', {rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio
|
||||
v-for="(item, index) in StateEnum.data"
|
||||
:key="index"
|
||||
:value="item.value">{{ item.name }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['money', { rules:[{ required: true }]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="有限期限(秒) " :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['expiration_time', { rules:[{ required: true }]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CodeApi from '@/api/code'
|
||||
import { InputNumberGroup } from '@/components'
|
||||
import CodeModel from '@/common/model/code/Index'
|
||||
import { isEmptyObject, assignment } from '@/utils/util'
|
||||
import {
|
||||
PassagewayEnum,
|
||||
StateEnum
|
||||
} from '@/common/enum/code'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InputNumberGroup
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 产码ID
|
||||
codeId: null,
|
||||
// 表单数据
|
||||
formData: CodeModel.formData
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
PassagewayEnum,
|
||||
StateEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
// 初始化数据
|
||||
this.initData()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 销毁产码详情
|
||||
CodeModel.formData.code = {}
|
||||
},
|
||||
methods: {
|
||||
|
||||
getOrderNo (event) {
|
||||
const url = event.target.value
|
||||
let orderId = url.match(/orderId=([^&]+)/)
|
||||
let custNo = url.match(/custNo=([^&]+)/)
|
||||
orderId = orderId !== null ? orderId[1] : ''
|
||||
custNo = custNo !== null ? custNo[1] : ''
|
||||
this.form.setFieldsValue({ 'code_account': custNo, 'order_no': orderId })
|
||||
},
|
||||
|
||||
// 初始化数据
|
||||
initData () {
|
||||
// 记录产码ID
|
||||
this.codeId = this.$route.query.codeId
|
||||
// 获取form所需的数据
|
||||
this.isLoading = true
|
||||
CodeModel.getFromData(this.codeId)
|
||||
.then(() => {
|
||||
// 产码表单数据
|
||||
if (!isEmptyObject(this.form.getFieldsValue())) {
|
||||
this.form.setFieldsValue(CodeModel.getFieldsValue())
|
||||
}
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
// 刷新店铺列表
|
||||
onReloadShopList () {
|
||||
this.isLoading = true
|
||||
CodeModel.getShopList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 定位到错误的tab选项卡
|
||||
*/
|
||||
onTargetTabError (errors) {
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
CodeApi.edit({ codeId: this.codeId, form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="300"
|
||||
:visible="visible"
|
||||
:isLoading="isLoading"
|
||||
:confirmLoading="isLoading"
|
||||
:maskClosable="false"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="isLoading">
|
||||
<p>单号:{{ record.order_no }}</p>
|
||||
<img class='qrcode' :src="record.qrcode" />
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '二维码',
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
isLoading: false,
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
show (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.qrcode{width: 260px;}
|
||||
</style>
|
||||
@@ -0,0 +1,3 @@
|
||||
import QrcodeForm from './QrcodeForm'
|
||||
|
||||
export { QrcodeForm }
|
||||
@@ -0,0 +1,25 @@
|
||||
.tabs-content {
|
||||
.tab-pane {
|
||||
animation: fadenum 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 18px;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-number-group {
|
||||
margin: 3px 0;
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="公司名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="公司地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司地址"
|
||||
v-decorator="['address', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="纳税识别号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入纳税识别号"
|
||||
v-decorator="['tin', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系人" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系人"
|
||||
v-decorator="['contact_name', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系电话" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系电话"
|
||||
v-decorator="['contact_tel', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="身份证号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入身份证号"
|
||||
v-decorator="['idcard', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入请求地址"
|
||||
v-decorator="['url', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="公司编号(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司编号"
|
||||
v-decorator="['orgNo', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="appKey(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司appKey"
|
||||
v-decorator="['appKey', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="公司私钥(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea class="company-textarea" v-decorator="['privateKey']" placeholder="请输入公司私钥base64编码" />
|
||||
</a-form-item>
|
||||
<a-form-item label="公司公钥(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea class="company-textarea" v-decorator="['publicKey']" placeholder="请输入公司公钥base64编码" />
|
||||
</a-form-item>
|
||||
<a-form-item label="平台公钥(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea class="company-textarea" v-decorator="['platformPublicKey']" placeholder="请输入平台公钥base64编码" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CompanyApi from '@/api/company'
|
||||
import CompanyModel from '@/common/model/company/Index'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 表单数据
|
||||
formData: CompanyModel.formData
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
this.isLoading = true
|
||||
// 获取form所需的数据
|
||||
CompanyModel.getFromData()
|
||||
.then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
CompanyApi.add({ form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,341 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="关键字搜索">
|
||||
<a-input v-decorator="['search']" placeholder="公司编号/公司名称/公司地址/联系人/联系电话/身份证号" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<a-button
|
||||
v-if="$auth('/company/create')"
|
||||
class="fl-l"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleCreate"
|
||||
>新增</a-button>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>
|
||||
</a-button-group>
|
||||
<a-button-group class="ml-10">
|
||||
<a-button
|
||||
v-action:status
|
||||
icon="arrow-up"
|
||||
@click="handleUpdateStatus(selectedRowKeys, true)"
|
||||
>启用</a-button>
|
||||
<a-button
|
||||
v-action:status
|
||||
icon="arrow-down"
|
||||
@click="handleUpdateStatus(selectedRowKeys, false)"
|
||||
>停用</a-button>
|
||||
<a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="company_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 公司地址 -->
|
||||
<span slot="address" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 400px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 公司状态 -->
|
||||
<span slot="status" slot-scope="text, item">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text === 10 ? 'green' : 'red'"
|
||||
@click="handleUpdateStatus([item.company_id], text !== 10)"
|
||||
>{{ text === 10 ? '启用' : '停用' }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<div class="actions" slot="action" slot-scope="text, item">
|
||||
<a v-action:stock @click="handleStock([item.company_id])">更新库存</a>
|
||||
<a title="公司对接参数" v-action:para @click="handleApiPara(item)">对接参数</a>
|
||||
<a title="公司充值" v-action:recharge @click="handleRecharge(item)">充值</a>
|
||||
<a title="创建用户" v-action:account @click="handleAccount(item)">创建用户</a>
|
||||
<router-link v-if="$auth('/company/update')" :to="{ path: '/company/update', query: { companyId: item.company_id } }">编辑</router-link>
|
||||
<a v-action:delete @click="handleDelete([item.company_id])">删除</a>
|
||||
</div>
|
||||
</s-table>
|
||||
<RechargeForm ref="RechargeForm" @handleSubmit="handleRefresh" />
|
||||
<ApiParaForm ref="ApiParaForm" @handleSubmit="handleRefresh" />
|
||||
<AccountForm ref="AccountForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CompanyApi from '@/api/company'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import { CompanyStatusEnum } from '@/common/enum/company'
|
||||
import { RechargeForm, ApiParaForm, AccountForm } from './modules'
|
||||
import { assignment, inArray } from '@/utils/util'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '公司ID',
|
||||
width: '70px',
|
||||
dataIndex: 'company_id'
|
||||
},
|
||||
{
|
||||
title: '公司编号',
|
||||
width: '150px',
|
||||
dataIndex: 'orgNo'
|
||||
},
|
||||
{
|
||||
title: '公司名称',
|
||||
width: '150px',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '公司地址',
|
||||
width: '400px',
|
||||
dataIndex: 'address'
|
||||
},
|
||||
{
|
||||
title: '纳税识别号',
|
||||
width: '200px',
|
||||
dataIndex: 'tin'
|
||||
},
|
||||
{
|
||||
title: '余额',
|
||||
width: '150px',
|
||||
dataIndex: 'balance'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
width: '100px',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
/*{
|
||||
title: '联系人',
|
||||
width: '150px',
|
||||
dataIndex: 'contact_name'
|
||||
},
|
||||
{
|
||||
title: '联系电话',
|
||||
width: '150px',
|
||||
dataIndex: 'contact_tel'
|
||||
},
|
||||
{
|
||||
title: '身份证号',
|
||||
width: '150px',
|
||||
dataIndex: 'idcard'
|
||||
},*/
|
||||
{
|
||||
title: '可下单数量',
|
||||
width: '100px',
|
||||
dataIndex: 'canOrderNum'
|
||||
},
|
||||
{
|
||||
title: '未使用数量',
|
||||
width: '100px',
|
||||
dataIndex: 'unUseNum'
|
||||
},
|
||||
{
|
||||
title: '已使用数量',
|
||||
width: '100px',
|
||||
dataIndex: 'useNum'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
width: '100px',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '300px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
RechargeForm,
|
||||
ApiParaForm,
|
||||
AccountForm,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CompanyApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray,
|
||||
CompanyStatusEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
// 修改商品状态(上下架)
|
||||
handleUpdateStatus (companyIds, state = true) {
|
||||
if (!this.$auth('/company/changeState')) {
|
||||
return false
|
||||
}
|
||||
this.isLoading = true
|
||||
CompanyApi.changeState({ companyIds, state })
|
||||
.then(result => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
this.handleRefresh()
|
||||
})
|
||||
.finally(result => { this.isLoading = false })
|
||||
},
|
||||
|
||||
// 商户充值
|
||||
handleRecharge (item) {
|
||||
this.$refs.RechargeForm.handle(item)
|
||||
},
|
||||
// 商户对接参数
|
||||
handleApiPara (item) {
|
||||
this.$refs.ApiParaForm.handle(item)
|
||||
},
|
||||
// 商户对接参数
|
||||
handleAccount (item) {
|
||||
this.$refs.AccountForm.handle(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (companyIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return CompanyApi.deleted(companyIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新库存
|
||||
*/
|
||||
handleStock (companyIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '执行此操作将更新商品可用库存',
|
||||
content: '',
|
||||
onOk () {
|
||||
return CompanyApi.stock(companyIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleCreate () {
|
||||
this.$router.push('/company/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="公司名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="公司地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司地址"
|
||||
v-decorator="['address', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="纳税识别号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入纳税识别号"
|
||||
v-decorator="['tin', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系人" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系人"
|
||||
v-decorator="['contact_name', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系电话" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系电话"
|
||||
v-decorator="['contact_tel', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="身份证号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入身份证号"
|
||||
v-decorator="['idcard', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="请求地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入请求地址"
|
||||
v-decorator="['url', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="公司编号(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司编号"
|
||||
v-decorator="['orgNo', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="appKey(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入公司appKey"
|
||||
v-decorator="['appKey', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="公司私钥(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea class="company-textarea" v-decorator="['privateKey']" placeholder="请输入公司私钥base64编码" />
|
||||
</a-form-item>
|
||||
<a-form-item label="公司公钥(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea class="company-textarea" v-decorator="['publicKey']" placeholder="请输入公司公钥base64编码" />
|
||||
</a-form-item>
|
||||
<a-form-item label="平台公钥(平台提供)" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea class="company-textarea" v-decorator="['platformPublicKey']" placeholder="请输入平台公钥base64编码" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CompanyApi from '@/api/company'
|
||||
import { InputNumberGroup } from '@/components'
|
||||
import CompanyModel from '@/common/model/company/Index'
|
||||
import { isEmptyObject } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InputNumberGroup
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 公司ID
|
||||
companyId: null,
|
||||
// 表单数据
|
||||
formData: CompanyModel.formData
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 初始化数据
|
||||
this.initData()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 销毁商户详情
|
||||
CompanyModel.formData.company = {}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 初始化数据
|
||||
initData () {
|
||||
// 记录商户ID
|
||||
this.companyId = this.$route.query.companyId
|
||||
// 获取form所需的数据
|
||||
this.isLoading = true
|
||||
CompanyModel.getFromData(this.companyId)
|
||||
.then(() => {
|
||||
// 商户表单数据
|
||||
if (!isEmptyObject(this.form.getFieldsValue())) {
|
||||
this.form.setFieldsValue(CompanyModel.getFieldsValue())
|
||||
}
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 定位到错误的tab选项卡
|
||||
*/
|
||||
onTargetTabError (errors) {
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
CompanyApi.edit({ companyId: this.companyId, form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="公司名称">
|
||||
<a-input v-decorator="['search']" placeholder="请输入公司名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="余额变动场景">
|
||||
<a-select v-decorator="['scene', { initialValue: 0 }]">
|
||||
<a-select-option :value="0">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in SceneEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="变动时间">
|
||||
<a-range-picker format="YYYY-MM-DD" v-decorator="['betweenTime']" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="log_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 商户 -->
|
||||
<span slot="company" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 150px;">{{ item.name }}</p>
|
||||
</span>
|
||||
<!-- 余额变动场景 -->
|
||||
<span slot="scene" slot-scope="text">
|
||||
<a-tag>{{ SceneEnum[text].name }}</a-tag>
|
||||
</span>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/company/balance'
|
||||
import { STable } from '@/components/Table'
|
||||
import SceneEnum from '@/common/enum/company/balance/log/Scene'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 枚举类
|
||||
SceneEnum,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'log_id'
|
||||
},
|
||||
{
|
||||
title: '公司信息',
|
||||
dataIndex: 'company',
|
||||
scopedSlots: { customRender: 'company' }
|
||||
},
|
||||
{
|
||||
title: '余额变动场景',
|
||||
dataIndex: 'scene',
|
||||
scopedSlots: { customRender: 'scene' }
|
||||
},
|
||||
{
|
||||
title: '变动金额',
|
||||
dataIndex: 'money'
|
||||
},
|
||||
{
|
||||
title: '描述/说明',
|
||||
width: '260px',
|
||||
dataIndex: 'describe'
|
||||
},
|
||||
{
|
||||
title: '管理员备注',
|
||||
width: '260px',
|
||||
dataIndex: 'remark'
|
||||
},
|
||||
{
|
||||
title: '变动时间',
|
||||
dataIndex: 'create_time'
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.log({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<a-modal
|
||||
class="noborder"
|
||||
:title="title"
|
||||
:width="520"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<template>
|
||||
<a-form-item class="mb-5" label="公司ID" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.company_id }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="公司名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.name }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="创建用户数" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="1"
|
||||
v-decorator="[`users`, { initialValue: '', rules: [{ required: true, message: '请输入用户数' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/company'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '创建公司用户',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 显示对话框
|
||||
handle (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
const { record } = this
|
||||
this.confirmLoading = true
|
||||
values.company_id = record.company_id
|
||||
Api.account({ companyId: record.company_id, form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-modal-body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<a-modal
|
||||
class="noborder"
|
||||
:title="title"
|
||||
:width="900"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-tabs :activeKey="activeKey" @change="onChangeTabs">
|
||||
<a-tab-pane :key="RECHARGE_TYPE_BALANCE" tab="公司对接参数">
|
||||
<template v-if="activeKey === RECHARGE_TYPE_BALANCE">
|
||||
<a-form-item class="mb-5" label="请求地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.url }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="公司编号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.orgNo }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="公司appKey" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.appKey }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="公司私钥" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.privateKey }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="公司公钥" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.publicKey }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="平台公司公钥" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.platformPublicKey }}</span>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import pick from 'lodash.pick'
|
||||
|
||||
// 充值类型枚举: 余额
|
||||
const RECHARGE_TYPE_BALANCE = 'balance'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '公司对接参数',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前tab索引
|
||||
activeKey: RECHARGE_TYPE_BALANCE,
|
||||
// 充值类型
|
||||
RECHARGE_TYPE_BALANCE,
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 显示对话框
|
||||
handle (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
},
|
||||
|
||||
// 切换tabs事件
|
||||
onChangeTabs (activeKey) {
|
||||
this.activeKey = activeKey
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-modal-body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<a-modal
|
||||
class="noborder"
|
||||
:title="title"
|
||||
:width="520"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-tabs :activeKey="activeKey" @change="onChangeTabs">
|
||||
<a-tab-pane :key="RECHARGE_TYPE_BALANCE" tab="充值余额">
|
||||
<template v-if="activeKey === RECHARGE_TYPE_BALANCE">
|
||||
<a-form-item class="mb-5" label="公司ID" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.company_id }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="当前余额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="c-p">{{ record.balance }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="[`${RECHARGE_TYPE_BALANCE}.mode`, { initialValue: 'inc', rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio value="inc">增加</a-radio>
|
||||
<a-radio value="dec">减少</a-radio>
|
||||
<a-radio value="final">最终金额</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="变更金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="[`${RECHARGE_TYPE_BALANCE}.money`, { initialValue: '', rules: [{ required: true, message: '请输入变更的金额' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="管理员备注" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
placeholder="请输入管理员备注"
|
||||
:rows="3"
|
||||
v-decorator="[`${RECHARGE_TYPE_BALANCE}.remark`, { rules: [{ required: true, message: '请输入管理员备注' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
<!--<a-tab-pane :key="RECHARGE_TYPE_POINTS" tab="充值积分">
|
||||
<template v-if="activeKey === RECHARGE_TYPE_POINTS">
|
||||
<a-form-item class="mb-5" label="商户ID" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.company_id }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="当前积分" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="c-p">{{ record.points }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="[`${RECHARGE_TYPE_POINTS}.mode`, { initialValue: 'inc', rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio value="inc">增加</a-radio>
|
||||
<a-radio value="dec">减少</a-radio>
|
||||
<a-radio value="final">最终积分</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="变更数量" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="[`${RECHARGE_TYPE_POINTS}.value`, { initialValue: '', rules: [{ required: true, message: '请输入变更的金数量' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="管理员备注" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
placeholder="请输入管理员备注"
|
||||
:rows="3"
|
||||
v-decorator="[`${RECHARGE_TYPE_POINTS}.remark`, { rules: [{ required: true, message: '请输入管理员备注' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>-->
|
||||
</a-tabs>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/company'
|
||||
|
||||
// 充值类型枚举: 余额
|
||||
const RECHARGE_TYPE_BALANCE = 'balance'
|
||||
|
||||
// 充值类型枚举: 积分
|
||||
const RECHARGE_TYPE_POINTS = 'points'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '公司充值',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前tab索引
|
||||
activeKey: RECHARGE_TYPE_BALANCE,
|
||||
// 充值类型
|
||||
RECHARGE_TYPE_BALANCE,
|
||||
RECHARGE_TYPE_POINTS,
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 显示对话框
|
||||
handle (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
},
|
||||
|
||||
// 切换tabs事件
|
||||
onChangeTabs (activeKey) {
|
||||
this.activeKey = activeKey
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
const { record, activeKey } = this
|
||||
this.confirmLoading = true
|
||||
Api.recharge({ companyId: record.company_id, target: activeKey, form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-modal-body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,9 @@
|
||||
import RechargeForm from './RechargeForm'
|
||||
import ApiParaForm from './ApiParaForm'
|
||||
import AccountForm from './AccountForm'
|
||||
|
||||
export {
|
||||
RechargeForm,
|
||||
ApiParaForm,
|
||||
AccountForm
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
.tabs-content {
|
||||
.tab-pane {
|
||||
animation: fadenum 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 18px;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-number-group {
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.company-textarea{
|
||||
height: 80px;
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="文章标题">
|
||||
<a-input v-decorator="['title']" placeholder="请输入文章标题" />
|
||||
</a-form-item>
|
||||
<a-form-item label="文章分类">
|
||||
<a-select v-decorator="['categoryId', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in categoryList"
|
||||
:key="index"
|
||||
:value="item.category_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态">
|
||||
<a-select v-decorator="['status', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option :value="1">显示</a-select-option>
|
||||
<a-select-option :value="0">隐藏</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="article_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 文章封面图 -->
|
||||
<span slot="image_url" slot-scope="text">
|
||||
<a title="点击查看原图" :href="text" target="_blank">
|
||||
<img height="50" :src="text" alt="封面图" />
|
||||
</a>
|
||||
</span>
|
||||
<!-- 文章标题 -->
|
||||
<span slot="stitle" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 所属分类 -->
|
||||
<span slot="category" slot-scope="text">{{ text.name }}</span>
|
||||
<!-- 状态 -->
|
||||
<span slot="status" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '显示' : '隐藏' }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</s-table>
|
||||
<AddForm ref="AddForm" :categoryList="categoryList" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" :categoryList="categoryList" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as ArticleApi from '@/api/content/article'
|
||||
import * as CategoryApi from '@/api/content/article/category'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import EditForm from './modules/EditForm'
|
||||
import AddForm from './modules/AddForm'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'article_id'
|
||||
},
|
||||
{
|
||||
title: '封面图',
|
||||
dataIndex: 'image_url',
|
||||
scopedSlots: { customRender: 'image_url' }
|
||||
},
|
||||
{
|
||||
title: '文章标题',
|
||||
dataIndex: 'title',
|
||||
width: '320px',
|
||||
scopedSlots: { customRender: 'stitle' }
|
||||
},
|
||||
{
|
||||
title: '所属分类',
|
||||
dataIndex: 'category',
|
||||
scopedSlots: { customRender: 'category' }
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
width: '180px',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
width: '180px',
|
||||
dataIndex: 'update_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '150px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
expand: false,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 分类列表
|
||||
categoryList: [],
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return ArticleApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取分类列表
|
||||
this.getCategoryList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 获取分类列表
|
||||
*/
|
||||
getCategoryList () {
|
||||
this.isLoading = true
|
||||
CategoryApi.list()
|
||||
.then(result => {
|
||||
this.categoryList = result.data.list
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return ArticleApi.deleted({ articleId: item.article_id })
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item.article_id)
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</div>
|
||||
<a-table
|
||||
v-if="!isLoading"
|
||||
rowKey="category_id"
|
||||
:columns="columns"
|
||||
:dataSource="categoryList"
|
||||
:defaultExpandAllRows="true"
|
||||
:expandIconColumnIndex="1"
|
||||
:pagination="false"
|
||||
:loading="isLoading"
|
||||
>
|
||||
<!-- 状态 -->
|
||||
<span slot="status" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '显示' : '隐藏' }}</a-tag>
|
||||
</span>
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</a-table>
|
||||
<AddForm ref="AddForm" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/content/article/category'
|
||||
import { STable } from '@/components'
|
||||
import AddForm from './modules/AddForm'
|
||||
import EditForm from './modules/EditForm'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 分类列表
|
||||
categoryList: [],
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '分类ID',
|
||||
dataIndex: 'category_id'
|
||||
},
|
||||
{
|
||||
title: '分类名称',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取分类列表
|
||||
this.getCategoryList(true)
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 获取分类列表
|
||||
*/
|
||||
getCategoryList (bool) {
|
||||
bool && (this.isLoading = true)
|
||||
Api.list()
|
||||
.then(result => {
|
||||
this.categoryList = result.data.list
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const self = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ categoryId: item['category_id'] })
|
||||
.then((result) => {
|
||||
self.$message.success(result.message, 1.5)
|
||||
self.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh () {
|
||||
// 获取分类列表
|
||||
this.getCategoryList()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="编辑商品分类"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="分类名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/content/article/category'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="编辑商品分类"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="分类名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/content/article/category'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前分类记录
|
||||
this.record = record
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(pick(this.record, ['name', 'status', 'sort']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ categoryId: this.record['category_id'], form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="780"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="文章标题" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['title', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="文章分类" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
v-decorator="['category_id', {rules: [{required: true, message: '请选择1个文章分类'}]}]"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in categoryList"
|
||||
:key="index"
|
||||
:value="item.category_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="列表显示方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['show_type', {initialValue: 10, rules: [{required: true}]}]">
|
||||
<a-radio :value="10">小图模式</a-radio>
|
||||
<a-radio :value="20">大图模式</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<p class="extra">小图模式建议封面图尺寸:300 * 188</p>
|
||||
<p class="extra">大图模式建议封面图尺寸:750 * 455</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="封面图" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<SelectImage
|
||||
v-decorator="['image_id', {rules: [{required: true, message: '请选择1个封面图'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="文章内容" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<Ueditor v-decorator="['content', {rules: [{required: true, message: '文章内容不能为空'}]}]" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="虚拟阅读量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="用户看到的阅读量 = 实际阅读量 + 虚拟阅读量"
|
||||
>
|
||||
<a-input-number :min="0" v-decorator="['virtual_views', {initialValue: 100}]" />
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/content/article'
|
||||
import { SelectImage, Ueditor } from '@/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage,
|
||||
Ueditor
|
||||
},
|
||||
props: {
|
||||
// 分类列表
|
||||
categoryList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '新增文章',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="780"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="文章标题" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['title', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="文章分类" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
v-decorator="['category_id', {rules: [{required: true, message: '请选择1个文章分类'}]}]"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in categoryList"
|
||||
:key="index"
|
||||
:value="item.category_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="列表显示方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['show_type', {initialValue: 10, rules: [{required: true}]}]">
|
||||
<a-radio :value="10">小图模式</a-radio>
|
||||
<a-radio :value="20">大图模式</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<p class="extra">小图模式建议封面图尺寸:300 * 188</p>
|
||||
<p class="extra">大图模式建议封面图尺寸:750 * 455</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="封面图" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<SelectImage
|
||||
:defaultList="record.image ? [record.image] : []"
|
||||
v-decorator="['image_id', { rules: [{ required: true, message: '请选择1个封面图' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="文章内容" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<Ueditor v-decorator="['content', { rules: [{ required: true, message: '文章内容不能为空' }] }]" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="虚拟阅读量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="用户看到的阅读量 = 实际阅读量 + 虚拟阅读量"
|
||||
>
|
||||
<a-input-number :min="0" v-decorator="['virtual_views', {initialValue: 100}]" />
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/content/article'
|
||||
import { SelectImage, Ueditor } from '@/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage,
|
||||
Ueditor
|
||||
},
|
||||
props: {
|
||||
// 分类列表
|
||||
categoryList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '编辑文章',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 当前记录ID
|
||||
articleId: null,
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (articleId) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录ID
|
||||
this.articleId = articleId
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.confirmLoading = true
|
||||
Api.detail({ articleId: this.articleId })
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.detail
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { form: { setFieldsValue } } = this
|
||||
this.$nextTick(() => {
|
||||
setFieldsValue(pick(this.record, [
|
||||
'title', 'show_type', 'category_id', 'image_id', 'content', 'sort', 'status', 'virtual_views'
|
||||
]))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.record = {}
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ articleId: this.articleId, form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="文件名称">
|
||||
<a-input v-decorator="['fileName']" placeholder="请输入文件名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="文件分组">
|
||||
<a-tree-select
|
||||
treeDefaultExpandAll
|
||||
allowClear
|
||||
:treeData="groupListTreeSelect"
|
||||
:dropdownStyle="{ maxHeight: '500px', overflow: 'auto' }"
|
||||
v-decorator="['groupId', { initialValue: -1 }]"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="存储方式">
|
||||
<a-select v-decorator="['storage', { initialValue: '' }]">
|
||||
<a-select-option :value="''">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in StorageEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="上传来源">
|
||||
<a-select v-decorator="['channel', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in ChannelEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button @click="handleReset">重置</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<div class="tab-list fl-l">
|
||||
<a-radio-group :defaultValue="queryParam.fileType" @change="handleTabs">
|
||||
<a-radio-button :value="-1">全部</a-radio-button>
|
||||
<a-radio-button
|
||||
v-for="(item, index) in FileTypeEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group>
|
||||
<a-button icon="swap" @click="handleBatchMove">移动</a-button>
|
||||
<a-button icon="delete" @click="handleBatchDelete">删除</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 列表内容 -->
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="file_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 文件预览 -->
|
||||
<span slot="preview_url" slot-scope="text, item">
|
||||
<div class="preview-box">
|
||||
<a :href="item.external_url" target="_blank">
|
||||
<img :src="text" />
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
<!-- 存储方式 -->
|
||||
<span slot="storage" slot-scope="text">
|
||||
<a-tag>{{ StorageEnum[text].name }}</a-tag>
|
||||
</span>
|
||||
<!-- 文件类型 -->
|
||||
<span slot="file_type" slot-scope="text">
|
||||
<a-tag>{{ FileTypeEnum[text].name }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作 -->
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</s-table>
|
||||
<!-- 移动分组 -->
|
||||
<MoveGroupForm ref="MoveGroupForm" :groupList="groupListTree" @handleSubmit="handleRefresh" />
|
||||
<!-- 编辑记录 -->
|
||||
<EditForm ref="EditForm" :groupList="groupListTree" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/files'
|
||||
import * as GroupApi from '@/api/files/group'
|
||||
import { STable } from '@/components'
|
||||
import MoveGroupForm from './modules/MoveGroupForm'
|
||||
import EditForm from './modules/EditForm'
|
||||
import FileTypeEnum from '@/common/enum/file/FileType'
|
||||
import StorageEnum from '@/common/enum/file/Storage'
|
||||
import ChannelEnum from '@/common/enum/file/Channel'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
MoveGroupForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 枚举数据
|
||||
FileTypeEnum,
|
||||
StorageEnum,
|
||||
ChannelEnum,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: { fileType: -1 },
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '文件ID',
|
||||
dataIndex: 'file_id'
|
||||
},
|
||||
{
|
||||
title: '文件预览',
|
||||
dataIndex: 'preview_url',
|
||||
scopedSlots: { customRender: 'preview_url' }
|
||||
},
|
||||
{
|
||||
title: '文件名称',
|
||||
width: '302px',
|
||||
dataIndex: 'file_name'
|
||||
},
|
||||
{
|
||||
title: '存储方式',
|
||||
dataIndex: 'storage',
|
||||
scopedSlots: { customRender: 'storage' }
|
||||
},
|
||||
{
|
||||
title: '文件类型',
|
||||
dataIndex: 'file_type',
|
||||
scopedSlots: { customRender: 'file_type' }
|
||||
},
|
||||
{
|
||||
title: '文件大小(字节)',
|
||||
dataIndex: 'file_size'
|
||||
},
|
||||
{
|
||||
title: '文件后缀',
|
||||
dataIndex: 'file_ext'
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
width: '180px',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '150px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
},
|
||||
// 文件分组列表(树状结构)
|
||||
groupListTree: [],
|
||||
// 文件分组列表(用于筛选组件)
|
||||
groupListTreeSelect: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取分组列表
|
||||
this.getGroupList()
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 切换tab
|
||||
handleTabs (e) {
|
||||
this.queryParam.fileType = e.target.value
|
||||
this.handleRefresh()
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.selectedRowKeys = []
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取分组列表
|
||||
*/
|
||||
getGroupList () {
|
||||
this.isLoading = true
|
||||
GroupApi.list().then(result => {
|
||||
const { list } = result.data
|
||||
// 格式化分组列表
|
||||
const groupListTree = this.formatTreeData(list)
|
||||
// 记录到data
|
||||
this.groupListTree = groupListTree
|
||||
this.groupListTreeSelect = [{
|
||||
title: '全部',
|
||||
key: -1,
|
||||
value: -1
|
||||
}, {
|
||||
title: '未分组',
|
||||
key: 0,
|
||||
value: 0
|
||||
}].concat(groupListTree)
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化分组列表
|
||||
*/
|
||||
formatTreeData (list) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
// 新的元素
|
||||
const netItem = {
|
||||
title: item.name,
|
||||
key: item.group_id,
|
||||
value: item.group_id
|
||||
}
|
||||
// 递归整理子集
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeData(item['children'])
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
this.onDelete([item['file_id']])
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
handleBatchDelete () {
|
||||
this.onDelete(this.selectedRowKeys)
|
||||
},
|
||||
|
||||
/**
|
||||
* 执行删除
|
||||
*/
|
||||
onDelete (fileIds) {
|
||||
const that = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该文件吗?',
|
||||
content: '删除后不可恢复,请谨慎操作',
|
||||
onOk () {
|
||||
return Api.deleted({ fileIds })
|
||||
.then(result => {
|
||||
that.$message.success(result.message, 1.5)
|
||||
that.handleRefresh()
|
||||
})
|
||||
.catch(() => true)
|
||||
.finally(result => modal.destroy())
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 批量移动文件
|
||||
*/
|
||||
handleBatchMove () {
|
||||
this.$refs.MoveGroupForm.show(this.selectedRowKeys)
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = true) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
// 预览图
|
||||
.preview-box {
|
||||
width: 120px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</div>
|
||||
<a-table
|
||||
v-if="!isLoading"
|
||||
rowKey="group_id"
|
||||
:columns="columns"
|
||||
:dataSource="groupList"
|
||||
:defaultExpandAllRows="true"
|
||||
:expandIconColumnIndex="1"
|
||||
:pagination="false"
|
||||
:loading="isLoading"
|
||||
>
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</a-table>
|
||||
<AddForm ref="AddForm" :groupList="groupList" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" :groupList="groupList" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/files/group'
|
||||
import { STable } from '@/components'
|
||||
import AddForm from './modules/AddForm'
|
||||
import EditForm from './modules/EditForm'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 分组列表
|
||||
groupList: [],
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '分组ID',
|
||||
dataIndex: 'group_id'
|
||||
},
|
||||
{
|
||||
title: '分组名称',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取分组列表
|
||||
this.getGroupList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 获取分组列表
|
||||
*/
|
||||
getGroupList () {
|
||||
this.isLoading = true
|
||||
Api.list()
|
||||
.then(result => {
|
||||
this.groupList = result.data.list
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const self = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ groupId: item['group_id'] })
|
||||
.then((result) => {
|
||||
self.$message.success(result.message, 1.5)
|
||||
self.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh () {
|
||||
// 获取分组列表
|
||||
this.getGroupList()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="新增文件分组"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="分组名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="上级分组" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
:treeData="groupListTree"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['parent_id', {initialValue: 0}]"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/files/group'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 分组列表
|
||||
groupList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 上级分组列表
|
||||
groupListTree: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 获取分组列表
|
||||
this.getGroupList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取分组列表
|
||||
*/
|
||||
getGroupList () {
|
||||
const { groupList } = this
|
||||
// 格式化分组列表
|
||||
this.groupListTree = [{
|
||||
title: '顶级分组',
|
||||
key: 0,
|
||||
value: 0
|
||||
}].concat(this.formatTreeData(groupList))
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化分组列表
|
||||
*/
|
||||
formatTreeData (list, disabled = false) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
// 新的元素
|
||||
const netItem = {
|
||||
title: item.name,
|
||||
key: item.group_id,
|
||||
value: item.group_id
|
||||
}
|
||||
// 递归整理子集
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeData(item['children'], netItem.disabled)
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="编辑文件分组"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="分组名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="上级分组" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
:treeData="groupListTree"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['parent_id']"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/files/group'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 分组列表
|
||||
groupList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 当前记录
|
||||
record: {},
|
||||
// 上级分组列表
|
||||
groupListTree: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前分组记录
|
||||
this.record = record
|
||||
// 获取分组列表
|
||||
this.getGroupList()
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(_.pick(this.record, ['name', 'parent_id', 'sort']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取分组列表
|
||||
*/
|
||||
getGroupList () {
|
||||
const { groupList } = this
|
||||
// 格式化分组列表
|
||||
const selectList = this.formatTreeData(groupList)
|
||||
// 顶级分组
|
||||
selectList.unshift({
|
||||
title: '顶级分组',
|
||||
key: 0,
|
||||
value: 0
|
||||
})
|
||||
this.groupListTree = selectList
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化分组列表
|
||||
*/
|
||||
formatTreeData (list, disabled = false) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
// 新的元素
|
||||
const netItem = {
|
||||
title: item.name,
|
||||
key: item.group_id,
|
||||
value: item.group_id
|
||||
}
|
||||
// 禁用的分组
|
||||
if (
|
||||
[item.group_id, item.parent_id].includes(this.record.group_id) ||
|
||||
disabled === true
|
||||
) {
|
||||
netItem.disabled = true
|
||||
}
|
||||
// 递归整理子集
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeData(item['children'], netItem.disabled)
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ groupId: this.record['group_id'], form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="编辑文件"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="文件名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['file_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="上级分组" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
:treeData="groupTreeData"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['group_id']"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/files'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 分组列表
|
||||
groupList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 当前记录
|
||||
record: {},
|
||||
// 分组列表 树状结构
|
||||
groupTreeData: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前分组记录
|
||||
this.record = record
|
||||
// 获取分组列表
|
||||
this.getGroupList()
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(_.pick(this.record, ['file_name', 'group_id']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取分组列表
|
||||
*/
|
||||
getGroupList () {
|
||||
if (this.groupTreeData.length <= 0) {
|
||||
this.groupTreeData = [{
|
||||
title: '未分组',
|
||||
key: 0,
|
||||
value: 0
|
||||
}].concat(this.groupList)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
values.status = values.status ? 1 : 0
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ fileId: this.record['file_id'], form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="420"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-tree
|
||||
v-if="groupTreeData.length"
|
||||
:selectable="true"
|
||||
:blockNode="true"
|
||||
:treeData="groupTreeData"
|
||||
:autoExpandParent="true"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/files'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 分组列表
|
||||
groupList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '移动到分组',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 7 }
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 13 }
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 文件ID集
|
||||
filesIds: {},
|
||||
// 分组列表 树状结构
|
||||
groupTreeData: [],
|
||||
// 选中的分组
|
||||
selectedKeys: []
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 新增操作权限
|
||||
*/
|
||||
show (filesIds) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
this.filesIds = filesIds
|
||||
// 获取分组列表
|
||||
this.getList()
|
||||
},
|
||||
|
||||
// 获取分组列表
|
||||
getList () {
|
||||
if (this.groupTreeData.length <= 0) {
|
||||
this.groupTreeData = [{
|
||||
title: '未分组',
|
||||
key: 0,
|
||||
value: 0
|
||||
}].concat(this.groupList)
|
||||
}
|
||||
},
|
||||
|
||||
// 记录选中项
|
||||
onSelect (selectedKeys) {
|
||||
this.selectedKeys = selectedKeys
|
||||
},
|
||||
|
||||
// 确认按钮
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
if (this.selectedKeys.length) {
|
||||
// 提交到后端api
|
||||
this.onFormSubmit()
|
||||
} else {
|
||||
// 关闭对话框
|
||||
this.handleCancel()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 取消按钮
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit () {
|
||||
this.confirmLoading = true
|
||||
// 数据提交
|
||||
Api.moveGroup({ groupId: this.selectedKeys[0], fileIds: this.filesIds })
|
||||
.then(result => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message)
|
||||
// 关闭对话框
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit')
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="help_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 内容 -->
|
||||
<span slot="content" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 420px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 操作 -->
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</s-table>
|
||||
<AddForm ref="AddForm" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/content/help'
|
||||
import { STable } from '@/components'
|
||||
import { AddForm, EditForm } from './modules'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '帮助ID',
|
||||
dataIndex: 'help_id'
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'title'
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
dataIndex: 'content',
|
||||
scopedSlots: { customRender: 'content' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'update_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ helpId: item.help_id })
|
||||
.then((result) => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
/**
|
||||
* 检索查询
|
||||
*/
|
||||
onSearch () {
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="帮助标题" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input v-decorator="['title', { rules: [{ required: true, message: '请输入联系人姓名' }] }]" />
|
||||
</a-form-item>
|
||||
<a-form-item label="帮助内容" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['content', { rules: [{ required: true, message: '请输入帮助内容' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', { initialValue: 100, rules: [{ required: true, message: '请输入排序值' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/content/help'
|
||||
import { SelectRegion } from '@/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '编辑帮助',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="帮助标题" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input v-decorator="['title', { rules: [{ required: true, message: '请输入联系人姓名' }] }]" />
|
||||
</a-form-item>
|
||||
<a-form-item label="帮助内容" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['content', { rules: [{ required: true, message: '请输入帮助内容' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', { initialValue: 100, rules: [{ required: true, message: '请输入排序值' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/content/help'
|
||||
import { SelectRegion } from '@/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectRegion
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '编辑帮助',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, form: { setFieldsValue } } = this
|
||||
this.$nextTick(() => {
|
||||
setFieldsValue(pick(record, ['title', 'content', 'sort']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ helpId: this.record.help_id, form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,4 @@
|
||||
import AddForm from './AddForm'
|
||||
import EditForm from './EditForm'
|
||||
|
||||
export { AddForm, EditForm }
|
||||
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<a-result status="403" title="403" sub-title="Sorry, you don't have access to this page.">
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="toHome">返回首页</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Exception403',
|
||||
methods: {
|
||||
toHome () {
|
||||
this.$router.push({ path: '/' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<a-result status="404" title="404" sub-title="Sorry, the page you visited does not exist.">
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="toHome">返回首页</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Exception404',
|
||||
methods: {
|
||||
toHome () {
|
||||
this.$router.push({ path: '/' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<a-result status="500" title="500" sub-title="Sorry, the server is reporting an error.">
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="toHome">返回首页</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Exception500',
|
||||
methods: {
|
||||
toHome () {
|
||||
this.$router.push({ path: '/' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,513 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
<a-tab-pane :key="1" tab="规格/库存"></a-tab-pane>
|
||||
<a-tab-pane :key="2" tab="商品详情"></a-tab-pane>
|
||||
<a-tab-pane :key="3" tab="更多设置"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="商品名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入商品名称"
|
||||
v-decorator="['goods_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="商品分类" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
placeholder="请选择商品分类"
|
||||
:dropdownStyle="{ maxHeight: '500px', overflow: 'auto' }"
|
||||
:treeData="formData.categoryList"
|
||||
treeCheckable
|
||||
treeCheckStrictly
|
||||
allowClear
|
||||
v-decorator="['categorys', {rules: [{required: true, message: '请至少选择1个商品分类'}]}]"
|
||||
></a-tree-select>
|
||||
<div class="form-item-help">
|
||||
<router-link target="_blank" :to="{ path: '/goods/category/index' }">去新增</router-link>
|
||||
<a href="javascript:;" @click="onReloadCategoryList">刷新</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="商品图片"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="建议尺寸:750*750像素, 最多上传10张, 可拖拽图片调整顺序, 第1张将作为商品首图"
|
||||
>
|
||||
<SelectImage
|
||||
multiple
|
||||
:maxNum="10"
|
||||
v-decorator="['imagesIds', {rules: [{required: true, message: '请至少上传1张商品图片'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="卡券类型" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="选择中石油油券时所属省份和商品编码必填,选择优惠券时优惠券必选">
|
||||
<a-select style="width: 300px" v-decorator="[`oilCardType`, {rules: [{required: true, message: '请选择卡券类型'}], initialValue: 'zsy_ticket' }]">
|
||||
<a-select-option
|
||||
v-for="(item, index) in OilCardTypeEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="所属省份" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['province', {rules: [{message: '请选择所属省份'}]}]"
|
||||
placeholder="请选择所属省份"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.province"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<!--<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['delivery_id', {rules: [{required: true, message: '请选择运费模板'}]}]"
|
||||
placeholder="请选择运费模板"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.deliveryList"
|
||||
:key="index"
|
||||
:value="item.delivery_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
<div class="form-item-help">
|
||||
<router-link
|
||||
target="_blank"
|
||||
:to="{ path: '/setting/delivery/template/create' }"
|
||||
>新增模板</router-link>
|
||||
<a href="javascript:;" @click="onReloadDeliveryList">刷新</a>
|
||||
</div>-->
|
||||
</a-form-item>
|
||||
<a-form-item label="商品编码" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input style="width: 300px" placeholder="请输入商品编码" v-decorator="['goods_no', {rules: [{min: 2, message: '请输入至少2个字符'}]}]" />
|
||||
</a-form-item>
|
||||
<MultiCoupon ref="MultiCoupon" :couponList="formData.coupon" @change="handleCouponChange" />
|
||||
<a-form-item label="商品状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['status', {initialValue: 10, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="10">上架</a-radio>
|
||||
<a-radio :value="20">下架</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="商品排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules:[{ required: true }]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 规格/库存 -->
|
||||
<div class="tab-pane" v-show="tabKey == 1">
|
||||
<a-form-item label="规格类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['spec_type', { initialValue: 10, rules: [{ required: true }] }]"
|
||||
@change="onForceUpdate()"
|
||||
>
|
||||
<a-radio :value="10">单规格</a-radio>
|
||||
<a-radio :value="20">多规格</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<!-- 多规格的表单内容 -->
|
||||
<div v-show="form.getFieldValue('spec_type') == 20">
|
||||
<MultiSpec ref="MultiSpec" />
|
||||
</div>
|
||||
<!-- 单规格的表单内容 -->
|
||||
<div v-show="form.getFieldValue('spec_type') == 10">
|
||||
<a-form-item
|
||||
label="商品价格"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="商品的实际购买金额,最低0.01"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
v-decorator="['goods_price', { initialValue: '', rules: [{ required: true, message: '请输入商品价格' }] }]"
|
||||
/>
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="划线价"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="划线价仅用于商品页展示"
|
||||
>
|
||||
<a-input-number :min="0" :precision="2" v-decorator="['line_price']" />
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="当前库存数量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="商品的实际库存数量,为0时用户无法下单"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:precision="0"
|
||||
v-decorator="['stock_num', { initialValue: 100, rules:[{ required: true, message: '请输入库存数量' }] }]"
|
||||
/>
|
||||
<span class="ml-10">件</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="商品重量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="商品的实际重量,用于计算运费"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['goods_weight', { initialValue: 0, rules:[{ required: true, message: '请输入库存数量' }] }]"
|
||||
/>
|
||||
<span class="ml-10">千克 (Kg)</span>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<a-form-item label="库存计算方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['deduct_stock_type', {initialValue: 10, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="10">下单减库存</a-radio>
|
||||
<a-radio :value="20">付款减库存</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 商品详情 -->
|
||||
<div class="tab-pane" v-show="tabKey == 2">
|
||||
<a-form-item label="商品详情" :labelCol="labelCol" :wrapperCol="{span: 16}">
|
||||
<Ueditor
|
||||
v-decorator="['content', { rules: [{ required: true, message: '商品详情不能为空' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 更多设置 -->
|
||||
<div class="tab-pane" v-show="tabKey == 3">
|
||||
<a-form-item
|
||||
label="主图视频"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="建议视频宽高比19:9,建议时长8-45秒"
|
||||
>
|
||||
<SelectVideo :multiple="false" v-decorator="['video_id']" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="视频封面"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="建议尺寸:750像素*750像素"
|
||||
>
|
||||
<SelectImage :multiple="false" v-decorator="['video_cover_id']" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="商品卖点"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="一句话简述,例如:此款商品美观大方 性价比较高 不容错过"
|
||||
>
|
||||
<a-input placeholder="请输入商品卖点" v-decorator="['selling_point']" />
|
||||
</a-form-item>
|
||||
<a-form-item label="服务与承诺" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
v-if="formData.serviceList"
|
||||
mode="multiple"
|
||||
v-decorator="['serviceIds', { initialValue: formData.defaultServiceIds }]"
|
||||
placeholder="请选择服务与承诺"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.serviceList"
|
||||
:key="index"
|
||||
:value="item.service_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
<div class="form-item-help">
|
||||
<router-link target="_blank" :to="{ path: '/goods/service/index' }">去新增</router-link>
|
||||
<a href="javascript:;" @click="onReloadServiceList">刷新</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="初始销量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="用户端展示的销量 = 初始销量 + 实际销量"
|
||||
>
|
||||
<a-input-number v-decorator="['sales_initial', {initialValue: 0}]" />
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left">积分设置</a-divider>
|
||||
<a-form-item
|
||||
label="积分赠送"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="开启后用户购买此商品将获得积分"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_points_gift', {initialValue: 1, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="积分抵扣"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="开启后用户购买此商品可以使用积分进行抵扣"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_points_discount', {initialValue: 1, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left">会员折扣设置</a-divider>
|
||||
<a-form-item
|
||||
label="会员折扣"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="开启后会员折扣,会员购买此商品可以享受会员等级折扣价"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_enable_grade', {initialValue: 1, rules: [{ required: true }]}]"
|
||||
@change="onForceUpdate(true)"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="form.getFieldValue('is_enable_grade')"
|
||||
label="会员折扣设置"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_alone_grade', { initialValue: 0, rules: [{ required: true }] }]"
|
||||
@change="onForceUpdate(true)"
|
||||
>
|
||||
<a-radio :value="0">默认等级折扣</a-radio>
|
||||
<a-radio :value="1">单独设置折扣</a-radio>
|
||||
</a-radio-group>
|
||||
<!-- 会员等级列表 -->
|
||||
<div v-if="form.getFieldValue('is_alone_grade')">
|
||||
<a-form-item v-for="item in formData.userGradeList" :key="item.grade_id">
|
||||
<InputNumberGroup
|
||||
:addonBefore="item.name"
|
||||
addonAfter="折"
|
||||
:inputProps="{ min: 0, max: 9.9 }"
|
||||
v-decorator="[`alone_grade_equity[grade_id:${item.grade_id}]`, {
|
||||
initialValue: formData.defaultUserGradeValue[item.grade_id], rules: [{required: true, message: '折扣率不能为空'}]
|
||||
}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="form-item-help">
|
||||
<p
|
||||
class="extra"
|
||||
v-if="form.getFieldValue('is_alone_grade')"
|
||||
>单独折扣:折扣率范围0.0-9.9,例如: 9.8代表98折,0代表不折扣</p>
|
||||
<p class="extra" v-else>默认折扣:默认为用户所属会员等级的折扣率</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { assignment } from '@/utils/util'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import { SelectImage, SelectVideo, Ueditor, InputNumberGroup } from '@/components'
|
||||
import GoodsModel from '@/common/model/goods/Index'
|
||||
import MultiSpec from './modules/MultiSpec'
|
||||
import MultiCoupon from './modules/MultiCoupon'
|
||||
import { OilCardTypeEnum } from '@/common/enum/order'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage,
|
||||
SelectVideo,
|
||||
Ueditor,
|
||||
InputNumberGroup,
|
||||
MultiSpec,
|
||||
MultiCoupon
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 表单数据
|
||||
formData: GoodsModel.formData,
|
||||
couponList: []
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
OilCardTypeEnum
|
||||
})
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
this.isLoading = true
|
||||
// 获取form所需的数据
|
||||
GoodsModel.getFromData()
|
||||
.then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
// 刷新分类列表
|
||||
onReloadCategoryList () {
|
||||
this.isLoading = true
|
||||
GoodsModel.getCategoryList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新服务与承诺列表
|
||||
onReloadServiceList () {
|
||||
this.isLoading = true
|
||||
GoodsModel.getServiceList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新配送模板列表
|
||||
onReloadDeliveryList () {
|
||||
this.isLoading = true
|
||||
GoodsModel.getDeliveryList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 验证多规格
|
||||
if (values.spec_type === 20) {
|
||||
const MultiSpec = this.$refs.MultiSpec
|
||||
if (!MultiSpec.verifyForm()) {
|
||||
this.tabKey = 1
|
||||
return false
|
||||
}
|
||||
// 记录多规格数据
|
||||
values.specData = MultiSpec.getFromSpecData()
|
||||
}
|
||||
// 整理商品分类ID集
|
||||
values.categoryIds = values.categorys.map(item => item.value)
|
||||
delete values.categorys
|
||||
// 整理优惠券数据
|
||||
values.couponList = this.couponList
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 定位到错误的tab选项卡
|
||||
*/
|
||||
onTargetTabError (errors) {
|
||||
// 表单字段与tabKey对应关系
|
||||
// 只需要必填字段就可
|
||||
const tabsFieldsMap = [
|
||||
['goods_name', 'categorys', 'imagesIds', 'province'],
|
||||
['spec_type', 'goods_price'],
|
||||
['content'],
|
||||
['alone_grade_equity', 'first_money', 'second_money', 'third_money']
|
||||
]
|
||||
const field = Object.keys(errors).shift()
|
||||
for (const key in tabsFieldsMap) {
|
||||
if (tabsFieldsMap[key].indexOf(field) > -1) {
|
||||
this.tabKey = parseInt(key)
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
GoodsApi.add({ form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
handleCouponChange (val) {
|
||||
// console.log('最新优惠券列表:', val)
|
||||
this.couponList = val
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,335 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="商品名称">
|
||||
<a-input v-decorator="['goodsName']" placeholder="请输入商品名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="商品编码">
|
||||
<a-input v-decorator="['goodsNo']" placeholder="请输入商品编码" />
|
||||
</a-form-item>
|
||||
<a-form-item label="商品分类">
|
||||
<a-tree-select
|
||||
:treeData="categoryListTree"
|
||||
:dropdownStyle="{ maxHeight: '500px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['categoryId', { initialValue: 0 }]"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<div class="tab-list fl-l">
|
||||
<a-radio-group :defaultValue="queryParam.listType" @change="handleTabs">
|
||||
<a-radio-button value="all">全部</a-radio-button>
|
||||
<a-radio-button value="on_sale">出售中</a-radio-button>
|
||||
<a-radio-button value="off_sale">已下架</a-radio-button>
|
||||
<a-radio-button value="sold_out">已售罄</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<a-button
|
||||
v-if="$auth('/goods/create')"
|
||||
class="fl-l"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleCreate"
|
||||
>创建商品</a-button>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button
|
||||
v-action:status
|
||||
icon="arrow-up"
|
||||
@click="handleUpdateStatus(selectedRowKeys, true)"
|
||||
>上架</a-button>
|
||||
<a-button
|
||||
v-action:status
|
||||
icon="arrow-down"
|
||||
@click="handleUpdateStatus(selectedRowKeys, false)"
|
||||
>下架</a-button>
|
||||
<a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="goods_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 商品图片 -->
|
||||
<span slot="goods_image" slot-scope="text">
|
||||
<a title="点击查看原图" :href="text" target="_blank">
|
||||
<img width="50" height="50" :src="text" alt="商品图片" />
|
||||
</a>
|
||||
</span>
|
||||
<!-- 商品名称 -->
|
||||
<span slot="goods_name" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 商品名称 -->
|
||||
<span slot="oilCardType" slot-scope="text">
|
||||
<p>{{ OilCardTypeEnum[text].name }}</p>
|
||||
</span>
|
||||
<!-- 商品状态 -->
|
||||
<span slot="status" slot-scope="text, item">
|
||||
<a-tag
|
||||
class="cur-p"
|
||||
:color="text == 10 ? 'green' : 'red'"
|
||||
@click="handleUpdateStatus([item.goods_id], text != 10)"
|
||||
>{{ text == 10 ? '上架' : '下架' }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<div class="actions" slot="action" slot-scope="text, item">
|
||||
<router-link :to="{ path: '/goods/update', query: { goodsId: item.goods_id } }">编辑</router-link>
|
||||
<a v-action:delete @click="handleDelete([item.goods_id])">删除</a>
|
||||
</div>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { assignment } from '@/utils/util'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import CategoryModel from '@/common/model/Category'
|
||||
import { OilCardTypeEnum } from '@/common/enum/order'
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '商品ID',
|
||||
dataIndex: 'goods_id'
|
||||
},
|
||||
{
|
||||
title: '省份',
|
||||
dataIndex: 'province'
|
||||
},
|
||||
{
|
||||
title: '卡券类型',
|
||||
dataIndex: 'oilCardType',
|
||||
scopedSlots: { customRender: 'oilCardType' }
|
||||
},
|
||||
{
|
||||
title: '商品图片',
|
||||
dataIndex: 'goods_image',
|
||||
scopedSlots: { customRender: 'goods_image' }
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
dataIndex: 'goods_name',
|
||||
width: '200px',
|
||||
scopedSlots: { customRender: 'goods_name' }
|
||||
},
|
||||
{
|
||||
title: '商品编码',
|
||||
dataIndex: 'goods_no',
|
||||
width: '100px',
|
||||
scopedSlots: { customRender: 'goods_no' }
|
||||
},
|
||||
{
|
||||
title: '商品价格',
|
||||
dataIndex: 'goods_price_min',
|
||||
scopedSlots: { customRender: 'goods_price_min' }
|
||||
},
|
||||
{
|
||||
title: '总销量',
|
||||
dataIndex: 'sales_actual'
|
||||
},
|
||||
{
|
||||
title: '库存总量',
|
||||
dataIndex: 'stock_total'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
width: '180px',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '150px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 商品分类列表
|
||||
categoryListTree: [],
|
||||
// 查询参数
|
||||
queryParam: {
|
||||
listType: 'all'
|
||||
},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return GoodsApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
OilCardTypeEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
// 默认的查询参数
|
||||
if (this.$route.query.listType) {
|
||||
this.queryParam.listType = this.$route.query.listType
|
||||
}
|
||||
// 获取商品分类列表
|
||||
this.getCategoryList()
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 切换tab
|
||||
handleTabs (e) {
|
||||
this.queryParam.listType = e.target.value
|
||||
this.handleRefresh(true)
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
// 获取分类列表
|
||||
getCategoryList () {
|
||||
this.isLoading = true
|
||||
CategoryModel.getListFromScreen()
|
||||
.then(selectList => {
|
||||
this.categoryListTree = selectList
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 修改商品状态(上下架)
|
||||
handleUpdateStatus (goodsIds, state = true) {
|
||||
if (!this.$auth('/goods/index.status')) {
|
||||
return false
|
||||
}
|
||||
this.isLoading = true
|
||||
GoodsApi.state({ goodsIds, state })
|
||||
.then(result => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
this.handleRefresh()
|
||||
})
|
||||
.finally(result => { this.isLoading = false })
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (goodsIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return GoodsApi.deleted({ goodsIds })
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleCreate () {
|
||||
this.$router.push('/goods/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,558 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
<a-tab-pane :key="1" tab="规格/库存"></a-tab-pane>
|
||||
<a-tab-pane :key="2" tab="商品详情"></a-tab-pane>
|
||||
<a-tab-pane :key="3" tab="更多设置"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="商品名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入商品名称"
|
||||
v-decorator="['goods_name', { rules: [{ required: true, min: 2, message: '请输入至少2个字符' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="商品分类" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
placeholder="请选择商品分类"
|
||||
:dropdownStyle="{ maxHeight: '500px', overflow: 'auto' }"
|
||||
:treeData="formData.categoryList"
|
||||
treeCheckable
|
||||
treeCheckStrictly
|
||||
allowClear
|
||||
v-decorator="['categorys', { rules: [{required: true, message: '请至少选择1个商品分类'}]}]"
|
||||
></a-tree-select>
|
||||
<div class="form-item-help">
|
||||
<router-link target="_blank" :to="{ path: '/goods/category/index' }">去新增</router-link>
|
||||
<a href="javascript:;" @click="onReloadCategoryList">刷新</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="商品图片"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="建议尺寸:750*750像素, 最多上传10张, 可拖拽图片调整顺序, 第1张将作为商品首图"
|
||||
>
|
||||
<SelectImage
|
||||
multiple
|
||||
:maxNum="10"
|
||||
:defaultList="formData.goods.goods_images"
|
||||
v-decorator="['imagesIds', { rules: [{ required: true, message: '请至少上传1张商品图片' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="卡券类型" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="选择中石油油券时所属省份和商品编码必填,选择优惠券时优惠券必选">
|
||||
<a-select style="width: 300px" v-decorator="[`oilCardType`, { rules: [{required: true, message: '请选择卡券类型'}], initialValue: 'zsy_ticket' }]">
|
||||
<a-select-option
|
||||
v-for="(item, index) in OilCardTypeEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="所属省份" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['province', {rules: [{message: '请选择所属省份'}]}]"
|
||||
placeholder="请选择所属省份"
|
||||
>
|
||||
<a-select-option key="" value="">无</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.province"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
<!--<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['delivery_id', {rules: [{required: true, message: '请选择运费模板'}]}]"
|
||||
placeholder="请选择运费模板"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.deliveryList"
|
||||
:key="index"
|
||||
:value="item.delivery_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
<div class="form-item-help">
|
||||
<router-link
|
||||
target="_blank"
|
||||
:to="{ path: '/setting/delivery/template/create' }"
|
||||
>新增模板</router-link>
|
||||
<a href="javascript:;" @click="onReloadDeliveryList">刷新</a>
|
||||
</div>-->
|
||||
</a-form-item>
|
||||
<a-form-item label="商品编码" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input style="width: 300px" placeholder="请输入商品编码" v-decorator="['goods_no', {rules: [{message: '请输入至少2个字符'}]}]" />
|
||||
</a-form-item>
|
||||
<MultiCoupon ref="MultiCoupon" :couponList="formData.coupon" :defaultCouponList="formData.goods.couponList" @change="handleCouponChange" />
|
||||
<a-form-item label="商品状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['status', {initialValue: 10, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="10">上架</a-radio>
|
||||
<a-radio :value="20">下架</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="商品排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules:[{ required: true }]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 规格/库存 -->
|
||||
<div class="tab-pane" v-show="tabKey == 1">
|
||||
<a-form-item label="规格类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['spec_type', {initialValue: 10, rules: [{ required: true }]}]"
|
||||
@change="onForceUpdate()"
|
||||
>
|
||||
<a-radio :value="10">单规格</a-radio>
|
||||
<a-radio :value="20">多规格</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<!-- 多规格的表单内容 -->
|
||||
<div v-show="form.getFieldValue('spec_type') == 20">
|
||||
<MultiSpec
|
||||
ref="MultiSpec"
|
||||
:defaultSpecList="formData.goods.specList"
|
||||
:defaultSkuList="formData.goods.skuList"
|
||||
/>
|
||||
</div>
|
||||
<!-- 单规格的表单内容 -->
|
||||
<div v-show="form.getFieldValue('spec_type') == 10">
|
||||
<a-form-item
|
||||
label="商品价格"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="商品的实际购买金额,最低0.01"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
v-decorator="['goods_price', { rules:[{ required: true, message: '请输入商品价格' }] }]"
|
||||
/>
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="划线价"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="划线价仅用于商品页展示"
|
||||
>
|
||||
<a-input-number :min="0" :precision="2" v-decorator="['line_price']" />
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="当前库存数量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="商品的实际库存数量,为0时用户无法下单"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:precision="0"
|
||||
v-decorator="['stock_num', { initialValue: 100, rules:[{ required: true, message: '请输入库存数量' }] }]"
|
||||
/>
|
||||
<span class="ml-10">件</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="商品重量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="商品的实际重量,用于计算运费"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['goods_weight', { initialValue: 0, rules:[{ required: true, message: '请输入库存数量' }] }]"
|
||||
/>
|
||||
<span class="ml-10">千克 (Kg)</span>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<a-form-item label="库存计算方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['deduct_stock_type', {initialValue: 10, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="10">下单减库存</a-radio>
|
||||
<a-radio :value="20">付款减库存</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 商品详情 -->
|
||||
<div class="tab-pane" v-show="tabKey == 2">
|
||||
<a-form-item label="商品详情" :labelCol="labelCol" :wrapperCol="{span: 16}">
|
||||
<Ueditor v-decorator="['content', {rules: [{required: true, message: '商品详情不能为空'}]}]" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 更多设置 -->
|
||||
<div class="tab-pane" v-show="tabKey == 3">
|
||||
<a-form-item
|
||||
label="主图视频"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="建议视频宽高比19:9,建议时长8-45秒"
|
||||
>
|
||||
<SelectVideo
|
||||
:multiple="false"
|
||||
:defaultList="formData.goods.video ? [formData.goods.video] : []"
|
||||
v-decorator="['video_id']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="视频封面"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="建议尺寸:750像素*750像素"
|
||||
>
|
||||
<SelectImage
|
||||
:multiple="false"
|
||||
:defaultList="formData.goods.videoCover ? [formData.goods.videoCover] : []"
|
||||
v-decorator="['video_cover_id']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="商品卖点"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="一句话简述,例如:此款商品美观大方 性价比较高 不容错过"
|
||||
>
|
||||
<a-input placeholder="请输入商品卖点" v-decorator="['selling_point']" />
|
||||
</a-form-item>
|
||||
<a-form-item label="服务与承诺" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
v-if="formData.serviceList"
|
||||
mode="multiple"
|
||||
v-decorator="['serviceIds']"
|
||||
placeholder="请选择服务与承诺"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in formData.serviceList"
|
||||
:key="index"
|
||||
:value="item.service_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
<div class="form-item-help">
|
||||
<router-link target="_blank" :to="{ path: '/goods/service/index' }">去新增</router-link>
|
||||
<a href="javascript:;" @click="onReloadServiceList">刷新</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="初始销量"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="用户端展示的销量 = 初始销量 + 实际销量"
|
||||
>
|
||||
<a-input-number v-decorator="['sales_initial', {initialValue: 0}]" />
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left">积分设置</a-divider>
|
||||
<a-form-item
|
||||
label="积分赠送"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="开启后用户购买此商品将获得积分"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_points_gift', {initialValue: 1, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="积分抵扣"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="开启后用户购买此商品可以使用积分进行抵扣"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_points_discount', {initialValue: 1, rules: [{ required: true }]}]"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left">会员折扣设置</a-divider>
|
||||
<a-form-item
|
||||
label="会员折扣"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="开启后会员折扣,会员购买此商品可以享受会员等级折扣价"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_enable_grade', {initialValue: 1, rules: [{ required: true }]}]"
|
||||
@change="onForceUpdate(true)"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-show="form.getFieldValue('is_enable_grade')"
|
||||
label="会员折扣设置"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-radio-group
|
||||
v-decorator="['is_alone_grade', {initialValue: 0, rules: [{ required: true }]}]"
|
||||
@change="onForceUpdate(true)"
|
||||
>
|
||||
<a-radio :value="0">默认等级折扣</a-radio>
|
||||
<a-radio :value="1">单独设置折扣</a-radio>
|
||||
</a-radio-group>
|
||||
<!-- 会员等级列表 -->
|
||||
<div v-show="form.getFieldValue('is_alone_grade')">
|
||||
<a-form-item v-for="item in formData.userGradeList" :key="item.grade_id">
|
||||
<InputNumberGroup
|
||||
:addonBefore="item.name"
|
||||
addonAfter="折"
|
||||
:inputProps="{ min: 0, max: 9.9 }"
|
||||
v-decorator="[`alone_grade_equity[grade_id:${item.grade_id}]`, {
|
||||
initialValue: formData.defaultUserGradeValue[item.grade_id], rules: [{required: true, message: '折扣率不能为空'}]
|
||||
}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="form-item-help">
|
||||
<p
|
||||
class="extra"
|
||||
v-if="form.getFieldValue('is_alone_grade')"
|
||||
>单独折扣:折扣率范围0.0-9.9,例如: 9.8代表98折,0代表不折扣</p>
|
||||
<p class="extra" v-else>默认折扣:默认为用户所属会员等级的折扣率</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import { SelectImage, SelectVideo, Ueditor, InputNumberGroup } from '@/components'
|
||||
import GoodsModel from '@/common/model/goods/Index'
|
||||
import MultiSpec from './modules/MultiSpec'
|
||||
import MultiCoupon from './modules/MultiCoupon'
|
||||
import { isEmptyObject, assignment } from '@/utils/util'
|
||||
import { OilCardTypeEnum } from '@/common/enum/order'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage,
|
||||
SelectVideo,
|
||||
Ueditor,
|
||||
InputNumberGroup,
|
||||
MultiSpec,
|
||||
MultiCoupon
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 商品ID
|
||||
goodsId: null,
|
||||
// 表单数据
|
||||
formData: GoodsModel.formData,
|
||||
couponList: []
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
OilCardTypeEnum
|
||||
})
|
||||
},
|
||||
created () {
|
||||
// 初始化数据
|
||||
this.initData()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 销毁商品详情
|
||||
GoodsModel.formData.goods = {}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 初始化数据
|
||||
initData () {
|
||||
// 记录商品ID
|
||||
this.goodsId = this.$route.query.goodsId
|
||||
// 获取form所需的数据
|
||||
this.isLoading = true
|
||||
GoodsModel.getFromData(this.goodsId)
|
||||
.then(() => {
|
||||
// 商品表单数据
|
||||
if (!isEmptyObject(this.form.getFieldsValue())) {
|
||||
this.form.setFieldsValue(GoodsModel.getFieldsValue())
|
||||
}
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
// 刷新分类列表
|
||||
onReloadCategoryList () {
|
||||
this.isLoading = true
|
||||
GoodsModel.getCategoryList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新服务与承诺列表
|
||||
onReloadServiceList () {
|
||||
this.isLoading = true
|
||||
GoodsModel.getServiceList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
// 获取最新库存
|
||||
onReloadStock () {
|
||||
this.isLoading = true
|
||||
GoodsApi.onReloadStock({ goodsId: this.goodsId })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
this.form.setFieldsValue({ stock_num: result.data.canOrderNum })
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新配送模板列表
|
||||
onReloadDeliveryList () {
|
||||
this.isLoading = true
|
||||
GoodsModel.getDeliveryList().then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 验证多规格
|
||||
if (values.spec_type === 20) {
|
||||
const MultiSpec = this.$refs.MultiSpec
|
||||
if (!MultiSpec.verifyForm()) {
|
||||
this.tabKey = 1
|
||||
return false
|
||||
}
|
||||
// 记录多规格数据
|
||||
values.specData = MultiSpec.getFromSpecData()
|
||||
}
|
||||
// 整理商品分类ID集
|
||||
values.categoryIds = values.categorys.map(item => item.value)
|
||||
delete values.categorys
|
||||
// 整理优惠券数据
|
||||
values.couponList = this.couponList
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 定位到错误的tab选项卡
|
||||
*/
|
||||
onTargetTabError (errors) {
|
||||
// 表单字段与tabKey对应关系
|
||||
// 只需要必填字段就可
|
||||
const tabsFieldsMap = [
|
||||
['goods_name', 'categorys', 'imagesIds', 'province'],
|
||||
['spec_type', 'goods_price'],
|
||||
['content'],
|
||||
['alone_grade_equity', 'first_money', 'second_money', 'third_money']
|
||||
]
|
||||
const field = Object.keys(errors).shift()
|
||||
for (const key in tabsFieldsMap) {
|
||||
if (tabsFieldsMap[key].indexOf(field) > -1) {
|
||||
this.tabKey = parseInt(key)
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
GoodsApi.edit({ goodsId: this.goodsId, form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
handleCouponChange (val) {
|
||||
// console.log('最新优惠券列表:', val)
|
||||
this.couponList = val
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</div>
|
||||
<a-table
|
||||
v-if="!isLoading"
|
||||
rowKey="category_id"
|
||||
:columns="columns"
|
||||
:dataSource="categoryList"
|
||||
:defaultExpandAllRows="true"
|
||||
:expandIconColumnIndex="1"
|
||||
:pagination="false"
|
||||
:loading="isLoading"
|
||||
>
|
||||
<!-- 状态 -->
|
||||
<span slot="status" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '显示' : '隐藏' }}</a-tag>
|
||||
</span>
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</a-table>
|
||||
<AddForm ref="AddForm" :categoryList="categoryList" :provinceList="provinceList" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" :categoryList="categoryList" :provinceList="provinceList" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/category'
|
||||
import { STable } from '@/components'
|
||||
import AddForm from './modules/AddForm'
|
||||
import EditForm from './modules/EditForm'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 分类列表
|
||||
categoryList: [],
|
||||
provinceList: [],
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '分类ID',
|
||||
dataIndex: 'category_id'
|
||||
},
|
||||
{
|
||||
title: '分类名称',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '省份',
|
||||
dataIndex: 'province'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取分类列表
|
||||
this.getCategoryList(true)
|
||||
// 获取省份
|
||||
this.getProvinceList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 获取分类列表
|
||||
*/
|
||||
getCategoryList (bool) {
|
||||
bool && (this.isLoading = true)
|
||||
Api.list()
|
||||
.then(result => {
|
||||
this.categoryList = result.data.list
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 获取省份
|
||||
getProvinceList () {
|
||||
return new Promise((resolve, reject) => {
|
||||
GoodsApi.province()
|
||||
.then(result => {
|
||||
this.provinceList = result.data.list
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const self = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ categoryId: item['category_id'] })
|
||||
.then((result) => {
|
||||
self.$message.success(result.message, 1.5)
|
||||
self.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh () {
|
||||
// 获取分类列表
|
||||
this.getCategoryList()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="新增商品分类"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="分类名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="上级分类" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
:treeData="categoryListTree"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['parent_id', {initialValue: 0}]"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="所属省份" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['province', {rules: [{message: '请选择所属省份'}]}]"
|
||||
placeholder="请选择所属省份"
|
||||
>
|
||||
<a-select-option
|
||||
key=""
|
||||
value=""
|
||||
>不限</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in provinceList"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="分类图片" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<SelectImage v-decorator="['image_id']" />
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/category'
|
||||
import { SelectImage } from '@/components'
|
||||
import CategoryModel from '@/common/model/Category'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage
|
||||
},
|
||||
props: {
|
||||
// 分类列表
|
||||
categoryList: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
// 省份列表
|
||||
provinceList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 上级分类列表
|
||||
categoryListTree: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 获取分类列表
|
||||
this.getCategoryList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取分类列表
|
||||
*/
|
||||
getCategoryList () {
|
||||
const { categoryList } = this
|
||||
// 格式化分类列表
|
||||
const selectList = CategoryModel.formatTreeData(categoryList)
|
||||
// 顶级分类
|
||||
this.categoryListTree = [{
|
||||
title: '顶级分类',
|
||||
key: 0,
|
||||
value: 0
|
||||
}].concat(selectList)
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,196 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="编辑商品分类"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="分类名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="上级分类" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
:treeData="categoryListTree"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['parent_id']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="分类图片" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<SelectImage
|
||||
:defaultList="record.image ? [record.image] : []"
|
||||
v-decorator="['image_id']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="所属省份" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['province', {rules: [{message: '请选择所属省份'}]}]"
|
||||
placeholder="请选择所属省份"
|
||||
>
|
||||
<a-select-option
|
||||
key=""
|
||||
value=""
|
||||
>不限</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in provinceList"
|
||||
:key="index"
|
||||
:value="item"
|
||||
>{{ item }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', { initialValue: 1, rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import * as Api from '@/api/category'
|
||||
import { SelectImage } from '@/components'
|
||||
import CategoryModel from '@/common/model/Category'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage
|
||||
},
|
||||
props: {
|
||||
// 分类列表
|
||||
categoryList: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
// 省份列表
|
||||
provinceList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 上级分类列表
|
||||
categoryListTree: [],
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前分类记录
|
||||
this.record = record
|
||||
// 获取分类列表
|
||||
this.getCategoryList()
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, form: { setFieldsValue } } = this
|
||||
// 设置表单内容
|
||||
this.$nextTick(() => {
|
||||
setFieldsValue(_.pick(record, ['name', 'parent_id', 'image_id', 'status', 'province', 'sort']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取分类列表
|
||||
*/
|
||||
getCategoryList () {
|
||||
const { categoryList } = this
|
||||
// 格式化分类列表
|
||||
const selectList = CategoryModel.formatTreeData(categoryList)
|
||||
// 顶级分类
|
||||
this.categoryListTree = [{
|
||||
title: '顶级分类',
|
||||
key: 0,
|
||||
value: 0
|
||||
}].concat(selectList)
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ categoryId: this.record['category_id'], form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="商品名称">
|
||||
<a-input v-decorator="['goodsName']" placeholder="请输入商品名称/编码" />
|
||||
</a-form-item>
|
||||
<a-form-item label="订单号">
|
||||
<a-input v-decorator="['orderNo']" placeholder="请输入订单号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="会员ID">
|
||||
<a-input v-decorator="['userId']" placeholder="请输入会员ID" />
|
||||
</a-form-item>
|
||||
<a-form-item label="状态">
|
||||
<a-select v-decorator="['status', { initialValue: -1 }]">
|
||||
<a-select-option :value="-1">全部</a-select-option>
|
||||
<a-select-option :value="1">显示</a-select-option>
|
||||
<a-select-option :value="0">隐藏</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<div class="tab-list fl-l">
|
||||
<a-radio-group :defaultValue="queryParam.score" @change="handleTabs">
|
||||
<a-radio-button :value="0">全部</a-radio-button>
|
||||
<a-radio-button :value="10">好评</a-radio-button>
|
||||
<a-radio-button :value="20">中评</a-radio-button>
|
||||
<a-radio-button :value="30">差评</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="comment_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 商品信息 -->
|
||||
<span slot="orderGoods" slot-scope="goods">
|
||||
<GoodsItem
|
||||
:data="{
|
||||
image: goods.goods_image,
|
||||
imageAlt: '商品图片',
|
||||
title: goods.goods_name,
|
||||
goodsProps: goods.goods_props
|
||||
}"
|
||||
/>
|
||||
</span>
|
||||
<!-- 会员信息 -->
|
||||
<span slot="user" slot-scope="text">
|
||||
<UserItem :user="text" />
|
||||
</span>
|
||||
<!-- 评分 -->
|
||||
<span slot="score" slot-scope="text">
|
||||
<a-tag
|
||||
:color="{ 10: 'green', 20: '', 30: 'red' }[text]"
|
||||
>{{ {10: '好评', 20: '中评', 30: '差评'}[text] }}</a-tag>
|
||||
</span>
|
||||
<!-- 评价内容 -->
|
||||
<span slot="content" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 图片评价 -->
|
||||
<span slot="is_picture" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '是' : '否' }}</a-tag>
|
||||
</span>
|
||||
<!-- 状态 -->
|
||||
<span slot="status" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '显示' : '隐藏' }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</s-table>
|
||||
<EditForm ref="EditForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as CommentApi from '@/api/goods/comment'
|
||||
// import { ContentHeader } from '@/components'
|
||||
import { STable, GoodsItem, UserItem } from '@/components/Table'
|
||||
import EditForm from './modules/EditForm'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'comment_id'
|
||||
},
|
||||
{
|
||||
title: '商品信息',
|
||||
dataIndex: 'orderGoods',
|
||||
width: '320px',
|
||||
scopedSlots: { customRender: 'orderGoods' }
|
||||
},
|
||||
{
|
||||
title: '买家',
|
||||
dataIndex: 'user',
|
||||
scopedSlots: { customRender: 'user' }
|
||||
},
|
||||
{
|
||||
title: '评分',
|
||||
dataIndex: 'score',
|
||||
scopedSlots: { customRender: 'score' }
|
||||
},
|
||||
{
|
||||
title: '评价内容',
|
||||
dataIndex: 'content',
|
||||
scopedSlots: { customRender: 'content' }
|
||||
},
|
||||
{
|
||||
title: '图片评价',
|
||||
dataIndex: 'is_picture',
|
||||
scopedSlots: { customRender: 'is_picture' }
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '评价时间',
|
||||
width: '180px',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '150px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
// ContentHeader,
|
||||
STable,
|
||||
GoodsItem,
|
||||
UserItem,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
expand: false,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 评价分类列表
|
||||
categoryListTree: [],
|
||||
// 查询参数
|
||||
queryParam: {
|
||||
score: 0
|
||||
},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return CommentApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 切换tab
|
||||
handleTabs (e) {
|
||||
this.queryParam.score = e.target.value
|
||||
this.handleRefresh(true)
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return CommentApi.deleted({ commentId: item.comment_id })
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item.comment_id)
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="评分" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['score', {initialValue: 10, rules: [{required: true}]}]">
|
||||
<a-radio :value="10">好评</a-radio>
|
||||
<a-radio :value="20">中评</a-radio>
|
||||
<a-radio :value="30">差评</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="评价内容" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
placeholder="请输入评价内容 (300个字符以内)"
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['content']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="评价图片"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="最多允许6张,可拖拽调整显示顺序"
|
||||
>
|
||||
<SelectImage
|
||||
multiple
|
||||
:maxNum="6"
|
||||
:defaultList="record.imageList"
|
||||
v-decorator="['imageIds']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/goods/comment'
|
||||
import { SelectImage } from '@/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '编辑评价',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 当前记录ID
|
||||
commentId: null,
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (commentId) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录ID
|
||||
this.commentId = commentId
|
||||
// 获取当前详情记录
|
||||
this.getRecordData()
|
||||
},
|
||||
|
||||
// 获取当前详情记录
|
||||
getRecordData () {
|
||||
this.confirmLoading = true
|
||||
Api.detail({ commentId: this.commentId })
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.detail
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { form: { setFieldsValue } } = this
|
||||
this.$nextTick(() => {
|
||||
setFieldsValue(pick(this.record, ['score', 'content', 'status', 'sort', 'imageIds']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.record = {}
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ commentId: this.commentId, form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div class="goods-type">
|
||||
<div
|
||||
class="type-item"
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
:class="{ checked: value == item.value }"
|
||||
v-show="!onlyShowChecked || value == item.value"
|
||||
@click="handleItem(item.value)"
|
||||
>
|
||||
<div class="type-title">{{ item.title }}</div>
|
||||
<div class="type-help">{{ item.help }}</div>
|
||||
<a-icon v-if="value == item.value" class="icon-checked" type="check" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||
import { GoodsTypeEnum } from '@/common/enum/goods'
|
||||
|
||||
// 数字输入框组
|
||||
export default {
|
||||
name: 'GoodsType',
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
// 当前选中项的value
|
||||
value: PropTypes.any,
|
||||
// 仅显示选中的项
|
||||
onlyShowChecked: PropTypes.bool.def(false)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
defaultValue: GoodsTypeEnum.PHYSICAL.value,
|
||||
list: [
|
||||
{
|
||||
title: GoodsTypeEnum.PHYSICAL.name,
|
||||
help: '物流发货',
|
||||
value: GoodsTypeEnum.PHYSICAL.value
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 切换选中事件
|
||||
handleItem (value) {
|
||||
this.$emit('change', value)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 商品类型
|
||||
.goods-type {
|
||||
display: flex;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.type-item {
|
||||
position: relative;
|
||||
border-radius: 2px;
|
||||
padding: 8px 26px;
|
||||
margin-right: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
background-color: #ffffff;
|
||||
color: #262626;
|
||||
border: 1px solid #d9d9d9;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: all .2s ease .1s;
|
||||
|
||||
&.checked {
|
||||
border-color: @primary-color;
|
||||
|
||||
.type-title {
|
||||
color: @primary-color;
|
||||
transition: all .2s ease .1s;
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 20px solid transparent;
|
||||
border-bottom-color: @primary-color;
|
||||
transform: translate(20px, 20px) rotate(135deg);
|
||||
}
|
||||
}
|
||||
|
||||
.type-title {
|
||||
color: #262626;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.type-help {
|
||||
color: #8a9099;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.icon-checked {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
z-index: 1;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-form-item
|
||||
label="优惠券"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<!-- 添加按钮 -->
|
||||
<div class="sku-batch">
|
||||
<a-button @click="handleAddCoupon">添加优惠券</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 优惠券列表 -->
|
||||
<a-table
|
||||
class="sku-list"
|
||||
:columns="columns"
|
||||
:dataSource="multiCouponData"
|
||||
:scroll="{ x: true }"
|
||||
:pagination="false"
|
||||
bordered
|
||||
rowKey="row_id"
|
||||
>
|
||||
<!-- 选择优惠券 -->
|
||||
<template slot="coupon_id" slot-scope="text, item">
|
||||
<a-select
|
||||
v-model="item.coupon_id"
|
||||
placeholder="请选择优惠券"
|
||||
style="width: 100%"
|
||||
@change="emitChange"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(sub_item, index) in couponList"
|
||||
:key="index"
|
||||
:value="sub_item.coupon_id"
|
||||
>
|
||||
{{ sub_item.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<!-- 发送数量 -->
|
||||
<template slot="send_num" slot-scope="text, item">
|
||||
<a-input-number
|
||||
v-model="item.send_num"
|
||||
size="small"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
@change="emitChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 删除操作 -->
|
||||
<template slot="action" slot-scope="text, item">
|
||||
<a @click="handleDelete(item)">删除</a>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '优惠券',
|
||||
dataIndex: 'coupon_id',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'coupon_id' }
|
||||
},
|
||||
{
|
||||
title: '数量',
|
||||
dataIndex: 'send_num',
|
||||
width: 120,
|
||||
scopedSlots: { customRender: 'send_num' }
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '150px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
props: {
|
||||
couponList: PropTypes.any,
|
||||
defaultCouponList: PropTypes.array.def([]),
|
||||
isCouponLocked: PropTypes.bool.def(false)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
columns,
|
||||
labelCol: { span: 3 },
|
||||
wrapperCol: { span: 21 },
|
||||
multiCouponData: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
defaultCouponList (val) {
|
||||
if (val.length) {
|
||||
this.getData()
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData () {
|
||||
this.multiCouponData = this.defaultCouponList.map((item, index) => ({
|
||||
...item,
|
||||
row_id: item.row_id || Date.now() + index
|
||||
}))
|
||||
this.emitChange()
|
||||
},
|
||||
handleAddCoupon () {
|
||||
this.multiCouponData.push({
|
||||
coupon_id: null,
|
||||
send_num: 1,
|
||||
row_id: Date.now()
|
||||
})
|
||||
this.emitChange()
|
||||
},
|
||||
handleDelete (record) {
|
||||
this.multiCouponData = this.multiCouponData.filter(item => item !== record)
|
||||
this.emitChange()
|
||||
},
|
||||
emitChange () {
|
||||
this.$emit('change', this.multiCouponData)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
// 商品多规格
|
||||
.spec-group {
|
||||
width: 895px;
|
||||
margin-bottom: 15px;
|
||||
line-height: normal;
|
||||
|
||||
.ant-input {
|
||||
height: 28px;
|
||||
padding: 4px 11px;
|
||||
font-size: @font-size-base;
|
||||
line-height: 1.5;
|
||||
|
||||
&::placeholder {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
}
|
||||
|
||||
.form-item-help {
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.spec-group-item {
|
||||
background: #f4f5f9;
|
||||
padding: 7px 12px;
|
||||
line-height: 28px;
|
||||
|
||||
.group-item-input {
|
||||
float: left;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.group-item-delete {
|
||||
font-size: 12px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.spec-value {
|
||||
background: #fbfbfb;
|
||||
padding: 8px 35px;
|
||||
|
||||
.spec-value-add,
|
||||
.spec-value-item {
|
||||
float: left;
|
||||
margin-bottom: 6px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.spec-value-add {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
|
||||
a {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.spec-value-item {
|
||||
position: relative;
|
||||
margin-right: 20px;
|
||||
|
||||
.value-item-input {
|
||||
width: 186px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.icon-close {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
color: #7d7d7d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加规格按钮
|
||||
.spec-group-add-btn {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
|
||||
// 批量设置sku
|
||||
.sku-batch {
|
||||
line-height: 40px;
|
||||
margin-bottom: 12px;
|
||||
.title {
|
||||
line-height: 28px;
|
||||
margin-right: 15px;
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
/deep/.ant-input,
|
||||
/deep/.ant-input-number {
|
||||
width: 120px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
/deep/.ant-input {
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
|
||||
// sku列表
|
||||
.sku-list {
|
||||
width: 895px;
|
||||
/deep/.ant-table-thead > tr > th,
|
||||
/deep/.ant-table-tbody > tr > td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
/deep/.ant-table-tbody > tr > td {
|
||||
padding: 12px 18px;
|
||||
}
|
||||
|
||||
/deep/.ant-input-sm,
|
||||
/deep/.ant-input-number-sm {
|
||||
height: 28px;
|
||||
}
|
||||
/deep/.ant-input-number-sm input {
|
||||
height: 26px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,407 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-form-item label="商品规格" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<div v-if="true" class="form-item-help" style="line-height: 36px">
|
||||
<small>最多添加3个商品规格组,生成的SKU数量不能超出50个</small>
|
||||
</div>
|
||||
<!-- 规格组 -->
|
||||
<div class="spec-group" v-for="(item, index) in multiSpecData.specList" :key="index">
|
||||
<div class="spec-group-item clearfix">
|
||||
<a-input
|
||||
class="group-item-input"
|
||||
v-model="item.spec_name"
|
||||
:readOnly="isSpecLocked"
|
||||
placeholder="请输入规格名称"
|
||||
@change="onChangeSpecGroupIpt"
|
||||
/>
|
||||
<a
|
||||
v-if="!isSpecLocked"
|
||||
class="group-item-delete"
|
||||
href="javascript:;"
|
||||
@click="handleDeleteSpecGroup(index)"
|
||||
>删除规格组</a>
|
||||
</div>
|
||||
<div class="spec-value clearfix">
|
||||
<div class="spec-value-item" v-for="(itm, idx) in item.valueList" :key="idx">
|
||||
<a-input
|
||||
class="value-item-input"
|
||||
v-model="itm.spec_value"
|
||||
:readOnly="isSpecLocked"
|
||||
placeholder="请输入规格值"
|
||||
@change="onChangeSpecValueIpt"
|
||||
/>
|
||||
<a-icon
|
||||
v-if="!isSpecLocked"
|
||||
class="icon-close"
|
||||
theme="filled"
|
||||
type="close-circle"
|
||||
@click="handleDeleteSpecValue(index, idx)"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!isSpecLocked" class="spec-value-add">
|
||||
<a
|
||||
class="group-item-delete"
|
||||
href="javascript:;"
|
||||
@click="handleAddSpecValue(index)"
|
||||
>新增规格值</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加规格按钮 -->
|
||||
<a-button
|
||||
v-if="!isSpecLocked && multiSpecData.specList.length < 3"
|
||||
class="spec-group-add-btn"
|
||||
icon="plus"
|
||||
@click="handleAddSpecGroup"
|
||||
>添加规格组</a-button>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-show="multiSpecData.skuList.length"
|
||||
label="SKU列表"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<!-- 批量设置 -->
|
||||
<div v-if="multiSpecData.skuList.length > 1" class="sku-batch">
|
||||
<span class="title">批量设置:</span>
|
||||
<a-input-number
|
||||
v-model="multiSpecData.skuBatchForm.goods_price"
|
||||
placeholder="商品价格"
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
/>
|
||||
<a-input-number
|
||||
v-model="multiSpecData.skuBatchForm.line_price"
|
||||
placeholder="划线价格"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
/>
|
||||
<a-input-number
|
||||
v-model="multiSpecData.skuBatchForm.stock_num"
|
||||
placeholder="库存数量"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
/>
|
||||
<a-input-number
|
||||
v-model="multiSpecData.skuBatchForm.goods_weight"
|
||||
placeholder="商品重量"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
/>
|
||||
<a-input v-model="multiSpecData.skuBatchForm.goods_sku_no" placeholder="sku编码" />
|
||||
<a-button @click="handleSkuBatch">立即设置</a-button>
|
||||
</div>
|
||||
<!-- sku列表table -->
|
||||
<a-table
|
||||
class="sku-list"
|
||||
:columns="multiSpecData.skuColumns"
|
||||
:dataSource="multiSpecData.skuList"
|
||||
:scroll="{ x: true }"
|
||||
:pagination="false"
|
||||
bordered
|
||||
>
|
||||
<!-- 预览图 -->
|
||||
<template slot="image" slot-scope="text, item">
|
||||
<SelectImage
|
||||
v-model="item.image_id"
|
||||
:defaultList="(item.image_id > 0 && item.image) ? [item.image] : []"
|
||||
:width="50"
|
||||
/>
|
||||
</template>
|
||||
<!-- 商品价格 -->
|
||||
<template slot="goods_price" slot-scope="text, item">
|
||||
<a-input-number v-model="item.goods_price" size="small" :min="0.01" :precision="2" />
|
||||
</template>
|
||||
<!-- 划线价格 -->
|
||||
<template slot="line_price" slot-scope="text, item">
|
||||
<a-input-number v-model="item.line_price" size="small" :min="0" :precision="2" />
|
||||
</template>
|
||||
<!-- 库存数量 -->
|
||||
<template slot="stock_num" slot-scope="text, item">
|
||||
<a-input-number v-model="item.stock_num" size="small" :min="0" :precision="0" />
|
||||
</template>
|
||||
<!-- 商品重量 -->
|
||||
<template slot="goods_weight" slot-scope="text, item">
|
||||
<a-input-number v-model="item.goods_weight" size="small" :min="0" :precision="2" />
|
||||
</template>
|
||||
<!-- sku编码 -->
|
||||
<template slot="goods_sku_no" slot-scope="text, item">
|
||||
<a-input v-model="item.goods_sku_no" size="small" />
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||
import MultiSpecModel from '@/common/model/goods/MultiSpec'
|
||||
import { SelectImage } from '@/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectImage
|
||||
},
|
||||
props: {
|
||||
// 默认的规格列表
|
||||
defaultSpecList: PropTypes.array.def([]),
|
||||
// 默认的SKU列表
|
||||
defaultSkuList: PropTypes.array.def([]),
|
||||
// 商品规格是否锁定(锁定状态下不允许编辑规格)
|
||||
isSpecLocked: PropTypes.bool.def(false)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 21 },
|
||||
// 商品多规格模型
|
||||
MultiSpecModel: new MultiSpecModel(),
|
||||
// MultiSpecModel: Object,
|
||||
multiSpecData: {
|
||||
// 规格列表
|
||||
specList: [],
|
||||
// SKU列表
|
||||
skuList: []
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
defaultSpecList (val) {
|
||||
if (val.length && this.MultiSpecModel.isEmpty()) {
|
||||
this.getData()
|
||||
}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取规格及SKU信息
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取规格及SKU信息(展示)
|
||||
getData () {
|
||||
const { defaultSpecList, defaultSkuList } = this
|
||||
this.multiSpecData = this.MultiSpecModel.getData(defaultSpecList, defaultSkuList)
|
||||
},
|
||||
|
||||
// 获取规格及SKU信息(表单提交)
|
||||
getFromSpecData () {
|
||||
return this.MultiSpecModel.getFromSpecData()
|
||||
},
|
||||
|
||||
// 添加规格组
|
||||
handleAddSpecGroup () {
|
||||
if (this.checkSkuMaxNum()) {
|
||||
this.MultiSpecModel.handleAddSpecGroup()
|
||||
}
|
||||
},
|
||||
|
||||
// 删除规格组
|
||||
handleDeleteSpecGroup (groupIndex) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该规格组吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
// 删除元素
|
||||
app.MultiSpecModel.handleDeleteSpecGroup(groupIndex)
|
||||
// 关闭对话框
|
||||
modal.destroy()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 新增规格值
|
||||
handleAddSpecValue (groupIndex) {
|
||||
if (this.checkSkuMaxNum()) {
|
||||
this.MultiSpecModel.handleAddSpecValue(groupIndex)
|
||||
}
|
||||
},
|
||||
|
||||
// 删除规格值
|
||||
handleDeleteSpecValue (groupIndex, valueIndex) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该规格值吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
// 删除元素
|
||||
app.MultiSpecModel.handleDeleteSpecValue(groupIndex, valueIndex)
|
||||
// 关闭对话框
|
||||
modal.destroy()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 规格组输入框change事件
|
||||
onChangeSpecGroupIpt () {
|
||||
// 更新skuList
|
||||
this.MultiSpecModel.onUpdate(true)
|
||||
},
|
||||
|
||||
// 规格值输入框change事件
|
||||
onChangeSpecValueIpt (event, itm) {
|
||||
// 更新skuList
|
||||
this.MultiSpecModel.onUpdate(true)
|
||||
},
|
||||
|
||||
// 验证最大sku数量
|
||||
checkSkuMaxNum () {
|
||||
const skuList = this.multiSpecData.skuList
|
||||
if (skuList.length >= 50) {
|
||||
this.$message.error(`生成的sku列表数量不能大于50个,当前数量:${skuList.length}个`, 2.5)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
// 批量设置sku事件
|
||||
handleSkuBatch () {
|
||||
this.MultiSpecModel.handleSkuBatch()
|
||||
},
|
||||
|
||||
// 验证多规格表单
|
||||
verifyForm () {
|
||||
if (!this.MultiSpecModel.verifyForm()) {
|
||||
this.$message.error(this.MultiSpecModel.getError(), 2)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
// 商品多规格
|
||||
.spec-group {
|
||||
width: 895px;
|
||||
margin-bottom: 15px;
|
||||
line-height: normal;
|
||||
|
||||
.ant-input {
|
||||
height: 28px;
|
||||
padding: 4px 11px;
|
||||
font-size: @font-size-base;
|
||||
line-height: 1.5;
|
||||
|
||||
&::placeholder {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
}
|
||||
|
||||
.form-item-help {
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.spec-group-item {
|
||||
background: #f4f5f9;
|
||||
padding: 7px 12px;
|
||||
line-height: 28px;
|
||||
|
||||
.group-item-input {
|
||||
float: left;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.group-item-delete {
|
||||
font-size: 12px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.spec-value {
|
||||
background: #fbfbfb;
|
||||
padding: 8px 35px;
|
||||
|
||||
.spec-value-add,
|
||||
.spec-value-item {
|
||||
float: left;
|
||||
margin-bottom: 6px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.spec-value-add {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
|
||||
a {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.spec-value-item {
|
||||
position: relative;
|
||||
margin-right: 20px;
|
||||
|
||||
.value-item-input {
|
||||
width: 186px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.icon-close {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
color: #7d7d7d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加规格按钮
|
||||
.spec-group-add-btn {
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
|
||||
// 批量设置sku
|
||||
.sku-batch {
|
||||
line-height: 40px;
|
||||
margin-bottom: 12px;
|
||||
.title {
|
||||
line-height: 28px;
|
||||
margin-right: 15px;
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
/deep/.ant-input,
|
||||
/deep/.ant-input-number {
|
||||
width: 120px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
/deep/.ant-input {
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
|
||||
// sku列表
|
||||
.sku-list {
|
||||
width: 895px;
|
||||
/deep/.ant-table-thead > tr > th,
|
||||
/deep/.ant-table-tbody > tr > td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
/deep/.ant-table-tbody > tr > td {
|
||||
padding: 12px 18px;
|
||||
}
|
||||
|
||||
/deep/.ant-input-sm,
|
||||
/deep/.ant-input-number-sm {
|
||||
height: 28px;
|
||||
}
|
||||
/deep/.ant-input-number-sm input {
|
||||
height: 26px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,5 @@
|
||||
import GoodsType from './GoodsType'
|
||||
import MultiSpec from './MultiSpec'
|
||||
import MultiCoupon from './MultiCoupon'
|
||||
|
||||
export { GoodsType, MultiSpec, MultiCoupon }
|
||||
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-row>
|
||||
<a-col :span="6">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</a-col>
|
||||
<a-col :span="8" :offset="10">
|
||||
<a-input-search
|
||||
style="max-width: 300px; min-width: 150px;float: right;"
|
||||
v-model="queryParam.search"
|
||||
placeholder="请输入服务名称"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="service_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 概述 -->
|
||||
<span slot="summary" slot-scope="text">
|
||||
<p class="summary oneline-hide">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 是否默认 -->
|
||||
<span slot="is_default" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '是' : '否' }}</a-tag>
|
||||
</span>
|
||||
<!-- 状态 -->
|
||||
<span slot="status" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '显示' : '隐藏' }}</a-tag>
|
||||
</span>
|
||||
<!-- 操作 -->
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</s-table>
|
||||
<AddForm ref="AddForm" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/goods/service'
|
||||
import { STable } from '@/components'
|
||||
import AddForm from './modules/AddForm'
|
||||
import EditForm from './modules/EditForm'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '服务ID',
|
||||
dataIndex: 'service_id'
|
||||
},
|
||||
{
|
||||
title: '服务名称',
|
||||
dataIndex: 'name',
|
||||
width: '300px'
|
||||
},
|
||||
{
|
||||
title: '概述',
|
||||
dataIndex: 'summary',
|
||||
scopedSlots: { customRender: 'summary' }
|
||||
},
|
||||
{
|
||||
title: '是否默认',
|
||||
dataIndex: 'is_default',
|
||||
scopedSlots: { customRender: 'is_default' }
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'update_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const self = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ serviceId: item['service_id'] })
|
||||
.then((result) => {
|
||||
self.$message.success(result.message, 1.5)
|
||||
self.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
/**
|
||||
* 检索查询
|
||||
*/
|
||||
onSearch () {
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.summary {
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="服务名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入服务与承诺的名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="概述" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
placeholder="请输入概述内容 (300个字符以内)"
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['summary']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="是否默认" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="新增商品时是否默认勾选">
|
||||
<a-radio-group v-decorator="['is_default', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">是</a-radio>
|
||||
<a-radio :value="0">否</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/goods/service'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.title = '新增记录'
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="服务名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入服务与承诺的名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="概述" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
placeholder="请输入概述内容 (300个字符以内)"
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['summary']"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="是否默认" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="新增商品时是否默认勾选">
|
||||
<a-radio-group v-decorator="['is_default', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">是</a-radio>
|
||||
<a-radio :value="0">否</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="用户端是否展示">
|
||||
<a-radio-group v-decorator="['status', {initialValue: 1, rules: [{required: true}]}]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/goods/service'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.title = '编辑记录'
|
||||
this.visible = true
|
||||
// 当前管理员记录
|
||||
this.record = record
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { form: { setFieldsValue } } = this
|
||||
this.$nextTick(() => {
|
||||
setFieldsValue(pick(this.record, ['name', 'summary', 'is_default', 'status', 'sort']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ serviceId: this.record['service_id'], form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,25 @@
|
||||
.tabs-content {
|
||||
.tab-pane {
|
||||
animation: fadenum 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 18px;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-number-group {
|
||||
margin: 3px 0;
|
||||
}
|
||||
@@ -0,0 +1,526 @@
|
||||
<template>
|
||||
<a-spin :spinning="isLoading">
|
||||
<div class="container">
|
||||
<!-- 实时概况 -->
|
||||
<a-card class="overview" :bordered="false">
|
||||
<div class="card-title">
|
||||
<span>实时概况(今日)</span>
|
||||
</div>
|
||||
<a-row :gutter="32">
|
||||
<a-col class :span="6">
|
||||
<div class="item flex">
|
||||
<div class="col-left">
|
||||
<div class="icon-body flex flex-x-center flex-y-center">
|
||||
<a-icon :component="Icons.overview.sale" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-right">
|
||||
<p class="name">销售额 (元)</p>
|
||||
<p class="value">{{ data.overview.orderTotalPrice.tday }}</p>
|
||||
<p class="yesterday">昨日:{{ data.overview.orderTotalPrice.yday }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col class :span="6">
|
||||
<div class="item flex">
|
||||
<div class="col-right">
|
||||
<p class="name">支付订单数</p>
|
||||
<p class="value">{{ data.overview.orderTotal.tday }}</p>
|
||||
<p class="yesterday">昨日:{{ data.overview.orderTotal.yday }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
<!--<a-col class :span="6">
|
||||
<div class="item flex">
|
||||
<div class="col-left">
|
||||
<div class="icon-body flex flex-x-center flex-y-center">
|
||||
<a-icon :component="Icons.overview.increase" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-right">
|
||||
<p class="name">新增会员数</p>
|
||||
<p class="value">{{ data.overview.newUserTotal.tday }}</p>
|
||||
<p class="yesterday">昨日:{{ data.overview.newUserTotal.yday }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col class :span="6">
|
||||
<div class="item flex">
|
||||
<div class="col-right">
|
||||
<p class="name">付款会员数</p>
|
||||
<p class="value">{{ data.overview.consumeUserTotal.tday }}</p>
|
||||
<p class="yesterday">昨日:{{ data.overview.consumeUserTotal.yday }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>-->
|
||||
</a-row>
|
||||
</a-card>
|
||||
|
||||
<!-- 统计 -->
|
||||
<a-row class="statistics mt-20" :gutter="32" v-if="data.power.super">
|
||||
<a-col class="item" :span="6">
|
||||
<a-card :bordered="false">
|
||||
<div class="flex flex-y-center">
|
||||
<div class="col-left">
|
||||
<div class="icon-body flex flex-x-center flex-y-center">
|
||||
<a-icon class="icon" :component="Icons.statistics.goods" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-right">
|
||||
<p class="info">商品总数量</p>
|
||||
<p class="keynote">{{ data.statistics.goodsTotal }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col class="item" :span="6">
|
||||
<a-card :bordered="false">
|
||||
<div class="flex flex-y-center">
|
||||
<div class="col-left">
|
||||
<div class="icon-body flex flex-x-center flex-y-center">
|
||||
<a-icon class="icon" :component="Icons.statistics.user" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-right">
|
||||
<p class="info">会员总人数</p>
|
||||
<p class="keynote">{{ data.statistics.userTotal }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col class="item" :span="6">
|
||||
<a-card :bordered="false">
|
||||
<div class="flex flex-y-center">
|
||||
<div class="col-left">
|
||||
<div class="icon-body flex flex-x-center flex-y-center">
|
||||
<a-icon class="icon" :component="Icons.statistics.order" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-right">
|
||||
<p class="info">付款订单总量</p>
|
||||
<p class="keynote">{{ data.statistics.orderTotal }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col class="item" :span="6">
|
||||
<a-card :bordered="false">
|
||||
<div class="flex flex-y-center">
|
||||
<div class="col-left">
|
||||
<div class="icon-body flex flex-x-center flex-y-center">
|
||||
<a-icon class="icon" :component="Icons.statistics.consume" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-right">
|
||||
<p class="info">消费总金额</p>
|
||||
<p class="keynote">{{ data.statistics.orderMoneyTotal }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<!-- 待办事项 -->
|
||||
<!--<a-card class="pending mt-20" :bordered="false">
|
||||
<a-row :gutter="32">
|
||||
<a-col :span="6">
|
||||
<div class="item">
|
||||
<router-link to="/order/list/delivery">
|
||||
<p class="name">待发货订单(笔)</p>
|
||||
<p class="value">{{ data.pending.deliverOrderTotal }}</p>
|
||||
</router-link>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<div class="item">
|
||||
<router-link to="/order/refund/index">
|
||||
<p class="name">售后单(笔)</p>
|
||||
<p class="value">{{ data.pending.refundTotal }}</p>
|
||||
</router-link>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<div class="item">
|
||||
<router-link to="/order/list/pay">
|
||||
<p class="name">待付款订单(笔)</p>
|
||||
<p class="value">{{ data.pending.paidOrderTotal }}</p>
|
||||
</router-link>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<div class="item">
|
||||
<router-link :to="{ path: '/goods/index', query: { listType: 'sold_out' } }">
|
||||
<p class="name">已售罄商品</p>
|
||||
<p class="value">{{ data.pending.soldoutGoodsTotal }}</p>
|
||||
</router-link>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>--》
|
||||
|
||||
<!-- 常用功能 -->
|
||||
<!--<a-card class="functions mt-20" :bordered="false">
|
||||
<div class="card-title">
|
||||
<span>常用功能</span>
|
||||
</div>
|
||||
<a-row :gutter="32">
|
||||
<a-col class :span="6" v-for="(item, index) in functions" :key="index">
|
||||
<div class="item" @click="handleLink(item.link)">
|
||||
<div class="flex flex-y-center">
|
||||
<div
|
||||
class="icon flex flex-x-center flex-y-center"
|
||||
:style="{ backgroundColor: item.color }"
|
||||
>
|
||||
<a-icon :component="item.icon" />
|
||||
</div>
|
||||
<span class="name">{{ item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>-->
|
||||
|
||||
<!-- 近七日交易走势 -->
|
||||
<a-card class="trade-trend mt-20" :bordered="false">
|
||||
<div class="card-title">
|
||||
<span>近七日交易走势</span>
|
||||
</div>
|
||||
<div class="echarts-body">
|
||||
<div id="main" style="width: 100%; height: 400px;"></div>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
import 'echarts/theme/fresh-cut'
|
||||
import * as Api from '@/api/home'
|
||||
import * as Icons from './modules/icon'
|
||||
|
||||
// 常用功能
|
||||
const functions = [
|
||||
{
|
||||
name: '发布商品',
|
||||
icon: Icons.functions.goods,
|
||||
color: '#00BF57',
|
||||
link: '/goods/create'
|
||||
},
|
||||
{
|
||||
name: '店铺装修',
|
||||
icon: Icons.functions.decorate,
|
||||
color: '#f15858',
|
||||
link: '/page/index'
|
||||
},
|
||||
{
|
||||
name: '会员管理',
|
||||
icon: Icons.functions.user,
|
||||
color: '#139dff',
|
||||
link: '/user/index'
|
||||
},
|
||||
{
|
||||
name: '订单管理',
|
||||
icon: Icons.functions.order,
|
||||
color: '#139dff',
|
||||
link: '/order/list/all'
|
||||
},
|
||||
{
|
||||
name: '售后管理',
|
||||
icon: Icons.functions.refund,
|
||||
color: '#139dff',
|
||||
link: '/order/refund/index'
|
||||
},
|
||||
{
|
||||
name: '优惠券',
|
||||
icon: Icons.functions.coupon,
|
||||
color: '#f15858',
|
||||
link: '/market/coupon/index'
|
||||
},
|
||||
{
|
||||
name: '数据统计',
|
||||
icon: Icons.functions.statistics,
|
||||
color: '#139dff',
|
||||
link: '/statistics'
|
||||
}
|
||||
]
|
||||
|
||||
const data = {
|
||||
overview: {
|
||||
orderTotalPrice: {
|
||||
tday: '0.00',
|
||||
ytd: '0.00'
|
||||
},
|
||||
orderTotal: {
|
||||
tday: '0',
|
||||
ytd: '0'
|
||||
},
|
||||
newUserTotal: {
|
||||
tday: '0',
|
||||
ytd: '0'
|
||||
},
|
||||
consumeUserTotal: {
|
||||
tday: '0',
|
||||
ytd: '0'
|
||||
}
|
||||
},
|
||||
statistics: {
|
||||
goodsTotal: '0',
|
||||
userTotal: '0',
|
||||
orderTotal: '0',
|
||||
orderMoneyTotal: '0',
|
||||
consumeUserTotal: '0'
|
||||
},
|
||||
pending: {
|
||||
deliverOrderTotal: 0,
|
||||
refundTotal: 0,
|
||||
paidOrderTotal: 0,
|
||||
soldoutGoodsTotal: 0
|
||||
},
|
||||
tradeTrend: {
|
||||
date: [],
|
||||
orderTotal: [],
|
||||
orderTotalPrice: []
|
||||
},
|
||||
power: {
|
||||
super: 0
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
data () {
|
||||
return {
|
||||
Icons,
|
||||
functions,
|
||||
// 正在提交
|
||||
isLoading: false,
|
||||
// 首页数据
|
||||
data
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取首页数据
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取首页数据
|
||||
getData () {
|
||||
this.isLoading = true
|
||||
Api.data()
|
||||
.then(result => {
|
||||
this.data = result.data.data
|
||||
// 渲染走势图
|
||||
this.$nextTick(() => {
|
||||
this.myEcharts()
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到指定link
|
||||
handleLink (link) {
|
||||
const app = this
|
||||
if (!app.$auth(link)) {
|
||||
app.$message.info('很抱歉,没有该页面的访问权限')
|
||||
return false
|
||||
}
|
||||
app.$router.push(link)
|
||||
},
|
||||
|
||||
// 渲染走势图
|
||||
myEcharts () {
|
||||
const { data } = this
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
const myChart = echarts.init(document.getElementById('main'), 'fresh-cut')
|
||||
|
||||
// 指定图表的配置项和数据
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['成交量', '成交额']
|
||||
},
|
||||
toolbox: {
|
||||
show: true,
|
||||
showTitle: false,
|
||||
feature: {
|
||||
mark: { show: true },
|
||||
magicType: { show: true, type: ['line', 'bar'] }
|
||||
}
|
||||
},
|
||||
calculable: true,
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: data.tradeTrend.date
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '成交额',
|
||||
type: 'line',
|
||||
data: data.tradeTrend.orderTotalPrice
|
||||
},
|
||||
{
|
||||
name: '成交量',
|
||||
type: 'line',
|
||||
data: data.tradeTrend.orderTotal
|
||||
}
|
||||
]
|
||||
}
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
myChart.setOption(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.card-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
// 统计
|
||||
.statistics {
|
||||
line-height: 1;
|
||||
|
||||
.ant-card {
|
||||
.ant-card-body {
|
||||
height: 100%;
|
||||
padding: 30px 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.col-left {
|
||||
margin-right: 25px;
|
||||
font-size: 24px;
|
||||
color: #4799ff;
|
||||
|
||||
.icon-body {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
border-radius: 50%;
|
||||
background-color: #eff6ff;
|
||||
}
|
||||
}
|
||||
|
||||
.col-right {
|
||||
margin-top: -5px;
|
||||
|
||||
.keynote {
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 待办事项
|
||||
.pending {
|
||||
text-align: center;
|
||||
padding: 15px 0;
|
||||
|
||||
.item {
|
||||
display: inline-block;
|
||||
padding: 0 20px;
|
||||
|
||||
a {
|
||||
color: unset;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
font-size: 13.6px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// 常用功能
|
||||
.functions {
|
||||
.item {
|
||||
display: block;
|
||||
padding: 13px 20px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: @font-size-base;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
// background : #139dff !important;
|
||||
color: #fff;
|
||||
font-size: @font-size-base;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
// 实时概况
|
||||
.overview {
|
||||
a {
|
||||
color: unset;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 13px 20px;
|
||||
}
|
||||
|
||||
.col-left {
|
||||
color: #4799ff;
|
||||
font-size: 28px;
|
||||
margin-right: 35px;
|
||||
|
||||
.icon-body {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
border-radius: 50%;
|
||||
background-color: #eff6ff;
|
||||
}
|
||||
}
|
||||
|
||||
.col-right {
|
||||
.name {
|
||||
font-size: @font-size-base;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #000;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.yesterday {
|
||||
display: none;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 首页图标库
|
||||
*/
|
||||
import fCoupon from '@/assets/icons/home/functions/coupon.svg?inline'
|
||||
import fGoods from '@/assets/icons/home/functions/goods.svg?inline'
|
||||
import fOrder from '@/assets/icons/home/functions/order.svg?inline'
|
||||
import fRefund from '@/assets/icons/home/functions/refund.svg?inline'
|
||||
import fStatistics from '@/assets/icons/home/functions/statistics.svg?inline'
|
||||
import fUser from '@/assets/icons/home/functions/user.svg?inline'
|
||||
import fDecorate from '@/assets/icons/home/functions/decorate.svg?inline'
|
||||
|
||||
import oSale from '@/assets/icons/home/overview/sale.svg?inline'
|
||||
import oIncrease from '@/assets/icons/home/overview/increase.svg?inline'
|
||||
|
||||
import sGoods from '@/assets/icons/home/statistics/goods.svg?inline'
|
||||
import sOrder from '@/assets/icons/home/statistics/order.svg?inline'
|
||||
import sUser from '@/assets/icons/home/statistics/user.svg?inline'
|
||||
import sConsume from '@/assets/icons/home/statistics/consume.svg?inline'
|
||||
|
||||
// 常用功能
|
||||
const functions = {
|
||||
coupon: fCoupon,
|
||||
goods: fGoods,
|
||||
order: fOrder,
|
||||
refund: fRefund,
|
||||
statistics: fStatistics,
|
||||
user: fUser,
|
||||
decorate: fDecorate
|
||||
}
|
||||
|
||||
// 实时概况
|
||||
const overview = { sale: oSale, increase: oIncrease }
|
||||
|
||||
// 统计
|
||||
const statistics = { goods: sGoods, order: sOrder, user: sUser, consume: sConsume }
|
||||
|
||||
export { functions, overview, statistics }
|
||||
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<content-header title="管理员设置"></content-header>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="姓名" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="管理员姓名">
|
||||
<a-input
|
||||
v-decorator="['real_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="用户名" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="后台登录用户名">
|
||||
<a-input
|
||||
v-decorator="['user_name', {rules: [{required: true, min: 4, message: '请输入至少4个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="用户密码" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="后台登录密码">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['password', {rules: [{min: 6, message: '请输入至少6个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="确认密码" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['password_confirm', {rules: [
|
||||
{message: '请输入确认密码'},
|
||||
{validator: compareToFirstPassword}
|
||||
]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapperCol="{span: 13, offset: 6}">
|
||||
<a-button
|
||||
type="primary"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
@click="handleSubmit"
|
||||
>提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/store/user'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
name: 'TableList',
|
||||
components: {
|
||||
ContentHeader,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 6
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// 正在提交
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 获取管理员设置
|
||||
this.getInfo()
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 获取管理员设置
|
||||
*/
|
||||
getInfo () {
|
||||
this.isLoading = true
|
||||
Api.getInfo()
|
||||
.then((result) => {
|
||||
const { data: { userInfo } } = result
|
||||
this.form.setFieldsValue(_.pick(userInfo, 'user_name', 'real_name'))
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 验证确认密码是否一致
|
||||
*/
|
||||
compareToFirstPassword (rule, value, callback) {
|
||||
const { form } = this
|
||||
const passwordVal = form.getFieldValue('password')
|
||||
if (passwordVal && (value !== passwordVal)) {
|
||||
return new Error('您输入的确认密码不一致')
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
const { form: { validateFields } } = this
|
||||
// 表单的验证
|
||||
validateFields((errors, values) => {
|
||||
if (!errors) {
|
||||
this.isLoading = true
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
return Api.renew({ form: values })
|
||||
.then(result => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message)
|
||||
setTimeout(() => {
|
||||
window.location.reload()
|
||||
}, 800)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-button type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</div>
|
||||
<a-table
|
||||
v-if="!isLoading"
|
||||
rowKey="role_id"
|
||||
:columns="columns"
|
||||
:dataSource="roleList"
|
||||
:defaultExpandAllRows="true"
|
||||
:expandIconColumnIndex="1"
|
||||
:pagination="false"
|
||||
:loading="isLoading"
|
||||
>
|
||||
<!-- 创建人 -->
|
||||
<span slot="storeUser" slot-scope="text, item">
|
||||
<p class="twoline-hide" >{{ item.storeUser?item.storeUser.real_name:'无' }}</p>
|
||||
</span>
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<template>
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</template>
|
||||
</span>
|
||||
</a-table>
|
||||
<AddForm
|
||||
ref="AddForm"
|
||||
:roleList="roleList"
|
||||
:menuList="menuList"
|
||||
@handleSubmit="handleRefresh"
|
||||
/>
|
||||
<EditForm
|
||||
ref="EditForm"
|
||||
:roleList="roleList"
|
||||
:menuList="menuList"
|
||||
@handleSubmit="handleRefresh"
|
||||
/>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/store/role'
|
||||
import * as MenuApi from '@/api/store/menu'
|
||||
import { STable } from '@/components'
|
||||
import AddForm from './modules/AddForm'
|
||||
import EditForm from './modules/EditForm'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 角色列表
|
||||
roleList: [],
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: true,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '角色ID',
|
||||
dataIndex: 'role_id'
|
||||
},
|
||||
{
|
||||
title: '角色名称',
|
||||
dataIndex: 'role_name'
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'storeUser',
|
||||
width: '100px',
|
||||
scopedSlots: { customRender: 'storeUser' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
// 权限列表
|
||||
menuList: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取角色列表
|
||||
this.getRoleList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
getRoleList () {
|
||||
this.isLoading = true
|
||||
Api.list()
|
||||
.then(result => {
|
||||
this.roleList = result.data.list
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取菜单列表数据
|
||||
*/
|
||||
async getMenuList () {
|
||||
if (!this.menuList.length) {
|
||||
this.isLoading = true
|
||||
await MenuApi.list().then(response => {
|
||||
this.menuList = response.data.list
|
||||
}).finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
async handleAdd () {
|
||||
// 获取菜单列表数据
|
||||
await this.getMenuList()
|
||||
// 显示对话框
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
async handleEdit (record) {
|
||||
// 获取菜单列表数据
|
||||
await this.getMenuList()
|
||||
// 显示对话框
|
||||
this.$refs.EditForm.edit(record)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (record) {
|
||||
const self = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ roleId: record['role_id'] })
|
||||
.then(result => {
|
||||
self.$message.success(result.message, 1.5)
|
||||
self.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
*/
|
||||
handleRefresh () {
|
||||
// 获取角色列表
|
||||
this.getRoleList()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,309 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="新增角色"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="角色名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['role_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="上级角色" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
:treeData="roleListTree"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['parent_id']"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="菜单权限"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="设置该角色有权操作的功能"
|
||||
>
|
||||
<a-tree
|
||||
ref="MenuTree"
|
||||
v-model="checkedKeys"
|
||||
checkable
|
||||
checkStrictly
|
||||
:treeData="menuListTreeData"
|
||||
:autoExpandParent="false"
|
||||
@check="onCheckedMenu"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/store/role'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 角色列表
|
||||
roleList: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
// 菜单列表
|
||||
menuList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 上级角色列表
|
||||
roleListTree: [],
|
||||
// 菜单列表 树状结构
|
||||
menuListTreeData: [],
|
||||
// 当前选中的keys
|
||||
checkedKeys: {
|
||||
checked: [],
|
||||
halfChecked: []
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 获取角色列表
|
||||
this.getRoleList()
|
||||
// 获取API权限列表
|
||||
this.getMenuList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
getMenuList () {
|
||||
const { menuList } = this
|
||||
this.menuListTreeData = this.formatTreeDataForMenuList(menuList)
|
||||
},
|
||||
|
||||
// 节点选中事件
|
||||
onCheckedMenu (checkedKeys, { checked, node }) {
|
||||
// 寻找当前选择的节点
|
||||
const { menuListTreeData } = this
|
||||
const nodeData = this.findNode(node.eventKey, menuListTreeData)
|
||||
// 选择节点时联动所有子节点
|
||||
this.onCheckChilds(checked, nodeData)
|
||||
// 选择节点时联动所有父节点
|
||||
this.onCheckParents(checked, nodeData)
|
||||
},
|
||||
|
||||
// 寻找指定的的节点
|
||||
findNode (key, list) {
|
||||
for (let index = 0; index < list.length; index++) {
|
||||
const item = list[index]
|
||||
if (item.key === key) {
|
||||
return item
|
||||
} else if (item.children) {
|
||||
const result = this.findNode(key, item.children)
|
||||
if (result) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
// 选择节点时联动所有父节点
|
||||
onCheckParents (checked, node) {
|
||||
// 查找所有父节点(方法)
|
||||
const { menuListTreeData } = this
|
||||
const findParentKeys = (parentKey) => {
|
||||
let keys = []
|
||||
const parent = this.findNode(parentKey, menuListTreeData)
|
||||
if (!parent) {
|
||||
return keys
|
||||
}
|
||||
keys.push(parent.key)
|
||||
if (parent.children) {
|
||||
const arr = findParentKeys(parent.parentKey)
|
||||
arr.length && (keys = keys.concat(arr))
|
||||
}
|
||||
return keys
|
||||
}
|
||||
// 查找所有父节点
|
||||
const parentKeys = findParentKeys(node.parentKey)
|
||||
// 设置为选中
|
||||
if (checked && parentKeys.length) {
|
||||
this.checkedKeys.checked = _.union(this.checkedKeys.checked, parentKeys)
|
||||
}
|
||||
},
|
||||
|
||||
// 选择节点时联动所有子节点
|
||||
onCheckChilds (checked, node) {
|
||||
// 获取当前节点的所有子级ID
|
||||
const childKeys = node.children ? this.getAllMenuKeys(node.children) : []
|
||||
if (childKeys.length) {
|
||||
this.checkedKeys.checked = checked ? _.union(this.checkedKeys.checked, childKeys) : _.difference(this.checkedKeys.checked, childKeys)
|
||||
}
|
||||
},
|
||||
|
||||
// 获取菜单列表中所有子级的id
|
||||
getAllMenuKeys (list) {
|
||||
let keysArr = []
|
||||
list.forEach(item => {
|
||||
keysArr.push(item.key)
|
||||
if (item.children && item.children.length) {
|
||||
const childrenArr = this.getAllMenuKeys(item.children)
|
||||
childrenArr.length && (keysArr = keysArr.concat(childrenArr))
|
||||
}
|
||||
})
|
||||
return keysArr
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
getRoleList () {
|
||||
const { roleList } = this
|
||||
// 格式化角色列表
|
||||
const selectList = this.formatTreeForRoleList(roleList)
|
||||
// 顶级角色
|
||||
selectList.unshift({
|
||||
title: '顶级角色',
|
||||
key: 0,
|
||||
value: 0
|
||||
})
|
||||
this.roleListTree = selectList
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化角色列表
|
||||
*/
|
||||
formatTreeForRoleList (list) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
// 新的元素
|
||||
const netItem = {
|
||||
title: item.role_name,
|
||||
key: item.role_id,
|
||||
value: item.role_id
|
||||
}
|
||||
// 递归整理子集
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeForRoleList(item['children'])
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
// 格式化菜单列表
|
||||
formatTreeDataForMenuList (list) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
// 新的元素
|
||||
const netItem = {
|
||||
title: item.name,
|
||||
key: item.menu_id,
|
||||
parentKey: item.parent_id
|
||||
}
|
||||
// 递归整理子集
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeDataForMenuList(item['children'])
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit({ ...values, menus: this.getCheckedKeys() })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取所有选中的节点(菜单)
|
||||
*/
|
||||
getCheckedKeys () {
|
||||
const { $refs: { MenuTree } } = this
|
||||
return [
|
||||
...MenuTree.getCheckedKeys(),
|
||||
...MenuTree.getHalfCheckedKeys()
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
const { $refs: { MenuTree } } = this
|
||||
MenuTree.clearExpandedKeys()
|
||||
this.checkedKeys.checked = []
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,346 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="编辑角色"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="角色名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['role_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="上级角色" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-tree-select
|
||||
:treeData="roleListTree"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
allowClear
|
||||
v-decorator="['parent_id']"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="菜单权限"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="设置该角色有权操作的功能"
|
||||
>
|
||||
<a-tree
|
||||
ref="MenuTree"
|
||||
v-model="checkedKeys"
|
||||
checkable
|
||||
checkStrictly
|
||||
:treeData="menuListTreeData"
|
||||
:autoExpandParent="false"
|
||||
@check="onCheckedMenu"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/store/role'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 角色列表
|
||||
roleList: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
// 菜单列表
|
||||
menuList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 当前记录
|
||||
record: {},
|
||||
// 上级角色列表
|
||||
roleListTree: [],
|
||||
// 菜单列表 树状结构
|
||||
menuListTreeData: [],
|
||||
// 当前选中的keys
|
||||
checkedKeys: {
|
||||
checked: [],
|
||||
halfChecked: []
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前角色记录
|
||||
this.record = record
|
||||
// 获取角色列表
|
||||
this.getRoleList()
|
||||
// 获取API权限列表
|
||||
this.getMenuList()
|
||||
// 默认选中的API权限
|
||||
this.setMenuChecked()
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(_.pick(this.record, ['role_name', 'parent_id', 'sort']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
getMenuList () {
|
||||
const { menuList } = this
|
||||
this.menuListTreeData = this.formatTreeDataForMenuList(menuList)
|
||||
},
|
||||
|
||||
// 节点选中事件
|
||||
onCheckedMenu (checkedKeys, { checked, node }) {
|
||||
// 寻找当前选择的节点
|
||||
const { menuListTreeData } = this
|
||||
const nodeData = this.findNode(node.eventKey, menuListTreeData)
|
||||
// 选择节点时联动所有子节点
|
||||
this.onCheckChilds(checked, nodeData)
|
||||
// 选择节点时联动所有父节点
|
||||
this.onCheckParents(checked, nodeData)
|
||||
},
|
||||
|
||||
// 寻找指定的的节点
|
||||
findNode (key, list) {
|
||||
for (let index = 0; index < list.length; index++) {
|
||||
const item = list[index]
|
||||
if (item.key === key) {
|
||||
return item
|
||||
} else if (item.children) {
|
||||
const result = this.findNode(key, item.children)
|
||||
if (result) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
// 选择节点时联动所有父节点
|
||||
onCheckParents (checked, node) {
|
||||
// 查找所有父节点(方法)
|
||||
const { menuListTreeData } = this
|
||||
const findParentKeys = (parentKey) => {
|
||||
let keys = []
|
||||
const parent = this.findNode(parentKey, menuListTreeData)
|
||||
if (!parent) {
|
||||
return keys
|
||||
}
|
||||
keys.push(parent.key)
|
||||
if (parent.children) {
|
||||
const arr = findParentKeys(parent.parentKey)
|
||||
arr.length && (keys = keys.concat(arr))
|
||||
}
|
||||
return keys
|
||||
}
|
||||
// 查找所有父节点
|
||||
const parentKeys = findParentKeys(node.parentKey)
|
||||
// 设置为选中
|
||||
if (checked && parentKeys.length) {
|
||||
this.checkedKeys.checked = _.union(this.checkedKeys.checked, parentKeys)
|
||||
}
|
||||
},
|
||||
|
||||
// 选择节点时联动所有子节点
|
||||
onCheckChilds (checked, node) {
|
||||
// 获取当前节点的所有子级ID
|
||||
const childKeys = node.children ? this.getAllMenuKeys(node.children) : []
|
||||
if (childKeys.length) {
|
||||
this.checkedKeys.checked = checked ? _.union(this.checkedKeys.checked, childKeys) : _.difference(this.checkedKeys.checked, childKeys)
|
||||
}
|
||||
},
|
||||
|
||||
// 获取菜单列表中所有子级的id
|
||||
getAllMenuKeys (list) {
|
||||
let keysArr = []
|
||||
list.forEach(item => {
|
||||
keysArr.push(item.key)
|
||||
if (item.children && item.children.length) {
|
||||
const childrenArr = this.getAllMenuKeys(item.children)
|
||||
childrenArr.length && (keysArr = keysArr.concat(childrenArr))
|
||||
}
|
||||
})
|
||||
return keysArr
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认选中的菜单
|
||||
*/
|
||||
setMenuChecked () {
|
||||
// 菜单列表所有子集
|
||||
const { menuListTreeData, record } = this
|
||||
const allMenuKeys = this.getAllMenuKeys(menuListTreeData)
|
||||
// 默认选中的菜单
|
||||
this.checkedKeys.checked = _.intersection(record.menuIds, allMenuKeys)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
getRoleList () {
|
||||
const { roleList } = this
|
||||
// 格式化角色列表
|
||||
const selectList = this.formatTreeForRoleList(roleList)
|
||||
// 顶级角色
|
||||
selectList.unshift({
|
||||
title: '顶级角色',
|
||||
key: 0,
|
||||
value: 0
|
||||
})
|
||||
this.roleListTree = selectList
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化角色列表
|
||||
*/
|
||||
formatTreeForRoleList (list, disabled = false) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
// 新的元素
|
||||
const netItem = {
|
||||
title: item.role_name,
|
||||
key: item.role_id,
|
||||
value: item.role_id
|
||||
}
|
||||
// 禁用的角色
|
||||
if (
|
||||
[item.role_id, item.parent_id].includes(this.record.role_id) ||
|
||||
disabled === true
|
||||
) {
|
||||
netItem.disabled = true
|
||||
}
|
||||
// 递归整理子集
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeForRoleList(item['children'], netItem.disabled)
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
// 格式化菜单列表
|
||||
formatTreeDataForMenuList (list) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
// 新的元素
|
||||
const netItem = {
|
||||
title: item.name,
|
||||
key: item.menu_id,
|
||||
parentKey: item.parent_id
|
||||
}
|
||||
// 递归整理子集
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeDataForMenuList(item['children'])
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
this.onFormSubmit({ ...values, menus: this.getCheckedKeys() })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取所有选中的节点(菜单)
|
||||
*/
|
||||
getCheckedKeys () {
|
||||
const { $refs: { MenuTree } } = this
|
||||
return [
|
||||
...MenuTree.getCheckedKeys(),
|
||||
...MenuTree.getHalfCheckedKeys()
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
const { $refs: { MenuTree } } = this
|
||||
MenuTree.clearExpandedKeys()
|
||||
this.checkedKeys.checked = []
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ roleId: this.record['role_id'], form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-row>
|
||||
<a-col :span="6">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</a-col>
|
||||
<a-col :span="8" :offset="10">
|
||||
<a-input-search
|
||||
style="max-width: 300px; min-width: 150px;float: right;"
|
||||
v-model="queryParam.search"
|
||||
placeholder="请输入用户名/姓名"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="store_user_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<div slot="user_name" slot-scope="text, item">
|
||||
<span style="margin-right: 6px">{{ text }}</span>
|
||||
<a-tag v-if="item.is_super" color="green">超级管理员</a-tag>
|
||||
</div>
|
||||
<div class="actions" slot="action" slot-scope="text, item">
|
||||
<a v-action:edit @click="handleEdit(item)">编辑</a>
|
||||
<template v-if="!item.is_super && item.store_user_id !== user.store_user_id">
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</template>
|
||||
</div>
|
||||
</s-table>
|
||||
<AddForm ref="AddForm" :roleList="roleList" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" :roleList="roleList" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/store/user'
|
||||
import * as RoleApi from '@/api/store/role'
|
||||
import { STable } from '@/components'
|
||||
import AddForm from './modules/AddForm'
|
||||
import EditForm from './modules/EditForm'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 角色列表
|
||||
roleList: [],
|
||||
user: [],
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '管理员ID',
|
||||
dataIndex: 'store_user_id'
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'user_name',
|
||||
scopedSlots: { customRender: 'user_name' }
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'real_name'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 获取角色列表
|
||||
this.getRoleList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
getRoleList () {
|
||||
this.isLoading = true
|
||||
RoleApi.list()
|
||||
.then(result => {
|
||||
this.roleList = result.data.list
|
||||
this.user = result.data.user
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ userId: item['store_user_id'] })
|
||||
.then((result) => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
/**
|
||||
* 检索查询
|
||||
*/
|
||||
onSearch () {
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="管理员姓名" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['real_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="用户名" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="后台登录用户名">
|
||||
<a-input
|
||||
v-decorator="['user_name', {rules: [{required: true, min: 4, message: '请输入至少4个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="所属角色" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="后台管理员角色">
|
||||
<a-tree-select
|
||||
treeCheckable
|
||||
treeCheckStrictly
|
||||
treeDefaultExpandAll
|
||||
allowClear
|
||||
:treeData="roleListTreeData"
|
||||
:dropdownStyle="{ maxHeight: '500px', overflow: 'auto' }"
|
||||
v-decorator="['roles', {rules: [{required: true, message: '请至少选择一个角色'}]}]"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="关联代理商" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="关联代理商">
|
||||
<!--mode="multiple"-->
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['merchant_id', {rules: [{required: false, message: '请选择代理商'}]}]"
|
||||
placeholder="请选择代理商"
|
||||
>
|
||||
<a-select-option :value="0">无</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in merchantListData"
|
||||
:key="index"
|
||||
:value="item.merchant_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="用户密码" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="后台登录密码">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['password', {rules: [
|
||||
{required: true, min: 6, message: '请输入至少6个字符'}
|
||||
]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="确认密码" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['password_confirm', {rules: [
|
||||
{required: true, message: '请输入确认密码'},
|
||||
{validator: compareToFirstPassword}
|
||||
]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import * as Api from '@/api/store/user'
|
||||
import * as MerchantApi from '@/api/merchant'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 角色列表
|
||||
roleList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 角色列表 树状结构
|
||||
roleListTreeData: [],
|
||||
//商户数据
|
||||
merchantListData: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
this.title = '新增管理员'
|
||||
this.visible = true
|
||||
// 获取角色列表
|
||||
this.getRoleList()
|
||||
this.getMerchantList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
getRoleList () {
|
||||
const { roleList } = this
|
||||
// 格式化角色列表
|
||||
const selectList = this.formatTreeData(roleList)
|
||||
this.roleListTreeData = selectList
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取商户列表
|
||||
*/
|
||||
getMerchantList () {
|
||||
this.isLoading = true
|
||||
MerchantApi.all()
|
||||
.then(result => {
|
||||
this.merchantListData = result.data.list
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认选中的角色
|
||||
*/
|
||||
getCheckedRoleKeys () {
|
||||
const { roleList, record } = this
|
||||
const getCheckedKeys = (list) => {
|
||||
let keysArr = []
|
||||
list.forEach(item => {
|
||||
if (record['roleIds'].includes(item['role_id'])) {
|
||||
keysArr.push({
|
||||
label: item['role_name'],
|
||||
value: item['role_id']
|
||||
})
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
const childrenArr = getCheckedKeys(item.children)
|
||||
childrenArr.length && (keysArr = keysArr.concat(childrenArr))
|
||||
}
|
||||
})
|
||||
return keysArr
|
||||
}
|
||||
return getCheckedKeys(roleList)
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化角色列表
|
||||
*/
|
||||
formatTreeData (list) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
const netItem = {
|
||||
title: item.role_name,
|
||||
key: item.role_id,
|
||||
value: item.role_id
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeData(item['children'])
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
const { form: { validateFields } } = this
|
||||
// 表单验证
|
||||
validateFields((errors, values) => {
|
||||
// 整理角色id
|
||||
if (values.roles) {
|
||||
values.roles = values.roles.map(item => item.value)
|
||||
}
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 验证确认密码是否一致
|
||||
*/
|
||||
compareToFirstPassword (rule, value, callback) {
|
||||
const { form } = this
|
||||
if (value && value !== form.getFieldValue('password')) {
|
||||
return new Error('您输入的确认密码不一致')
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item label="管理员姓名" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['real_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="用户名" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="后台登录用户名">
|
||||
<a-input
|
||||
v-decorator="['user_name', {rules: [{required: true, min: 4, message: '请输入至少4个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="!record.is_super && record.store_user_id !== user.store_user_id"
|
||||
label="所属角色"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="后台管理员角色"
|
||||
>
|
||||
<a-tree-select
|
||||
treeCheckable
|
||||
treeCheckStrictly
|
||||
treeDefaultExpandAll
|
||||
allowClear
|
||||
:treeData="roleListTreeData"
|
||||
:dropdownStyle="{ maxHeight: '500px', overflow: 'auto' }"
|
||||
v-decorator="['roles', {rules: [{required: true, message: '请至少选择一个角色'}]}]"
|
||||
></a-tree-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="关联代理商" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="关联代理商">
|
||||
<!--mode="multiple"-->
|
||||
<a-select
|
||||
style="width: 300px"
|
||||
v-decorator="['merchant_id', {rules: [{required: false, message: '请选择代理商'}]}]"
|
||||
placeholder="请选择代理商"
|
||||
>
|
||||
<a-select-option :value="0">无</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in merchantListData"
|
||||
:key="index"
|
||||
:value="item.merchant_id"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="用户密码" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="后台登录密码">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['password', {rules: [{min: 6, message: '请输入至少6个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="确认密码" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
type="password"
|
||||
v-decorator="['password_confirm', {rules: [
|
||||
{ message: '请输入确认密码'},
|
||||
{validator: compareToFirstPassword}
|
||||
]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入至少1个数字'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import * as UserApi from '@/api/store/user'
|
||||
import * as MerchantApi from '@/api/merchant'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
// 角色列表
|
||||
roleList: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '',
|
||||
// 标签布局属性
|
||||
labelCol: {
|
||||
span: 7
|
||||
},
|
||||
// 输入框布局属性
|
||||
wrapperCol: {
|
||||
span: 13
|
||||
},
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
|
||||
// 角色列表 树状结构
|
||||
roleListTreeData: [],
|
||||
// 当前记录
|
||||
record: {},
|
||||
//商户数据
|
||||
merchantListData: [],
|
||||
user: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.title = '编辑管理员'
|
||||
this.visible = true
|
||||
// 当前管理员记录
|
||||
this.record = record
|
||||
// 获取角色列表
|
||||
!record['is_super'] && this.getRoleList()
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
this.getMerchantList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { form: { setFieldsValue }, getCheckedRoleKeys } = this
|
||||
this.$nextTick(() => {
|
||||
const data = _.pick(this.record, ['user_name', 'real_name', 'sort'])
|
||||
data.roles = getCheckedRoleKeys()
|
||||
data.merchant_id = eval('(' + this.record.merchant_id + ')')
|
||||
setFieldsValue(data)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
getRoleList () {
|
||||
const { roleList } = this
|
||||
// 格式化角色列表
|
||||
const selectList = this.formatTreeData(roleList)
|
||||
this.roleListTreeData = selectList
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取商户列表
|
||||
*/
|
||||
getMerchantList () {
|
||||
this.isLoading = true
|
||||
MerchantApi.all()
|
||||
.then(result => {
|
||||
this.merchantListData = result.data.list
|
||||
this.user = result.data.user
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认选中的角色
|
||||
*/
|
||||
getCheckedRoleKeys () {
|
||||
const { roleList, record } = this
|
||||
const getCheckedKeys = (list) => {
|
||||
let keysArr = []
|
||||
list.forEach(item => {
|
||||
if (record['roleIds'].includes(item['role_id'])) {
|
||||
keysArr.push({
|
||||
label: item['role_name'],
|
||||
value: item['role_id']
|
||||
})
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
const childrenArr = getCheckedKeys(item.children)
|
||||
childrenArr.length && (keysArr = keysArr.concat(childrenArr))
|
||||
}
|
||||
})
|
||||
return keysArr
|
||||
}
|
||||
return getCheckedKeys(roleList)
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化角色列表
|
||||
*/
|
||||
formatTreeData (list) {
|
||||
const data = []
|
||||
list.forEach(item => {
|
||||
const netItem = {
|
||||
title: item.role_name,
|
||||
key: item.role_id,
|
||||
value: item.role_id
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
netItem['children'] = this.formatTreeData(item['children'])
|
||||
}
|
||||
data.push(netItem)
|
||||
})
|
||||
return data
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 整理角色id
|
||||
if (values.roles) {
|
||||
values.roles = values.roles.map(item => item.value)
|
||||
}
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 验证确认密码是否一致
|
||||
*/
|
||||
compareToFirstPassword (rule, value, callback) {
|
||||
const { form } = this
|
||||
if (value && value !== form.getFieldValue('password')) {
|
||||
return new Error('您输入的确认密码不一致')
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
UserApi.edit({ userId: this.record['store_user_id'], form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="是否开启满额包邮" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['is_open', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="单笔订单满" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:precision="2"
|
||||
v-decorator="['money', { rules: [{ required: true, message: '请输入包邮的订单额度' }] }]"
|
||||
/>
|
||||
<span class="ml-10">元包邮</span>
|
||||
<div class="form-item-help">
|
||||
<small>如设置0为全场包邮</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="不参与包邮的商品" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<SelectGoods :defaultList="excludedGoodsList" v-decorator="['excludedGoodsIds']" />
|
||||
</a-form-item>
|
||||
<a-form-item label="不参与包邮的地区" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-button @click="handleAreasModal">选择地区</a-button>
|
||||
<p class="content">
|
||||
<span v-for="(province, pidx) in excludedRegions.selectedText" :key="pidx">
|
||||
<span>{{ province.name }}</span>
|
||||
<template v-if="province.citys.length">
|
||||
<span>[</span>
|
||||
<span
|
||||
class="city-name"
|
||||
v-for="(city, cidx) in province.citys"
|
||||
:key="cidx"
|
||||
>{{ city.name }}{{ province.citys.length > cidx + 1 ? '、': '' }}</span>
|
||||
<span>]</span>
|
||||
</template>
|
||||
<span class="mr-5"></span>
|
||||
</span>
|
||||
</p>
|
||||
</a-form-item>
|
||||
<a-form-item label="满额包邮说明" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['describe', { rules: [{ required: true, message: '请输入满额包邮说明' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<AreasModal ref="AreasModal" @handleSubmit="handleAreaSubmit" />
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/setting/store'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import { SelectGoods } from '@/components'
|
||||
import { AreasModal } from '@/components/Modal'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectGoods,
|
||||
AreasModal
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前设置项的key
|
||||
key: 'full_free',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 12 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录详情
|
||||
record: {},
|
||||
// 不参与包邮的地区
|
||||
excludedRegions: {
|
||||
cityIds: [],
|
||||
selectedText: []
|
||||
},
|
||||
// 不参与包邮的商品列表
|
||||
excludedGoodsList: []
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
async created () {
|
||||
// 获取当前详情记录
|
||||
await this.getDetail()
|
||||
// 获取不参与包邮的商品列表
|
||||
await this.getExcludedGoodsList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
async getDetail () {
|
||||
this.isLoading = true
|
||||
await Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.values
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 获取不参与包邮的商品列表
|
||||
async getExcludedGoodsList () {
|
||||
const { record: { excludedGoodsIds } } = this
|
||||
if (excludedGoodsIds.length > 0) {
|
||||
this.isLoading = true
|
||||
await GoodsApi.listByIds(excludedGoodsIds)
|
||||
.then(result => {
|
||||
this.excludedGoodsList = result.data.list
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
this.excludedRegions = record.excludedRegions
|
||||
setFieldsValue(pick(record, ['is_open', 'money', 'describe']))
|
||||
})
|
||||
},
|
||||
|
||||
// 显示选择地区对话框
|
||||
handleAreasModal () {
|
||||
this.$refs.AreasModal.handle({}, this.excludedRegions.cityIds)
|
||||
},
|
||||
|
||||
// 选择地区后的回调
|
||||
handleAreaSubmit (result) {
|
||||
this.excludedRegions = {
|
||||
cityIds: result.selectedCityIds,
|
||||
selectedText: result.selectedText
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields }, excludedRegions } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
if (!errors) {
|
||||
values.excludedRegions = excludedRegions
|
||||
this.onFormSubmit(values)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 提交到后端api
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
color: #505050;
|
||||
line-height: 1.6;
|
||||
.city-name {
|
||||
font-size: 12.5px;
|
||||
color: #7b7b7b;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="优惠券名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入优惠券名称"
|
||||
v-decorator="['name', { rules: [{ required: true, min: 2, message: '请输入至少2个字符' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="优惠券类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['coupon_type', { initialValue: 10, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="10">满减券</a-radio>
|
||||
<a-radio :value="20">折扣券</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="form.getFieldValue('coupon_type') == 10"
|
||||
label="减免金额"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
v-decorator="['reduce_price', { rules: [{ required: true, message: '请输入减免金额' }] }]"
|
||||
/>
|
||||
<span class="ml-5">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="form.getFieldValue('coupon_type') == 20"
|
||||
label="折扣率"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:max="9.9"
|
||||
:precision="1"
|
||||
v-decorator="['discount', { initialValue: 9.9, rules: [{ required: true, message: '请输入折扣率' }] }]"
|
||||
/>
|
||||
<span class="ml-5">%</span>
|
||||
<p class="form-item-help">
|
||||
<small>折扣率范围 0-9.9,8代表打8折,0代表不折扣</small>
|
||||
</p>
|
||||
</a-form-item>
|
||||
<a-form-item label="最低消费金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="1"
|
||||
:precision="2"
|
||||
v-decorator="['min_price', { rules: [{ required: true, message: '请输入最低消费金额' }] }]"
|
||||
/>
|
||||
<span class="ml-5">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="到期类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['expire_type', { initialValue: 10, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="10">领取后生效</a-radio>
|
||||
<a-radio :value="20">固定时间</a-radio>
|
||||
</a-radio-group>
|
||||
<a-form-item v-show="form.getFieldValue('expire_type') == 10" class="expire_type-10">
|
||||
<InputNumberGroup
|
||||
addonBefore="有效期"
|
||||
addonAfter="天"
|
||||
:inputProps="{ min: 1, precision: 0 }"
|
||||
v-decorator="['expire_day', { initialValue: 7, rules: [{ required: true, message: '请输入有效期天数' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item v-show="form.getFieldValue('expire_type') == 20" class="expire_type-20">
|
||||
<a-range-picker
|
||||
format="YYYY-MM-DD"
|
||||
v-decorator="['betweenTime', { initialValue: defaultDate, rules: [{ required: true, message: '请选择有效期范围' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
<a-form-item label="券适用范围" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['apply_range', { initialValue: 10, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="10">全场通用</a-radio>
|
||||
<a-radio :value="20">指定商品</a-radio>
|
||||
</a-radio-group>
|
||||
<a-form-item v-if="form.getFieldValue('apply_range') == 20">
|
||||
<SelectGoods
|
||||
:defaultList="containGoodsList"
|
||||
v-decorator="['apply_range_config.applyGoodsIds', { initialValue: [], rules: [{ required: true, message: '请选择指定的商品' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
<a-form-item label="发放总数量" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="-1"
|
||||
:precision="0"
|
||||
v-decorator="['total_num', { initialValue: -1, rules: [{ required: true, message: '请输入发放总数量' }] }]"
|
||||
/>
|
||||
<span class="ml-5">张</span>
|
||||
<p class="form-item-help">
|
||||
<small>发放的优惠券总数量,-1为不限制</small>
|
||||
</p>
|
||||
</a-form-item>
|
||||
<a-form-item label="显示状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['status', { initialValue: 1, rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
<p class="form-item-help">
|
||||
<small>如果设为隐藏将不会展示在用户端页面</small>
|
||||
</p>
|
||||
</a-form-item>
|
||||
<a-form-item label="优惠券描述" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea :autoSize="{ minRows: 4 }" v-decorator="['describe']" />
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules:[{required: true, message: '请输入排序值'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
import * as Api from '@/api/market/coupon'
|
||||
import { InputNumberGroup, SelectGoods } from '@/components'
|
||||
import { ApplyRangeEnum, CouponTypeEnum, ExpireTypeEnum } from '@/common/enum/coupon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectGoods,
|
||||
InputNumberGroup
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 枚举类
|
||||
ApplyRangeEnum,
|
||||
CouponTypeEnum,
|
||||
ExpireTypeEnum,
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 默认日期范围
|
||||
defaultDate: [moment(), moment()],
|
||||
// 适用范围:指定的商品
|
||||
containGoodsList: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
this.$forceUpdate()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 确认按钮
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields }, onFormSubmit } = this
|
||||
validateFields((errors, values) => {
|
||||
!errors && onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
// 提交到后端api
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
Api.add({ form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-alert message="注:优惠券只能抵扣商品金额,最多优惠到0.01元,不能抵扣运费" banner />
|
||||
<div class="table-operator">
|
||||
<a-row>
|
||||
<a-col :span="6">
|
||||
<a-button
|
||||
v-if="$auth('/market/coupon/create')"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleAdd"
|
||||
>新增</a-button>
|
||||
</a-col>
|
||||
<a-col :span="8" :offset="10">
|
||||
<a-input-search
|
||||
style="max-width: 300px; min-width: 150px;float: right;"
|
||||
v-model="queryParam.search"
|
||||
placeholder="请输入优惠券名称"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="coupon_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 优惠券类型 -->
|
||||
<template slot="coupon_type" slot-scope="text">
|
||||
<a-tag>{{ CouponTypeEnum[text].name }}</a-tag>
|
||||
</template>
|
||||
<!-- 最低消费金额 -->
|
||||
<template slot="min_price" slot-scope="text">
|
||||
<p class="c-p">{{ text }}</p>
|
||||
</template>
|
||||
<!-- 优惠方式 -->
|
||||
<template slot="discount" slot-scope="item">
|
||||
<template v-if="item.coupon_type == 10">
|
||||
<span>立减</span>
|
||||
<span class="c-p mlr-2">{{ item.reduce_price }}</span>
|
||||
<span>元</span>
|
||||
</template>
|
||||
<template v-if="item.coupon_type == 20">
|
||||
<span>打</span>
|
||||
<span class="c-p mlr-2">{{ item.discount }}</span>
|
||||
<span>折</span>
|
||||
</template>
|
||||
</template>
|
||||
<!-- 有效期 -->
|
||||
<template slot="duetime" slot-scope="item">
|
||||
<template v-if="item.expire_type == 10">
|
||||
<span>领取</span>
|
||||
<span class="c-p mlr-2">{{ item.expire_day }}</span>
|
||||
<span>天内有效</span>
|
||||
</template>
|
||||
<template v-if="item.expire_type == 20">
|
||||
<span>{{ item.start_time }} ~ {{ item.end_time }}</span>
|
||||
</template>
|
||||
</template>
|
||||
<!-- 状态 -->
|
||||
<template slot="status" slot-scope="text">
|
||||
<a-tag :color="text ? 'green' : ''">{{ text ? '显示' : '隐藏' }}</a-tag>
|
||||
</template>
|
||||
<!-- 操作 -->
|
||||
<span class="actions" slot="action" slot-scope="item">
|
||||
<a v-if="$auth('/market/coupon/update')" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/market/coupon'
|
||||
import { STable } from '@/components'
|
||||
import { ApplyRangeEnum, CouponTypeEnum, ExpireTypeEnum } from '@/common/enum/coupon'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 枚举类
|
||||
ApplyRangeEnum,
|
||||
CouponTypeEnum,
|
||||
ExpireTypeEnum,
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '优惠券ID',
|
||||
dataIndex: 'coupon_id'
|
||||
},
|
||||
{
|
||||
title: '优惠券名称',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '优惠券类型',
|
||||
dataIndex: 'coupon_type',
|
||||
scopedSlots: { customRender: 'coupon_type' }
|
||||
},
|
||||
{
|
||||
title: '最低消费金额 (元)',
|
||||
dataIndex: 'min_price',
|
||||
scopedSlots: { customRender: 'min_price' }
|
||||
},
|
||||
{
|
||||
title: '优惠方式',
|
||||
scopedSlots: { customRender: 'discount' }
|
||||
},
|
||||
// {
|
||||
// title: '有效期',
|
||||
// scopedSlots: { customRender: 'duetime' }
|
||||
// },
|
||||
// {
|
||||
// title: '发放总数量',
|
||||
// dataIndex: 'total_num'
|
||||
// },
|
||||
{
|
||||
title: '已发放/领取数量',
|
||||
dataIndex: 'receive_num'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 新增记录
|
||||
handleAdd () {
|
||||
this.$router.push('./create')
|
||||
},
|
||||
|
||||
// 编辑记录
|
||||
handleEdit (item) {
|
||||
this.$router.push({ path: './update', query: { couponId: item.coupon_id } })
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ couponId: item.coupon_id })
|
||||
.then((result) => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
/**
|
||||
* 检索查询
|
||||
*/
|
||||
onSearch () {
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="优惠券名称">
|
||||
<a-input v-decorator="['couponName']" placeholder="请输入优惠券名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="会员昵称">
|
||||
<a-input v-decorator="['nickName']" placeholder="请输入会员昵称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="领取时间">
|
||||
<a-range-picker format="YYYY-MM-DD" v-decorator="['betweenTime']" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="user_coupon_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 会员信息 -->
|
||||
<template slot="user" slot-scope="item">
|
||||
<UserItem :user="item" />
|
||||
</template>
|
||||
<!-- 优惠券类型 -->
|
||||
<template slot="coupon_type" slot-scope="text">
|
||||
<a-tag>{{ CouponTypeEnum[text].name }}</a-tag>
|
||||
</template>
|
||||
<!-- 最低消费金额 -->
|
||||
<template slot="min_price" slot-scope="text">
|
||||
<p class="c-p">{{ text }}</p>
|
||||
</template>
|
||||
<!-- 优惠方式 -->
|
||||
<template slot="discount" slot-scope="item">
|
||||
<template v-if="item.coupon_type == CouponTypeEnum.FULL_DISCOUNT.value">
|
||||
<span>立减</span>
|
||||
<span class="c-p mlr-2">{{ item.reduce_price }}</span>
|
||||
<span>元</span>
|
||||
</template>
|
||||
<template v-if="item.coupon_type == CouponTypeEnum.DISCOUNT.value">
|
||||
<span>打</span>
|
||||
<span class="c-p mlr-2">{{ item.discount }}</span>
|
||||
<span>折</span>
|
||||
</template>
|
||||
</template>
|
||||
<!-- 有效期 -->
|
||||
<template slot="duetime" slot-scope="item">
|
||||
<template v-if="item.expire_type == 10">
|
||||
<span>领取</span>
|
||||
<span class="c-p mlr-2">{{ item.expire_day }}</span>
|
||||
<span>天内有效</span>
|
||||
</template>
|
||||
<template v-if="item.expire_type == 20">
|
||||
<span>{{ item.start_time }} ~ {{ item.end_time }}</span>
|
||||
</template>
|
||||
</template>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/market/coupon'
|
||||
import { STable, UserItem } from '@/components/Table'
|
||||
import { CouponTypeEnum } from '@/common/enum/coupon'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
UserItem
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 枚举类
|
||||
CouponTypeEnum,
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'user_coupon_id'
|
||||
},
|
||||
{
|
||||
title: '会员信息',
|
||||
dataIndex: 'user',
|
||||
scopedSlots: { customRender: 'user' }
|
||||
},
|
||||
{
|
||||
title: '优惠券名称',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '优惠券类型',
|
||||
dataIndex: 'coupon_type',
|
||||
scopedSlots: { customRender: 'coupon_type' }
|
||||
},
|
||||
{
|
||||
title: '最低消费金额 (元)',
|
||||
dataIndex: 'min_price',
|
||||
scopedSlots: { customRender: 'min_price' }
|
||||
},
|
||||
{
|
||||
title: '优惠方式',
|
||||
scopedSlots: { customRender: 'discount' }
|
||||
},
|
||||
{
|
||||
title: '有效期',
|
||||
scopedSlots: { customRender: 'duetime' }
|
||||
},
|
||||
{
|
||||
title: '领取时间',
|
||||
dataIndex: 'create_time'
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.receive({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="优惠券名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入优惠券名称"
|
||||
v-decorator="['name', { rules: [{ required: true, min: 2, message: '请输入至少2个字符' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="优惠券类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['coupon_type', { initialValue: 10, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="10">满减券</a-radio>
|
||||
<a-radio :value="20">折扣券</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-show="form.getFieldValue('coupon_type') == CouponTypeEnum.FULL_DISCOUNT.value"
|
||||
label="减免金额"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
v-decorator="['reduce_price', { rules: [{ required: true, message: '请输入减免金额' }] }]"
|
||||
/>
|
||||
<span class="ml-5">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-show="form.getFieldValue('coupon_type') == CouponTypeEnum.DISCOUNT.value"
|
||||
label="折扣率"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:max="9.9"
|
||||
:precision="1"
|
||||
v-decorator="['discount', { initialValue: 9.9, rules: [{ required: true, message: '请输入折扣率' }] }]"
|
||||
/>
|
||||
<span class="ml-5">%</span>
|
||||
<p class="form-item-help">
|
||||
<small>折扣率范围 0-9.9,8代表打8折,0代表不折扣</small>
|
||||
</p>
|
||||
</a-form-item>
|
||||
<a-form-item label="最低消费金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="1"
|
||||
:precision="2"
|
||||
v-decorator="['min_price', { rules: [{ required: true, message: '请输入最低消费金额' }] }]"
|
||||
/>
|
||||
<span class="ml-5">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="到期类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['expire_type', { initialValue: 10, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="10">领取后生效</a-radio>
|
||||
<a-radio :value="20">固定时间</a-radio>
|
||||
</a-radio-group>
|
||||
<a-form-item v-show="form.getFieldValue('expire_type') == 10" class="expire_type-10">
|
||||
<InputNumberGroup
|
||||
addonBefore="有效期"
|
||||
addonAfter="天"
|
||||
:inputProps="{ min: 1, precision: 0 }"
|
||||
v-decorator="['expire_day', { initialValue: 7, rules: [{ required: true, message: '请输入有效期天数' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item v-show="form.getFieldValue('expire_type') == 20" class="expire_type-20">
|
||||
<a-range-picker
|
||||
format="YYYY-MM-DD"
|
||||
v-decorator="['betweenTime', { initialValue: defaultDate, rules: [{ required: true, message: '请选择有效期范围' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
<a-form-item label="券适用范围" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['apply_range', { initialValue: 10, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="10">全场通用</a-radio>
|
||||
<a-radio :value="20">指定商品</a-radio>
|
||||
</a-radio-group>
|
||||
<a-form-item v-if="form.getFieldValue('apply_range') == 20">
|
||||
<SelectGoods
|
||||
:defaultList="containGoodsList"
|
||||
v-decorator="['apply_range_config.applyGoodsIds', { rules: [{ required: true, message: '请选择指定的商品' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
<a-form-item label="发放总数量" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="-1"
|
||||
:precision="0"
|
||||
v-decorator="['total_num', { initialValue: -1, rules: [{ required: true, message: '请输入发放总数量' }] }]"
|
||||
/>
|
||||
<span class="ml-5">张</span>
|
||||
<p class="form-item-help">
|
||||
<small>发放的优惠券总数量,-1为不限制</small>
|
||||
</p>
|
||||
</a-form-item>
|
||||
<a-form-item label="显示状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['status', { initialValue: 1, rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">显示</a-radio>
|
||||
<a-radio :value="0">隐藏</a-radio>
|
||||
</a-radio-group>
|
||||
<p class="form-item-help">
|
||||
<small>如果设为隐藏将不会展示在用户端页面</small>
|
||||
</p>
|
||||
</a-form-item>
|
||||
<a-form-item label="优惠券描述" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea :autoSize="{ minRows: 4 }" v-decorator="['describe']" />
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules:[{required: true, message: '请输入排序值'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
import { pick, get } from 'lodash'
|
||||
import * as Api from '@/api/market/coupon'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import { isEmpty } from '@/utils/util'
|
||||
import { InputNumberGroup, SelectGoods } from '@/components'
|
||||
import { ApplyRangeEnum, CouponTypeEnum, ExpireTypeEnum } from '@/common/enum/coupon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectGoods,
|
||||
InputNumberGroup
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 枚举类
|
||||
ApplyRangeEnum,
|
||||
CouponTypeEnum,
|
||||
ExpireTypeEnum,
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 默认日期范围
|
||||
defaultDate: [moment(), moment()],
|
||||
// 优惠券ID
|
||||
couponId: null,
|
||||
// 当前记录
|
||||
record: {},
|
||||
// 适用范围:指定的商品
|
||||
containGoodsList: []
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
// 记录优惠券ID
|
||||
this.couponId = this.$route.query.couponId
|
||||
// 获取当前记录
|
||||
await this.getDetail()
|
||||
// 获取适用范围:指定的商品
|
||||
await this.getContainGoodsList()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前记录
|
||||
async getDetail () {
|
||||
const { couponId } = this
|
||||
this.isLoading = true
|
||||
await Api.detail({ couponId })
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.detail
|
||||
// 设置表单默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 获取指定的商品列表
|
||||
async getContainGoodsList () {
|
||||
const { record } = this
|
||||
const goodsIds = get(record, 'apply_range_config.applyGoodsIds')
|
||||
if (goodsIds !== undefined && goodsIds.length) {
|
||||
this.isLoading = true
|
||||
await GoodsApi.listByIds(goodsIds)
|
||||
.then(result => {
|
||||
this.containGoodsList = result.data.list
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 设置表单默认值
|
||||
setFieldsValue () {
|
||||
const { record, form, $nextTick } = this
|
||||
// 设置表单内容
|
||||
!isEmpty(form.getFieldsValue()) && $nextTick(() => {
|
||||
// 表单数据
|
||||
const data = pick(record, [
|
||||
'name', 'coupon_type', 'reduce_price', 'discount', 'min_price', 'status',
|
||||
'expire_type', 'expire_day', 'apply_range', 'total_num', 'describe', 'sort'
|
||||
])
|
||||
// 时间范围
|
||||
data.betweenTime = this.getBetweenTime(record)
|
||||
form.setFieldsValue(data)
|
||||
})
|
||||
},
|
||||
|
||||
// 格式化时间范围
|
||||
getBetweenTime (record) {
|
||||
if (record.expire_type === ExpireTypeEnum.FIXED_TIME.value) {
|
||||
return [moment(new Date(record.start_time)), moment(new Date(record.end_time))]
|
||||
}
|
||||
return this.defaultDate
|
||||
},
|
||||
|
||||
// 确认按钮
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields }, onFormSubmit } = this
|
||||
validateFields((errors, values) => {
|
||||
!errors && onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
Api.edit({ couponId: this.couponId, form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="是否开启实体卡兑换" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['is_entrance', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>如设置关闭则用户端不显示兑换按钮</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="兑换说明" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['describe', { rules: [{ required: true, message: '请输入兑换说明' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/setting/store'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前设置项的key
|
||||
key: 'exchange',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.isLoading = true
|
||||
Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.values
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(pick(record, ['is_entrance', 'describe']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="会员昵称">
|
||||
<a-input v-decorator="['search']" placeholder="请输入会员昵称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="变动时间">
|
||||
<a-range-picker format="YYYY-MM-DD" v-decorator="['betweenTime']" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="log_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 会员信息 -->
|
||||
<span slot="user" slot-scope="text">
|
||||
<UserItem :user="text" />
|
||||
</span>
|
||||
<!-- 变动数量 -->
|
||||
<span slot="value" slot-scope="text">
|
||||
<p class="c-p">{{ text > 0 ? '+' : '' }}{{ text }}</p>
|
||||
</span>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/market/points'
|
||||
import { STable, UserItem } from '@/components/Table'
|
||||
import SceneEnum from '@/common/enum/user/balance/log/Scene'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
UserItem
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 枚举类
|
||||
SceneEnum,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'log_id'
|
||||
},
|
||||
{
|
||||
title: '会员信息',
|
||||
dataIndex: 'user',
|
||||
scopedSlots: { customRender: 'user' }
|
||||
},
|
||||
{
|
||||
title: '变动数量',
|
||||
dataIndex: 'value',
|
||||
scopedSlots: { customRender: 'value' }
|
||||
},
|
||||
{
|
||||
title: '描述/说明',
|
||||
dataIndex: 'describe'
|
||||
},
|
||||
{
|
||||
title: '管理员备注',
|
||||
dataIndex: 'remark'
|
||||
},
|
||||
{
|
||||
title: '变动时间',
|
||||
dataIndex: 'create_time'
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.log({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="积分名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
v-decorator="['points_name', { rules: [{ required: true, message: '请输入积分名称' }] }]"
|
||||
/>
|
||||
<div class="form-item-help">
|
||||
<small>注:商家使用自定义的积分名称来做品牌运营。如京东把积分称为“京豆”,淘宝把积分称为“淘金币”</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="积分说明" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['describe', { rules: [{ required: true, message: '请输入积分说明' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left">积分赠送</a-divider>
|
||||
<a-form-item label="购物送积分" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['is_shopping_gift', { initialValue: 1, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>积分赠送规则:1. 订单确认收货已完成; 2. 已完成订单超出后台设置的申请售后期限</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<div v-show="form.getFieldValue('is_shopping_gift') == 1">
|
||||
<a-form-item label="积分赠送比例" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0.1"
|
||||
:max="100"
|
||||
:precision="1"
|
||||
v-decorator="['gift_ratio', { rules: [{ required: true, message: '请输入积分赠送比例' }] }]"
|
||||
/>
|
||||
<span class="ml-10">%</span>
|
||||
<div class="form-item-help">
|
||||
<p class="extra">注:赠送比例请填写数字0~100;订单的运费不参与积分赠送</p>
|
||||
<p class="extra">例:订单付款金额(100.00元) * 积分赠送比例(100%) = 实际赠送的积分(100积分)</p>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<a-divider orientation="left">积分抵扣</a-divider>
|
||||
<a-form-item label="下单使用积分抵扣" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="['is_shopping_discount', { initialValue: 1, rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>注:如开启则用户下单时可选择使用积分抵扣订单金额</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<div v-show="form.getFieldValue('is_shopping_discount') == 1">
|
||||
<a-form-item label="积分抵扣比例" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<InputNumberGroup
|
||||
addonBefore="1个积分可抵扣"
|
||||
addonAfter="元"
|
||||
:inputProps="{ min: 0.01, precision: 2 }"
|
||||
v-decorator="['discount.discount_ratio', { rules: [{ required: true, message: '积分抵扣比例不能为空' }] }]"
|
||||
/>
|
||||
<div class="form-item-help">
|
||||
<small>例如:设置1个积分可抵扣0.1元,则10积分可抵扣1元,100积分可抵扣10元</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="最高可抵扣金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-form-item>
|
||||
<InputNumberGroup
|
||||
addonBefore="订单满"
|
||||
addonAfter="元"
|
||||
:inputProps="{ min: 0.01, precision: 2 }"
|
||||
v-decorator="['discount.full_order_price', { rules: [{ required: true, message: '抵扣条件不能为空' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<InputNumberGroup
|
||||
addonBefore="最高可抵扣金额"
|
||||
addonAfter="%"
|
||||
:inputProps="{ min: 0.1, max: 90, precision: 1 }"
|
||||
v-decorator="['discount.max_money_ratio', { rules: [{ required: true, message: '最高可抵扣金额不能为空' }] }]"
|
||||
/>
|
||||
<div class="form-item-help">
|
||||
<small>例如:设置最高可抵扣10%,订单金额100元,此时用户可抵扣10元</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/setting/store'
|
||||
import { InputNumberGroup } from '@/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InputNumberGroup
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前设置项的key
|
||||
key: 'points',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.isLoading = true
|
||||
Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.values
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(pick(record, [
|
||||
'points_name', 'describe',
|
||||
'is_shopping_gift', 'gift_ratio',
|
||||
'is_shopping_discount', 'discount'
|
||||
]))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="是否开启会员充值" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['is_entrance', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>如设置关闭则用户端不显示充值按钮</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值自定义金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['is_custom', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">允许</a-radio>
|
||||
<a-radio :value="0">不允许</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>是否允许用户填写自定义的充值金额</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-show="form.getFieldValue('is_custom') == 1"
|
||||
label="最低充值金额"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
v-decorator="['lowest_money', { rules: [{ required: true, message: '请输入最低充值金额' }] }]"
|
||||
/>
|
||||
<span class="ml-10">元</span>
|
||||
<div class="form-item-help">
|
||||
<small>低于该设定金额时不允许充值</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="自动匹配套餐" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['is_match_plan', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>充值自定义金额时 是否自动匹配充值套餐,如不开启则不参与套餐金额赠送</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值说明" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['describe', { rules: [{ required: true, message: '请输入充值说明' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/setting/store'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前设置项的key
|
||||
key: 'recharge',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.isLoading = true
|
||||
Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.values
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(pick(record, ['is_entrance', 'is_custom', 'lowest_money', 'is_match_plan', 'describe']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<a-row>
|
||||
<a-col :span="6">
|
||||
<a-button v-action:add type="primary" icon="plus" @click="handleAdd">新增</a-button>
|
||||
</a-col>
|
||||
<a-col :span="8" :offset="10">
|
||||
<a-input-search
|
||||
style="max-width: 300px; min-width: 150px;float: right;"
|
||||
v-model="queryParam.search"
|
||||
placeholder="请输入套餐名称"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="plan_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 充值金额 -->
|
||||
<span slot="money" slot-scope="text">
|
||||
<p class="c-p">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 赠送金额 -->
|
||||
<span slot="gift_money" slot-scope="text">
|
||||
<p class="c-p">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 操作 -->
|
||||
<span slot="action" slot-scope="text, item">
|
||||
<a v-action:edit style="margin-right: 8px;" @click="handleEdit(item)">编辑</a>
|
||||
<a v-action:delete @click="handleDelete(item)">删除</a>
|
||||
</span>
|
||||
</s-table>
|
||||
<AddForm ref="AddForm" @handleSubmit="handleRefresh" />
|
||||
<EditForm ref="EditForm" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/market/recharge/plan'
|
||||
import { STable } from '@/components'
|
||||
import { AddForm, EditForm } from './modules'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable,
|
||||
AddForm,
|
||||
EditForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: '套餐ID',
|
||||
dataIndex: 'plan_id'
|
||||
},
|
||||
{
|
||||
title: '套餐名称',
|
||||
dataIndex: 'plan_name'
|
||||
},
|
||||
{
|
||||
title: '充值金额 (元)',
|
||||
dataIndex: 'money',
|
||||
scopedSlots: { customRender: 'money' }
|
||||
},
|
||||
{
|
||||
title: '赠送金额 (元)',
|
||||
dataIndex: 'gift_money',
|
||||
scopedSlots: { customRender: 'gift_money' }
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort'
|
||||
},
|
||||
{
|
||||
title: '添加时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '180px',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleAdd () {
|
||||
this.$refs.AddForm.add()
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑记录
|
||||
*/
|
||||
handleEdit (item) {
|
||||
this.$refs.EditForm.edit(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (item) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return Api.deleted({ planId: item.plan_id })
|
||||
.then((result) => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
/**
|
||||
* 检索查询
|
||||
*/
|
||||
onSearch () {
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item
|
||||
label="套餐名称"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="便于后台查找,例如:充100元送10元"
|
||||
>
|
||||
<a-input
|
||||
v-decorator="['plan_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值金额" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="会员充值并支付的金额">
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="['money', {rules: [{required: true, message: '请输入充值的金额'}]}]"
|
||||
/>
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="赠送金额"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="充值成功后赠送的金额,不能大于充值金额"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="['gift_money', {rules: [{required: true, message: '请输入赠送的金额'}]}]"
|
||||
/>
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入排序值'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/market/recharge/plan'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '新增充值套餐',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
add () {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.add({ form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="title"
|
||||
:width="720"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-form-item
|
||||
label="套餐名称"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="便于后台查找,例如:充100元送10元"
|
||||
>
|
||||
<a-input
|
||||
v-decorator="['plan_name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值金额" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="会员充值并支付的金额">
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="['money', {rules: [{required: true, message: '请输入充值的金额'}]}]"
|
||||
/>
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="赠送金额"
|
||||
:labelCol="labelCol"
|
||||
:wrapperCol="wrapperCol"
|
||||
extra="充值成功后赠送的金额,不能大于充值金额"
|
||||
>
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="['gift_money', {rules: [{required: true, message: '请输入赠送的金额'}]}]"
|
||||
/>
|
||||
<span class="ml-10">元</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" extra="数字越小越靠前">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
v-decorator="['sort', {initialValue: 100, rules: [{required: true, message: '请输入排序值'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/market/recharge/plan'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '编辑充值套餐',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 显示对话框
|
||||
*/
|
||||
edit (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { form: { setFieldsValue } } = this
|
||||
this.$nextTick(() => {
|
||||
setFieldsValue(pick(this.record, ['plan_name', 'money', 'gift_money', 'sort']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.confirmLoading = true
|
||||
Api.edit({ planId: this.record.plan_id, form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,4 @@
|
||||
import AddForm from './AddForm'
|
||||
import EditForm from './EditForm'
|
||||
|
||||
export { AddForm, EditForm }
|
||||
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit">
|
||||
<a-form-item label="是否开启余额分享" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group v-decorator="['is_entrance', { rules: [{ required: true }] }]">
|
||||
<a-radio :value="1">开启</a-radio>
|
||||
<a-radio :value="0">关闭</a-radio>
|
||||
</a-radio-group>
|
||||
<div class="form-item-help">
|
||||
<small>如设置关闭则用户端不显示分享按钮</small>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="分享说明" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
:autoSize="{ minRows: 4 }"
|
||||
v-decorator="['describe', { rules: [{ required: true, message: '请输入分享说明' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/setting/store'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前设置项的key
|
||||
key: 'share',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 4 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前记录详情
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
// 获取当前详情记录
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 获取当前详情记录
|
||||
getDetail () {
|
||||
this.isLoading = true
|
||||
Api.detail(this.key)
|
||||
.then(result => {
|
||||
// 当前记录
|
||||
this.record = result.data.values
|
||||
// 设置默认值
|
||||
this.setFieldsValue()
|
||||
})
|
||||
.finally(result => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*/
|
||||
setFieldsValue () {
|
||||
const { record, $nextTick, form: { setFieldsValue } } = this
|
||||
$nextTick(() => {
|
||||
setFieldsValue(pick(record, ['is_entrance', 'describe']))
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
Api.update(this.key, { form: values })
|
||||
.then((result) => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
})
|
||||
.finally((result) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.ant-form-item-control {
|
||||
padding-left: 10px;
|
||||
.ant-form-item-control {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="代理商名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入代理商名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="代理商地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入代理商地址"
|
||||
v-decorator="['address', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系人" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系人"
|
||||
v-decorator="['contact_name', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系电话" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系电话"
|
||||
v-decorator="['contact_tel', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!--<a-form-item label="回调地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入回调地址"
|
||||
v-decorator="['callback', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as MerchantApi from '@/api/merchant'
|
||||
import MerchantModel from '@/common/model/merchant/Index'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 表单数据
|
||||
formData: MerchantModel.formData
|
||||
}
|
||||
},
|
||||
// 初始化数据
|
||||
created () {
|
||||
this.isLoading = true
|
||||
// 获取form所需的数据
|
||||
MerchantModel.getFromData()
|
||||
.then(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
MerchantApi.add({ form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="关键字搜索">
|
||||
<a-input v-decorator="['search']" placeholder="代理商编号/代理商名称/代理商地址/联系人/联系电话" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
<!-- 操作板块 -->
|
||||
<div class="row-item-tab clearfix">
|
||||
<a-button
|
||||
v-if="$auth('/merchant/create')"
|
||||
class="fl-l"
|
||||
type="primary"
|
||||
icon="plus"
|
||||
@click="handleCreate"
|
||||
>新增</a-button>
|
||||
<div v-if="selectedRowKeys.length" class="button-group">
|
||||
<a-button-group class="ml-10">
|
||||
<a-button v-action:delete icon="delete" @click="handleDelete(selectedRowKeys)">删除</a-button>
|
||||
</a-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="merchant_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowSelection="rowSelection"
|
||||
:pageSize="15"
|
||||
:scroll="{ x: 1450 }"
|
||||
>
|
||||
<!-- 代理商地址 -->
|
||||
<span slot="address" slot-scope="text">
|
||||
<p class="twoline-hide" style="width: 270px;">{{ text }}</p>
|
||||
</span>
|
||||
<!-- 操作项 -->
|
||||
<div class="actions" slot="action" slot-scope="text, item">
|
||||
<!-- <a title="代理商对接参数" v-action:para @click="handleApiPara(item)">对接参数</a>-->
|
||||
<a title="推广码" v-action:qrCode @click="handleQrCode(item)">推广码</a>
|
||||
<a title="代理商充值" v-action:recharge @click="handleRecharge(item)">充值</a>
|
||||
<router-link v-if="$auth('/merchant/update')" :to="{ path: '/merchant/update', query: { merchantId: item.merchant_id } }">编辑</router-link>
|
||||
<a v-action:delete @click="handleDelete([item.merchant_id])">删除</a>
|
||||
<a title="抖音发券" v-action:sendCoupon @click="handleSendCoupon(item)">抖音发券</a>
|
||||
</div>
|
||||
</s-table>
|
||||
<RechargeForm ref="RechargeForm" @handleSubmit="handleRefresh" />
|
||||
<ApiParaForm ref="ApiParaForm" @handleSubmit="handleRefresh" />
|
||||
<QrCodeForm ref="QrCodeForm" @handleSubmit="handleRefresh" />
|
||||
<SendCouponForm ref="SendCouponForm" :coupongoods="couponGoodsData" @handleSubmit="handleRefresh" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as MerchantApi from '@/api/merchant'
|
||||
import * as GoodsApi from '@/api/goods'
|
||||
import { ContentHeader, STable } from '@/components'
|
||||
import { RechargeForm, ApiParaForm, QrCodeForm, SendCouponForm } from './modules'
|
||||
import { assignment, inArray } from '@/utils/util'
|
||||
|
||||
// 表格表头
|
||||
const columns = [
|
||||
{
|
||||
title: '代理商ID',
|
||||
width: '70px',
|
||||
dataIndex: 'merchant_id'
|
||||
},
|
||||
{
|
||||
title: '代理商编号',
|
||||
width: '150px',
|
||||
dataIndex: 'orgNo'
|
||||
},
|
||||
{
|
||||
title: '代理商名称',
|
||||
width: '150px',
|
||||
dataIndex: 'name'
|
||||
},
|
||||
{
|
||||
title: '代理商地址',
|
||||
width: '200px',
|
||||
dataIndex: 'address'
|
||||
},
|
||||
{
|
||||
title: '联系人',
|
||||
width: '150px',
|
||||
dataIndex: 'contact_name'
|
||||
},
|
||||
{
|
||||
title: '联系电话',
|
||||
width: '150px',
|
||||
dataIndex: 'contact_tel'
|
||||
},
|
||||
{
|
||||
title: '余额',
|
||||
width: '150px',
|
||||
dataIndex: 'balance'
|
||||
},
|
||||
{
|
||||
title: '今日发券金额',
|
||||
width: '150px',
|
||||
dataIndex: 'day_money'
|
||||
},
|
||||
{
|
||||
title: '发券总金额',
|
||||
width: '150px',
|
||||
dataIndex: 'total_money'
|
||||
},
|
||||
/*{
|
||||
title: 'appKey',
|
||||
dataIndex: 'appKey',
|
||||
width: '300px'
|
||||
},
|
||||
{
|
||||
title: '回调地址',
|
||||
dataIndex: 'callback',
|
||||
width: '300px',
|
||||
scopedSlots: { customRender: 'callback' }
|
||||
},*/
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '300px',
|
||||
fixed: 'right',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ContentHeader,
|
||||
RechargeForm,
|
||||
ApiParaForm,
|
||||
QrCodeForm,
|
||||
SendCouponForm,
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns,
|
||||
// 选择的元素
|
||||
selectedRowKeys: [],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return MerchantApi.list({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
},
|
||||
// 优惠券商品
|
||||
couponGoodsData: []
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
// 批量给当前实例赋值
|
||||
assignment(this, {
|
||||
inArray
|
||||
})
|
||||
},
|
||||
created () {
|
||||
this.getCouponGoods()
|
||||
},
|
||||
computed: {
|
||||
rowSelection () {
|
||||
return {
|
||||
selectedRowKeys: this.selectedRowKeys,
|
||||
onChange: this.onSelectChange
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 选中项发生变化时的回调
|
||||
*/
|
||||
onSelectChange (selectedRowKeys) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置搜索表单
|
||||
handleReset () {
|
||||
this.searchForm.resetFields()
|
||||
},
|
||||
|
||||
// 代理商充值
|
||||
handleRecharge (item) {
|
||||
this.$refs.RechargeForm.handle(item)
|
||||
},
|
||||
// 代理商推广码
|
||||
handleQrCode (item) {
|
||||
this.$refs.QrCodeForm.handle(item)
|
||||
},
|
||||
// 代理商对接参数
|
||||
handleApiPara (item) {
|
||||
this.$refs.ApiParaForm.handle(item)
|
||||
},
|
||||
// 发券弹窗
|
||||
handleSendCoupon (item) {
|
||||
this.$refs.SendCouponForm.handle(item)
|
||||
},
|
||||
/**
|
||||
* 删除记录
|
||||
*/
|
||||
handleDelete (merchantIds) {
|
||||
const app = this
|
||||
const modal = this.$confirm({
|
||||
title: '您确定要删除该记录吗?',
|
||||
content: '删除后不可恢复',
|
||||
onOk () {
|
||||
return MerchantApi.deleted(merchantIds)
|
||||
.then(result => {
|
||||
app.$message.success(result.message, 1.5)
|
||||
app.handleRefresh()
|
||||
})
|
||||
.finally(result => {
|
||||
modal.destroy()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 新增记录
|
||||
*/
|
||||
handleCreate () {
|
||||
this.$router.push('/merchant/create')
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取优惠券商品
|
||||
*/
|
||||
getCouponGoods () {
|
||||
this.isLoading = true
|
||||
GoodsApi.all({ province: '', oilCardType: 'coupon' })
|
||||
.then(result => {
|
||||
this.couponGoodsData = result.data.list
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
// 筛选tab
|
||||
.tab-list {
|
||||
margin-right: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<a-spin :spinning="isLoading">
|
||||
<a-form :form="form" @submit="handleSubmit" :selfUpdate="true">
|
||||
<a-tabs :activeKey="tabKey" :tabBarStyle="{marginBottom: '30px'}" @change="handleTabs">
|
||||
<a-tab-pane :key="0" tab="基本信息"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="tabs-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="tab-pane" v-show="tabKey == 0">
|
||||
<a-form-item label="代理商名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入代理商名称"
|
||||
v-decorator="['name', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="代理商地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入代理商地址"
|
||||
v-decorator="['address', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系人" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系人"
|
||||
v-decorator="['contact_name', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="联系电话" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入联系电话"
|
||||
v-decorator="['contact_tel', {rules: [{required: false}]}]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!--<a-form-item label="回调地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input
|
||||
placeholder="请输入回调地址"
|
||||
v-decorator="['callback', {rules: [{required: true, min: 2, message: '请输入至少2个字符'}]}]"
|
||||
/>
|
||||
</a-form-item>-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a-form-item class="mt-20" :wrapper-col="{ span: wrapperCol.span, offset: labelCol.span }">
|
||||
<a-button type="primary" html-type="submit" :loading="isBtnLoading">提交</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as MerchantApi from '@/api/merchant'
|
||||
import { InputNumberGroup } from '@/components'
|
||||
import MerchantModel from '@/common/model/merchant/Index'
|
||||
import { isEmptyObject } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InputNumberGroup
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 默认的标签索引
|
||||
tabKey: 0,
|
||||
// 标签布局属性
|
||||
labelCol: { span: 3 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 10 },
|
||||
// loading状态
|
||||
isLoading: false,
|
||||
isBtnLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 代理商ID
|
||||
merchantId: null,
|
||||
// 表单数据
|
||||
formData: MerchantModel.formData
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 初始化数据
|
||||
this.initData()
|
||||
},
|
||||
beforeDestroy () {
|
||||
// 销毁代理商详情
|
||||
MerchantModel.formData.merchant = {}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 初始化数据
|
||||
initData () {
|
||||
// 记录代理商ID
|
||||
this.merchantId = this.$route.query.merchantId
|
||||
// 获取form所需的数据
|
||||
this.isLoading = true
|
||||
MerchantModel.getFromData(this.merchantId)
|
||||
.then(() => {
|
||||
// 代理商表单数据
|
||||
if (!isEmptyObject(this.form.getFieldsValue())) {
|
||||
this.form.setFieldsValue(MerchantModel.getFieldsValue())
|
||||
}
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 手动强制更新页面
|
||||
onForceUpdate (bool = false) {
|
||||
this.$forceUpdate()
|
||||
// bool为true时再执行一次 $forceUpdate, 特殊情况下需执行两次,原因如下:
|
||||
// 第一次执行 $forceUpdate时, 新元素绑定v-decorator无法获取到form.getFieldValue
|
||||
bool && setTimeout(() => {
|
||||
this.$forceUpdate()
|
||||
}, 10)
|
||||
},
|
||||
|
||||
// 切换tab选项卡
|
||||
handleTabs (key) {
|
||||
this.tabKey = key
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 定位到错误的tab选项卡
|
||||
if (errors) {
|
||||
this.onTargetTabError(errors)
|
||||
return false
|
||||
}
|
||||
// 提交到后端api
|
||||
this.onFormSubmit(values)
|
||||
return true
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 定位到错误的tab选项卡
|
||||
*/
|
||||
onTargetTabError (errors) {
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
this.isLoading = true
|
||||
this.isBtnLoading = true
|
||||
MerchantApi.edit({ merchantId: this.merchantId, form: values })
|
||||
.then(result => {
|
||||
// 显示提示信息
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 跳转到列表页
|
||||
setTimeout(() => {
|
||||
this.$router.push('./index')
|
||||
}, 1500)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isBtnLoading = false
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './style.less';
|
||||
</style>
|
||||
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<a-card :bordered="false">
|
||||
<div class="card-title">{{ $route.meta.title }}</div>
|
||||
<div class="table-operator">
|
||||
<!-- 搜索板块 -->
|
||||
<a-row class="row-item-search">
|
||||
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
|
||||
<a-form-item label="代理商名称">
|
||||
<a-input v-decorator="['search']" placeholder="请输入代理商名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="余额变动场景">
|
||||
<a-select v-decorator="['scene', { initialValue: 0 }]">
|
||||
<a-select-option :value="0">全部</a-select-option>
|
||||
<a-select-option
|
||||
v-for="(item, index) in SceneEnum.data"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="变动时间">
|
||||
<a-range-picker format="YYYY-MM-DD" v-decorator="['betweenTime']" />
|
||||
</a-form-item>
|
||||
<a-form-item class="search-btn">
|
||||
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-row>
|
||||
</div>
|
||||
<s-table
|
||||
ref="table"
|
||||
rowKey="log_id"
|
||||
:loading="isLoading"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:pageSize="15"
|
||||
>
|
||||
<!-- 代理商 -->
|
||||
<span slot="merchant" slot-scope="text, item">
|
||||
<p class="twoline-hide" style="width: 150px;">{{ item.name }}</p>
|
||||
</span>
|
||||
<!-- 余额变动场景 -->
|
||||
<span slot="scene" slot-scope="text">
|
||||
<a-tag>{{ SceneEnum[text].name }}</a-tag>
|
||||
</span>
|
||||
</s-table>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as Api from '@/api/merchant/balance'
|
||||
import { STable } from '@/components/Table'
|
||||
import SceneEnum from '@/common/enum/merchant/balance/log/Scene'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
STable
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 枚举类
|
||||
SceneEnum,
|
||||
// 当前表单元素
|
||||
searchForm: this.$form.createForm(this),
|
||||
// 查询参数
|
||||
queryParam: {},
|
||||
// 正在加载
|
||||
isLoading: false,
|
||||
// 表头
|
||||
columns: [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'log_id'
|
||||
},
|
||||
{
|
||||
title: '代理商信息',
|
||||
dataIndex: 'merchant',
|
||||
scopedSlots: { customRender: 'merchant' }
|
||||
},
|
||||
{
|
||||
title: '余额变动场景',
|
||||
dataIndex: 'scene',
|
||||
scopedSlots: { customRender: 'scene' }
|
||||
},
|
||||
{
|
||||
title: '变动金额',
|
||||
dataIndex: 'money'
|
||||
},
|
||||
{
|
||||
title: '描述/说明',
|
||||
width: '260px',
|
||||
dataIndex: 'describe'
|
||||
},
|
||||
{
|
||||
title: '管理员备注',
|
||||
width: '260px',
|
||||
dataIndex: 'remark'
|
||||
},
|
||||
{
|
||||
title: '变动时间',
|
||||
dataIndex: 'create_time'
|
||||
}
|
||||
],
|
||||
// 加载数据方法 必须为 Promise 对象
|
||||
loadData: param => {
|
||||
return Api.log({ ...param, ...this.queryParam })
|
||||
.then(response => {
|
||||
return response.data.list
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 刷新列表
|
||||
* @param Boolean bool 强制刷新到第一页
|
||||
*/
|
||||
handleRefresh (bool = false) {
|
||||
this.$refs.table.refresh(bool)
|
||||
},
|
||||
|
||||
// 确认搜索
|
||||
handleSearch (e) {
|
||||
e.preventDefault()
|
||||
this.searchForm.validateFields((error, values) => {
|
||||
if (!error) {
|
||||
this.queryParam = { ...this.queryParam, ...values }
|
||||
this.handleRefresh(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-card-body {
|
||||
padding: 22px 29px 25px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<a-modal
|
||||
class="noborder"
|
||||
:title="title"
|
||||
:width="900"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-tabs :activeKey="activeKey" @change="onChangeTabs">
|
||||
<a-tab-pane :key="RECHARGE_TYPE_BALANCE" tab="商户对接参数">
|
||||
<template v-if="activeKey === RECHARGE_TYPE_BALANCE">
|
||||
<a-form-item class="mb-5" label="商户编号" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.orgNo }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="商户appKey" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.appKey }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="商户私钥" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.privateKey }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="商户公钥" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.publicKey }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="回调地址" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.callback }}</span>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import pick from 'lodash.pick'
|
||||
|
||||
// 充值类型枚举: 余额
|
||||
const RECHARGE_TYPE_BALANCE = 'balance'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '商户对接参数',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前tab索引
|
||||
activeKey: RECHARGE_TYPE_BALANCE,
|
||||
// 充值类型
|
||||
RECHARGE_TYPE_BALANCE,
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 显示对话框
|
||||
handle (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
},
|
||||
|
||||
// 切换tabs事件
|
||||
onChangeTabs (activeKey) {
|
||||
this.activeKey = activeKey
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-modal-body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<a-modal
|
||||
class="noborder"
|
||||
:title="title"
|
||||
:width="500"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<img v-if="qrcode" width="260" :src="qrcode" alt="推广码" />
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import pick from 'lodash.pick'
|
||||
import * as MerchantApi from '@/api/merchant'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '推广码',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前记录
|
||||
record: {},
|
||||
qrcode: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 显示对话框
|
||||
handle (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
this.getMerchantQrcode(record.merchant_id)
|
||||
},
|
||||
|
||||
// 获取商户详情
|
||||
getMerchantQrcode (merchantId = null) {
|
||||
if (!merchantId) return false
|
||||
return new Promise((resolve, reject) => {
|
||||
MerchantApi.qrCode({ merchantId })
|
||||
.then(result => {
|
||||
this.qrcode = result.data.data
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-modal-body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<a-modal
|
||||
class="noborder"
|
||||
:title="title"
|
||||
:width="520"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
:maskClosable="false"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form :form="form">
|
||||
<a-tabs :activeKey="activeKey" @change="onChangeTabs">
|
||||
<a-tab-pane :key="RECHARGE_TYPE_BALANCE" tab="充值余额">
|
||||
<template v-if="activeKey === RECHARGE_TYPE_BALANCE">
|
||||
<a-form-item class="mb-5" label="商户ID" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.merchant_id }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="当前余额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="c-p">{{ record.balance }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="[`${RECHARGE_TYPE_BALANCE}.mode`, { initialValue: 'inc', rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio value="inc">增加</a-radio>
|
||||
<a-radio value="dec">减少</a-radio>
|
||||
<a-radio value="final">最终金额</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="变更金额" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="[`${RECHARGE_TYPE_BALANCE}.money`, { initialValue: '', rules: [{ required: true, message: '请输入变更的金额' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="管理员备注" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
placeholder="请输入管理员备注"
|
||||
:rows="3"
|
||||
v-decorator="[`${RECHARGE_TYPE_BALANCE}.remark`, { rules: [{ required: true, message: '请输入管理员备注' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
<!--<a-tab-pane :key="RECHARGE_TYPE_POINTS" tab="充值积分">
|
||||
<template v-if="activeKey === RECHARGE_TYPE_POINTS">
|
||||
<a-form-item class="mb-5" label="商户ID" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span>{{ record.merchant_id }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item class="mb-5" label="当前积分" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<span class="c-p">{{ record.points }}</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="充值方式" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-radio-group
|
||||
v-decorator="[`${RECHARGE_TYPE_POINTS}.mode`, { initialValue: 'inc', rules: [{ required: true }] }]"
|
||||
>
|
||||
<a-radio value="inc">增加</a-radio>
|
||||
<a-radio value="dec">减少</a-radio>
|
||||
<a-radio value="final">最终积分</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="变更数量" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-input-number
|
||||
:min="0.01"
|
||||
v-decorator="[`${RECHARGE_TYPE_POINTS}.value`, { initialValue: '', rules: [{ required: true, message: '请输入变更的金数量' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="管理员备注" :labelCol="labelCol" :wrapperCol="wrapperCol">
|
||||
<a-textarea
|
||||
placeholder="请输入管理员备注"
|
||||
:rows="3"
|
||||
v-decorator="[`${RECHARGE_TYPE_POINTS}.remark`, { rules: [{ required: true, message: '请输入管理员备注' }] }]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>-->
|
||||
</a-tabs>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import pick from 'lodash.pick'
|
||||
import * as Api from '@/api/merchant'
|
||||
|
||||
// 充值类型枚举: 余额
|
||||
const RECHARGE_TYPE_BALANCE = 'balance'
|
||||
|
||||
// 充值类型枚举: 积分
|
||||
const RECHARGE_TYPE_POINTS = 'points'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 对话框标题
|
||||
title: '商户充值',
|
||||
// 标签布局属性
|
||||
labelCol: { span: 7 },
|
||||
// 输入框布局属性
|
||||
wrapperCol: { span: 13 },
|
||||
// modal(对话框)是否可见
|
||||
visible: false,
|
||||
// modal(对话框)确定按钮 loading
|
||||
confirmLoading: false,
|
||||
// 当前表单元素
|
||||
form: this.$form.createForm(this),
|
||||
// 当前tab索引
|
||||
activeKey: RECHARGE_TYPE_BALANCE,
|
||||
// 充值类型
|
||||
RECHARGE_TYPE_BALANCE,
|
||||
RECHARGE_TYPE_POINTS,
|
||||
// 当前记录
|
||||
record: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 显示对话框
|
||||
handle (record) {
|
||||
// 显示窗口
|
||||
this.visible = true
|
||||
// 当前记录
|
||||
this.record = record
|
||||
},
|
||||
|
||||
// 切换tabs事件
|
||||
onChangeTabs (activeKey) {
|
||||
this.activeKey = activeKey
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
// 表单验证
|
||||
const { form: { validateFields } } = this
|
||||
validateFields((errors, values) => {
|
||||
// 提交到后端api
|
||||
!errors && this.onFormSubmit(values)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭对话框事件
|
||||
*/
|
||||
handleCancel () {
|
||||
this.visible = false
|
||||
this.form.resetFields()
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交到后端api
|
||||
*/
|
||||
onFormSubmit (values) {
|
||||
const { record, activeKey } = this
|
||||
this.confirmLoading = true
|
||||
Api.recharge({ merchantId: record.merchant_id, target: activeKey, form: values })
|
||||
.then((result) => {
|
||||
// 显示成功
|
||||
this.$message.success(result.message, 1.5)
|
||||
// 关闭对话框事件
|
||||
this.handleCancel()
|
||||
// 通知父端组件提交完成了
|
||||
this.$emit('handleSubmit', values)
|
||||
})
|
||||
.finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.ant-modal-body {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user