|
|
@@ -0,0 +1,244 @@
|
|
|
+<template>
|
|
|
+ <div class="product-ppoint admin-page">
|
|
|
+ <div class="header">
|
|
|
+ <h2>P点(可分配利润)配置</h2>
|
|
|
+ <div class="filters">
|
|
|
+ <el-input v-model="searchText" placeholder="商品名称搜索" prefix-icon="el-icon-search" style="width: 200px;" clearable @keyup.enter.native="loadList" />
|
|
|
+ <el-button type="primary" @click="loadList">查询</el-button>
|
|
|
+ <el-button type="success" @click="openAddDialog">新增配置</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div style="overflow:auto;max-height:calc(100vh - 300px);">
|
|
|
+ <el-table style="max-height:calc(100vh - 300px);" :data="list" v-loading="loading" border stripe>
|
|
|
+ <el-table-column prop="id" label="ID" width="70" />
|
|
|
+ <el-table-column label="商品图片" width="70">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <img v-if="row.coverImage" :src="row.coverImage" class="product-thumb" />
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="productName" label="商品名称" min-width="160" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="price" label="售价(元)" width="90">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.price != null ? (row.price / 100).toFixed(2) : '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="利润率" width="100">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.profitRate != null ? formatBps(row.profitRate) : '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="P点基点(bps)" width="120">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <span v-if="editId !== row.id">{{ row.ppoint != null ? row.ppoint + ' bps' : '-' }}</span>
|
|
|
+ <el-input-number
|
|
|
+ v-else
|
|
|
+ v-model="editPpoint"
|
|
|
+ :min="0"
|
|
|
+ :max="10000"
|
|
|
+ :step="100"
|
|
|
+ size="small"
|
|
|
+ style="width: 100px;"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="生效日期" width="100">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.effectiveDate || '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="状态" width="80">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-tag v-if="row.effectiveDate" :type="isEffectived(row.effectiveDate) ? 'success' : 'warning'" size="small">
|
|
|
+ {{ isEffectived(row.effectiveDate) ? '生效中' : '待生效' }}
|
|
|
+ </el-tag>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="150" fixed="right">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <template v-if="editId !== row.id">
|
|
|
+ <el-button type="primary" size="small" @click="startEdit(row)">编辑</el-button>
|
|
|
+ <el-button type="danger" size="small" @click="deleteRow(row)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <el-button type="success" size="small" @click="saveRow(row)">保存</el-button>
|
|
|
+ <el-button size="small" @click="cancelEdit">取消</el-button>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table></div>
|
|
|
+
|
|
|
+ <el-pagination
|
|
|
+ @size-change="onPageChange"
|
|
|
+ @current-change="onPageChange"
|
|
|
+ :current-page="page"
|
|
|
+ :page-size="size"
|
|
|
+ :total="total"
|
|
|
+ layout="total, prev, pager, next"
|
|
|
+ style="margin-top: 20px; text-align: right;"
|
|
|
+ />
|
|
|
+
|
|
|
+ <el-dialog title="新增P点配置" :visible.sync="addDialogVisible" width="500px">
|
|
|
+ <el-form :model="addForm" label-width="100px">
|
|
|
+ <el-form-item label="选择商品">
|
|
|
+ <el-select v-model="addForm.productId" filterable placeholder="搜索商品" style="width: 100%;">
|
|
|
+ <el-option v-for="p in productOptions" :key="p.id" :label="p.name" :value="p.id">
|
|
|
+ <span style="float:left">{{ p.name }}</span>
|
|
|
+ <span style="float:right;color:#999;font-size:12px;">{{ p.price != null ? (p.price/100).toFixed(2) + '元' : '' }}</span>
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="P点(bps)">
|
|
|
+ <el-input-number v-model="addForm.ppoint" :min="0" :max="10000" :step="100" style="width: 100%;" />
|
|
|
+ <div style="color:#999;font-size:12px;margin-top:4px;">10000 bps = 100%,例:1000 bps = 10%</div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="生效日期">
|
|
|
+ <el-date-picker v-model="addForm.effectiveDate" type="date" placeholder="选择日期" value-format="yyyy-MM-dd" style="width: 100%;" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer">
|
|
|
+ <el-button @click="addDialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="submitAdd">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { getProductPpointList, saveProductPpoint, deleteProductPpoint, getProductList } from '@/api/admin'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ list: [],
|
|
|
+ loading: false,
|
|
|
+ page: 1,
|
|
|
+ size: 20,
|
|
|
+ total: 0,
|
|
|
+ searchText: '',
|
|
|
+ editId: null,
|
|
|
+ editPpoint: 0,
|
|
|
+ addDialogVisible: false,
|
|
|
+ addForm: {
|
|
|
+ productId: null,
|
|
|
+ ppoint: 0,
|
|
|
+ effectiveDate: ''
|
|
|
+ },
|
|
|
+ productOptions: []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.loadList()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async loadList() {
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ const res = await getProductPpointList({ keyword: this.searchText, page: this.page, size: this.size })
|
|
|
+ this.list = res.data.records || res.data || []
|
|
|
+ this.total = res.data.total || 0
|
|
|
+ } catch (e) {
|
|
|
+ this.$message.error('加载失败')
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onPageChange(val) {
|
|
|
+ this.page = val
|
|
|
+ this.loadList()
|
|
|
+ },
|
|
|
+ formatBps(bps) {
|
|
|
+ return (bps / 100).toFixed(2) + '%'
|
|
|
+ },
|
|
|
+ isEffectived(dateStr) {
|
|
|
+ if (!dateStr) return false
|
|
|
+ return new Date(dateStr) <= new Date()
|
|
|
+ },
|
|
|
+ startEdit(row) {
|
|
|
+ this.editId = row.id
|
|
|
+ this.editPpoint = row.ppoint != null ? row.ppoint : 0
|
|
|
+ },
|
|
|
+ cancelEdit() {
|
|
|
+ this.editId = null
|
|
|
+ this.editPpoint = 0
|
|
|
+ },
|
|
|
+ async saveRow(row) {
|
|
|
+ if (this.editPpoint == null) {
|
|
|
+ return this.$message.warning('请设置P点')
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await saveProductPpoint({ id: row.id, ppoint: this.editPpoint })
|
|
|
+ this.$message.success('保存成功')
|
|
|
+ this.editId = null
|
|
|
+ this.loadList()
|
|
|
+ } catch (e) {
|
|
|
+ this.$message.error('保存失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async deleteRow(row) {
|
|
|
+ try {
|
|
|
+ await this.$confirm('确认删除该配置?', '提示', { type: 'warning' })
|
|
|
+ await deleteProductPpoint({ id: row.id })
|
|
|
+ this.$message.success('删除成功')
|
|
|
+ this.loadList()
|
|
|
+ } catch (e) {
|
|
|
+ if (e !== 'cancel') this.$message.error('删除失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async openAddDialog() {
|
|
|
+ this.addDialogVisible = true
|
|
|
+ this.addForm = { productId: null, ppoint: 0, effectiveDate: '' }
|
|
|
+ try {
|
|
|
+ const res = await getProductList({ status: 'online', keyword: '', productType: '' })
|
|
|
+ this.productOptions = res.data || []
|
|
|
+ } catch (e) {
|
|
|
+ this.productOptions = []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async submitAdd() {
|
|
|
+ if (!this.addForm.productId) return this.$message.warning('请选择商品')
|
|
|
+ if (!this.addForm.ppoint && this.addForm.ppoint !== 0) return this.$message.warning('请设置P点')
|
|
|
+ if (!this.addForm.effectiveDate) return this.$message.warning('请选择生效日期')
|
|
|
+ try {
|
|
|
+ await saveProductPpoint({
|
|
|
+ productId: this.addForm.productId,
|
|
|
+ ppoint: this.addForm.ppoint,
|
|
|
+ effectiveDate: this.addForm.effectiveDate
|
|
|
+ })
|
|
|
+ this.$message.success('添加成功')
|
|
|
+ this.addDialogVisible = false
|
|
|
+ this.loadList()
|
|
|
+ } catch (e) {
|
|
|
+ this.$message.error('添加失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.product-ppoint {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+.header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+.header h2 {
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+.filters {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.product-thumb {
|
|
|
+ width: 50px;
|
|
|
+ height: 50px;
|
|
|
+ object-fit: cover;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+</style>
|