Ver código fonte

卓美:添加公司提现明细,独特需求

yuhongqi 1 semana atrás
pai
commit
7c0a7e98e8

+ 26 - 0
src/api/company/withdrawDetail.js

@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+/** 分公司下拉(关键词模糊) */
+export function listWithdrawDetailCompanyOptions(query) {
+  return request({
+    url: '/company/withdrawDetailAdmin/companyOptions',
+    method: 'get',
+    params: query
+  })
+}
+
+export function listWithdrawDetail(query) {
+  return request({
+    url: '/company/withdrawDetailAdmin/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function exportWithdrawDetail(query) {
+  return request({
+    url: '/company/withdrawDetailAdmin/export',
+    method: 'get',
+    params: query
+  })
+}

+ 8 - 1
src/utils/request.js

@@ -33,7 +33,14 @@ service.interceptors.request.use(config => {
       const value = config.params[propName];
       var part = encodeURIComponent(propName) + "=";
       if (value !== null && typeof(value) !== "undefined") {
-        if (typeof value === 'object') {
+        // 数组:重复键名 companyIds=1&companyIds=2,便于 Spring @RequestParam List 绑定
+        if (Array.isArray(value)) {
+          value.forEach(item => {
+            if (item !== null && typeof item !== 'undefined') {
+              url += encodeURIComponent(propName) + '=' + encodeURIComponent(item) + '&';
+            }
+          });
+        } else if (typeof value === 'object') {
           for (const key of Object.keys(value)) {
             if (value[key] !== null && typeof (value[key]) !== 'undefined') {
               let params = propName + '[' + key + ']';

+ 298 - 0
src/views/company/companyMoneyLogsDetail/index.vue

@@ -0,0 +1,298 @@
+<template>
+  <div class="app-container withdraw-detail">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" class="search-form" label-width="88px">
+      <el-form-item label="分公司" prop="companyIds">
+        <el-select
+          v-model="queryParams.companyIds"
+          multiple
+          collapse-tags
+          filterable
+          remote
+          reserve-keyword
+          clearable
+          placeholder="分公司名称关键词模糊搜索"
+          :remote-method="remoteSearchCompany"
+          :loading="companyLoading"
+          style="width: 320px"
+        >
+          <el-option
+            v-for="item in companyOptions"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId"
+          />
+        </el-select>
+        <el-button type="text" size="small" @click="selectAllCompanies">全选</el-button>
+        <el-button type="text" size="small" @click="invertCompanySelection">反选</el-button>
+      </el-form-item>
+      <el-form-item label="明细类型" prop="detailTypes">
+        <el-select
+          v-model="queryParams.detailTypes"
+          multiple
+          collapse-tags
+          clearable
+          placeholder="全部"
+          style="width: 280px"
+        >
+          <el-option
+            v-for="item in detailTypeOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <p class="hint-text">不选分公司、不选类型时,查询全部公司与全部明细类型;数据自 2026-03-27 起。</p>
+
+    <el-row class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-download"
+          size="small"
+          @click="handleExport"
+          v-hasPermi="['company:companyMoneyLogsDetail:export']"
+        >导出</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table
+      v-loading="loading"
+      :data="tableList"
+      border
+      stripe
+      :header-cell-style="{ textAlign: 'center' }"
+      :cell-style="{ textAlign: 'center' }"
+    >
+      <el-table-column label="序号" width="70" align="center">
+        <template slot-scope="scope">
+          {{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column label="公司名称" prop="companyName" min-width="140" show-overflow-tooltip />
+      <el-table-column label="所属销售" prop="salesName" min-width="100">
+        <template slot-scope="scope">
+          {{ scope.row.salesName || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="订单号" prop="orderCode" min-width="160" show-overflow-tooltip>
+        <template slot-scope="scope">
+          {{ scope.row.orderCode || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="交易单号" prop="tradeNo" min-width="180" show-overflow-tooltip>
+        <template slot-scope="scope">
+          {{ scope.row.tradeNo || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="订单状态" align="center" min-width="100">
+        <template slot-scope="scope">
+          <template v-if="scope.row.orderStatusText != null && scope.row.orderStatusText !== ''">
+            <el-tag
+              v-for="(item, index) in statusOptions"
+              :key="index"
+              v-if="scope.row.orderStatusText == item.dictValue"
+            >{{ item.dictLabel }}</el-tag>
+            <el-tag v-if="!statusOptions.some(i => scope.row.orderStatusText == i.dictValue)">{{ scope.row.orderStatusText || scope.row.orderStatus }}</el-tag>
+          </template>
+          <el-tag v-else>{{ scope.row.orderStatusText || '-' }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="售后状态" prop="afterSalesStatusText" min-width="100">
+        <template slot-scope="scope">
+          {{ scope.row.afterSalesStatusText || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="订单记录时间" prop="recordTime" min-width="170" align="center">
+        <template slot-scope="scope">
+          {{ formatRecordTime(scope.row.recordTime) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="明细类型" prop="detailTypeText" min-width="130" />
+      <el-table-column label="金额" prop="amount" min-width="120" align="right" header-align="center">
+        <template slot-scope="scope">
+          <span :class="amountClass(scope.row.amount)">{{ formatAmount(scope.row.amount) }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listWithdrawDetailCompanyOptions, listWithdrawDetail, exportWithdrawDetail } from '@/api/company/withdrawDetail'
+
+export default {
+  name: 'CompanyWithdrawDetailAdmin',
+  data() {
+    return {
+      loading: true,
+      companyLoading: false,
+      companyOptions: [],
+      tableList: [],
+      total: 0,
+      detailTypeOptions: [
+        { value: 1, label: '订单金额入账' },
+        { value: 2, label: '订单金额扣减' },
+        { value: 3, label: '总公司充值' },
+        { value: 4, label: '总公司扣款' },
+        { value: 5, label: '分公司提现' },
+        { value: 6, label: '总公司驳回' }
+      ],
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyIds: [],
+        detailTypes: []
+      },
+      statusOptions: []
+    }
+  },
+  created() {
+    this.getDicts('store_order_status').then(res => {
+      this.statusOptions = res.data || []
+    })
+    this.remoteSearchCompany('')
+    this.getList()
+  },
+  methods: {
+    remoteSearchCompany(query) {
+      this.companyLoading = true
+      const keyword = query != null ? String(query).trim() : ''
+      listWithdrawDetailCompanyOptions({ keyword }).then(res => {
+        this.companyOptions = res.data || []
+        this.companyLoading = false
+      }).catch(() => {
+        this.companyLoading = false
+      })
+    },
+    selectAllCompanies() {
+      const ids = this.companyOptions.map(o => o.companyId).filter(id => id != null)
+      this.queryParams.companyIds = [...new Set(ids)]
+    },
+    invertCompanySelection() {
+      const ids = this.companyOptions.map(o => o.companyId).filter(id => id != null)
+      const next = new Set(this.queryParams.companyIds || [])
+      ids.forEach(id => {
+        if (next.has(id)) {
+          next.delete(id)
+        } else {
+          next.add(id)
+        }
+      })
+      this.queryParams.companyIds = [...next]
+    },
+    buildListParams() {
+      const p = {
+        pageNum: this.queryParams.pageNum,
+        pageSize: this.queryParams.pageSize
+      }
+      if (this.queryParams.companyIds && this.queryParams.companyIds.length > 0) {
+        p.companyIds = this.queryParams.companyIds
+      }
+      if (this.queryParams.detailTypes && this.queryParams.detailTypes.length > 0) {
+        p.detailTypes = this.queryParams.detailTypes
+      }
+      return p
+    },
+    getList() {
+      this.loading = true
+      listWithdrawDetail(this.buildListParams()).then(response => {
+        this.tableList = response.rows || []
+        this.total = response.total || 0
+        this.loading = false
+      }).catch(() => {
+        this.loading = false
+      })
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        companyIds: [],
+        detailTypes: []
+      }
+      this.remoteSearchCompany('')
+      this.getList()
+    },
+    formatRecordTime(val) {
+      if (!val) return '-'
+      if (typeof val === 'string') {
+        const norm = val.replace('T', ' ').replace(/-/g, '.')
+        if (norm.length >= 19) {
+          return norm.slice(0, 10) + '-' + norm.slice(11, 19)
+        }
+      }
+      return this.parseTime(val, '{y}.{m}.{d}-{h}:{i}:{s}')
+    },
+    formatAmount(val) {
+      if (val == null || val === '') return '-'
+      const n = Number(val)
+      if (Number.isNaN(n)) return String(val)
+      const abs = Math.abs(n).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
+      if (n > 0) return '+' + abs
+      if (n < 0) return '-' + abs
+      return '0.00'
+    },
+    amountClass(val) {
+      if (val == null || val === '') return ''
+      const n = Number(val)
+      if (n < 0) return 'amt-neg'
+      if (n > 0) return 'amt-pos'
+      return ''
+    },
+    handleExport() {
+      this.$confirm('是否按当前条件导出提现明细?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        const p = {}
+        if (this.queryParams.companyIds && this.queryParams.companyIds.length > 0) {
+          p.companyIds = this.queryParams.companyIds
+        }
+        if (this.queryParams.detailTypes && this.queryParams.detailTypes.length > 0) {
+          p.detailTypes = this.queryParams.detailTypes
+        }
+        return exportWithdrawDetail(p)
+      }).then(response => {
+        this.download(response.msg)
+      }).catch(() => {})
+    }
+  }
+}
+</script>
+
+<style scoped>
+.search-form {
+  margin-bottom: 8px;
+}
+.hint-text {
+  color: #909399;
+  font-size: 13px;
+  margin: 0 0 12px 0;
+}
+.withdraw-detail .amt-pos {
+  color: #67c23a;
+}
+.withdraw-detail .amt-neg {
+  color: #f56c6c;
+}
+</style>

+ 18 - 18
src/views/hisStore/components/productAfterSalesOrder.vue

@@ -329,24 +329,24 @@ export default {
           { required: true, message: "退款金额不能为空", trigger: "blur" }
         ],
         // 新增一级原因必填
-        reasonId1: [
-          { required: true, message: "请选择一级原因", trigger: "change" }
-        ],
-        reasonId2: [
-          {
-            validator: (rule, value, callback) => {
-              if (this.form.reasonId1 && !value) {
-                callback(new Error("请选择二级原因"));
-              } else {
-                callback();
-              }
-            },
-            trigger: "change"
-          }
-        ],
-        auditRemark: [
-          { required: true, message: "请输入审核备注", trigger: "blur" }
-        ]
+        // reasonId1: [
+        //   { required: true, message: "请选择一级原因", trigger: "change" }
+        // ],
+        // reasonId2: [
+        //   {
+        //     validator: (rule, value, callback) => {
+        //       if (this.form.reasonId1 && !value) {
+        //         callback(new Error("请选择二级原因"));
+        //       } else {
+        //         callback();
+        //       }
+        //     },
+        //     trigger: "change"
+        //   }
+        // ],
+        // auditRemark: [
+        //   { required: true, message: "请输入审核备注", trigger: "blur" }
+        // ]
       },
       reasonList: [],
       reason2List: []