瀏覽代碼

Merge remote-tracking branch 'origin/master'

cgp 2 周之前
父節點
當前提交
5b8cea3677

+ 39 - 0
src/api/hisStore/productDiscount.js

@@ -0,0 +1,39 @@
+import request from '@/utils/request'
+
+export function listProductDiscount(query) {
+  return request({
+    url: '/store/store/productDiscount/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getProductDiscount(id) {
+  return request({
+    url: '/store/store/productDiscount/' + id,
+    method: 'get'
+  })
+}
+
+export function addProductDiscount(data) {
+  return request({
+    url: '/store/store/productDiscount',
+    method: 'post',
+    data: data
+  })
+}
+
+export function updateProductDiscount(data) {
+  return request({
+    url: '/store/store/productDiscount',
+    method: 'put',
+    data: data
+  })
+}
+
+export function delProductDiscount(id) {
+  return request({
+    url: '/store/store/productDiscount/' + id,
+    method: 'delete'
+  })
+}

+ 39 - 0
src/api/hisStore/productFlashSale.js

@@ -0,0 +1,39 @@
+import request from '@/utils/request'
+
+export function listProductFlashSale(query) {
+  return request({
+    url: '/store/store/productFlashSale/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getProductFlashSale(id) {
+  return request({
+    url: '/store/store/productFlashSale/' + id,
+    method: 'get'
+  })
+}
+
+export function addProductFlashSale(data) {
+  return request({
+    url: '/store/store/productFlashSale',
+    method: 'post',
+    data: data
+  })
+}
+
+export function updateProductFlashSale(data) {
+  return request({
+    url: '/store/store/productFlashSale',
+    method: 'put',
+    data: data
+  })
+}
+
+export function delProductFlashSale(id) {
+  return request({
+    url: '/store/store/productFlashSale/' + id,
+    method: 'delete'
+  })
+}

+ 8 - 1
src/api/hisStore/storeAfterSales.js

@@ -52,7 +52,14 @@ export function exportStoreAfterSales(query) {
   })
 }
 
-
+// 查询售后原因列表
+export function listRefundReason(query) {
+  return request({
+    url: '/store/store/refundReason/list',
+    method: 'get',
+    params: query
+  })
+}
 
 export function cancel(data) {
   return request({

+ 48 - 7
src/views/hisStore/components/productAfterSalesOrder.vue

@@ -24,7 +24,8 @@
             <el-button size="mini"  @click="showOrder">查看订单</el-button>
          </div>
         </div>
-        <div style="margin: 20px 0px">
+
+        <div style="margin: 20px 0px" >
           <span class="font-small">基本信息</span>
         </div>
         <el-descriptions   :column="4" border  >
@@ -213,7 +214,7 @@
             </el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="二级原因" prop="reasonId2">
+        <el-form-item label="二级原因" v-if="form.reasonId1 != null" prop="reasonId2">
           <el-select v-model="form.reasonId2" placeholder="请选择二级原因" style="width: 100%">
             <el-option
               v-for="item in reason2List"
@@ -227,6 +228,7 @@
           <el-input
             type="textarea"
             :rows="3"
+            maxlength="200"
             placeholder="请输入审核备注"
             v-model="form.auditRemark">
           </el-input>
@@ -266,7 +268,7 @@
 </template>
 
 <script>
-import {getStoreAfterSales,cancel,refund,audit1,audit2,updateStoreAfterSales} from "@/api/hisStore/storeAfterSales";
+import {getStoreAfterSales,cancel,refund,audit1,audit2,updateStoreAfterSales,listRefundReason} from "@/api/hisStore/storeAfterSales";
 
 import productOrder from "./productOrder";
 export default {
@@ -309,6 +311,9 @@ export default {
       logs:[],
       form:{
         refundAmount:0,
+        reasonId1: null,
+        reasonId2: null,
+        auditRemark: ''
       },
       rules:{
         status: [
@@ -317,8 +322,9 @@ export default {
         refundAmount: [
           { required: true, message: "退款金额不能为空", trigger: "blur" }
         ],
-      }
-
+      },
+      reasonList: [],
+      reason2List: []
     };
   },
   computed: {
@@ -401,9 +407,44 @@ export default {
 
     },
     handleRefund(){
-        this.audit.open=true;
         this.form.salesId=this.afterSales.id;
         this.form.refundAmount=this.order.payMoney;
+        this.form.reasonId1 = null;
+        this.form.reasonId2 = null;
+        this.form.auditRemark = '';
+        this.reason2List = [];
+        this.audit.open=true;
+        this.getReasonList();
+    },
+    getReasonList() {
+      listRefundReason({ typeLevel: 1 }).then(response => {
+        this.reasonList = response.rows.map(item => {
+          return {
+            ...item,
+            children: []
+          };
+        });
+        this.reasonList.forEach(item => {
+          if (item.childrenCount > 0) {
+            this.getReason2List(item.id, item);
+          }
+        });
+      });
+    },
+    getReason2List(parentId, parent) {
+      listRefundReason({ parentId: parentId, typeLevel: 2 }).then(response => {
+        parent.children = response.rows;
+      });
+    },
+    handleReason1Change(val) {
+        this.form.reasonId2 = null;
+        this.reason2List = [];
+        if (val) {
+          const selected = this.reasonList.find(item => item.id === val);
+          if (selected && selected.children) {
+            this.reason2List = selected.children;
+          }
+        }
     },
     submitAuditForm() {
       this.$refs["form"].validate(valid => {
@@ -441,7 +482,7 @@ export default {
             this.user=response.user;
             this.order=response.order;
         });
-     }
+     },
   }
 };
 </script>

+ 528 - 0
src/views/hisStore/productDiscount/index.vue

@@ -0,0 +1,528 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+      <el-form-item label="商品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option label="上架" :value="1"/>
+          <el-option label="下架" :value="0"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="活动时间" prop="timeRange">
+        <el-date-picker
+          v-model="queryParams.timeRange"
+          type="datetimerange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          size="small"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['store:productDiscount:add']">新增</el-button>
+      </el-col>
+<!--      <el-col :span="1.5">-->
+<!--        <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['store:productDiscount:export']">导出</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="list" border>
+      <el-table-column label="序号" type="index" width="55" align="center" />
+      <el-table-column label="商品信息" align="center" min-width="200">
+        <template slot-scope="scope">
+          <div style="display:flex;align-items:center;">
+            <el-image v-if="scope.row.productImage" style="width:50px;height:50px;margin-right:10px;" :src="scope.row.productImage" fit="contain" :preview-src-list="[scope.row.productImage]"/>
+            <span>{{ scope.row.productName || '-' }}</span>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="原价" align="center" prop="originalPrice" width="100">
+        <template slot-scope="scope">
+          <span v-if="scope.row.originalPrice != null">¥{{ scope.row.originalPrice.toFixed(2) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="折扣" align="center" prop="discount" width="80">
+        <template slot-scope="scope">
+          <span>{{ (scope.row.discount * 10).toFixed(1) }}折</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="折扣价格" align="center" prop="discountPrice" width="110">
+        <template slot-scope="scope">
+          <span style="color:#f56c6c;font-weight:bold;">¥{{ scope.row.discountPrice ? scope.row.discountPrice.toFixed(2) : '0.00' }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="库存" align="center" prop="stock" width="80" />
+      <el-table-column label="开始时间" align="center" prop="startTime" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center" prop="endTime" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="80">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.status === 1" type="success">上架</el-tag>
+          <el-tag v-else type="info">下架</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['store:productDiscount:edit']">编辑</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['store:productDiscount:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+
+    <!-- 添加/编辑限时折扣 - 支持批量选择商品 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-alert
+        v-if="!form.id && selectedProducts.length === 0"
+        title="提示:可批量选择多个商品,统一设置折扣信息后一键添加"
+        type="info"
+        :closable="false"
+        show-icon
+        style="margin-bottom:15px;"
+      />
+
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <!-- 批量选择商品 -->
+        <el-form-item label="选择商品" prop="productIds" v-if="!form.id">
+          <el-select
+            v-model="selectedProducts"
+            multiple
+            filterable
+            remote
+            reserve-keyword
+            placeholder="请输入商品名称搜索,可多选"
+            :remote-method="searchProduct"
+            :loading="productLoading"
+            style="width:100%"
+            collapse-tags
+            collapse-tags-tooltip
+          >
+            <el-option
+              v-for="item in productOptions"
+              :key="item.productId"
+              :label="item.productName"
+              :value="item.productId"
+              :disabled="isProductSelected(item.productId)"
+            >
+              <div style="display:flex;justify-content:space-between;align-items:center;">
+                <span style="float:left">{{ item.productName }}</span>
+                <span style="float:right;color:#8492a6;font-size:12px;margin-left:15px;">ID:{{ item.productId }} | ¥{{ item.price || item.originalPrice || '-' }}</span>
+              </div>
+            </el-option>
+          </el-select>
+          <div style="color:#909399;font-size:12px;margin-top:5px;" v-if="selectedProducts.length > 0">
+            已选择 {{ selectedProducts.length }} 个商品
+          </div>
+        </el-form-item>
+
+        <!-- 编辑模式显示单个商品 -->
+        <el-form-item label="选择商品" prop="productId" v-if="form.id">
+          <el-select
+            v-model="form.productId"
+            filterable
+            remote
+            reserve-keyword
+            placeholder="请输入商品名称搜索"
+            :remote-method="searchProduct"
+            :loading="productLoading"
+            style="width:100%"
+            disabled
+          >
+            <el-option v-for="item in productOptions" :key="item.productId" :label="item.productName" :value="item.productId"/>
+          </el-select>
+        </el-form-item>
+
+        <!-- 公共设置项 -->
+        <el-divider content-position="left">折扣设置(以下设置将应用于所有选中商品)</el-divider>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="原价" prop="originalPrice">
+              <el-input-number v-model="form.originalPrice" :precision="2" :min="0" placeholder="请输入原价" style="width:100%" @change="handleOriginalPriceChange"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="库存" prop="stock">
+              <el-input-number v-model="form.stock" :min="0" placeholder="请输入库存数量" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 折扣滑块:支持小数步长 0.1 -->
+        <el-form-item label="折扣" prop="discount" class="discount-slider-item">
+          <el-slider
+            v-model="form.discountValue"
+            :marks="discountMarks"
+            :min="1"
+            :max="10"
+            :step="0.1"
+            show-input
+            @change="handleDiscountChange"
+          />
+        </el-form-item>
+
+        <el-form-item label="折扣价格" prop="discountPrice">
+          <el-input-number v-model="form.discountPrice" :precision="2" :min="0" placeholder="自动计算或手动输入" style="width:100%" @change="handleDiscountPriceChange"/>
+        </el-form-item>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="开始时间" prop="startTime">
+              <el-date-picker v-model="form.startTime" type="datetime" placeholder="选择开始时间" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="结束时间" prop="endTime">
+              <el-date-picker v-model="form.endTime" type="datetime" placeholder="选择结束时间" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio :label="1">上架</el-radio>
+            <el-radio :label="0">下架</el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" :rows="3"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm" :loading="submitLoading">{{ form.id ? '确 定' : `确 定 (${selectedProducts.length}个商品)` }}</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  addProductDiscount,
+  delProductDiscount,
+  getProductDiscount,
+  listProductDiscount,
+  updateProductDiscount
+} from '@/api/hisStore/productDiscount'
+import { getStoreProduct, listStoreProduct } from '@/api/hisStore/storeProduct'
+
+export default {
+  name: 'ProductDiscount',
+  data() {
+    return {
+      loading: true,
+      showSearch: true,
+      list: [],
+      total: 0,
+      title: '',
+      open: false,
+      submitLoading: false,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        productName: null,
+        status: null,
+        timeRange: null,
+        beginTime: null,
+        endTime: null
+      },
+      form: {},
+      rules: {
+        originalPrice: [{ required: true, message: '请输入原价', trigger: 'blur' }],
+        discount: [{ required: true, message: '请设置折扣', trigger: 'change' }],
+        discountPrice: [{ required: true, message: '请输入折扣价格', trigger: 'blur' }],
+        stock: [{ required: true, message: '请输入库存', trigger: 'blur' }],
+        startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
+        endTime: [{ required: true, message: '请选择结束时间', trigger: 'change' }],
+        status: [{ required: true, message: '请选择状态', trigger: 'change' }]
+      },
+      productLoading: false,
+      productOptions: [],
+      selectedProducts: [],
+      discountMarks: {
+        1: '1折',
+        5: '5折',
+        10: '不打折'
+      }
+    }
+  },
+  watch: {
+    'form.discountValue': {
+      handler(newVal) {
+        if (newVal !== undefined && newVal !== null) {
+          this.form.discount = newVal / 10
+          this.$nextTick(() => {
+            this.calcDiscountPrice()
+          })
+        }
+      },
+      immediate: true
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    getList() {
+      this.loading = true
+      const params = { ...this.queryParams }
+      if (this.queryParams.timeRange && this.queryParams.timeRange.length === 2) {
+        params.beginTime = this.queryParams.timeRange[0]
+        params.endTime = this.queryParams.timeRange[1]
+      }
+      delete params.timeRange
+      listProductDiscount(params).then(response => {
+        this.list = response.rows || []
+        this.total = response.total || 0
+        this.loading = false
+      })
+    },
+
+    searchProduct(query) {
+      if (query !== '') {
+        this.productLoading = true
+        listStoreProduct({ productName: query, isDel: 0, pageSize: 50 }).then(response => {
+          const currentSelected = this.selectedProducts.map(id =>
+            this.productOptions.find(p => p.productId === id)
+          ).filter(Boolean)
+          this.productOptions = [...currentSelected, ...(response.rows || [])]
+          this.productLoading = false
+        })
+      } else {
+        if (this.selectedProducts.length > 0) {
+          this.productOptions = this.selectedProducts.map(id =>
+            this.productOptions.find(p => p.productId === id)
+          ).filter(Boolean)
+        } else {
+          this.productOptions = []
+        }
+      }
+    },
+
+    isProductSelected(productId) {
+      return this.selectedProducts.includes(productId)
+    },
+
+    handleOriginalPriceChange(val) {
+      console.log('原价变化:', val)
+      this.calcDiscountPrice()
+    },
+
+    handleDiscountChange(val) {
+      console.log('折扣滑块变化:', val)
+      this.form.discount = this.form.discountValue / 10
+      this.calcDiscountPrice()
+    },
+
+    handleDiscountPriceChange(val) {
+      console.log('折扣价格变化:', val)
+      if (this.form.originalPrice && this.form.originalPrice > 0 && val >= 0) {
+        const newDiscount = parseFloat((val / this.form.originalPrice).toFixed(4))
+        if (newDiscount >= 0.1 && newDiscount <= 1) {
+          this.form.discountValue = newDiscount * 10
+          this.form.discount = newDiscount
+        }
+      }
+    },
+
+    calcDiscountPrice() {
+      if (this.form.originalPrice && this.form.originalPrice > 0 && this.form.discount !== undefined && this.form.discount !== null) {
+        if (this.form.discount >= 1) {
+          this.form.discountPrice = this.form.originalPrice
+        } else {
+          console.log("折扣价格-------》",parseFloat((this.form.originalPrice * this.form.discount).toFixed(2)))
+          this.form.discountPrice = parseFloat((this.form.originalPrice * this.form.discount).toFixed(2))
+        }
+        console.log('计算结果 - 原价:', this.form.originalPrice, '折扣:', this.form.discount, '价格:', this.form.discountPrice)
+      } else {
+        if (!this.form.originalPrice || this.form.originalPrice <= 0) {
+          this.form.discountPrice = null
+        }
+      }
+    },
+
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+
+    reset() {
+      this.form = {
+        id: null,
+        productId: null,
+        stock: 0,
+        originalPrice: null,
+        discount: 1,
+        discountValue: 10,
+        discountPrice: null,
+        startTime: null,
+        endTime: null,
+        status: 1,
+        remark: null
+      }
+      this.selectedProducts = []
+      this.productOptions = []
+      this.submitLoading = false
+      this.resetForm('form')
+    },
+
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '批量添加限时折扣'
+    },
+
+    handleUpdate(row) {
+      this.reset()
+      getProductDiscount(row.id).then(response => {
+        this.form = response.data
+        if (this.form.discount) {
+          this.form.discountValue = this.form.discount * 10
+        }
+        if (this.form.productId) {
+          getStoreProduct(this.form.productId).then(res => {
+            if (res.data) {
+              this.productOptions = [res.data]
+            }
+          })
+        }
+        this.selectedProducts = [this.form.productId]
+        this.open = true
+        this.title = '编辑限时折扣'
+      })
+    },
+
+    handleDelete(row) {
+      const ids = row.id
+      this.$confirm('是否确认删除限时折扣编号为"' + ids + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        return delProductDiscount(ids)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      }).catch(() => {})
+    },
+
+    handleExport() {
+      this.download('/store/store/productDiscount/export', {
+        ...this.queryParams
+      }, `productDiscount_${new Date().getTime()}.xlsx`)
+    },
+
+    async submitForm() {
+      if (!this.form.id && this.selectedProducts.length === 0) {
+        this.msgError('请至少选择一个商品')
+        return
+      }
+
+      try {
+        await this.$refs['form'].validate()
+
+        this.submitLoading = true
+
+        if (this.form.id) {
+          const submitData = { ...this.form }
+          delete submitData.discountValue
+          delete submitData.productIds
+
+          await updateProductDiscount(submitData)
+          this.msgSuccess('修改成功')
+          this.open = false
+          this.getList()
+        } else {
+          const baseData = { ...this.form }
+          delete baseData.id
+          delete baseData.productId
+          delete baseData.discountValue
+          delete baseData.productIds
+
+          const promises = this.selectedProducts.map(productId => {
+            const productData = {
+              ...baseData,
+              productId: productId
+            }
+            return addProductDiscount(productData)
+          })
+
+          await Promise.all(promises)
+          this.msgSuccess(`成功添加 ${this.selectedProducts.length} 个限时折扣商品`)
+          this.open = false
+          this.getList()
+        }
+
+        this.submitLoading = false
+      } catch (error) {
+        console.error('提交失败:', error)
+        this.submitLoading = false
+        if (error !== 'cancel') {
+          this.msgError(error.message || '操作失败,请重试')
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.discount-slider-item >>> .el-slider {
+  overflow: visible;
+  margin: 0 10px;
+}
+.discount-slider-item >>> .el-slider__marks-text {
+  white-space: nowrap;
+  font-size: 12px;
+  transform: translateX(-50%) scale(0.95);
+  min-width: 40px;
+  text-align: center;
+}
+.discount-slider-item >>> .el-slider__marks {
+  height: 30px;
+}
+
+/* 多选下拉框优化 */
+>>> .el-select .el-tag {
+  max-width: 150px;
+}
+>>> .el-select .el-tag__close {
+  margin-left: 4px;
+}
+</style>

+ 347 - 0
src/views/hisStore/productFlashSale/index.vue

@@ -0,0 +1,347 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+      <el-form-item label="商品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option label="上架" :value="1"/>
+          <el-option label="下架" :value="0"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['store:productFlashSale:add']">新增</el-button>
+      </el-col>
+<!--      <el-col :span="1.5">-->
+<!--        <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['store:productFlashSale:export']">导出</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="list" border>
+      <el-table-column label="序号" type="index" width="55" align="center" />
+      <el-table-column label="商品信息" align="center" min-width="200">
+        <template slot-scope="scope">
+          <div style="display:flex;align-items:center;">
+            <el-image v-if="scope.row.productImage" style="width:50px;height:50px;margin-right:10px;" :src="scope.row.productImage" fit="contain" :preview-src-list="[scope.row.productImage]"/>
+            <span>{{ scope.row.productName || '-' }}</span>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="原价" align="center" prop="originalPrice" width="100">
+        <template slot-scope="scope">
+          <span v-if="scope.row.originalPrice != null">¥{{ scope.row.originalPrice.toFixed(2) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="秒杀价" align="center" prop="flashPrice" width="110">
+        <template slot-scope="scope">
+          <span style="color:#f56c6c;font-weight:bold;">¥{{ scope.row.flashPrice ? scope.row.flashPrice.toFixed(2) : '0.00' }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="库存" align="center" prop="stock" width="80" />
+      <el-table-column label="开始时间" align="center" prop="startTime" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center" prop="endTime" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="80">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.status === 1" type="success">上架</el-tag>
+          <el-tag v-else type="info">下架</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['store:productFlashSale:edit']">编辑</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['store:productFlashSale:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="选择商品" prop="productId" v-if="!form.id">
+          <el-select
+            v-model="form.productId"
+            filterable
+            remote
+            reserve-keyword
+            placeholder="请输入商品名称搜索"
+            :remote-method="searchProduct"
+            :loading="productLoading"
+            style="width:100%"
+          >
+            <el-option
+              v-for="item in productOptions"
+              :key="item.productId"
+              :label="item.productName"
+              :value="item.productId"
+            >
+              <div style="display:flex;justify-content:space-between;align-items:center;">
+                <span style="float:left">{{ item.productName }}</span>
+                <span style="float:right;color:#8492a6;font-size:12px;margin-left:15px;">ID:{{ item.productId }} | ¥{{ item.price || item.originalPrice || '-' }}</span>
+              </div>
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="选择商品" v-if="form.id">
+          <el-select
+            v-model="form.productId"
+            filterable
+            remote
+            reserve-keyword
+            placeholder="请输入商品名称搜索"
+            :remote-method="searchProduct"
+            :loading="productLoading"
+            style="width:100%"
+            disabled
+          >
+            <el-option v-for="item in productOptions" :key="item.productId" :label="item.productName" :value="item.productId"/>
+          </el-select>
+        </el-form-item>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="原价" prop="originalPrice">
+              <el-input-number v-model="form.originalPrice" :precision="2" :min="0" placeholder="请输入原价" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="秒杀价" prop="flashPrice">
+              <el-input-number v-model="form.flashPrice" :precision="2" :min="0" placeholder="请输入秒杀价" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="库存" prop="stock">
+              <el-input-number v-model="form.stock" :min="0" placeholder="请输入库存数量" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="状态" prop="status">
+              <el-radio-group v-model="form.status">
+                <el-radio :label="1">上架</el-radio>
+                <el-radio :label="0">下架</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="开始时间" prop="startTime">
+              <el-date-picker v-model="form.startTime" type="datetime" placeholder="选择开始时间" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="结束时间" prop="endTime">
+              <el-date-picker v-model="form.endTime" type="datetime" placeholder="选择结束时间" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" :rows="3"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm" :loading="submitLoading">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  addProductFlashSale,
+  delProductFlashSale,
+  getProductFlashSale,
+  listProductFlashSale,
+  updateProductFlashSale
+} from '@/api/hisStore/productFlashSale'
+import { getStoreProduct, listStoreProduct } from '@/api/hisStore/storeProduct'
+
+export default {
+  name: 'ProductFlashSale',
+  data() {
+    return {
+      loading: true,
+      showSearch: true,
+      list: [],
+      total: 0,
+      title: '',
+      open: false,
+      submitLoading: false,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        productName: null,
+        status: null
+      },
+      form: {},
+      rules: {
+        productId: [{ required: true, message: '请选择商品', trigger: 'change' }],
+        originalPrice: [{ required: true, message: '请输入原价', trigger: 'blur' }],
+        flashPrice: [{ required: true, message: '请输入秒杀价', trigger: 'blur' }],
+        stock: [{ required: true, message: '请输入库存', trigger: 'blur' }],
+        startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
+        endTime: [{ required: true, message: '请选择结束时间', trigger: 'change' }],
+        status: [{ required: true, message: '请选择状态', trigger: 'change' }]
+      },
+      productLoading: false,
+      productOptions: []
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    getList() {
+      this.loading = true
+      listProductFlashSale(this.queryParams).then(response => {
+        this.list = response.rows || []
+        this.total = response.total || 0
+        this.loading = false
+      })
+    },
+
+    searchProduct(query) {
+      if (query !== '') {
+        this.productLoading = true
+        listStoreProduct({ productName: query, isDel: 0, pageSize: 50 }).then(response => {
+          this.productOptions = response.rows || []
+          this.productLoading = false
+        })
+      } else {
+        this.productOptions = []
+      }
+    },
+
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+
+    reset() {
+      this.form = {
+        id: null,
+        productId: null,
+        originalPrice: null,
+        flashPrice: null,
+        stock: 0,
+        startTime: null,
+        endTime: null,
+        status: 1,
+        remark: null
+      }
+      this.productOptions = []
+      this.submitLoading = false
+      this.resetForm('form')
+    },
+
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '新增秒杀商品'
+    },
+
+    handleUpdate(row) {
+      this.reset()
+      getProductFlashSale(row.id).then(response => {
+        this.form = response.data
+        if (this.form.productId) {
+          getStoreProduct(this.form.productId).then(res => {
+            if (res.data) {
+              this.productOptions = [res.data]
+            }
+          })
+        }
+        this.open = true
+        this.title = '编辑秒杀商品'
+      })
+    },
+
+    handleDelete(row) {
+      const ids = row.id
+      this.$confirm('是否确认删除秒杀商品编号为"' + ids + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        return delProductFlashSale(ids)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      }).catch(() => {})
+    },
+
+    handleExport() {
+      this.download('/store/store/productFlashSale/export', {
+        ...this.queryParams
+      }, `productFlashSale_${new Date().getTime()}.xlsx`)
+    },
+
+    submitForm() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          this.submitLoading = true
+          if (this.form.id) {
+            updateProductFlashSale(this.form).then(() => {
+              this.msgSuccess('修改成功')
+              this.open = false
+              this.getList()
+              this.submitLoading = false
+            }).catch(() => {
+              this.submitLoading = false
+            })
+          } else {
+            addProductFlashSale(this.form).then(() => {
+              this.msgSuccess('新增成功')
+              this.open = false
+              this.getList()
+              this.submitLoading = false
+            }).catch(() => {
+              this.submitLoading = false
+            })
+          }
+        }
+      })
+    }
+  }
+}
+</script>

+ 310 - 137
src/views/hisStore/refundReason/index.vue

@@ -1,141 +1,176 @@
 <template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="一级原因" prop="reasonName">
-        <el-input
-          v-model="queryParams.reasonName"
-          placeholder="请输入一级原因名称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['store:refundReason:add']"
-        >新增一级原因</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
+  <div class="app-container refund-reason-page">
+    <el-card shadow="never" class="refund-reason-page__filter">
+      <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="80px">
+        <el-form-item label="一级原因" prop="reasonName">
+          <el-input
+            v-model="queryParams.reasonName"
+            placeholder="请输入一级原因名称"
+            clearable
+            size="small"
+            style="width: 220px"
+            @keyup.enter.native="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </el-form>
+      <p v-show="showSearch" class="refund-reason-page__hint">
+        <i class="el-icon-info" />
+        点击每行左侧箭头展开查看二级原因;同一时间仅展开一行,便于逐层浏览。
+      </p>
+    </el-card>
 
-    <el-table
-      v-loading="loading"
-      :data="refundReasonList"
-      row-key="id"
-      @expand-change="handleExpandChange"
-    >
-      <el-table-column type="expand">
-        <template slot-scope="props">
-          <el-table
-            :data="props.row.children"
-            style="margin-left: 50px; width: calc(100% - 50px)"
-            v-loading="props.row.loading"
-          >
-            <el-table-column label="序号" type="index" width="80" align="center" />
-            <el-table-column label="二级原因" prop="reasonName" />
-            <el-table-column label="状态" align="center" prop="status" width="100">
-              <template slot-scope="scope">
-                <el-tag v-if="scope.row.status === 1" type="success">正常</el-tag>
-                <el-tag v-else type="danger">禁用</el-tag>
-              </template>
-            </el-table-column>
-            <el-table-column label="操作" align="center" width="200">
-              <template slot-scope="scope">
-                <el-button
-                  size="mini"
-                  type="text"
-                  icon="el-icon-edit"
-                  @click="handleUpdateChild(scope.row, props.row)"
-                  v-hasPermi="['store:refundReason:edit']"
-                >修改</el-button>
-                <el-button
-                  size="mini"
-                  type="text"
-                  icon="el-icon-delete"
-                  @click="handleDeleteChild(scope.row, props.row)"
-                  v-hasPermi="['store:refundReason:remove']"
-                >删除</el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </template>
-      </el-table-column>
-      <el-table-column label="序号" type="index" width="80" align="center" />
-      <el-table-column label="一级原因" prop="reasonName" />
-      <el-table-column label="二级原因数量" align="center" width="120">
-        <template slot-scope="scope">
-          {{ scope.row.childrenCount || 0 }}
-        </template>
-      </el-table-column>
-      <el-table-column label="状态" align="center" prop="status" width="100">
-        <template slot-scope="scope">
-          <el-tag v-if="scope.row.status === 1" type="success">正常</el-tag>
-          <el-tag v-else type="danger">禁用</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="280">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['store:refundReason:edit']"
-          >编辑</el-button>
+    <el-card shadow="never" class="refund-reason-page__table-card">
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
           <el-button
-            size="mini"
-            type="text"
+            type="primary"
+            plain
             icon="el-icon-plus"
-            @click="handleAddChild(scope.row)"
-            v-hasPermi="['store:refundReason:add']"
-          >新增二级原因</el-button>
-          <el-button
             size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['store:refundReason:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
+            @click="handleAdd"
+            v-hasPermi="['store:refundReason:add']"
+          >新增一级原因</el-button>
+        </el-col>
+        <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+      </el-row>
 
-    <pagination
-      v-show="total > 0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
+      <el-table
+        ref="refundReasonTable"
+        v-loading="loading"
+        :data="refundReasonList"
+        row-key="id"
+        :expand-row-keys="expandedRowKeys"
+        border
+        stripe
+        size="small"
+        class="refund-reason-table"
+        :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
+        @expand-change="handleExpandChange"
+      >
+        <el-table-column type="expand" width="46">
+          <template slot-scope="props">
+            <div class="refund-expand-panel">
+              <div class="refund-expand-panel__head">
+                <span class="refund-expand-panel__title">
+                  <i class="el-icon-tickets" />
+                  下属二级原因
+                </span>
+                <span class="refund-expand-panel__parent">「{{ props.row.reasonName }}」</span>
+                <el-tag size="mini" type="info" effect="plain">共 {{ props.row.childrenCount || 0 }} 条</el-tag>
+              </div>
+              <el-table
+                :key="'refund-child-' + props.row.id"
+                class="refund-reason-nested-table"
+                row-key="id"
+                :data="props.row.children"
+                size="mini"
+                border
+                v-loading="props.row.loading"
+                empty-text="暂无二级原因,可在该行操作列点击「新增二级原因」进行维护"
+              >
+                <el-table-column label="序号" type="index" width="56" align="center" />
+                <el-table-column label="二级原因" prop="reasonName" min-width="160" show-overflow-tooltip />
+                <el-table-column label="状态" align="center" prop="status" width="88">
+                  <template slot-scope="scope">
+                    <el-tag v-if="scope.row.status === 1" type="success" size="mini">正常</el-tag>
+                    <el-tag v-else type="danger" size="mini">禁用</el-tag>
+                  </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center" width="168" fixed="right">
+                  <template slot-scope="scope">
+                    <el-button
+                      size="mini"
+                      type="text"
+                      icon="el-icon-edit"
+                      @click="handleUpdateChild(scope.row, props.row)"
+                      v-hasPermi="['store:refundReason:edit']"
+                    >修改</el-button>
+                    <el-button
+                      size="mini"
+                      type="text"
+                      icon="el-icon-delete"
+                      class="refund-text-danger"
+                      @click="handleDeleteChild(scope.row, props.row)"
+                      v-hasPermi="['store:refundReason:remove']"
+                    >删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="序号" type="index" width="60" align="center" />
+        <el-table-column label="一级原因" prop="reasonName" min-width="160" show-overflow-tooltip />
+        <el-table-column label="二级原因数量" align="center" width="110">
+          <template slot-scope="scope">
+            <el-tag size="mini" type="info" effect="plain">{{ scope.row.childrenCount || 0 }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="状态" align="center" prop="status" width="88">
+          <template slot-scope="scope">
+            <el-tag v-if="scope.row.status === 1" type="success" size="small">正常</el-tag>
+            <el-tag v-else type="danger" size="small">禁用</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="280">
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-edit"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['store:refundReason:edit']"
+            >编辑</el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-plus"
+              @click="handleAddChild(scope.row)"
+              v-hasPermi="['store:refundReason:add']"
+            >新增二级原因</el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              class="refund-text-danger"
+              @click="handleDelete(scope.row)"
+              v-hasPermi="['store:refundReason:remove']"
+            >删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
 
-    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body custom-class="refund-reason-dialog">
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px" class="refund-reason-form">
         <el-form-item label="原因名称" prop="reasonName">
-          <el-input v-model="form.reasonName" placeholder="请输入原因名称" />
+          <el-input v-model="form.reasonName" placeholder="请输入原因名称" maxlength="100" show-word-limit />
         </el-form-item>
         <el-form-item label="状态" prop="status">
-          <el-select v-model="form.status" placeholder="请选择状态">
+          <el-select v-model="form.status" placeholder="请选择状态" style="width: 100%">
             <el-option label="正常" :value="1" />
             <el-option label="禁用" :value="0" />
           </el-select>
         </el-form-item>
         <el-form-item label="二级原因" v-if="form.typeLevel === 1 && form.id == null">
-          <el-button type="primary" size="mini" @click="addChildReason">添加二级原因</el-button>
-          <div v-for="(item, index) in form.childrenReasons" :key="index" style="margin-top: 10px;">
-            <el-input v-model="item.reasonName" placeholder="请输入二级原因名称" style="width: 400px;" />
-            <el-button type="danger" size="mini" @click="removeChildReason(index)" style="margin-left: 10px;">删除</el-button>
+          <div class="refund-dialog-children">
+            <el-button type="primary" size="mini" icon="el-icon-plus" @click="addChildReason">添加二级原因</el-button>
+            <div v-for="(item, index) in form.childrenReasons" :key="index" class="refund-dialog-children__row">
+              <el-input v-model="item.reasonName" placeholder="请输入二级原因名称" />
+              <el-button type="danger" size="mini" icon="el-icon-delete" @click="removeChildReason(index)">删除</el-button>
+            </div>
           </div>
         </el-form-item>
       </el-form>
@@ -167,6 +202,7 @@ export default {
         typeLevel: 1
       },
       form: {},
+      expandedRowKeys: [],
       rules: {
         reasonName: [
           { required: true, message: "原因名称不能为空", trigger: "blur" }
@@ -181,7 +217,14 @@ export default {
     this.getList();
   },
   methods: {
-    getList() {
+    normalizeGetListArg(arg) {
+      if (arg != null && typeof arg === "object") {
+        return null;
+      }
+      return arg != null ? arg : null;
+    },
+    getList(arg) {
+      const syncChildrenParentId = this.normalizeGetListArg(arg);
       this.loading = true;
       listRefundReason(this.queryParams).then(response => {
         this.refundReasonList = response.rows.map(item => {
@@ -193,16 +236,43 @@ export default {
         });
         this.total = response.total;
         this.loading = false;
+        if (syncChildrenParentId != null) {
+          const r = this.refundReasonList.find(x => x.id == syncChildrenParentId);
+          this.expandedRowKeys = r ? [r.id] : [];
+          this.$nextTick(() => {
+            this.reloadRowChildren(syncChildrenParentId);
+          });
+        } else {
+          this.expandedRowKeys = [];
+        }
       });
     },
-    handleExpandChange(row, expandedRows) {
-      if (expandedRows.find(item => item.id === row.id)) {
-        row.loading = true;
-        getChildrenByParentId(row.id).then(response => {
-          row.children = response.data;
-          row.childrenCount = response.data.length;
+    reloadRowChildren(parentId) {
+      const row = this.refundReasonList.find(r => r.id == parentId);
+      if (!row) {
+        return;
+      }
+      row.loading = true;
+      getChildrenByParentId(parentId)
+        .then(response => {
+          const list = response.data || [];
+          row.children = list;
+          row.childrenCount = list.length;
+        })
+        .finally(() => {
           row.loading = false;
         });
+    },
+    handleExpandChange(row, expandedRows) {
+      const isExpanded = expandedRows.some(r => r.id == row.id);
+      if (isExpanded) {
+        this.expandedRowKeys = [row.id];
+        this.reloadRowChildren(row.id);
+      } else {
+        this.expandedRowKeys = [];
+        this.$nextTick(() => {
+          row.children = [];
+        });
       }
     },
     cancel() {
@@ -273,7 +343,8 @@ export default {
             updateRefundReason(this.form).then(response => {
               this.msgSuccess("修改成功");
               this.open = false;
-              this.getList();
+              const syncId = this.form.typeLevel === 2 ? this.form.parentId : this.form.id;
+              this.getList(syncId);
             });
           } else {
             addRefundReason(this.form).then(response => {
@@ -293,7 +364,7 @@ export default {
                   Promise.all(promises).then(() => {
                     this.msgSuccess("新增成功");
                     this.open = false;
-                    this.getList();
+                    this.getList(parentId);
                   });
                 } else {
                   this.msgSuccess("新增成功");
@@ -303,7 +374,8 @@ export default {
               } else {
                 this.msgSuccess("新增成功");
                 this.open = false;
-                this.getList();
+                const syncId = this.form.typeLevel === 2 ? this.form.parentId : null;
+                this.getList(syncId);
               }
             });
           }
@@ -330,13 +402,114 @@ export default {
       }).then(() => {
         return delRefundReason(row.id);
       }).then(() => {
-        getChildrenByParentId(parent.id).then(response => {
-          parent.children = response.data;
-          parent.childrenCount = response.data.length;
-        });
+        this.reloadRowChildren(parent.id);
         this.msgSuccess("删除成功");
       }).catch(() => {});
     }
   }
 };
 </script>
+
+<style scoped>
+.refund-reason-page__filter {
+  margin-bottom: 12px;
+}
+
+.refund-reason-page__filter >>> .el-card__body {
+  padding-bottom: 8px;
+}
+
+.refund-reason-page__hint {
+  margin: 0 0 4px;
+  padding: 8px 12px;
+  font-size: 12px;
+  line-height: 1.5;
+  color: #909399;
+  background: #f4f8ff;
+  border-radius: 4px;
+  border: 1px solid #d9ecff;
+}
+
+.refund-reason-page__hint .el-icon-info {
+  margin-right: 6px;
+  color: #409eff;
+}
+
+.refund-reason-page__table-card >>> .el-card__body {
+  padding-top: 16px;
+}
+
+.refund-reason-table >>> .el-table__expanded-cell {
+  padding: 0;
+  background: transparent;
+}
+
+.refund-expand-panel {
+  padding: 14px 16px 16px 20px;
+  margin: 4px 12px 12px 8px;
+  background: linear-gradient(180deg, #f8fafc 0%, #f0f4f8 100%);
+  border-radius: 6px;
+  border: 1px solid #e4e7ed;
+  border-left: 3px solid #409eff;
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
+}
+
+.refund-expand-panel__head {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 12px;
+}
+
+.refund-expand-panel__title {
+  font-size: 13px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.refund-expand-panel__title .el-icon-tickets {
+  margin-right: 6px;
+  color: #409eff;
+}
+
+.refund-expand-panel__parent {
+  font-size: 12px;
+  color: #606266;
+}
+
+.refund-reason-nested-table {
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+/* 避免展开行内嵌套表格误渲染展开列,出现「多一个小箭头」 */
+.refund-reason-nested-table >>> .el-table__expand-column {
+  display: none !important;
+  width: 0 !important;
+  min-width: 0 !important;
+}
+
+.refund-text-danger {
+  color: #f56c6c !important;
+}
+
+.refund-dialog-children__row {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-top: 10px;
+}
+
+.refund-dialog-children__row .el-input {
+  flex: 1;
+  max-width: 400px;
+}
+</style>
+
+<style>
+.refund-reason-dialog .el-dialog__body {
+  padding-top: 10px;
+  padding-bottom: 8px;
+}
+</style>

+ 1 - 4
src/views/hisStore/storeAfterSales/index.vue

@@ -188,9 +188,6 @@
               <div prop="serviceType" v-for="(item, index) in serviceTypeOptions"    v-if="scope.row.serviceType==item.dictValue">{{item.dictLabel}}</div>
           </template>
       </el-table-column>
-      <el-table-column label="售后原因一级" align="center" prop="reasonValue1" />
-      <el-table-column label="售后原因二级" align="center" prop="reasonValue2" />
-      <el-table-column label="售后备注" align="center" prop="auditRemark" />
       <el-table-column label="申请原因" align="center" prop="reasons" />
       <el-table-column label="说明" align="center" prop="explains" />
       <el-table-column label="状态" align="center" prop="status" >
@@ -200,7 +197,7 @@
       </el-table-column>
       <el-table-column label="售后状态" align="center" prop="salesStatus" >
           <template slot-scope="scope">
-              <div prop="status" v-for="(item, index) in salesStatusOptions"    v-if="scope.row.salesStatus==item.dictValue">{{item.dictLabel}}</div>
+              <div prop="status" v-for="(item, index) in  salesStatusOptions"    v-if="scope.row.salesStatus==item.dictValue">{{item.dictLabel}}</div>
           </template>
       </el-table-column>
       <el-table-column label="订单状态" align="center" prop="orderStatus" >

+ 2 - 2
src/views/hisStore/storeProduct/index.vue

@@ -47,7 +47,7 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="所属店铺" v-if="this.isStores">
+      <el-form-item label="" v-if="this.isStores">
         <el-select style="width: 240px" v-model="queryParams.storeIds" placeholder="请选择店铺" clearable size="small" >
           <el-option
             v-for="item in storeOptions"
@@ -890,7 +890,7 @@
             />
           </el-select>
         </el-form-item>
-        <el-form-item label="所属店铺" prop="storeId" v-if="this.isStores">
+        <el-form-item label="所属店铺" v-if="this.isStores">
           <el-select style="width: 240px" v-model="form.storeId" placeholder="请选择店铺" clearable size="small" >
             <el-option
               v-for="item in storeOptions"