Browse Source

管理后台页面

zuypeng 1 year ago
parent
commit
243273cf31

+ 0 - 490
admin-web/src/views/admin/activity/coupon/dialog.vue

@@ -1,490 +0,0 @@
-<style scoped lang="scss">
-
-</style>
-<template>
-  <div class="system-dialog-container">
-    <el-dialog
-        :title="state.dialog.title"
-        v-model="state.dialog.isShowDialog"
-        width="820px"
-        draggable
-        destroy-on-close
-        :close-on-click-modal="false"
-        @close="onClose"
-        align-center>
-      <el-form
-          inline
-          :model="state.ruleForm"
-          :rules="state.rules"
-          ref="formRef"
-          size="default"
-          label-width="150px"
-          class="mt5">
-
-        <div class="sub-group-bottom"> 基本信息</div>
-        <el-form-item label="活动名称" prop="name" class="w100">
-          <el-input
-              v-model.trim="state.ruleForm.name"
-              placeholder="活动名称"
-              clearable
-              class="w100">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="活动描述" prop="remark" class="w100">
-          <el-input
-              maxlength="500"
-              show-word-limit
-              type="textarea"
-              :rows="3"
-              v-model.trim="state.ruleForm.activityDesc"
-              placeholder="活动描述"
-              clearable
-              class="w100">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="开始时间" prop="startTime">
-          <ext-date-picker
-              v-model.trim="state.ruleForm.startTime"
-              placeholder="开始时间"
-              type="datetime"
-              clearable
-              class="wd200">
-          </ext-date-picker>
-        </el-form-item>
-        <el-form-item label="结束时间" prop="endTime">
-          <ext-date-picker
-              v-model.trim="state.ruleForm.endTime"
-              placeholder="结束时间"
-              type="datetime"
-              clearable
-              class="wd200">
-          </ext-date-picker>
-        </el-form-item>
-<!--        RechargeRights  "Coupon"-->
-        <el-form-item label="优惠方式" prop="discountType">
-          <ext-d-select
-              v-model="state.ruleForm.discountType"
-              placeholder="优惠方式"
-              type="Activity.discountType"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-        </el-form-item>
-        <el-form-item label="目标用户" prop="targetUsers" v-if="state.ruleForm.discountType==='RechargeRights'">
-          <ext-d-select
-              v-model="state.ruleForm.targetUsers"
-              placeholder="目标用户"
-              type="Activity.targetUsers"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-        </el-form-item>
-
-<!--        <el-form-item label="优惠允许叠加" prop="allowStacke">-->
-<!--          <ext-d-select-->
-<!--              v-model="state.ruleForm.allowStacke"-->
-<!--              placeholder="优惠允许叠加"-->
-<!--              type="Activity.allowStacke"-->
-<!--              clearable-->
-<!--              class="wd200 ">-->
-<!--          </ext-d-select>-->
-<!--        </el-form-item> -->
-<!--        <el-form-item label="数量限制" prop="quantity">-->
-<!--          <el-input-->
-<!--              type="number"-->
-<!--              v-model.trim="state.ruleForm.quantity"-->
-<!--              placeholder="数量限制"-->
-<!--              clearable-->
-<!--              class="wd200">-->
-<!--          </el-input>-->
-<!--        </el-form-item>-->
-        <!--        <el-form-item label="活动状态" prop="status">
-                  <ext-d-select
-                      v-model="state.ruleForm.status"
-                      placeholder="活动状态"
-                      type="Activity.status"
-                      clearable
-                      class="wd200 ">
-                  </ext-d-select>
-                </el-form-item>-->
-        <el-form-item label="备注" prop="remark" class="w100">
-          <el-input
-              maxlength="500"
-              show-word-limit
-              type="textarea"
-              :rows="3"
-              v-model.trim="state.ruleForm.remark"
-              placeholder="备注信息"
-              clearable
-              class="w100">
-          </el-input>
-        </el-form-item>
-
-        <div class="sub-group-bottom"> 关联站点</div>
-<!--        <el-divider content-position="left">关联站点</el-divider>-->
-        <el-form-item label="适用站点" prop="applyStation">
-          <ext-d-select
-              @on-change="handleStationChange"
-              v-model="state.ruleForm.applyStation"
-              placeholder="适用站点"
-              type="Activity.applyStation"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-
-          <ext-select
-              v-model="state.ruleForm.stationIds"
-              multiple
-              placeholder="关联站点"
-              url="station/listStation"
-              url-method="get"
-              label-key="stationName"
-              value-key="stationId"
-              data-key=""
-              clearable
-              class="w100 mt5">
-          </ext-select>
-        </el-form-item>
-
-        <div class="sub-group-bottom"> 关联权益</div>
-<!--        <el-divider content-position="left">关联权益</el-divider>-->
-        <el-button size="small" plain type="success" class="ml10" @click="handleAddRightsItem">
-          <SvgIcon name="ele-FolderAdd"/>
-          新增权益
-        </el-button>
-
-<!--        服务费折扣权益 -->
-        <template v-if="state.ruleForm.discountType==='RechargeRights'">
-          <el-card v-for="(rights,idx) in state.ruleForm.rechargeRightsList" :key="idx" class="mt10" shadow="hover">
-            <template #header>
-              <div class="card-header">
-                <el-button class="button" plain type="danger" size="small" v-auth="'activity.modify'" @click="handleRemoveRightsItem(idx)">删除</el-button>
-              </div>
-            </template>
-
-            <el-form-item label="权益描述" prop="rightsDesc" class="w100">
-              <el-input
-                  maxlength="500"
-                  show-word-limit
-                  type="textarea"
-                  :rows="2"
-                  v-model.trim="rights.rightsDesc"
-                  placeholder="权益描述"
-                  clearable
-                  class="w100">
-              </el-input>
-            </el-form-item>
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="最小充值金额(元)" prop="amountMin">
-                  <ext-input-number  class="wd200"  v-model="rights.amountMin" :ratio="100"  placeholder="最小充值金额"></ext-input-number>
-<!--                  <el-input-number
-                      controls-position="right"
-                      v-model.trim="rights.amountMin"
-                      placeholder="最小充值金额"
-                      clearable
-                      :min="0"
-                      class="wd200">
-                  </el-input-number>-->
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="最大充值金额(元)" prop="amountMin">
-                  <ext-input-number  class="wd200"  v-model="rights.amountMax" :ratio="100"  placeholder="最大充值金额"></ext-input-number>
-<!--                  <el-input-number
-                      controls-position="right"
-                      v-model.trim="rights.amountMax"
-                      placeholder="最大充值金额"
-                      clearable
-                      :min="0"
-                      class="wd200">
-                  </el-input-number>-->
-                </el-form-item>
-
-              </el-col>
-            </el-row>
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="折扣" prop="discount">
-                  <el-input-number
-                      :controls="false"
-                      v-model.trim="rights.discount"
-                      placeholder="折扣:100代表无折扣,75代表75折"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="有效期(天)" prop="validity">
-                  <el-input-number
-                      :min="1"
-                      :controls="false"
-                      v-model.trim="rights.validity"
-                      placeholder="有效天数"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-          </el-card>
-        </template>
-
-<!--        优惠券-->
-        <template v-else>
-          <el-card v-for="(coupon,idx) in state.ruleForm.couponList" :key="idx" class="mt10" shadow="hover">
-            <template #header>
-              <div class="card-header">
-                <el-button class="button" plain type="danger" size="small" v-auth="'activity.modify'" @click="handleRemoveCouponItem(idx)">删除</el-button>
-              </div>
-            </template>
-
-
-
-              <el-form-item label="权益描述" prop="rightsDesc" class="w100">
-                <el-input
-                    maxlength="500"
-                    show-word-limit
-                    type="textarea"
-                    :rows="2"
-                    v-model.trim="coupon.couponDesc"
-                    placeholder="权益描述"
-                    clearable
-                    class="w100">
-                </el-input>
-              </el-form-item>
-
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="折扣类型" prop="couponType">
-                  <ext-d-select
-                      @on-change="handleStationChange"
-                      v-model="coupon.couponType"
-                      placeholder="折扣类型"
-                      type="Activity.couponType"
-                      clearable
-                      class="wd200 ">
-                  </ext-d-select>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="有效期(天)" prop="validity">
-                  <el-input-number
-                      :min="1"
-                      :controls="false"
-                      v-model.trim="coupon.validity"
-                      placeholder="有效天数"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-
-            <el-row :gutter="20">
-                <el-col :span="12">
-                  <el-form-item label="服务费门槛(元)" prop="minServiceMoney">
-                    <ext-input-number   class="wd200 "  v-model="coupon.minServiceMoney" :ratio="100"  placeholder="服务费门槛"></ext-input-number>
-                  </el-form-item>
-                </el-col>
-                <el-col :span="12">
-                  <el-form-item label="折扣" prop="discount">
-                    <el-input-number
-                        :controls="false"
-                        v-model.trim="coupon.discount"
-                        placeholder="折扣:100代表无折扣,75代表75折;折扣金额(分)"
-                        clearable
-                        class="wd200">
-                    </el-input-number>
-                  </el-form-item>
-                </el-col>
-              </el-row>
-
-
-
-          </el-card>
-        </template>
-
-
-      </el-form>
-
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button @click="onCancel" size="default">取 消</el-button>
-          <el-button v-if="state.action==='add'||state.action==='edit'" :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup lang="ts" name="ActivityDialog">
-import {reactive, ref} from 'vue';
-import {Msg} from "/@/utils/message";
-import {$body, $get} from "/@/utils/request";
-import u from '/@/utils/u'
-import ExtDatePicker from "/@/components/form/ExtDatePicker.vue";
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtSelect from "/@/components/form/ExtSelect.vue";
-import ExtInputNumber from "/@/components/form/ExtInputNumber.vue";
-
-// 定义子组件向父组件传值/事件
-const emit = defineEmits(['refresh']);
-const formRef = ref();
-//定义初始变量,重置使用
-const initState = () => ({
-  action: '',
-  ruleForm: {
-    id: 0,
-    rechargeRightsList: [] as Array<any>,
-    couponList: [] as Array<any>,
-  },
-  btnLoading: false,
-  dialog: {
-    isShowDialog: false,
-    type: '',
-    title: '',
-    submitTxt: '',
-  },
-  rules: {
-    name: [u.validator.required],
-    startTime: [u.validator.required],
-    endTime: [u.validator.required],
-    discountType: [u.validator.required],
-    targetUsers: [u.validator.required],
-    applyStation: [u.validator.required],
-    allowStacke: [u.validator.required],
-    quantity: [u.validator.required],
-    status: [u.validator.required],
-  },
-})
-
-// 定义变量内容
-const state = reactive(initState());
-
-
-// 打开弹窗
-const open = (action: string = 'add', row: any) => {
-  state.dialog.title = u.dialog.actions[action].title + "『活动』"
-  state.dialog.submitTxt = u.dialog.actions[action].btn + "『活动』"
-  state.dialog.isShowDialog = true;
-  state.action = action;
-  if (action !== 'add') {
-    loadData(row.id);
-  } else {
-    state.ruleForm = Object.assign(state.ruleForm, row);
-  }
-};
-// 关闭弹窗
-const onClose = () => {
-  state.dialog.isShowDialog = false;
-  Object.assign(state, initState())
-};
-// 取消
-const onCancel = () => {
-  onClose();
-};
-// 提交
-const onSubmit = () => {
-  let rechargeRightsList = state.ruleForm.rechargeRightsList;
-  if (!u.isEmptyOrNull(rechargeRightsList)) {
-    for (let i = 0; i < rechargeRightsList.length; i++) {
-      const item: any = rechargeRightsList[i];
-      if (item.amountMax <=0) {
-        Msg.message(`权益最大充值金额不能小于0`, 'error')
-        return false;
-      }
-
-      if (item.amountMin > item.amountMax) {
-        Msg.message(`权益最小充值金额不能大于最大充值金额`, 'error')
-        return false;
-      }
-    }
-
-/*    state.ruleForm.rechargeRightsList.forEach((rights: any) => {
-      rights.amountMin = rights.amountMin * 100;
-      rights.amountMax = rights.amountMax * 100;
-    })*/
-  }
-
-  formRef.value.validate((valid: boolean) => {
-    if (valid) {
-      state.btnLoading = true;
-      const url = state.ruleForm.id > 0 ? "activity/modify" : "activity/add"
-      $body(url, state.ruleForm).then(() => {
-        state.btnLoading = false;
-        Msg.message('操作成功');
-        console.log('submit!')
-        onClose();
-        emit('refresh');
-      })
-    }
-  }).catch(() => {
-    state.btnLoading = false;
-    Msg.message('请先完整填写表单', 'error');
-  })
-};
-
-const handleFormChange = (formData: any) => {
-  console.log(formData)
-}
-
-// 初始化表格数据
-const loadData = (id: number) => {
-  $get(`activity/${id}`).then((res: any) => {
-    if (res && res.rechargeRightsList) {
-/*      res.rechargeRightsList.forEach((rights: any) => {
-        rights.amountMin = rights.amountMin / 100;
-        rights.amountMax = rights.amountMax / 100;
-      })*/
-    }
-    state.ruleForm = res;
-    state.ruleForm.rechargeRightsList = res.rechargeRightsList || []
-  })
-}
-
-const handleStationChange = (applyStation: number) => {
-  console.log(applyStation)
-  if (applyStation == 0) {
-    // state.ruleForm.stationIds = [];
-  }
-
-}
-
-const handleAddRightsItem = () => {
-  if(state.ruleForm.discountType==='RechargeRights'){
-    state.ruleForm.rechargeRightsList.unshift({
-      rightsDesc: '',
-      amountMin: 0,
-      amountMax: 0,
-      validity: 1
-    })
-  }else if(state.ruleForm.discountType==='Coupon'){
-    state.ruleForm.couponList.unshift({
-      couponDesc: '',
-      couponType: 'Discount',
-      minServiceMoney: 0,
-      validity: 1
-    })
-  }
-
-}
-
-const handleRemoveRightsItem = (idx: number) => {
-  state.ruleForm.rechargeRightsList.splice(idx, 1)
-}
-const handleRemoveCouponItem = (idx: number) => {
-  state.ruleForm.couponList.splice(idx, 1)
-}
-
-// 暴露变量
-defineExpose({
-  open
-});
-
-
-</script>

+ 0 - 328
admin-web/src/views/admin/activity/coupon/index.vue

@@ -1,328 +0,0 @@
-<style scoped lang="scss">
-.system-container {
-
-  :deep(.el-card__body) {
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-    flex: 1;
-    overflow: auto;
-
-    .el-table {
-      flex: 1;
-    }
-
-  }
-}
-
-.page-content {
-  margin-bottom: 20px;
-}
-
-.page-pager {
-  background-color: #fff;
-  height: 24px;
-}
-</style>
-<template>
-  <div class="system-container layout-padding">
-    <el-card shadow="hover" class="layout-padding-auto">
-
-
-      <el-form
-          :model="state.formQuery"
-          ref="queryRef"
-          size="default" label-width="0px" class="mt5 mb5">
-        <el-input
-            v-model="state.formQuery.name"
-            placeholder="优惠券名称"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-<!--        <ext-date-picker
-            v-model="state.formQuery.startTime"
-            placeholder="开始时间"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-date-picker>
-        <ext-date-picker
-            v-model="state.formQuery.endTime"
-            placeholder="结束时间"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-date-picker>-->
-        <ext-d-select
-            v-model="state.formQuery.couponType"
-            placeholder="券种"
-            type="Activity.couponType"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-
-
-        <el-button class="ml10" plain size="default" type="success" @click="loadData(true)">
-          <SvgIcon name="ele-Search"/>
-          查询
-        </el-button>
-      </el-form>
-
-      <el-table
-          border
-          stripe="stripe"
-          :height="state.tableData.height"
-          highlight-current-row
-          current-row-key="id"
-          row-key="id"
-          :data="state.tableData.data"
-          v-loading="state.tableData.loading"
-          @row-dblclick="onRowClick('view',$event)"
-          @selection-change="handleTableSelectionChange"
-          @sort-change="handleTableSortChange">
-        <template #empty>
-          <el-empty></el-empty>
-        </template>
-        <el-table-column
-            v-for="field in state.tableData.columns"
-            :key="field.prop"
-            :label="field.label"
-            :column-key="field.prop"
-            :width="field.width"
-            :min-width="field.minWidth"
-            :fixed="field.fixed"
-            :sortable="field.sortable"
-            :show-overflow-tooltip="!field.fixed&&field.width>150"
-        >
-          <template #default="{row}">
-            <template v-if="field.prop==='expand'">
-              <p style="padding-left: 2em;" v-html="row[field.prop]"></p>
-            </template>
-            <template v-else-if="field.prop==='period'">
-              {{ row.startTime }} ~ {{ row.endTime }}
-            </template>
-            <template v-else-if="field.prop==='couponType'">
-              <ext-d-label type="Activity.couponType" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='status'">
-              <ext-d-label type="Coupon.status" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='minServiceMoney'">
-              {{u.fmt.fmtMoney(row.minServiceMoney)}}
-            </template>
-            <template v-else-if="field.prop==='allowStacke'">
-              {{row.allowStacke?'是':'否'}}
-            </template>
-            <template v-else-if="field.prop==='action'">
-<!--              <el-button v-auth="'coupon.list'" size="small" plain type="success" @click="onRowClick('view',row)">查看</el-button>-->
-              <el-button v-show="row.receiveType==='Release'" v-auth="'coupon.modify'"  size="small" plain type="danger" @click="onCouponDispatch(row)">发券</el-button>
-            </template>
-            <template v-else>
-              <div>{{ row[field.prop] }}</div>
-            </template>
-
-          </template>
-        </el-table-column>
-      </el-table>
-
-      <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
-    </el-card>
-  </div>
-  <ActivityDialog ref="activityDialogRef" @refresh="loadData(true)"/>
-  <ExtSContainer ref="userSelectDialogRef"></ExtSContainer>
-  <AccountMobileUpload ref="accountMobileUploadDialogRef" @on-import-finish="handleImportAccountPhone"></AccountMobileUpload>
-</template>
-
-<script setup lang="ts" name="ActivityList">
-import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance, nextTick, onBeforeUnmount} from 'vue';
-import {$body, $get} from "/@/utils/request";
-import {Msg} from "/@/utils/message";
-
-
-import ExtPage from '/@/components/form/ExtPage.vue'
-
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtDatePicker from "/@/components/form/ExtDatePicker.vue";
-import ExtDLabel from "/@/components/form/ExtDLabel.vue";
-import u from "/@/utils/u";
-
-const ActivityDialog = defineAsyncComponent(() => import("/@/views/admin/activity/coupon/dialog.vue"));
-const ExtSContainer = defineAsyncComponent(() => import('/@/components/form/ExtSContainer.vue'));
-const AccountMobileUpload = defineAsyncComponent(() => import('./upload.vue'));
-
-//定义引用
-const queryRef = ref();
-const activityDialogRef = ref();
-const userSelectDialogRef = ref();
-const accountMobileUploadDialogRef = ref();
-
-//定义变量
-const state = reactive({
-  formQuery: {
-    discountType:'Coupon'
-  },
-  pageQuery: {
-    pageNum: 1,
-    pageSize: 10,
-    total: 0
-  },
-  tableData: {
-    height: 500,
-    data: [] as Array<any>,
-    loading: false,
-    columns: [
-      {
-        label: '优惠券名称', prop: 'name', resizable: true, width: 170, fixed: 'left'
-      },
-      {label: '状态', prop: 'status', resizable: true, width: 80},
-      {label: '券种', prop: 'couponType', resizable: true, width: 80},
-      {label: '活动时间', prop: 'period', resizable: true, width: 350},
-      {label: '优惠券描述', prop: 'couponDesc', align: 'center', width: 200},
-      {label: '服务费门槛(元)', prop: 'minServiceMoney', resizable: true, width: 180},
-      {label: '折扣', prop: 'discount', resizable: true, width: 130},
-      {label: '已领取/发放数量', prop: 'claimedQuantity', resizable: true, width: 140},
-      // {label: '优惠允许叠加', prop: 'allowStacke', resizable: true, width: 130},
-      // {label: '数量限制', prop: 'quantity', resizable: true, width: 130},
-      {label: '创建时间', prop: 'createTime', resizable: true, width: 180},
-      {label: '更新时间', prop: 'updateTime', resizable: true, width: 180},
-      {
-        label: '操作', prop: 'action', width: 100, align: 'center', fixed: 'right',
-      }
-    ],
-  },
-  handleCoupon:null
-})
-
-
-// 监听双向绑定 modelValue 的变化
-// watch(
-//         () => state.pageNum,
-//         () => {
-//
-//         }
-// );
-
-//生命周期钩子
-onBeforeMount(() => {
-})
-
-onMounted(() => {
-  loadData();
-
-  nextTick(() => {
-    let bodyHeight = document.body.clientHeight;
-    let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 320
-  })
-
-});
-
-onBeforeUnmount(() => {
-})
-
-
-//region 方法区
-// 初始化表格数据
-const loadData = (refresh: boolean = false) => {
-  if (refresh) {
-    state.pageQuery.pageNum = 1;
-  }
-  state.tableData.loading = true;
-  $get(`/coupon/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let {list, total} = res;
-    state.tableData.data = list;
-    state.pageQuery.total = total;
-    state.tableData.loading = false;
-  }).catch(e => {
-    console.error(e)
-    state.tableData.loading = false;
-  })
-};
-
-const handleRowClick = (event) => {
-  console.log(event)
-  activityDialogRef.value.open("view", event);
-};
-
-const onRowClick = (type: string, row: any) => {
-  activityDialogRef.value.open(type, row);
-};
-
-const onCouponDispatch = (row: any) => {
-  state.handleCoupon = row;
-  Msg.confirm(`请选择发券方式`,'操作',{'ok':'选择用户发放','cancel':'导入号码发放'},'').then(() => {
-    //选择用户
-    let config ={
-      columns:[
-        {label: '手机号', query: true,width: 120, prop: 'mobilePhone', resizable: true,type:'text'},
-        // {label: '余额',query: false, width: 80, prop: 'balance', resizable: true,type:'number'},
-        {label: '状态', query: true,width: 80, prop: 'status', align: 'center',type:'dict',conf:{dict:'User.status'}},
-      ],
-      query:{},
-      url:'custom/listUser',
-      method:'get'
-    }
-      userSelectDialogRef.value.open(handleChooseAccount,true,config,[]);
-  }).catch(e=>{
-    console.log(e)
-    if('close'==e)return;
-    //上传用户手机号
-    accountMobileUploadDialogRef.value?.open();
-  });
-};
-
-const handleChooseAccount = (accountList:Array<any>)=>{
-  console.log(accountList)
-  if(u.isEmptyOrNull(accountList)){
-    Msg.message('请选择用户','error')
-    return;
-  }
-  let params ={
-    userIds:accountList.map(k=>k.userId),
-    couponIds:[state.handleCoupon.id]
-  }
-  $body(`coupon/issueCoupons`,params).then(()=>{
-    Msg.message('发放成功')
-  }).catch(e=>{
-    Msg.message('发放失败','error')
-  })
-}
-
-const handleImportAccountPhone = (phoneList:Array<any>) => {
-  console.log(phoneList)
-  if(u.isEmptyOrNull(phoneList)||u.isEmptyOrNull(phoneList.dataList)){
-    Msg.message('请导入用户手机号','error')
-    return;
-  }
-  let params ={
-    phones:phoneList?.dataList?.map(k=>k.mobilePhone),
-    couponIds:[state.handleCoupon.id]
-  }
-  $body(`coupon/issueCoupons`,params).then(()=>{
-    Msg.message('发放成功')
-  }).catch(e=>{
-    Msg.message('发放失败','error')
-  })
-}
-
-const handleTableSelectionChange = (selection: any) => {
-  console.log("handleTableSelectionChange>>", selection)
-  // emit("on-check-change", selection)
-}
-
-const handleTableSortChange = (column, prop, order) => {
-  console.log("handleTableSortChange>>", column, prop, order)
-  // emit("on-sort-change", column)
-}
-
-
-//endregion
-
-
-// 暴露变量
-// defineExpose({
-//     loadData,
-// });
-</script>

+ 0 - 473
admin-web/src/views/admin/activity/coupon/upload.vue

@@ -1,473 +0,0 @@
-<template>
-  <el-dialog
-      :title="'导入号码'"
-      v-model="state.dialog.visible"
-      width="75%"
-      destroy-on-close
-      :close-on-click-modal="false"
-      :close-on-press-escape="false"
-      draggable
-      class="pd0 dialog-padding-none"
-  >
-
-    <el-tabs class="demo-tabs">
-      <el-tab-pane>
-        <template #label>
-        <span class="custom-tabs-label">
-          <SvgIcon name="ele-Grid"></SvgIcon>
-          <span>Excel导入</span>
-        </span>
-        </template>
-
-        <el-button @click="handleOpenFile" plain type="success" class="mt5"> 请选择excel文件上传导入</el-button>
-        <el-text type="primary" class="ml5">{{ state.uploadFileName }} <SvgIcon v-if="state.uploadFileName" name="ele-Remove" @click="reset" color="var(--el-color-danger)"></SvgIcon></el-text>
-
-        <!--        <ext-upload
-                    v-model="state.excelForm.file"
-                    placeholder="请选择上传文件"
-                    tips="请选择excel文件上传导入"
-                    style="width: 100%"
-                    :limit="1"
-                    mime="excel"
-                    @on-success="handleUploadFileSuccess">
-                </ext-upload>-->
-
-      </el-tab-pane>
-
-    </el-tabs>
-
-
-
-    <div class="w100 mt5">
-      <div class="w100">
-        <el-scrollbar @scroll="handleFieldHeaderScroll" ref="fieldHeaderScrollRef" :min-size="0">
-          <div class="model-field-select-wrapper">
-            <div class="model-field-select-header" v-for="(field,idx) in state.excelForm.columns"
-                 :key="'select_'+idx">
-              <template v-if="idx===0">
-                <div style="width: 135px;height: 32px;line-height:32px;border:1px solid #eee;text-align: center;">导入列选择</div>
-              </template>
-              <el-select-v2 v-else
-                            v-model="state.excelForm.importFields[idx]"
-                            :options="state.excelForm.selectFields"
-                            style="width: 135px;height: 36px;border:none;display: inline-block;flex-shrink: 0;margin-right: 10px;"
-                            filterable
-                            clearable>
-              </el-select-v2>
-            </div>
-          </div>
-        </el-scrollbar>
-      </div>
-
-      <vxe-table
-          ref="excelRef"
-          border="full"
-          show-header-overflow
-          :show-footer="false"
-          :max-height="state.tableHeight"
-          :loading="false"
-          header-cell-class-name="task-list-header"
-          header-align="left"
-          empty-text=" "
-          @cell-click="handleCellClick"
-          :data="state.excelForm.data"
-          @scroll="handleDataTableScroll"
-          :row-config="{isHover:true,isCurrent:true}"
-          :tooltip-config="{zIndex:9999}"
-          :scroll-x="{enabled: true, gt: 100}"
-          :scroll-y="{enabled: true, gt: 100}">
-
-        <vxe-column
-            v-for="(field,idx) in state.excelForm.columns"
-            :key="idx"
-            :field="field.field"
-            :width="135"
-            :title="field.name"
-            show-overflow="title">
-          <template v-if="field.field==='idx'" #default="{row,rowIndex}">
-            <div class="w100  flex flex-align-items-center flex-justify-center  hover-parent">
-
-              <el-dropdown @command="handleRow($event,row,rowIndex)">
-                <el-text type="primary" class="hover-child ml5 cursor-pointer font12">        <span>{{ rowIndex+1}}</span></el-text>
-                <template #dropdown>
-                  <el-dropdown-item command="setHeader" style="color:var(--el-color-success)" class="font12">设为表头</el-dropdown-item>
-                  <el-dropdown-item command="delete" style="color:var(--el-color-danger)" class="font12">删除本行</el-dropdown-item>
-                </template>
-              </el-dropdown>
-            </div>
-          </template>
-        </vxe-column>
-      </vxe-table>
-
-    </div>
-
-    <template #footer>
-				<span class="dialog-footer">
-					<el-button @click="onClose" size="default">取 消</el-button>
-					<el-button type="primary" @click="handleConfirm" :loading="state.importLoading" size="default">导入</el-button>
-				</span>
-    </template>
-  </el-dialog>
-</template>
-
-<script setup lang="ts" name="EndpointImportDialog">
-import {reactive, onMounted, nextTick, ref, toRaw, unref} from 'vue';
-
-//定义初始变量,重置使用
-import {useFileDialog} from '@vueuse/core'
-
-import {$body, $post} from "/@/utils/request";
-import {Msg} from "/@/utils/message";
-import {VxeTable, VxeColumn, VxeTableInstance} from "vxe-table";
-import 'vxe-table/lib/style.css'
-import {useDebounceFn, useThrottleFn} from '@vueuse/core'
-
-import {ElScrollbar} from 'element-plus'
-import * as XLSX from 'xlsx'
-
-const fieldHeaderScrollRef = ref<InstanceType<typeof ElScrollbar>>();
-const excelRef = ref<VxeTableInstance>();
-
-
-const {files, open: handleOpenFile, reset, onChange:handleFileChange} = useFileDialog(
-    {
-      multiple: false,
-      accept: '.xls,.xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel'
-    })
-
-
-handleFileChange((files)=>{
-  parseExcel()
-})
-
-const initState = () => ({
-  dialog: {
-    visible: false,
-    type: '',
-    title: '',
-    submitTxt: '',
-  },
-  initColumnList: [{field: 'idx', name: '#', fixed: 'left'}],
-  excelForm: {
-    file: '',
-    rowHeaderIndex: 0,
-    rowContentIndex: 1,
-    columns: [] as any[],
-    sheet: '',
-    sheets: [] as string[],
-    data: [],
-    loading: false,
-    importFields: [] as string[],
-    selectFields: []
-  },
-  uploadFileName: '' as String | null,
-  importLoading: false,
-  tableHeight: 400,
-  fieldList:[
-    {label:'手机号',value:'mobilePhone'},
-  ]
-})
-
-// 定义变量内容
-const state = reactive(initState());
-
-const emit = defineEmits(['on-import-finish']);
-
-
-onMounted(() => {
-
-})
-
-const open = () => {
-  state.dialog.visible = true;
-
-  nextTick(() => {
-    let clientHeight = document.body.clientHeight;
-    let th = clientHeight - 60 - 120 - 300
-    state.tableHeight = th;
-  })
-  state.excelForm.selectFields = state.fieldList.map((k: any) => {
-    return {
-      value: k.value,
-      label: k.label
-    }
-  })
-}
-
-// 关闭弹窗
-const onClose = () => {
-  state.dialog.visible = false;
-  Object.assign(state, initState())
-  reset();
-};
-
-
-const handleCellClick = (e: any) => {
-  let {row, rowIndex, $rowIndex, column, columnIndex, $columnIndex} = e;
-  if (columnIndex === 0) {
-    return;
-  }
-  let val = state.excelForm.data[rowIndex][column.property]
-  Msg.prompt(`修改导入的数据`, '修改',
-      {
-        draggable: true,
-        type: 'primary',
-        value: val
-      }
-  ).then((res: any) => {
-    let {value, action} = res;
-    if (action === 'confirm') {
-      state.excelForm.data[rowIndex][column.property] = value
-    }
-  })
-}
-
-const handleConfirm = () => {
-  let checks: Array<string> = [];
-  let checkPass= true;
-  state.excelForm.importFields.forEach(key => {
-    if (key) {
-      if (checks.includes(key)) {
-        checkPass = false;
-        Msg.message('表头不可重复', 'error')
-        return false;
-      } else {
-        checks.push(key)
-      }
-    }
-  })
-  if(!checkPass)return;
-  debounceImport();
-}
-
-const debounceImport = useThrottleFn(() => {
-  state.importLoading = true;
-  let fieldIndexes: Array<number> = []
-  state.excelForm.importFields.forEach((key, idx) => {
-    if (key) {
-      fieldIndexes.push(idx - 1);
-    }
-  })
-let  fields=state.excelForm.importFields.filter(k => !!k);
-  let dataList : Array<any> = [];
-  state.excelForm.data.forEach(data => {
-    let item ={}
-    let arr: Array<any> = []
-    fieldIndexes.forEach((idx, i) => {
-      item[fields[i]] = data[`f${idx}`] || ""
-    })
-    dataList.push(item)
-  })
-
-  let params = {
-    fields: state.excelForm.importFields.filter(k => !!k),
-    fieldIndexes,
-    dataList
-  }
-
-  emit('on-import-finish',params)
-  state.dialog.visible = false;
-  state.importLoading = false;
-/*  $body(`station/importStation`, params).then(() => {
-    Msg.message(`导入成功`)
-    state.importLoading = false;
-    emit('on-import-finish')
-    state.dialog.visible = false;
-  }).catch(() => {
-    state.importLoading = false;
-  })*/
-}, 1500)
-
-//表头选择器滚动
-const handleFieldHeaderScroll = (ev: any) => {
-  let {scrollLeft, scrollTop} = ev;
-  // console.log(scrollLeft, scrollTop, ev)
-  if (scrollLeft >= 0) {
-    let st = excelRef.value.getScroll();
-    const el = excelRef.value?.$el.querySelector('.vxe-table--body-wrapper')
-    if (el) {
-      el.scrollLeft = scrollLeft
-    }
-  }
-}
-
-//数据表格滚动
-const handleDataTableScroll = (ev: any) => {
-  let {scrollLeft} = ev;
-  // console.log(type, scrollLeft, scrollHeight)
-  if (scrollLeft >= 0) {
-    fieldHeaderScrollRef.value?.setScrollLeft(scrollLeft);
-  }
-}
-
-const handleRow = (command: string, row: any, rowIndex: number) => {
-  if (command === 'setHeader') {
-    let tmpHeaders: any[] = []
-    let tmpHeader = state.excelForm.data[rowIndex]
-    Object.keys(tmpHeader).forEach((key, i) => {
-      if (key.startsWith("f")) {
-        let header = tmpHeader[key]
-        let find = state.fieldList.find((k: any) => k.name == header);
-        if (find) {
-          state.excelForm.importFields[i + 1] = find.label;
-        } else {
-          state.excelForm.importFields[i + 1] = "";
-        }
-        tmpHeaders.push({
-          field: `f${i}`,
-          name: header
-        });
-      }
-    })
-    state.excelForm.columns = state.initColumnList.concat(tmpHeaders)
-    state.excelForm.data.splice(rowIndex, 1)
-    excelRef.value?.reloadData(state.excelForm.data);
-  } else if (command === 'delete') {
-    state.excelForm.data.splice(rowIndex, 1)
-    excelRef.value?.reloadData(state.excelForm.data);
-  }
-}
-
-const parseExcel = (sheetName: string = "") => {
-  // console.log(sheetName, state.excelForm.sheet,files)
-  // if(sheetName==state.excelForm.sheet&&state.excelForm.sheet){
-  //   return;
-  // }
-  if (!files || !files.value || !files.value[0]) {
-    state.excelForm.columns = []
-    excelRef.value?.reloadData([])
-    state.uploadFileName = null;
-    state.excelForm.sheets = []
-    return;
-  }
-  // console.log(files)
-  Msg.showLoading('解析中...')
-  state.uploadFileName = files.value[0].name;
-  let reader = new FileReader();
-  reader.onload = function () {
-    // console.log(reader)
-
-    let fileData = reader.result;
-    let wb = XLSX.read(fileData, {type: 'binary', cellDates: true});
-    state.excelForm.sheets = wb.SheetNames;
-    // {header:1} 取消标题列.
-    // console.log(wb.SheetNames)
-    let sheet = sheetName || wb.SheetNames[0];
-    state.excelForm.sheet = sheet;
-    let rowList: (any) = XLSX.utils.sheet_to_json(wb.Sheets[sheet], {header: 1});
-    // console.log(rowList)
-    let maxColumnLength = 1;
-    rowList.forEach((row: any, idx: number) => {
-      // console.log(row)
-      if (idx < 10) {
-        maxColumnLength = Math.max(maxColumnLength, row.length);
-      }
-    })
-
-    // console.log(maxColumnLength, rowList)
-    let tmpHeaders: Array<any> = []
-    let headers = rowList[state.excelForm.rowHeaderIndex];
-    for (let i = 0; i < maxColumnLength; i++) {
-      let header = i >= headers.length ? '' : headers[i];
-      let find = state.fieldList.find((k: any) => k.name == header);
-      if (find) {
-        state.excelForm.importFields[i + 1] = find.cname;
-      } else {
-        state.excelForm.importFields[i + 1] = "";
-      }
-      tmpHeaders.push({
-        field: `f${i}`,
-        name: header
-      });
-
-    }
-    state.excelForm.columns = state.initColumnList.concat(tmpHeaders)
-    // console.log(state.excelForm.columns)
-
-    let tmpContents: any[] = []
-    for (let i = state.excelForm.rowContentIndex; i < rowList.length; i++) {
-      let dl = rowList[i];
-      let rowItem = {}
-      dl.forEach((rowValue: any, columnIdx: number) => {
-        rowItem[`f${columnIdx}`] = rowValue
-      })
-      tmpContents.push(rowItem)
-    }
-    state.excelForm.data = tmpContents;
-    state.excelForm.loading = false;
-    excelRef.value?.reloadData(state.excelForm.data)
-    // data.exportTableData = rowObj;
-    Msg.hideLoading();
-  };
-  // 已二进制的形式读取文件
-  reader.readAsBinaryString(unref(files)[0]);
-  // 导入标识改为true
-  // data.exportSign = true;
-}
-
-const handleClick = (sheet: string) => {
-  parseExcel(sheet)
-  // handleRow("setHeader",state.excelForm.data[0],0)
-}
-
-/*
-onChange = ((files) => {
-  parseExcel();
-})
-*/
-
-
-defineExpose({
-  open
-})
-</script>
-
-<style scoped lang="scss">
-.custom-tabs-label {
-  display: inline-flex;
-  align-items: center;
-  align-content: center;
-  justify-content: space-between;
-}
-
-.model-field-select-wrapper {
-  width: 100%;
-  display: inline-flex;
-}
-
-.sheet-item {
-  width: 135px;
-  border-right: 2px solid #ddd;
-  border-bottom: 2px solid #ddd;
-  text-align: center;
-  cursor: pointer;
-}
-
-.model-field-select-header {
-  width: 135px;
-  height: 36px;
-  //overflow-x: auto;
-  //display: inline-flex;
-  //flex-wrap: wrap;
-
-  :deep(.el-select-v2__wrapper) {
-    border: 1px solid #eee !important;
-    border-radius: 0px !important;
-  }
-}
-
-:deep(.vxe-loading) {
-  display: none !important;
-}
-
-.pd0 {
-  :deep(.el-dialog__body) {
-    padding: 0 !important;
-  }
-}
-
-.vxe-table--tooltip-wrapper{
-  z-index: 10000 !important;
-}
-
-</style>

+ 0 - 584
admin-web/src/views/admin/activity/dialog.vue

@@ -1,584 +0,0 @@
-<style scoped lang="scss">
-.preview {
-  width: 430px;
-  height: 850px;
-  background-image: url('/@/assets/phone.png');
-  background-repeat: no-repeat;
-
-  &_body {
-    margin: 110px 40px;
-    height: 600px;
-    overflow: auto;
-  }
-}
-</style>
-<template>
-  <div class="system-dialog-container">
-    <el-dialog
-        :title="state.dialog.title"
-        v-model="state.dialog.isShowDialog"
-        width="920px"
-        draggable
-        destroy-on-close
-        :close-on-click-modal="false"
-        @close="onClose"
-        align-center>
-      <el-form
-          inline
-          :model="state.ruleForm"
-          :rules="state.rules"
-          ref="formRef"
-          size="default"
-          label-width="150px"
-          class="mt5">
-
-        <div class="sub-group-bottom"> 基本信息</div>
-        <el-form-item label="活动名称" prop="name" class="w100">
-          <el-input
-              v-model.trim="state.ruleForm.name"
-              placeholder="活动名称"
-              clearable
-              class="w100">
-          </el-input>
-        </el-form-item>
-
-        <el-form-item label="活动描述" prop="remark" class="w100"></el-form-item>
-        <div class="w100 flex mt20 mb20 flex-justify-between">
-          <ext-editor style="width:380px;flex:1;margin-right: 10px;" ref="ext_editor_ref"
-                      v-model="state.ruleForm.activityDesc"></ext-editor>
-
-          <!--          <el-divider direction="vertical"></el-divider>-->
-          <div class="preview">
-            <div class="preview_body" v-html="state.ruleForm.activityDesc"></div>
-          </div>
-        </div>
-
-        <el-form-item label="开始时间" prop="startTime">
-          <ext-date-picker
-              v-model.trim="state.ruleForm.startTime"
-              placeholder="开始时间"
-              type="datetime"
-              clearable
-              class="wd200">
-          </ext-date-picker>
-        </el-form-item>
-        <el-form-item label="结束时间" prop="endTime">
-          <ext-date-picker
-              v-model.trim="state.ruleForm.endTime"
-              placeholder="结束时间"
-              type="datetime"
-              clearable
-              class="wd200">
-          </ext-date-picker>
-        </el-form-item>
-        <!--        RechargeRights  "Coupon"-->
-        <el-form-item label="优惠方式" prop="discountType">
-          <ext-d-select
-              v-model="state.ruleForm.discountType"
-              placeholder="优惠方式"
-              type="Activity.discountType"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-        </el-form-item>
-        <!--        <el-form-item label="目标用户" prop="targetUsers" v-if="state.ruleForm.discountType==='RechargeRights'">-->
-        <!--          <ext-d-select-->
-        <!--              v-model="state.ruleForm.targetUsers"-->
-        <!--              placeholder="目标用户"-->
-        <!--              type="Activity.targetUsers"-->
-        <!--              clearable-->
-        <!--              class="wd200 ">-->
-        <!--          </ext-d-select>-->
-        <!--        </el-form-item>-->
-
-        <!--        <el-form-item label="优惠允许叠加" prop="allowStacke">-->
-        <!--          <ext-d-select-->
-        <!--              v-model="state.ruleForm.allowStacke"-->
-        <!--              placeholder="优惠允许叠加"-->
-        <!--              type="Activity.allowStacke"-->
-        <!--              clearable-->
-        <!--              class="wd200 ">-->
-        <!--          </ext-d-select>-->
-        <!--        </el-form-item>-->
-        <!--        <el-form-item label="数量限制" prop="quantity">-->
-        <!--          <el-input-->
-        <!--              type="number"-->
-        <!--              v-model.trim="state.ruleForm.quantity"-->
-        <!--              placeholder="数量限制"-->
-        <!--              clearable-->
-        <!--              class="wd200">-->
-        <!--          </el-input>-->
-        <!--        </el-form-item>-->
-        <!--        <el-form-item label="活动状态" prop="status">
-                  <ext-d-select
-                      v-model="state.ruleForm.status"
-                      placeholder="活动状态"
-                      type="Activity.status"
-                      clearable
-                      class="wd200 ">
-                  </ext-d-select>
-                </el-form-item>-->
-        <el-form-item label="备注" prop="remark" class="w100">
-          <el-input
-              maxlength="500"
-              show-word-limit
-              type="textarea"
-              :rows="3"
-              v-model.trim="state.ruleForm.remark"
-              placeholder="备注信息"
-              clearable
-              class="w100">
-          </el-input>
-
-        </el-form-item>
-
-        <div class="sub-group-bottom"> 关联站点</div>
-        <!--        <el-divider content-position="left">关联站点</el-divider>-->
-        <el-form-item label="适用站点" prop="applyStation">
-          <ext-d-select
-              @on-change="handleStationChange"
-              v-model="state.ruleForm.applyStation"
-              placeholder="适用站点"
-              type="Activity.applyStation"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-
-          <ext-select
-              v-model="state.ruleForm.stationIds"
-              multiple
-              placeholder="关联站点"
-              url="station/listStation"
-              url-method="get"
-              label-key="stationName"
-              value-key="stationId"
-              data-key=""
-              clearable
-              class="w100 mt5">
-          </ext-select>
-        </el-form-item>
-
-        <div class="sub-group-bottom"> 关联权益</div>
-        <!--        <el-divider content-position="left">关联权益</el-divider>-->
-        <el-button size="small" plain type="success" class="ml10" @click="handleAddRightsItem">
-          <SvgIcon name="ele-FolderAdd"/>
-          新增权益
-        </el-button>
-
-        <!--        服务费折扣权益 -->
-        <template v-if="state.ruleForm.discountType==='RechargeRights'">
-          <el-card v-for="(rights,idx) in state.ruleForm.rechargeRightsList" :key="idx" class="mt10" shadow="hover">
-            <template #header>
-              <div class="card-header">
-                <el-button class="button" plain type="danger" size="small" v-auth="'activity.modify'"
-                           @click="handleRemoveRightsItem(idx)">删除
-                </el-button>
-              </div>
-            </template>
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="权益名称" prop="rights.name">
-                  <el-input
-                      v-model="rights.name"
-                      placeholder="名称"
-                      clearable
-                      class="wd200 ">
-                  </el-input>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-            <el-form-item label="权益描述" prop="rightsDesc" class="w100">
-              <el-input
-                  maxlength="500"
-                  show-word-limit
-                  type="textarea"
-                  :rows="2"
-                  v-model.trim="rights.rightsDesc"
-                  placeholder="权益描述"
-                  clearable
-                  class="w100">
-              </el-input>
-            </el-form-item>
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="最小充值金额(元)" prop="amountMin">
-                  <ext-input-number class="wd200" v-model="rights.amountMin" :ratio="100"
-                                    placeholder="最小充值金额"></ext-input-number>
-                  <!--                  <el-input-number
-                                        controls-position="right"
-                                        v-model.trim="rights.amountMin"
-                                        placeholder="最小充值金额"
-                                        clearable
-                                        :min="0"
-                                        class="wd200">
-                                    </el-input-number>-->
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="最大充值金额(元)" prop="amountMin">
-                  <ext-input-number class="wd200" v-model="rights.amountMax" :ratio="100"
-                                    placeholder="最大充值金额"></ext-input-number>
-                  <!--                  <el-input-number
-                                        controls-position="right"
-                                        v-model.trim="rights.amountMax"
-                                        placeholder="最大充值金额"
-                                        clearable
-                                        :min="0"
-                                        class="wd200">
-                                    </el-input-number>-->
-                </el-form-item>
-
-              </el-col>
-            </el-row>
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="折扣率(%)" prop="discount">
-                  <ext-input-number class="wd200"
-                                    v-model="rights.discount"
-                                    placeholder="例:75代表75折"
-                                    precision="0"
-                  >
-                  </ext-input-number>
-                  <!--                  <el-input-number-->
-                  <!--                      :controls="false"-->
-                  <!--                      v-model.trim="rights.discount"-->
-                  <!--                      placeholder="例:75代表75折"-->
-                  <!--                      clearable-->
-                  <!--                      class="wd200">-->
-                  <!--                  </el-input-number>-->
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="有效期(天)" prop="validity">
-                  <el-input-number
-                      :min="1"
-                      :controls="false"
-                      v-model.trim="rights.validity"
-                      placeholder="有效天数"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-          </el-card>
-        </template>
-
-        <!--        优惠券-->
-        <template v-else>
-          <el-card v-for="(coupon,idx) in state.ruleForm.couponList" :key="idx" class="mt10" shadow="hover">
-            <template #header>
-              <div class="card-header">
-                <el-button class="button" plain type="danger" size="small" v-auth="'activity.modify'"
-                           @click="handleRemoveCouponItem(idx)">删除
-                </el-button>
-              </div>
-            </template>
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="名称" prop="coupon.name">
-                  <el-input
-                      v-model="coupon.name"
-                      placeholder="名称"
-                      clearable
-                      class="wd200 ">
-                  </el-input>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-            <el-form-item label="权益描述" prop="rightsDesc" class="w100">
-              <el-input
-                  maxlength="500"
-                  show-word-limit
-                  type="textarea"
-                  :rows="2"
-                  v-model.trim="coupon.couponDesc"
-                  placeholder="权益描述"
-                  clearable
-                  class="w100">
-              </el-input>
-
-            </el-form-item>
-
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="折扣类型" prop="couponType">
-                  <ext-d-select
-                      v-model="coupon.couponType"
-                      placeholder="折扣类型"
-                      type="Activity.couponType"
-                      clearable
-                      class="wd200 ">
-                  </ext-d-select>
-                </el-form-item>
-              </el-col>
-
-              <el-col :span="12">
-                <el-form-item v-if="coupon.couponType==='Discount'" label="折扣率(%)" prop="discount">
-                  <el-input-number
-                      :controls="false"
-                      v-model.trim="coupon.discount"
-                      placeholder="请输入折扣率"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-
-              <el-form-item v-if="coupon.couponType==='FullDiscount'" label="折扣金额(元)" prop="discount">
-                  <ext-input-number
-                      :ratio="100"
-                      :controls="false"
-                      v-model.trim="coupon.discount"
-                      placeholder="请输入折扣金额"
-                      clearable
-                      class="wd200">
-                  </ext-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="服务费门槛(元)" prop="minServiceMoney">
-                  <ext-input-number class="wd200 " v-model="coupon.minServiceMoney" :ratio="100"
-                                    placeholder="服务费门槛"></ext-input-number>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="数量(0为不限)" prop="quantity">
-                  <el-input-number
-                      :min=0
-                      :controls="false"
-                      v-model.trim="coupon.quantity"
-                      placeholder="数量"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="领取方式" prop="receiveType">
-                  <ext-d-select
-                      v-model="coupon.receiveType"
-                      placeholder="优惠券领取方式"
-                      type="Coupon.receiveType"
-                      clearable
-                      class="wd200 ">
-                  </ext-d-select>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="有效期(天)" prop="validity">
-                  <el-input-number
-                      :min="1"
-                      :controls="false"
-                      v-model.trim="coupon.validity"
-                      placeholder="有效天数"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-          </el-card>
-        </template>
-
-
-      </el-form>
-
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button @click="onCancel" size="default">取 消</el-button>
-          <el-button v-if="state.action==='add'||state.action==='edit'" :loading="state.btnLoading" type="primary"
-                     @click="onSubmit" size="default">{{ state.dialog.submitTxt }}
-          </el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup lang="ts" name="ActivityDialog">
-import {reactive, ref} from 'vue';
-import {Msg} from "/@/utils/message";
-import {$body, $get} from "/@/utils/request";
-import u from '/@/utils/u'
-import ExtDatePicker from "/@/components/form/ExtDatePicker.vue";
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtSelect from "/@/components/form/ExtSelect.vue";
-import ExtInputNumber from "/@/components/form/ExtInputNumber.vue";
-import ExtEditor from "/@/components/form/ExtEditor.vue";
-
-// 定义子组件向父组件传值/事件
-const emit = defineEmits(['refresh']);
-const formRef = ref();
-const ext_editor_ref = ref();
-//定义初始变量,重置使用
-const initState = () => ({
-  action: '',
-  ruleForm: {
-    id: 0,
-    rechargeRightsList: [] as Array<any>,
-    couponList: [] as Array<any>,
-  },
-  btnLoading: false,
-  dialog: {
-    isShowDialog: false,
-    type: '',
-    title: '',
-    submitTxt: '',
-  },
-  rules: {
-    name: [u.validator.required],
-    startTime: [u.validator.required],
-    endTime: [u.validator.required],
-    discountType: [u.validator.required],
-    targetUsers: [u.validator.required],
-    applyStation: [u.validator.required],
-    // allowStacke: [u.validator.required],
-    // quantity: [u.validator.required],
-    status: [u.validator.required],
-  },
-})
-
-// 定义变量内容
-const state = reactive(initState());
-
-
-// 打开弹窗
-const open = (action: string = 'add', row: any) => {
-  state.dialog.title = u.dialog.actions[action].title + "『活动』"
-  state.dialog.submitTxt = u.dialog.actions[action].btn + "『活动』"
-  state.dialog.isShowDialog = true;
-  state.action = action;
-  if (action !== 'add') {
-    loadData(row.id);
-  } else {
-    state.ruleForm = Object.assign(state.ruleForm, row);
-    ext_editor_ref.value?.initText(state.ruleForm.activityDesc || '');
-  }
-};
-// 关闭弹窗
-const onClose = () => {
-  state.dialog.isShowDialog = false;
-  Object.assign(state, initState())
-};
-// 取消
-const onCancel = () => {
-  onClose();
-};
-// 提交
-const onSubmit = () => {
-  console.log(state.ruleForm)
-  let rechargeRightsList = state.ruleForm.rechargeRightsList;
-  if (!u.isEmptyOrNull(rechargeRightsList)) {
-    for (let i = 0; i < rechargeRightsList.length; i++) {
-      const item: any = rechargeRightsList[i];
-      if (item.amountMax <= 0) {
-        Msg.message(`权益最大充值金额不能小于0`, 'error')
-        return false;
-      }
-
-      if (item.amountMin > item.amountMax) {
-        Msg.message(`权益最小充值金额不能大于最大充值金额`, 'error')
-        return false;
-      }
-    }
-
-    /*    state.ruleForm.rechargeRightsList.forEach((rights: any) => {
-          rights.amountMin = rights.amountMin * 100;
-          rights.amountMax = rights.amountMax * 100;
-        })*/
-  }
-
-  formRef.value.validate((valid: boolean) => {
-    if (valid) {
-      state.btnLoading = true;
-      const url = state.ruleForm.id > 0 ? "activity/modify" : "activity/add"
-      $body(url, state.ruleForm).then(() => {
-        state.btnLoading = false;
-        Msg.message('操作成功');
-        console.log('submit!')
-        onClose();
-        emit('refresh');
-      })
-    }
-  }).catch(() => {
-    state.btnLoading = false;
-    Msg.message('请先完整填写表单', 'error');
-  })
-};
-
-const handleFormChange = (formData: any) => {
-  console.log(formData)
-}
-
-// 初始化表格数据
-const loadData = (id: number) => {
-  $get(`activity/${id}`).then((res: any) => {
-    if (res && res.rechargeRightsList) {
-      /*      res.rechargeRightsList.forEach((rights: any) => {
-              rights.amountMin = rights.amountMin / 100;
-              rights.amountMax = rights.amountMax / 100;
-            })*/
-    }
-    state.ruleForm = res;
-    state.ruleForm.rechargeRightsList = res.rechargeRightsList || []
-
-    ext_editor_ref.value?.initText(res.activityDesc || '');
-  })
-}
-
-const handleStationChange = (applyStation: number) => {
-  console.log(applyStation)
-  if (applyStation == 0) {
-    // state.ruleForm.stationIds = [];
-  }
-
-}
-
-const handleAddRightsItem = () => {
-  if (state.ruleForm.discountType === 'RechargeRights') {
-    state.ruleForm.rechargeRightsList.unshift({
-      rightsDesc: '',
-      amountMin: 0,
-      amountMax: 0,
-      validity: 1
-    })
-  } else if (state.ruleForm.discountType === 'Coupon') {
-    state.ruleForm.couponList.unshift({
-      couponDesc: '',
-      couponType: 'Discount',
-      minServiceMoney: 0,
-      validity: 1,
-      quantity: 0,
-    })
-  }
-
-}
-
-const handleRemoveRightsItem = (idx: number) => {
-  state.ruleForm.rechargeRightsList.splice(idx, 1)
-}
-const handleRemoveCouponItem = (idx: number) => {
-  state.ruleForm.couponList.splice(idx, 1)
-}
-
-// 暴露变量
-defineExpose({
-  open
-});
-
-
-</script>

+ 0 - 294
admin-web/src/views/admin/activity/index.vue

@@ -1,294 +0,0 @@
-<style scoped lang="scss">
-.system-container {
-
-  :deep(.el-card__body) {
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-    flex: 1;
-    overflow: auto;
-
-    .el-table {
-      flex: 1;
-    }
-
-  }
-}
-
-.page-content {
-  margin-bottom: 20px;
-}
-
-.page-pager {
-  background-color: #fff;
-  height: 24px;
-}
-</style>
-<template>
-  <div class="system-container layout-padding">
-    <el-card shadow="hover" class="layout-padding-auto">
-
-
-      <el-form
-          :model="state.formQuery"
-          ref="queryRef"
-          size="default" label-width="0px" class="mt5 mb5">
-        <el-input
-            v-model="state.formQuery.name"
-            placeholder="活动名称"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <ext-date-picker
-            v-model="state.formQuery.startTime"
-            placeholder="开始时间"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-date-picker>
-        <ext-date-picker
-            v-model="state.formQuery.endTime"
-            placeholder="结束时间"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-date-picker>
-        <ext-d-select
-            v-model="state.formQuery.discountType"
-            placeholder="优惠方式"
-            type="Activity.discountType"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-
-        <ext-d-select
-            v-model="state.formQuery.status"
-            placeholder="活动状态"
-            type="Activity.status"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-
-        <el-button class="ml10" plain size="default" type="success" @click="loadData(true)">
-          <SvgIcon name="ele-Search"/>
-          查询
-        </el-button>
-        <el-button v-auth="'activity.add'" size="default" plain type="success" class="ml10" @click="onRowClick('add',null)">
-          <SvgIcon name="ele-FolderAdd"/>
-          新增
-        </el-button>
-      </el-form>
-
-      <el-table
-          border
-          stripe="stripe"
-          :height="state.tableData.height"
-          highlight-current-row
-          current-row-key="id"
-          row-key="id"
-          :data="state.tableData.data"
-          v-loading="state.tableData.loading"
-          @row-dblclick="onRowClick('view',$event)"
-          @selection-change="handleTableSelectionChange"
-          @sort-change="handleTableSortChange">
-        <template #empty>
-          <el-empty></el-empty>
-        </template>
-        <el-table-column
-            v-for="field in state.tableData.columns"
-            :key="field.prop"
-            :label="field.label"
-            :column-key="field.prop"
-            :width="field.width"
-            :min-width="field.minWidth"
-            :fixed="field.fixed"
-            :sortable="field.sortable"
-            :show-overflow-tooltip="!field.fixed&&field.width>150"
-        >
-          <template #default="{row}">
-            <template v-if="field.prop==='expand'">
-              <p style="padding-left: 2em;" v-html="row[field.prop]"></p>
-            </template>
-            <template v-else-if="field.prop==='period'">
-              {{ row.startTime }} ~ {{ row.endTime }}
-            </template>
-            <template v-else-if="field.prop==='discountType'">
-              <ext-d-label type="Activity.discountType" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='applyStation'">
-              <ext-d-label type="Activity.applyStation" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='status'">
-              <ext-d-label type="Activity.status" v-model="row[field.prop]"></ext-d-label>
-            </template>
-<!--            <template v-else-if="field.prop==='targetUsers'">-->
-<!--              <ext-d-label type="Activity.targetUsers" v-model="row[field.prop]"></ext-d-label>-->
-<!--            </template>-->
-<!--            <template v-else-if="field.prop==='allowStacke'">-->
-<!--              <ext-d-label type="Activity.allowStacke" v-model="row[field.prop]"></ext-d-label>-->
-<!--            </template>-->
-            <template v-else-if="field.prop==='action'">
-              <el-button v-auth="'activity.list'" size="small" plain type="success" @click="onRowClick('view',row)">查看</el-button>
-              <el-button v-auth="'activity.modify'" v-if="row.status==0||row.status==1"  size="small" plain type="danger" @click="onRowTerminal(row)">终止</el-button>
-            </template>
-            <template v-else>
-              <div>{{ row[field.prop] }}</div>
-            </template>
-
-          </template>
-        </el-table-column>
-      </el-table>
-
-      <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
-    </el-card>
-  </div>
-  <ActivityDialog ref="activityDialogRef" @refresh="loadData(true)"/>
-</template>
-
-<script setup lang="ts" name="ActivityList">
-import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance, nextTick, onBeforeUnmount} from 'vue';
-import {$body, $get} from "/@/utils/request";
-import {Msg} from "/@/utils/message";
-
-
-import ExtPage from '/@/components/form/ExtPage.vue'
-
-import mittBus from '/@/utils/mitt';
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtDatePicker from "/@/components/form/ExtDatePicker.vue";
-import ExtDLabel from "/@/components/form/ExtDLabel.vue";
-
-const ActivityDialog = defineAsyncComponent(() => import("/@/views/admin/activity/dialog.vue"));
-
-//定义引用
-const queryRef = ref();
-const activityDialogRef = ref();
-
-//定义变量
-const state = reactive({
-  formQuery: {},
-  pageQuery: {
-    pageNum: 1,
-    pageSize: 10,
-    total: 0
-  },
-  tableData: {
-    height: 500,
-    data: [] as Array<any>,
-    loading: false,
-    columns: [
-      {
-        label: '活动名称', prop: 'name', resizable: true, width: 170, fixed: 'left'
-      },
-      {label: '活动时间', prop: 'period', resizable: true, width: 350},
-      // {label: '结束时间', prop: 'endTime',  resizable: true, width: 150},
-      {label: '活动状态', prop: 'status', align: 'center', width: 130},
-      {label: '优惠方式', prop: 'discountType', resizable: true, width: 130},
-      // {label: '目标用户', prop: 'targetUsers', resizable: true, width: 130},
-      {label: '适用站点', prop: 'applyStation', resizable: true, width: 130},
-      // {label: '优惠允许叠加', prop: 'allowStacke', resizable: true, width: 130},
-      // {label: '数量限制', prop: 'quantity', resizable: true, width: 130},
-      {label: '创建时间', prop: 'createTime', resizable: true, width: 180},
-      {label: '更新时间', prop: 'updateTime', resizable: true, width: 180},
-      {
-        label: '操作', prop: 'action', width: 180, align: 'center', fixed: 'right',
-      }
-    ],
-  },
-})
-
-
-// 监听双向绑定 modelValue 的变化
-// watch(
-//         () => state.pageNum,
-//         () => {
-//
-//         }
-// );
-
-//生命周期钩子
-onBeforeMount(() => {
-})
-
-onMounted(() => {
-  loadData();
-
-  nextTick(() => {
-    let bodyHeight = document.body.clientHeight;
-    let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 320
-  })
-
-  mittBus.on("activity.refresh", () => {
-    loadData();
-  })
-});
-
-onBeforeUnmount(() => {
-  mittBus.off("activity.refresh")
-})
-
-
-//region 方法区
-// 初始化表格数据
-const loadData = (refresh: boolean = false) => {
-  if (refresh) {
-    state.pageQuery.pageNum = 1;
-  }
-  state.tableData.loading = true;
-  $get(`/activity`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let {list, total} = res;
-    state.tableData.data = list;
-    state.pageQuery.total = total;
-    state.tableData.loading = false;
-  }).catch(e => {
-    console.error(e)
-    state.tableData.loading = false;
-  })
-};
-
-// 打开修改用户弹窗
-const handleRowClick = (event) => {
-  console.log(event)
-  activityDialogRef.value.open("view", event);
-};
-
-// 打开修改用户弹窗
-const onRowClick = (type: string, row: any) => {
-  activityDialogRef.value.open(type, row);
-};
-
-// 删除用户
-const onRowTerminal = (row: any) => {
-  Msg.confirm(`此操作将终止:『${row.name}』,是否继续?`).then(() => {
-    $get(`/activity/terminateActivity/${row.id}`).then(() => {
-      Msg.message("终止成功", 'success')
-      loadData(true)
-    }).catch(() => {
-      Msg.message("终止失败", 'error')
-    })
-  });
-};
-
-const handleTableSelectionChange = (selection: any) => {
-  console.log("handleTableSelectionChange>>", selection)
-  // emit("on-check-change", selection)
-}
-
-const handleTableSortChange = (column, prop, order) => {
-  console.log("handleTableSortChange>>", column, prop, order)
-  // emit("on-sort-change", column)
-}
-
-
-//endregion
-
-
-// 暴露变量
-// defineExpose({
-//     loadData,
-// });
-</script>

+ 0 - 490
admin-web/src/views/admin/activity/userCoupon/dialog.vue

@@ -1,490 +0,0 @@
-<style scoped lang="scss">
-
-</style>
-<template>
-  <div class="system-dialog-container">
-    <el-dialog
-        :title="state.dialog.title"
-        v-model="state.dialog.isShowDialog"
-        width="820px"
-        draggable
-        destroy-on-close
-        :close-on-click-modal="false"
-        @close="onClose"
-        align-center>
-      <el-form
-          inline
-          :model="state.ruleForm"
-          :rules="state.rules"
-          ref="formRef"
-          size="default"
-          label-width="150px"
-          class="mt5">
-
-        <div class="sub-group-bottom"> 基本信息</div>
-        <el-form-item label="活动名称" prop="name" class="w100">
-          <el-input
-              v-model.trim="state.ruleForm.name"
-              placeholder="活动名称"
-              clearable
-              class="w100">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="活动描述" prop="remark" class="w100">
-          <el-input
-              maxlength="500"
-              show-word-limit
-              type="textarea"
-              :rows="3"
-              v-model.trim="state.ruleForm.activityDesc"
-              placeholder="活动描述"
-              clearable
-              class="w100">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="开始时间" prop="startTime">
-          <ext-date-picker
-              v-model.trim="state.ruleForm.startTime"
-              placeholder="开始时间"
-              type="datetime"
-              clearable
-              class="wd200">
-          </ext-date-picker>
-        </el-form-item>
-        <el-form-item label="结束时间" prop="endTime">
-          <ext-date-picker
-              v-model.trim="state.ruleForm.endTime"
-              placeholder="结束时间"
-              type="datetime"
-              clearable
-              class="wd200">
-          </ext-date-picker>
-        </el-form-item>
-<!--        RechargeRights  "Coupon"-->
-        <el-form-item label="优惠方式" prop="discountType">
-          <ext-d-select
-              v-model="state.ruleForm.discountType"
-              placeholder="优惠方式"
-              type="Activity.discountType"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-        </el-form-item>
-        <el-form-item label="目标用户" prop="targetUsers" v-if="state.ruleForm.discountType==='RechargeRights'">
-          <ext-d-select
-              v-model="state.ruleForm.targetUsers"
-              placeholder="目标用户"
-              type="Activity.targetUsers"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-        </el-form-item>
-
-        <el-form-item label="优惠允许叠加" prop="allowStacke">
-          <ext-d-select
-              v-model="state.ruleForm.allowStacke"
-              placeholder="优惠允许叠加"
-              type="Activity.allowStacke"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-        </el-form-item>
-        <el-form-item label="数量限制" prop="quantity">
-          <el-input
-              type="number"
-              v-model.trim="state.ruleForm.quantity"
-              placeholder="数量限制"
-              clearable
-              class="wd200">
-          </el-input>
-        </el-form-item>
-        <!--        <el-form-item label="活动状态" prop="status">
-                  <ext-d-select
-                      v-model="state.ruleForm.status"
-                      placeholder="活动状态"
-                      type="Activity.status"
-                      clearable
-                      class="wd200 ">
-                  </ext-d-select>
-                </el-form-item>-->
-        <el-form-item label="备注" prop="remark" class="w100">
-          <el-input
-              maxlength="500"
-              show-word-limit
-              type="textarea"
-              :rows="3"
-              v-model.trim="state.ruleForm.remark"
-              placeholder="备注信息"
-              clearable
-              class="w100">
-          </el-input>
-        </el-form-item>
-
-        <div class="sub-group-bottom"> 关联站点</div>
-<!--        <el-divider content-position="left">关联站点</el-divider>-->
-        <el-form-item label="适用站点" prop="applyStation">
-          <ext-d-select
-              @on-change="handleStationChange"
-              v-model="state.ruleForm.applyStation"
-              placeholder="适用站点"
-              type="Activity.applyStation"
-              clearable
-              class="wd200 ">
-          </ext-d-select>
-
-          <ext-select
-              v-model="state.ruleForm.stationIds"
-              multiple
-              placeholder="关联站点"
-              url="station/listStation"
-              url-method="get"
-              label-key="stationName"
-              value-key="stationId"
-              data-key=""
-              clearable
-              class="w100 mt5">
-          </ext-select>
-        </el-form-item>
-
-        <div class="sub-group-bottom"> 关联权益</div>
-<!--        <el-divider content-position="left">关联权益</el-divider>-->
-        <el-button size="small" plain type="success" class="ml10" @click="handleAddRightsItem">
-          <SvgIcon name="ele-FolderAdd"/>
-          新增权益
-        </el-button>
-
-<!--        服务费折扣权益 -->
-        <template v-if="state.ruleForm.discountType==='RechargeRights'">
-          <el-card v-for="(rights,idx) in state.ruleForm.rechargeRightsList" :key="idx" class="mt10" shadow="hover">
-            <template #header>
-              <div class="card-header">
-                <el-button class="button" plain type="danger" size="small" v-auth="'activity.modify'" @click="handleRemoveRightsItem(idx)">删除</el-button>
-              </div>
-            </template>
-
-            <el-form-item label="权益描述" prop="rightsDesc" class="w100">
-              <el-input
-                  maxlength="500"
-                  show-word-limit
-                  type="textarea"
-                  :rows="2"
-                  v-model.trim="rights.rightsDesc"
-                  placeholder="权益描述"
-                  clearable
-                  class="w100">
-              </el-input>
-            </el-form-item>
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="最小充值金额(元)" prop="amountMin">
-                  <ext-input-number  class="wd200"  v-model="rights.amountMin" :ratio="100"  placeholder="最小充值金额"></ext-input-number>
-<!--                  <el-input-number
-                      controls-position="right"
-                      v-model.trim="rights.amountMin"
-                      placeholder="最小充值金额"
-                      clearable
-                      :min="0"
-                      class="wd200">
-                  </el-input-number>-->
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="最大充值金额(元)" prop="amountMin">
-                  <ext-input-number  class="wd200"  v-model="rights.amountMax" :ratio="100"  placeholder="最大充值金额"></ext-input-number>
-<!--                  <el-input-number
-                      controls-position="right"
-                      v-model.trim="rights.amountMax"
-                      placeholder="最大充值金额"
-                      clearable
-                      :min="0"
-                      class="wd200">
-                  </el-input-number>-->
-                </el-form-item>
-
-              </el-col>
-            </el-row>
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="折扣" prop="discount">
-                  <el-input-number
-                      :controls="false"
-                      v-model.trim="rights.discount"
-                      placeholder="折扣:100代表无折扣,75代表75折"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="有效期(天)" prop="validity">
-                  <el-input-number
-                      :min="1"
-                      :controls="false"
-                      v-model.trim="rights.validity"
-                      placeholder="有效天数"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-          </el-card>
-        </template>
-
-<!--        优惠券-->
-        <template v-else>
-          <el-card v-for="(coupon,idx) in state.ruleForm.couponList" :key="idx" class="mt10" shadow="hover">
-            <template #header>
-              <div class="card-header">
-                <el-button class="button" plain type="danger" size="small" v-auth="'activity.modify'" @click="handleRemoveCouponItem(idx)">删除</el-button>
-              </div>
-            </template>
-
-
-
-              <el-form-item label="权益描述" prop="rightsDesc" class="w100">
-                <el-input
-                    maxlength="500"
-                    show-word-limit
-                    type="textarea"
-                    :rows="2"
-                    v-model.trim="coupon.couponDesc"
-                    placeholder="权益描述"
-                    clearable
-                    class="w100">
-                </el-input>
-              </el-form-item>
-
-
-            <el-row :gutter="20">
-              <el-col :span="12">
-                <el-form-item label="折扣类型" prop="couponType">
-                  <ext-d-select
-                      @on-change="handleStationChange"
-                      v-model="coupon.couponType"
-                      placeholder="折扣类型"
-                      type="Activity.couponType"
-                      clearable
-                      class="wd200 ">
-                  </ext-d-select>
-                </el-form-item>
-              </el-col>
-              <el-col :span="12">
-                <el-form-item label="有效期(天)" prop="validity">
-                  <el-input-number
-                      :min="1"
-                      :controls="false"
-                      v-model.trim="coupon.validity"
-                      placeholder="有效天数"
-                      clearable
-                      class="wd200">
-                  </el-input-number>
-                </el-form-item>
-              </el-col>
-            </el-row>
-
-
-            <el-row :gutter="20">
-                <el-col :span="12">
-                  <el-form-item label="服务费门槛(元)" prop="minServiceMoney">
-                    <ext-input-number   class="wd200 "  v-model="coupon.minServiceMoney" :ratio="100"  placeholder="服务费门槛"></ext-input-number>
-                  </el-form-item>
-                </el-col>
-                <el-col :span="12">
-                  <el-form-item label="折扣" prop="discount">
-                    <el-input-number
-                        :controls="false"
-                        v-model.trim="coupon.discount"
-                        placeholder="折扣:100代表无折扣,75代表75折;折扣金额(分)"
-                        clearable
-                        class="wd200">
-                    </el-input-number>
-                  </el-form-item>
-                </el-col>
-              </el-row>
-
-
-
-          </el-card>
-        </template>
-
-
-      </el-form>
-
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button @click="onCancel" size="default">取 消</el-button>
-          <el-button v-if="state.action==='add'||state.action==='edit'" :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup lang="ts" name="ActivityDialog">
-import {reactive, ref} from 'vue';
-import {Msg} from "/@/utils/message";
-import {$body, $get} from "/@/utils/request";
-import u from '/@/utils/u'
-import ExtDatePicker from "/@/components/form/ExtDatePicker.vue";
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtSelect from "/@/components/form/ExtSelect.vue";
-import ExtInputNumber from "/@/components/form/ExtInputNumber.vue";
-
-// 定义子组件向父组件传值/事件
-const emit = defineEmits(['refresh']);
-const formRef = ref();
-//定义初始变量,重置使用
-const initState = () => ({
-  action: '',
-  ruleForm: {
-    id: 0,
-    rechargeRightsList: [] as Array<any>,
-    couponList: [] as Array<any>,
-  },
-  btnLoading: false,
-  dialog: {
-    isShowDialog: false,
-    type: '',
-    title: '',
-    submitTxt: '',
-  },
-  rules: {
-    name: [u.validator.required],
-    startTime: [u.validator.required],
-    endTime: [u.validator.required],
-    discountType: [u.validator.required],
-    targetUsers: [u.validator.required],
-    applyStation: [u.validator.required],
-    allowStacke: [u.validator.required],
-    quantity: [u.validator.required],
-    status: [u.validator.required],
-  },
-})
-
-// 定义变量内容
-const state = reactive(initState());
-
-
-// 打开弹窗
-const open = (action: string = 'add', row: any) => {
-  state.dialog.title = u.dialog.actions[action].title + "『活动』"
-  state.dialog.submitTxt = u.dialog.actions[action].btn + "『活动』"
-  state.dialog.isShowDialog = true;
-  state.action = action;
-  if (action !== 'add') {
-    loadData(row.id);
-  } else {
-    state.ruleForm = Object.assign(state.ruleForm, row);
-  }
-};
-// 关闭弹窗
-const onClose = () => {
-  state.dialog.isShowDialog = false;
-  Object.assign(state, initState())
-};
-// 取消
-const onCancel = () => {
-  onClose();
-};
-// 提交
-const onSubmit = () => {
-  let rechargeRightsList = state.ruleForm.rechargeRightsList;
-  if (!u.isEmptyOrNull(rechargeRightsList)) {
-    for (let i = 0; i < rechargeRightsList.length; i++) {
-      const item: any = rechargeRightsList[i];
-      if (item.amountMax <=0) {
-        Msg.message(`权益最大充值金额不能小于0`, 'error')
-        return false;
-      }
-
-      if (item.amountMin > item.amountMax) {
-        Msg.message(`权益最小充值金额不能大于最大充值金额`, 'error')
-        return false;
-      }
-    }
-
-/*    state.ruleForm.rechargeRightsList.forEach((rights: any) => {
-      rights.amountMin = rights.amountMin * 100;
-      rights.amountMax = rights.amountMax * 100;
-    })*/
-  }
-
-  formRef.value.validate((valid: boolean) => {
-    if (valid) {
-      state.btnLoading = true;
-      const url = state.ruleForm.id > 0 ? "activity/modify" : "activity/add"
-      $body(url, state.ruleForm).then(() => {
-        state.btnLoading = false;
-        Msg.message('操作成功');
-        console.log('submit!')
-        onClose();
-        emit('refresh');
-      })
-    }
-  }).catch(() => {
-    state.btnLoading = false;
-    Msg.message('请先完整填写表单', 'error');
-  })
-};
-
-const handleFormChange = (formData: any) => {
-  console.log(formData)
-}
-
-// 初始化表格数据
-const loadData = (id: number) => {
-  $get(`activity/${id}`).then((res: any) => {
-    if (res && res.rechargeRightsList) {
-/*      res.rechargeRightsList.forEach((rights: any) => {
-        rights.amountMin = rights.amountMin / 100;
-        rights.amountMax = rights.amountMax / 100;
-      })*/
-    }
-    state.ruleForm = res;
-    state.ruleForm.rechargeRightsList = res.rechargeRightsList || []
-  })
-}
-
-const handleStationChange = (applyStation: number) => {
-  console.log(applyStation)
-  if (applyStation == 0) {
-    // state.ruleForm.stationIds = [];
-  }
-
-}
-
-const handleAddRightsItem = () => {
-  if(state.ruleForm.discountType==='RechargeRights'){
-    state.ruleForm.rechargeRightsList.unshift({
-      rightsDesc: '',
-      amountMin: 0,
-      amountMax: 0,
-      validity: 1
-    })
-  }else if(state.ruleForm.discountType==='Coupon'){
-    state.ruleForm.couponList.unshift({
-      couponDesc: '',
-      couponType: 'Discount',
-      minServiceMoney: 0,
-      validity: 1
-    })
-  }
-
-}
-
-const handleRemoveRightsItem = (idx: number) => {
-  state.ruleForm.rechargeRightsList.splice(idx, 1)
-}
-const handleRemoveCouponItem = (idx: number) => {
-  state.ruleForm.couponList.splice(idx, 1)
-}
-
-// 暴露变量
-defineExpose({
-  open
-});
-
-
-</script>

+ 0 - 301
admin-web/src/views/admin/activity/userCoupon/index.vue

@@ -1,301 +0,0 @@
-<style scoped lang="scss">
-.system-container {
-
-  :deep(.el-card__body) {
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-    flex: 1;
-    overflow: auto;
-
-    .el-table {
-      flex: 1;
-    }
-
-  }
-}
-
-.page-content {
-  margin-bottom: 20px;
-}
-
-.page-pager {
-  background-color: #fff;
-  height: 24px;
-}
-</style>
-<template>
-  <div class="system-container layout-padding">
-    <el-card shadow="hover" class="layout-padding-auto">
-
-
-      <el-form
-          :model="state.formQuery"
-          ref="queryRef"
-          size="default" label-width="0px" class="mt5 mb5">
-        <el-input
-            v-model="state.formQuery.activityName"
-            placeholder="活动名称"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <el-input
-            v-model="state.formQuery.couponName"
-            placeholder="优惠券名称"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-<!--        <el-input-->
-<!--            v-model="state.formQuery.userName"-->
-<!--            placeholder="用户名称"-->
-<!--            clearable-->
-<!--            @blur="loadData(true)"-->
-<!--            class="wd150 mr10">-->
-<!--        </el-input>-->
-        <el-input
-            v-model="state.formQuery.mobilePhone"
-            placeholder="手机号"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <ext-d-select
-            v-model="state.formQuery.couponType"
-            placeholder="券种"
-            type="Activity.couponType"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-
-<!--        <ext-d-select-->
-<!--            placeholder="用户状态"-->
-<!--            v-model="state.formQuery.status"-->
-<!--            type="User.status"-->
-<!--            clearable-->
-<!--            @blur="loadData(true)"-->
-<!--            class="wd150 mr10">-->
-<!--        </ext-d-select>-->
-
-
-        <ext-d-select
-            placeholder="使用状态"
-            v-model="state.formQuery.usageStatus"
-            type="UserCoupon.usage"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-
-        <el-button class="ml10" plain size="default" type="success" @click="loadData(true)">
-          <SvgIcon name="ele-Search"/>
-          查询
-        </el-button>
-      </el-form>
-
-      <el-table
-          border
-          stripe="stripe"
-          :height="state.tableData.height"
-          highlight-current-row
-          current-row-key="id"
-          row-key="id"
-          :data="state.tableData.data"
-          v-loading="state.tableData.loading"
-          @row-dblclick="onRowClick('view',$event)"
-          @selection-change="handleTableSelectionChange"
-          @sort-change="handleTableSortChange">
-        <template #empty>
-          <el-empty></el-empty>
-        </template>
-        <el-table-column
-            v-for="field in state.tableData.columns"
-            :key="field.prop"
-            :label="field.label"
-            :column-key="field.prop"
-            :width="field.width"
-            :min-width="field.minWidth"
-            :fixed="field.fixed"
-            :sortable="field.sortable"
-            :show-overflow-tooltip="!field.fixed&&field.width>150"
-        >
-          <template #default="{row}">
-            <template v-if="field.prop==='expand'">
-              <p style="padding-left: 2em;" v-html="row[field.prop]"></p>
-            </template>
-            <template v-else-if="field.prop==='period'">
-              {{ row.startTime }} ~ {{ row.endTime }}
-            </template>
-            <template v-else-if="field.prop==='couponType'">
-              <ext-d-label type="Activity.couponType" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='status'">
-              <ext-d-label type="User.status" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='usageStatus'">
-              <ext-d-label type="UserCoupon.usage" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='allowStacke'">
-              <ext-d-label type="Activity.allowStacke" v-model="row[field.prop]"></ext-d-label>
-            </template>
-            <template v-else-if="field.prop==='action'">
-<!--              <el-button   size="small" plain type="danger" @click="onRowTerminal(row)">终止</el-button>-->
-            </template>
-            <template v-else>
-              <div>{{ row[field.prop] }}</div>
-            </template>
-
-          </template>
-        </el-table-column>
-      </el-table>
-
-      <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
-    </el-card>
-  </div>
-  <ActivityDialog ref="activityDialogRef" @refresh="loadData(true)"/>
-</template>
-
-<script setup lang="ts" name="ActivityList">
-import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance, nextTick, onBeforeUnmount} from 'vue';
-import {$body, $get} from "/@/utils/request";
-import {Msg} from "/@/utils/message";
-
-
-import ExtPage from '/@/components/form/ExtPage.vue'
-
-import mittBus from '/@/utils/mitt';
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtDLabel from "/@/components/form/ExtDLabel.vue";
-
-const ActivityDialog = defineAsyncComponent(() => import("/@/views/admin/activity/dialog.vue"));
-
-//定义引用
-const queryRef = ref();
-const activityDialogRef = ref();
-
-//定义变量
-const state = reactive({
-  formQuery: {},
-  pageQuery: {
-    pageNum: 1,
-    pageSize: 10,
-    total: 0
-  },
-  tableData: {
-    height: 500,
-    data: [] as Array<any>,
-    loading: false,
-    columns: [
-      {label: '活动名称', prop: 'activityName', resizable: true, width: 180, fixed: 'left'},
-      {label: '优惠券发放/领取时间 ~ 失效时间', prop: 'period', resizable: true, width: 320},
-      {label: '优惠券ID', prop: 'couponId', align: 'center', width: 180},
-      {label: '优惠券名称', prop: 'couponName', align: 'center', width: 150},
-      {label: '用户ID', prop: 'userId', resizable: true, width: 130},
-      {label: '手机号', prop: 'mobilePhone', resizable: true, width: 120},
-      {label: '有效期(天)', prop: 'validity', resizable: true, width: 120},
-      {label: '优惠券状态', prop: 'status', resizable: true, width: 110},
-      {label: '使用状态', prop: 'usageStatus', resizable: true, width: 110},
-      {label: '优惠允许叠加', prop: 'allowStacke', resizable: true, width: 130},
-      {label: '创建时间', prop: 'createTime', resizable: true, width: 180},
-      {label: '更新时间', prop: 'updateTime', resizable: true, width: 180},
-   /*   {
-        label: '操作', prop: 'action', width: 180, align: 'center', fixed: 'right',
-      }*/
-    ],
-  },
-})
-
-
-// 监听双向绑定 modelValue 的变化
-// watch(
-//         () => state.pageNum,
-//         () => {
-//
-//         }
-// );
-
-//生命周期钩子
-onBeforeMount(() => {
-})
-
-onMounted(() => {
-  loadData();
-
-  nextTick(() => {
-    let bodyHeight = document.body.clientHeight;
-    let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 320
-  })
-
-  mittBus.on("activity.refresh", () => {
-    loadData();
-  })
-});
-
-onBeforeUnmount(() => {
-  mittBus.off("activity.refresh")
-})
-
-
-//region 方法区
-// 初始化表格数据
-const loadData = (refresh: boolean = false) => {
-  if (refresh) {
-    state.pageQuery.pageNum = 1;
-  }
-  state.tableData.loading = true;
-  $get(`/coupon/listUserCoupons`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let {list, total} = res;
-    state.tableData.data = list;
-    state.pageQuery.total = total;
-    state.tableData.loading = false;
-  }).catch(e => {
-    console.error(e)
-    state.tableData.loading = false;
-  })
-};
-
-// 打开修改用户弹窗
-const handleRowClick = (event) => {
-  console.log(event)
-  activityDialogRef.value.open("view", event);
-};
-
-// 打开修改用户弹窗
-const onRowClick = (type: string, row: any) => {
-  activityDialogRef.value.open(type, row);
-};
-
-// 删除用户
-const onRowTerminal = (row: any) => {
-  Msg.confirm(`此操作将终止:『${row.name}』,是否继续?`).then(() => {
-    $get(`/activity/terminateActivity/${row.id}`).then(() => {
-      Msg.message("终止成功", 'success')
-      loadData(true)
-    }).catch(() => {
-      Msg.message("终止失败", 'error')
-    })
-  });
-};
-
-const handleTableSelectionChange = (selection: any) => {
-  console.log("handleTableSelectionChange>>", selection)
-  // emit("on-check-change", selection)
-}
-
-const handleTableSortChange = (column, prop, order) => {
-  console.log("handleTableSortChange>>", column, prop, order)
-  // emit("on-sort-change", column)
-}
-
-
-//endregion
-
-
-// 暴露变量
-// defineExpose({
-//     loadData,
-// });
-</script>

+ 203 - 0
admin-web/src/views/admin/feedback/dialog.vue

@@ -0,0 +1,203 @@
+<style scoped lang="scss">
+
+</style>
+<template>
+  <div class="system-dialog-container">
+    <el-dialog
+        :title="state.dialog.title"
+        v-model="state.dialog.isShowDialog"
+        width="820px"
+        draggable
+        destroy-on-close
+        :close-on-click-modal="false"
+        align-center>
+      <el-form
+          inline
+          :model="state.ruleForm"
+          :rules="rules"
+          label-position="top"
+          ref="formRef"
+          size="default"
+          label-width="100px"
+          class="mt5">
+        <el-form-item label="附件列表" prop="attachList">
+          <el-input
+              v-model="state.ruleForm.attachList"
+              placeholder="附件列表"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="详情描述" prop="content">
+          <el-input
+              v-model="state.ruleForm.content"
+              placeholder="详情描述"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="回复内容" prop="replyContent">
+          <el-input
+              v-model="state.ruleForm.replyContent"
+              placeholder="回复内容"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="回复时间" prop="replyTime">
+          <el-input
+              v-model="state.ruleForm.replyTime"
+              placeholder="回复时间"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="回复人" prop="replyUserId">
+          <el-input
+              v-model="state.ruleForm.replyUserId"
+              placeholder="回复人"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-input
+              v-model="state.ruleForm.status"
+              placeholder="状态"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="提交时间" prop="submitTime">
+          <el-input
+              v-model="state.ruleForm.submitTime"
+              placeholder="提交时间"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="反馈人" prop="submitUserId">
+          <el-input
+              v-model="state.ruleForm.submitUserId"
+              placeholder="反馈人"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="反馈标题" prop="title">
+          <el-input
+              v-model="state.ruleForm.title"
+              placeholder="反馈标题"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="纠错类型" prop="type">
+          <el-input
+              v-model="state.ruleForm.type"
+              placeholder="纠错类型"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+				<span class="dialog-footer">
+					<el-button @click="onCancel" size="default">取 消</el-button>
+					<el-button :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
+				</span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts" name="FeedbackDialog">
+import {defineAsyncComponent, reactive, onMounted, ref} from 'vue';
+import {Msg} from "/@/utils/message";
+import {$body, $get} from "/@/utils/request";
+import u from '/@/utils/u'
+
+// 引入组件
+const ExtDetailForm = defineAsyncComponent(() => import('/@/components/form/ExtDetailForm.vue'));
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['refresh']);
+const formRef = ref();
+//定义初始变量,重置使用
+const initState = () => ({
+  ruleForm: {
+    id: 0
+  },
+  btnLoading: false,
+  dialog: {
+    isShowDialog: false,
+    type: '',
+    title: '',
+    submitTxt: '',
+  },
+  rules: {},
+})
+
+// 定义变量内容
+const state = reactive(initState());
+
+
+// 打开弹窗
+const open = (action: string = 'add', row: any) => {
+  state.dialog.title = u.dialog.actions[action].title + "『纠错反馈』"
+  state.dialog.submitTxt = u.dialog.actions[action].btn + "『纠错反馈』"
+  state.dialog.isShowDialog = true;
+  if (action !== 'add') {
+    loadData(row.id);
+  } else {
+    state.ruleForm = Object.assign(state.ruleForm, row);
+  }
+};
+// 关闭弹窗
+const onClose = () => {
+  state.dialog.isShowDialog = false;
+  Object.assign(state, initState())
+};
+// 取消
+const onCancel = () => {
+  onClose();
+};
+// 提交
+const onSubmit = () => {
+  formRef.value.validate((v: boolean) => {
+    if (v) {
+      state.btnLoading = true;
+      const url = state.ruleForm.id > 0 ? "feedback/modify" : "feedback/add"
+      $body(url, state.ruleForm).then(() => {
+        state.btnLoading = false;
+        Msg.message('操作成功');
+        console.log('submit!')
+        onClose();
+        emit('refresh');
+      })
+    } else {
+      state.btnLoading = false;
+      Msg.message('请先完整填写表单', 'error');
+    }
+  })
+};
+
+const handleFormChange = (formData: any) => {
+  console.log(formData)
+}
+
+// 初始化数据
+const loadData = (id: number) => {
+  $get(`feedback/detail/${id}`).then((res: any) => {
+    state.ruleForm = res;
+  })
+}
+
+// 暴露变量
+defineExpose({
+  open
+});
+
+
+</script>

+ 118 - 139
admin-web/src/views/admin/feedback/index.vue

@@ -27,148 +27,133 @@
 <template>
   <div class="system-container layout-padding">
     <el-card shadow="hover" class="layout-padding-auto">
-
-
-      <el-form
-          :model="state.formQuery"
+      <ext-query-form
+          class="page-search"
           ref="queryRef"
-          size="default" label-width="0px" class="mt5 mb5">
-        <el-input
-            v-model="state.formQuery.mobilePhone"
-            placeholder="用户手机号"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <el-input
-            v-model="state.formQuery.outTradeNo"
-            placeholder="商户订单号"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <el-input
-            v-model="state.formQuery.transactionId"
-            placeholder="微信订单号"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <!--        <el-input
-                    v-model="state.formQuery.tradeType"
-                    placeholder="交易类型,枚举值:JSAPI:公众号支付 NATIVE:扫码支付 APP:APP支付 MICROPAY:付款码支付 MWEB:H5支付 FACEPAY:刷脸支付"
-                    clearable
-                    @blur="loadData(true)"
-                    class="wd150 mr10">
-                </el-input>-->
-        <!--        <el-input
-                    v-model="state.formQuery.tradeState"
-                    placeholder="交易状态,枚举值:SUCCESS:支付成功REFUND:转入退款NOTPAY:未支付CLOSED:已关闭REVOKED:已撤销(付款码支付)USERPAYING:用户支付中(付款码支付)PAYERROR:支付失败(其他原因,如银行返回失败)"
-                    clearable
-                    @blur="loadData(true)"
-                    class="wd150 mr10">
-                </el-input>-->
-
-
-        <el-button class="ml10" plain size="default" type="success" @click="loadData(true)">
-          <SvgIcon name="ele-Search"/>
-          查询
-        </el-button>
-      </el-form>
-
-      <el-table
-          border
-          stripe="stripe"
+          v-model="state.formQuery"
+          :columns="state.columns"
+          :import-config="state.importConfig"
+          :export-config="state.exportConfig"
+          @on-change="loadData(true)"
+          @imported="loadData(true)">
+        <!--  <template #extraQuery></template>
+          <template #extraLeft></template>
+          <template #extraRight></template>-->
+      </ext-query-form>
+
+      <ext-table
+          class="page-content"
           :height="state.tableData.height"
-          highlight-current-row
-          current-row-key="id"
-          row-key="id"
-          :data="state.tableData.data"
-          v-loading="state.tableData.loading"
-          @selection-change="handleTableSelectionChange"
-          @sort-change="handleTableSortChange">
-        <template #empty>
-          <el-empty></el-empty>
-        </template>
-        <el-table-column
-            v-for="field in state.tableData.columns"
-            :key="field.prop"
-            :label="field.label"
-            :column-key="field.prop"
-            :width="field.width"
-            :min-width="field.minWidth"
-            :fixed="field.fixed"
-            :sortable="field.sortable"
-            :show-overflow-tooltip="!field.fixed&&field.width>150"
-        >
-          <template #default="{row}">
-            <template v-if="field.prop==='expand'">
-              <p style="padding-left: 2em;" v-html="row[field.prop]"></p>
-            </template>
-            <template v-if="field.prop==='rechargeAmount'">
-              {{u.fmt.fmtMoney(row[field.prop])}}
-            </template>
-            <template v-else>
-              <div>{{ row[field.prop] }}</div>
-            </template>
-
-          </template>
-        </el-table-column>
-      </el-table>
+          :data-list="state.tableData.data"
+          :columns="state.columns"
+          :border="true"
+          :loading="state.tableData.loading">
+      </ext-table>
 
       <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
     </el-card>
   </div>
+  <FeedbackDialog ref="feedbackDialogRef" @refresh="loadData(true)"/>
 </template>
 
-<script setup lang="ts" name="PayLogList">
-import {nextTick, onBeforeMount, onBeforeUnmount, onMounted, reactive, ref} from 'vue';
-import {$get} from "/@/utils/request";
+<script setup lang="ts" name="FeedbackList">
+import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance,nextTick,onBeforeUnmount} from 'vue';
+import {$body,$get} from "/@/utils/request";
+import u from '/@/utils/u'
 import {Msg} from "/@/utils/message";
-import u from "/@/utils/u"
+import {Session} from "/@/utils/storage";
+
+const {proxy}: any = getCurrentInstance();
 
-import {useRoute} from "vue-router";
 import ExtPage from '/@/components/form/ExtPage.vue'
+import ExtQueryForm from "/@/components/form/ExtQueryForm.vue";
+import ExtTable from "/@/components/form/ExtTable.vue";
 
 import mittBus from '/@/utils/mitt';
 
-const route = useRoute();
+import {ElButton} from 'element-plus'
+
 
+const FeedbackDialog = defineAsyncComponent(() => import("/@/views/admin/feedback/dialog.vue"));
 
 //定义引用
 const queryRef = ref();
-const payLogDialogRef = ref();
+const feedbackDialogRef = ref();
 
 //定义变量
 const state = reactive({
   formQuery: {},
   pageQuery: {
-    pageNum: 1,
+    pageIndex: 1,
     pageSize: 10,
     total: 0
   },
   tableData: {
-    height: 500,
-    data: [] as Array<any>,
-    loading: false,
-    columns: [
-      {label: '用户ID', prop: 'userId', width: 200, resizable: true, fixed: 'left'},
-      {label: '用户手机号', prop: 'mobilePhone', width: 150, resizable: true, fixed: 'left'},
-      {label: '商户订单号', prop: 'outTradeNo', width: 250, resizable: true},
-      {label: '微信订单号', prop: 'transactionId', width: 250, resizable: true},
-      {label: '订单总金额', prop: 'rechargeAmount', resizable: true, width: 130},
-      // {label: '交易类型', prop: 'tradeType', width: 150, resizable: true},
-      {label: '交易状态', prop: 'tradeState', width: 150, resizable: true},
-      {label: '用户支付币种', prop: 'currency', width: 150, resizable: true},
-      {label: '支付完成时间', prop: 'transactionTime', sortable: 'custom', resizable: true, width: 200, fixed: 'right'},
-    ],
+    height:500,
+    data: [] as Array < any >,
+    loading: false
   },
+  importConfig: {},
+  exportConfig: {},
+  columns: [
+    {type: 'selection', width: 60, align: 'center', fixed: 'left'},
+    {label: '详情描述', prop: 'content', query: true, type: 'text', resizable: true},
+    {label: '创建时间', prop: 'createTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '回复内容', prop: 'replyContent', query: true, type: 'text', resizable: true},
+    {label: '回复时间', prop: 'replyTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '状态', prop: 'status', sortable: 'custom', align: 'center', query: true, type: 'dict', conf: {dict: 'Feedback.status'}},
+    {label: '提交时间', prop: 'submitTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {
+      label: '反馈标题', prop: 'title', query: true, type: "text", resizable: true,
+      render: (h: any, row: any) => {
+        return h('div', null, [
+          h('div', {
+            style:{
+              cursor:'pointer',
+              color:'var(--el-color-primary-light-1)'
+            },
+            onClick: () => {
+              onRowClick('view', row)
+            }
+          }, row.name||row.title)])
+      }
+    },
+    {label: '纠错类型', prop: 'type', query: true, type: '', resizable: true},
+    {label: '更新时间', prop: 'updateTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {                label: '操作', prop: 'action', type: 'render', width: 180, align: 'center', fixed: 'right',
+      render: (h: any, row: any) => {
+        return (
+            h('div', null, [
+              proxy.$auth('feedback.modify') ?
+                  h(ElButton, {
+                    type: 'warning',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      onRowClick('edit', row)
+                    }
+                  }, () => '编辑') : '',
+              proxy.$auth('feedback.remove') ?
+                  h(ElButton, {
+                    type: 'danger',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      console.error("delxxxx", row)
+                      onRowDel(row)
+                    }
+                  }, () => '删除') : '',
+            ])
+        )
+      }
+    }
+  ],
 })
 
 
 // 监听双向绑定 modelValue 的变化
 // watch(
-//         () => state.pageNum,
+//         () => state.pageIndex,
 //         () => {
 //
 //         }
@@ -176,30 +161,36 @@ const state = reactive({
 
 //生命周期钩子
 onBeforeMount(() => {
+  let token = Session.get("token")
+  let encodeToken = encodeURIComponent(token)
+  let exportUrl = `poi/export?type=feedback&X-Token=${encodeToken}`
+  //导入导出参数配置
+  state.importConfig = {
+    auths: ['feedback.add'],
+    url: `poi/import?type=feedback&X-Token=${encodeToken}`,
+    template: `${exportUrl}&isTemplate=true`
+  }
+
+  state.exportConfig = {url: exportUrl,}
+
 })
 
 onMounted(() => {
-  var query = route.query;
-  console.log(route.params, route.query)
-  if (query.mobilePhone) {
-    state.formQuery.mobilePhone = query.mobilePhone;
-  }
-
   loadData();
 
-  nextTick(() => {
+  nextTick(()=>{
     let bodyHeight = document.body.clientHeight;
     let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 320
+    state.tableData.height = bodyHeight - queryHeight - 220
   })
 
-  mittBus.on("payLog.refresh", () => {
+  mittBus.on("feedback.refresh",()=>{
     loadData();
   })
 });
 
-onBeforeUnmount(() => {
-  mittBus.off("payLog.refresh")
+onBeforeUnmount(()=>{
+  mittBus.off("feedback.refresh")
 })
 
 
@@ -207,13 +198,13 @@ onBeforeUnmount(() => {
 // 初始化表格数据
 const loadData = (refresh: boolean = false) => {
   if (refresh) {
-    state.pageQuery.pageNum = 1;
+    state.pageQuery.pageIndex = 1;
   }
   state.tableData.loading = true;
-  $get(`/custom/listRecharge`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let {list, total} = res;
+  $body(`/feedback/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
+    let {list, count} = res;
     state.tableData.data = list;
-    state.pageQuery.total = total;
+    state.pageQuery.total = count;
     state.tableData.loading = false;
   }).catch(e => {
     console.error(e)
@@ -223,13 +214,12 @@ const loadData = (refresh: boolean = false) => {
 
 // 打开修改用户弹窗
 const onRowClick = (type: string, row: any) => {
-  payLogDialogRef.value.open(type, row);
+  feedbackDialogRef.value.open(type, row);
 };
-
 // 删除用户
 const onRowDel = (row: any) => {
   Msg.confirm(`此操作将永久删除:『${row.name}』,是否继续?`).then(() => {
-    $get(`/payLog/delete/${row.id}`).then(() => {
+    $get(`/feedback/delete/${row.id}`).then(() => {
       Msg.message("删除成功", 'success')
     }).catch(() => {
       Msg.message("删除失败", 'error')
@@ -237,17 +227,6 @@ const onRowDel = (row: any) => {
   });
 };
 
-const handleTableSelectionChange = (selection: any) => {
-  console.log("handleTableSelectionChange>>", selection)
-  // emit("on-check-change", selection)
-}
-
-const handleTableSortChange = (column, prop, order) => {
-  console.log("handleTableSortChange>>", column, prop, order)
-  // emit("on-sort-change", column)
-}
-
-
 //endregion
 
 
@@ -255,4 +234,4 @@ const handleTableSortChange = (column, prop, order) => {
 // defineExpose({
 //     loadData,
 // });
-</script>
+</script>

+ 395 - 0
admin-web/src/views/admin/ordering/dialog.vue

@@ -0,0 +1,395 @@
+<style scoped lang="scss">
+
+</style>
+<template>
+  <div class="system-dialog-container">
+    <el-dialog
+        :title="state.dialog.title"
+        v-model="state.dialog.isShowDialog"
+        width="820px"
+        draggable
+        destroy-on-close
+        :close-on-click-modal="false"
+        align-center>
+      <el-form
+          inline
+          :model="state.ruleForm"
+          :rules="rules"
+          label-position="top"
+          ref="formRef"
+          size="default"
+          label-width="100px"
+          class="mt5">
+        <el-form-item label="消费总额,等于各单项费用之和(单位分)" prop="amount">
+          <el-input
+              v-model="state.ruleForm.amount"
+              placeholder="消费总额,等于各单项费用之和(单位分)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="应收金额,如果大于预付金额,则限制为预付金额并关机,否则等于消费总金额(单位分)" prop="amountReceivable">
+          <el-input
+              v-model="state.ruleForm.amountReceivable"
+              placeholder="应收金额,如果大于预付金额,则限制为预付金额并关机,否则等于消费总金额(单位分)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="实收金额等于应收金额乘会员折扣(单位分)" prop="amountReceived">
+          <el-input
+              v-model="state.ruleForm.amountReceived"
+              placeholder="实收金额等于应收金额乘会员折扣(单位分)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="卡内余额(仅限刷储值卡的订单有效,普通卡为总是为0)" prop="cardBalance">
+          <el-input
+              v-model="state.ruleForm.cardBalance"
+              placeholder="卡内余额(仅限刷储值卡的订单有效,普通卡为总是为0)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="卡过期时间,从1970年开始的时间戳(仅限刷储值卡的订单有效,普通卡为总是为0)" prop="cardExpired">
+          <el-input
+              v-model="state.ruleForm.cardExpired"
+              placeholder="卡过期时间,从1970年开始的时间戳(仅限刷储值卡的订单有效,普通卡为总是为0)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="卡内码,卡出厂的时候厂家写入的ID(仅限刷卡订单)" prop="cardId">
+          <el-input
+              v-model="state.ruleForm.cardId"
+              placeholder="卡内码,卡出厂的时候厂家写入的ID(仅限刷卡订单)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="卡串号,印刷在卡的表面,通过电脑上的卡管理工具写入卡内。(仅限刷卡订单)" prop="cardSn">
+          <el-input
+              v-model="state.ruleForm.cardSn"
+              placeholder="卡串号,印刷在卡的表面,通过电脑上的卡管理工具写入卡内。(仅限刷卡订单)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="卡类型(仅限刷卡订单,1表示普通卡,2表示储值卡)" prop="cardType">
+          <el-input
+              v-model="state.ruleForm.cardType"
+              placeholder="卡类型(仅限刷卡订单,1表示普通卡,2表示储值卡)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="关机方式:button维护按钮,network网络命令,no_balance超过预设金额,idle_timeout设备空闲超时,operation_timeout操作超时,card刷卡。注意:为空表示还没有关机,正在使用" prop="closeType">
+          <el-input
+              v-model="state.ruleForm.closeType"
+              placeholder="关机方式:button维护按钮,network网络命令,no_balance超过预设金额,idle_timeout设备空闲超时,operation_timeout操作超时,card刷卡。注意:为空表示还没有关机,正在使用"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="投币的累计金额(仅限刷卡订单,单位分)" prop="coinMoney">
+          <el-input
+              v-model="state.ruleForm.coinMoney"
+              placeholder="投币的累计金额(仅限刷卡订单,单位分)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="投币的次数仅限刷卡订单" prop="coinNum">
+          <el-input
+              v-model="state.ruleForm.coinNum"
+              placeholder="投币的次数仅限刷卡订单"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="" prop="companyId">
+          <el-input
+              v-model="state.ruleForm.companyId"
+              placeholder=""
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="费用明细:name 名称 price 单价(单位分) seconds 时长(单位秒) amount 费用(单位分) space⻋位或场地,water清水,foam泡沫,cleaner吸尘,tap水龙头,user_ext用户扩展,消毒或吹干等功能,coat镀膜,blow吹气" prop="detail">
+          <el-input
+              v-model="state.ruleForm.detail"
+              placeholder="费用明细:name 名称 price 单价(单位分) seconds 时长(单位秒) amount 费用(单位分) space⻋位或场地,water清水,foam泡沫,cleaner吸尘,tap水龙头,user_ext用户扩展,消毒或吹干等功能,coat镀膜,blow吹气"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="设备名称" prop="deviceName">
+          <el-input
+              v-model="state.ruleForm.deviceName"
+              placeholder="设备名称"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="优惠金额(分)" prop="discountAmount">
+          <el-input
+              v-model="state.ruleForm.discountAmount"
+              placeholder="优惠金额(分)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="优惠金额等于消费总额减去实收金额(单位分)" prop="discountMoney">
+          <el-input
+              v-model="state.ruleForm.discountMoney"
+              placeholder="优惠金额等于消费总额减去实收金额(单位分)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="优惠方式:RechargeRights-充值权益 Coupon-优惠券" prop="discountType">
+          <el-input
+              v-model="state.ruleForm.discountType"
+              placeholder="优惠方式:RechargeRights-充值权益 Coupon-优惠券"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="结束时间" prop="endTime">
+          <el-input
+              v-model="state.ruleForm.endTime"
+              placeholder="结束时间"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="设备空闲关机倒计时剩余时间(单位秒),开机后从idle_timeout开始每秒减1,见到0关机,关机原因close_type=idle_time(递减过程中按任意功能键,重新开始从idle_timeout递减)" prop="idleRemainTime">
+          <el-input
+              v-model="state.ruleForm.idleRemainTime"
+              placeholder="设备空闲关机倒计时剩余时间(单位秒),开机后从idle_timeout开始每秒减1,见到0关机,关机原因close_type=idle_time(递减过程中按任意功能键,重新开始从idle_timeout递减)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="发票id" prop="invoiceId">
+          <el-input
+              v-model="state.ruleForm.invoiceId"
+              placeholder="发票id"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="发票状态:0-待开票 1-已开票 2-已作废(用不上) 3-开票中" prop="invoiceStatus">
+          <el-input
+              v-model="state.ruleForm.invoiceStatus"
+              placeholder="发票状态:0-待开票 1-已开票 2-已作废(用不上) 3-开票中"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="会员折扣比例(0-100,100表示不享受折扣,95表示9.5折优惠)" prop="memberDiscount">
+          <el-input
+              v-model="state.ruleForm.memberDiscount"
+              placeholder="会员折扣比例(0-100,100表示不享受折扣,95表示9.5折优惠)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="开机方式:button维护按钮,network网络命令,coin投币,card刷卡" prop="openType">
+          <el-input
+              v-model="state.ruleForm.openType"
+              placeholder="开机方式:button维护按钮,network网络命令,coin投币,card刷卡"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="订单操作剩余操作时间(单位秒),开机后从operation_timeout开始每秒减1,减到0关机,关机原因close_type=operation_timeout" prop="operationRemainTime">
+          <el-input
+              v-model="state.ruleForm.operationRemainTime"
+              placeholder="订单操作剩余操作时间(单位秒),开机后从operation_timeout开始每秒减1,减到0关机,关机原因close_type=operation_timeout"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="订单号,和开机命令的order_id相同,如果使用按钮快速开机,order_id是空字符串" prop="orderId">
+          <el-input
+              v-model="state.ruleForm.orderId"
+              placeholder="订单号,和开机命令的order_id相同,如果使用按钮快速开机,order_id是空字符串"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="本机订单号" prop="orderIdLocal">
+          <el-input
+              v-model="state.ruleForm.orderIdLocal"
+              placeholder="本机订单号"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="订单状态:-1:未知,0-开机,1:成功,2:失败,3:取消" prop="orderStatus">
+          <el-input
+              v-model="state.ruleForm.orderStatus"
+              placeholder="订单状态:-1:未知,0-开机,1:成功,2:失败,3:取消"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="支付状态:0:未支付,1:已支付" prop="payStatus">
+          <el-input
+              v-model="state.ruleForm.payStatus"
+              placeholder="支付状态:0:未支付,1:已支付"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="本次开机的预付金额(单位分,本次开机最大消费金额限制)" prop="prepayMoney">
+          <el-input
+              v-model="state.ruleForm.prepayMoney"
+              placeholder="本次开机的预付金额(单位分,本次开机最大消费金额限制)"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="产品key" prop="productKey">
+          <el-input
+              v-model="state.ruleForm.productKey"
+              placeholder="产品key"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="开始时间" prop="startTime">
+          <el-input
+              v-model="state.ruleForm.startTime"
+              placeholder="开始时间"
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="" prop="stationId">
+          <el-input
+              v-model="state.ruleForm.stationId"
+              placeholder=""
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="" prop="stopReason">
+          <el-input
+              v-model="state.ruleForm.stopReason"
+              placeholder=""
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="" prop="userId">
+          <el-input
+              v-model="state.ruleForm.userId"
+              placeholder=""
+              clearable
+              class="wd350">
+          </el-input>
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+				<span class="dialog-footer">
+					<el-button @click="onCancel" size="default">取 消</el-button>
+					<el-button :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
+				</span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts" name="WashOrderDialog">
+import {defineAsyncComponent, reactive, onMounted, ref} from 'vue';
+import {Msg} from "/@/utils/message";
+import {$body, $get} from "/@/utils/request";
+import u from '/@/utils/u'
+
+// 引入组件
+const ExtDetailForm = defineAsyncComponent(() => import('/@/components/form/ExtDetailForm.vue'));
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['refresh']);
+const formRef = ref();
+//定义初始变量,重置使用
+const initState = () => ({
+  ruleForm: {
+    id: 0
+  },
+  btnLoading: false,
+  dialog: {
+    isShowDialog: false,
+    type: '',
+    title: '',
+    submitTxt: '',
+  },
+  rules: {},
+})
+
+// 定义变量内容
+const state = reactive(initState());
+
+
+// 打开弹窗
+const open = (action: string = 'add', row: any) => {
+  state.dialog.title = u.dialog.actions[action].title + "『洗车订单表』"
+  state.dialog.submitTxt = u.dialog.actions[action].btn + "『洗车订单表』"
+  state.dialog.isShowDialog = true;
+  if (action !== 'add') {
+    loadData(row.id);
+  } else {
+    state.ruleForm = Object.assign(state.ruleForm, row);
+  }
+};
+// 关闭弹窗
+const onClose = () => {
+  state.dialog.isShowDialog = false;
+  Object.assign(state, initState())
+};
+// 取消
+const onCancel = () => {
+  onClose();
+};
+// 提交
+const onSubmit = () => {
+  formRef.value.validate((v: boolean) => {
+    if (v) {
+      state.btnLoading = true;
+      const url = state.ruleForm.id > 0 ? "washOrder/modify" : "washOrder/add"
+      $body(url, state.ruleForm).then(() => {
+        state.btnLoading = false;
+        Msg.message('操作成功');
+        console.log('submit!')
+        onClose();
+        emit('refresh');
+      })
+    } else {
+      state.btnLoading = false;
+      Msg.message('请先完整填写表单', 'error');
+    }
+  })
+};
+
+const handleFormChange = (formData: any) => {
+  console.log(formData)
+}
+
+// 初始化数据
+const loadData = (id: number) => {
+  $get(`washOrder/detail/${id}`).then((res: any) => {
+    state.ruleForm = res;
+  })
+}
+
+// 暴露变量
+defineExpose({
+  open
+});
+
+
+</script>

+ 131 - 299
admin-web/src/views/admin/ordering/index.vue

@@ -27,298 +27,142 @@
 <template>
   <div class="system-container layout-padding">
     <el-card shadow="hover" class="layout-padding-auto">
-
-
-      <el-form
-          :model="state.formQuery"
+      <ext-query-form
+          class="page-search"
           ref="queryRef"
-          size="default" label-width="0px" class="mt5 mb5">
-        <el-input
-            v-model="state.formQuery.mobilePhone"
-            placeholder="用户手机号"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <ext-select
-            v-model="state.formQuery.stationId"
-            placeholder="站点"
-            clearable
-            url="station/listStation"
-            urlMethod="get"
-            data-key=""
-            label-key="stationName"
-            value-key="stationId"
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-        </ext-select>
-        <el-input
-            v-model="state.formQuery.startChargeSeq"
-            placeholder="充电订单号"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <el-input
-            v-model="state.formQuery.connectorId"
-            placeholder="充电设备接口编码"
-            clearable
-            @blur="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-        <el-date-picker
-            v-model="state.formQuery.startDate"
-            placeholder="开始时间"
-            type="date"
-            value-format="YYYY-MM-DD"
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-        </el-date-picker>
-        <el-date-picker
-            v-model="state.formQuery.endDate"
-            placeholder="结束时间"
-            type="date"
-            value-format="YYYY-MM-DD"
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-        </el-date-picker>
-        <ext-d-select
-            v-model="state.formQuery.orderStatus"
-            type="ChargeOrder.orderStatus"
-            placeholder="订单状态"
-            clearable
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-        <ext-d-select
-            v-model="state.formQuery.chargeStatus"
-            placeholder="充电状态"
-            clearable
-            type="ChargeOrder.chargeStatus"
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-        <!--        <ext-d-select-->
-        <!--            v-model="state.formQuery.stopReason"-->
-        <!--            placeholder="充电停止原因"-->
-        <!--            clearable-->
-        <!--            type="ChargeOrder.stopReason"-->
-        <!--            @blur="loadData(true)"-->
-        <!--            class="wd150 mr10">-->
-        <!--        </ext-d-select>-->
-        <ext-d-select
-            v-model="state.formQuery.invoiceStatus"
-            placeholder="发票状态"
-            clearable
-            type="ChargeOrder.invoiceStatus"
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-        </ext-d-select>
-
-
-        <el-button class="ml10" plain size="default" type="success" @click="loadData(true)">
-          <SvgIcon name="ele-Search"/>
-          查询
-        </el-button>
-      </el-form>
-
-      <el-card class="w100">
-        <div class="order-summary">
-          <span>订单笔数:</span>
-          <el-tag type="success">{{ state.extraData.totalOrders }} 笔</el-tag>
-          <span class="ml5">电量:</span>
-          <el-tag type="success">{{ state.extraData.totalPower }} 度</el-tag>
-          <span class="ml5">订单金额:</span>
-          <el-tag type="success">{{ u.fmt.fmtMoney(state.extraData.totalMoney) }} 元</el-tag>
-          <span class="ml5"> 电费:</span>
-          <el-tag type="success">{{ u.fmt.fmtMoney(state.extraData.elecMoney) }} 元</el-tag>
-          <span class="ml5">服务费:</span>
-          <el-tag type="success">{{ u.fmt.fmtMoney(state.extraData.serviceMoney) }} 元</el-tag>
-          <span class="ml5">服务费优惠:</span>
-          <el-tag type="success">{{ u.fmt.fmtMoney(state.extraData.serviceMoneyDiscount) }} 元</el-tag>
-          <span class="ml5">实付服务费:</span>
-          <el-tag type="success">{{ u.fmt.fmtMoney(state.extraData.payServiceAmount) }} 元</el-tag>
-        </div>
-
-      </el-card>
-
-      <el-table
-          border
-          stripe="stripe"
+          v-model="state.formQuery"
+          :columns="state.columns"
+          :import-config="state.importConfig"
+          :export-config="state.exportConfig"
+          @on-change="loadData(true)"
+          @imported="loadData(true)">
+        <!--  <template #extraQuery></template>
+          <template #extraLeft></template>
+          <template #extraRight></template>-->
+      </ext-query-form>
+
+      <ext-table
+          class="page-content"
           :height="state.tableData.height"
-          highlight-current-row
-          current-row-key="id"
-          row-key="id"
-          :data="state.tableData.data"
-          v-loading="state.tableData.loading"
-          @selection-change="handleTableSelectionChange"
-          @sort-change="handleTableSortChange">
-        <template #empty>
-          <el-empty></el-empty>
-        </template>
-        <el-table-column
-            v-for="field in state.tableData.columns"
-            :key="field.prop"
-            :label="field.label"
-            :align="field.align||'left'"
-            :column-key="field.prop"
-            :width="field.width"
-            :min-width="field.minWidth"
-            :fixed="field.fixed"
-            :sortable="field.sortable"
-            :show-overflow-tooltip="!field.fixed&&field.width>150"
-        >
-          <template #default="{row}">
-            <template v-if="field.prop==='expand'">
-              <p style="padding-left: 2em;" v-html="row[field.prop]"></p>
-            </template>
-            <template v-else-if="'totalMoney'===field.prop">
-              {{ u.fmt.fmtMoney(row[field.prop]) }}
-            </template>
-            <template v-else-if="'elecMoney'===field.prop">
-              {{ u.fmt.fmtMoney(row[field.prop]) }}
-            </template>
-            <template v-else-if="'serviceMoney'===field.prop">
-              {{ u.fmt.fmtMoney(row[field.prop]) }}
-            </template>
-            <template v-else-if="'payAmount'===field.prop">
-              {{ u.fmt.fmtMoney(row[field.prop]) }}
-            </template>
-            <template v-else-if="'discountAmount'===field.prop">
-              {{ u.fmt.fmtMoney(row[field.prop]) }}
-            </template>
-            <template v-else-if="'serviceMoneyDiscount'===field.prop">
-              {{ u.fmt.fmtMoney(row[field.prop]) }}
-            </template>
-            <template v-else-if="'payServiceAmount'===field.prop">
-              {{ u.fmt.fmtMoney(row[field.prop]) }}
-            </template>
-            <template v-else-if="'orderStatus'===field.prop">
-              <ext-d-label type="ChargeOrder.orderStatus" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'chargeStatus'===field.prop">
-              <ext-d-label type="ChargeOrder.chargeStatus" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'stopReason'===field.prop">
-              <ext-d-label type="ChargeOrder.stopReason" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'invoiceStatus'===field.prop">
-              <ext-d-label type="ChargeOrder.invoiceStatus" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'startTime'===field.prop">
-              <div title="充电开始时间">
-                {{ (row.startTime) }}
-              </div>
-              <hr>
-              <div title="充电结束时间">
-                {{ (row.endTime) }}
-              </div>
-            </template>
-
-            <template v-else-if="'stationId'===field.prop">
-              <div >
-                {{ (row.stationId) }}
-              </div>
-              <hr v-if="row.stationName">
-              <div >
-                {{ (row.stationName) }}
-              </div>
-            </template>
-
-            <template v-else>
-              <div>{{ row[field.prop] }}</div>
-            </template>
-
-          </template>
-        </el-table-column>
-      </el-table>
+          :data-list="state.tableData.data"
+          :columns="state.columns"
+          :border="true"
+          :loading="state.tableData.loading">
+      </ext-table>
 
       <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
     </el-card>
   </div>
-  <!--  <ChargeOrderDialog ref="chargeOrderDialogRef" @refresh="loadData(true)"/>-->
+  <WashOrderDialog ref="washOrderDialogRef" @refresh="loadData(true)"/>
 </template>
 
-<script setup lang="ts" name="ChargeOrderList">
-import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance, nextTick, onBeforeUnmount} from 'vue';
-import {$body, $get} from "/@/utils/request";
+<script setup lang="ts" name="WashOrderList">
+import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance,nextTick,onBeforeUnmount} from 'vue';
+import {$body,$get} from "/@/utils/request";
+import u from '/@/utils/u'
 import {Msg} from "/@/utils/message";
-import u from "/@/utils/u"
+import {Session} from "/@/utils/storage";
 
-import {useRoute} from "vue-router";
-
-const route = useRoute();
+const {proxy}: any = getCurrentInstance();
 
 import ExtPage from '/@/components/form/ExtPage.vue'
+import ExtQueryForm from "/@/components/form/ExtQueryForm.vue";
+import ExtTable from "/@/components/form/ExtTable.vue";
 
 import mittBus from '/@/utils/mitt';
-import ExtDatePicker from "/@/components/form/ExtDatePicker.vue";
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtDLabel from "/@/components/form/ExtDLabel.vue";
-import ExtSelect from "/@/components/form/ExtSelect.vue";
 
-// const ChargeOrderDialog = defineAsyncComponent(() => import("/@/views/page/ChargeOrderDialog.vue"));
+import {ElButton} from 'element-plus'
+
+
+const WashOrderDialog = defineAsyncComponent(() => import("/@/views/page/WashOrderDialog.vue"));
 
 //定义引用
 const queryRef = ref();
-const chargeOrderDialogRef = ref();
+const washOrderDialogRef = ref();
 
 //定义变量
 const state = reactive({
   formQuery: {},
   pageQuery: {
-    pageNum: 1,
+    pageIndex: 1,
     pageSize: 10,
     total: 0
   },
   tableData: {
-    height: 500,
-    data: [] as Array<any>,
-    loading: false,
-    columns: [
-      {label: '站点ID/名称', prop: 'stationId', width: 130,align:'center', resizable: true, fixed: 'left'},
-      {label: '用户手机号', prop: 'mobilePhone', width: 120, resizable: true, fixed: 'left'},
-      // {label: '站点ID',  prop: 'stationId',width:100, resizable: true, fixed: 'left'},
-      // {label: '站点', prop: 'stationName', width: 150, resizable: true, fixed: 'left'},
-      {label: '充电订单号', prop: 'startChargeSeq', width: 170, resizable: true, fixed: 'left'},
-      {label: '设备编号', prop: 'shortId', width: 90, resizable: true},
-      {label: '充电设备接口编码', prop: 'connectorId', width: 160, resizable: true},
-      {label: '充电开始/结束时间', prop: 'startTime', sortable: 'custom', width: 175, resizable: true},
-      // {label: '充电结束时间', prop: 'endTime', sortable: 'custom', width: 160, resizable: true},
-      {label: '充电量/度', prop: 'totalPower', width: 95, resizable: true},
-      {label: '订单总金额', prop: 'totalMoney', width: 105, resizable: true},
-      {label: '服务费优惠', prop: 'serviceMoneyDiscount', width: 105, resizable: true},
-      {label: '实付金额', prop: 'payAmount', width: 90, resizable: true},
-      {label: '总电费', prop: 'elecMoney', width: 80, resizable: true},
-      {label: '总服务费', prop: 'serviceMoney', width: 90, resizable: true},
-      {label: '实付服务费', prop: 'payServiceAmount', width: 105, resizable: true},
-      // {label: '时段数:0~32', prop: 'sumPeriod', width:150, resizable: true},
-      // {label: '充电明细信息', prop: 'chargeDetail', width:150, resizable: true},
-      {label: '订单状态', prop: 'orderStatus', width: 90, resizable: true},
-      {label: '充电状态', prop: 'chargeStatus', width: 90, resizable: true},
-      {label: '充电停止原因', prop: 'stopReason', width: 120, resizable: true},
-      {label: '发票状态', prop: 'invoiceStatus', width: 90, resizable: true},
-      // {label: '创建时间', prop: 'createTime', sortable: 'custom', width:150, resizable: true},
-      // {label: '更新时间', prop: 'updateTime', sortable: 'custom',width:150,  resizable: true},
-      // {
-      //   label: '操作', prop: 'action', width: 180, align: 'center', fixed: 'right',
-      // }
-    ],
-
+    height:500,
+    data: [] as Array < any >,
+    loading: false
   },
-  extraData: {
-    totalOrders: 0,
-    totalPower: 0,
-    elecMoney: 0,
-    serviceMoney: 0,
-    totalMoney: 0,
-  }
+  importConfig: {},
+  exportConfig: {},
+  columns: [
+    {type: 'selection', width: 60, align: 'center', fixed: 'left'},
+    {label: '消费总额,等于各单项费用之和(单位分)', prop: 'amount', query: true, type: '', resizable: true},
+    {label: '应收金额,如果大于预付金额,则限制为预付金额并关机,否则等于消费总金额(单位分)', prop: 'amountReceivable', query: true, type: '', resizable: true},
+    {label: '实收金额等于应收金额乘会员折扣(单位分)', prop: 'amountReceived', query: true, type: '', resizable: true},
+    {label: '卡内余额(仅限刷储值卡的订单有效,普通卡为总是为0)', prop: 'cardBalance', query: true, type: '', resizable: true},
+    {label: '卡过期时间,从1970年开始的时间戳(仅限刷储值卡的订单有效,普通卡为总是为0)', prop: 'cardExpired', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '卡内码,卡出厂的时候厂家写入的ID(仅限刷卡订单)', prop: 'cardId', query: true, type: 'text', resizable: true},
+    {label: '卡串号,印刷在卡的表面,通过电脑上的卡管理工具写入卡内。(仅限刷卡订单)', prop: 'cardSn', query: true, type: 'text', resizable: true},
+    {label: '卡类型(仅限刷卡订单,1表示普通卡,2表示储值卡)', prop: 'cardType', query: true, type: '', resizable: true},
+    {label: '关机方式:button维护按钮,network网络命令,no_balance超过预设金额,idle_timeout设备空闲超时,operation_timeout操作超时,card刷卡。注意:为空表示还没有关机,正在使用', prop: 'closeType', query: true, type: 'text', resizable: true},
+    {label: '投币的累计金额(仅限刷卡订单,单位分)', prop: 'coinMoney', query: true, type: '', resizable: true},
+    {label: '投币的次数仅限刷卡订单', prop: 'coinNum', query: true, type: '', resizable: true},
+    {label: '', prop: 'createTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '费用明细:name 名称 price 单价(单位分) seconds 时长(单位秒) amount 费用(单位分) space⻋位或场地,water清水,foam泡沫,cleaner吸尘,tap水龙头,user_ext用户扩展,消毒或吹干等功能,coat镀膜,blow吹气', prop: 'detail', query: true, type: 'text', resizable: true},
+    {label: '设备名称', prop: 'deviceName', query: true, type: 'text', resizable: true},
+    {label: '优惠金额(分)', prop: 'discountAmount', query: true, type: '', resizable: true},
+    {label: '优惠金额等于消费总额减去实收金额(单位分)', prop: 'discountMoney', query: true, type: '', resizable: true},
+    {label: '优惠方式:RechargeRights-充值权益 Coupon-优惠券', prop: 'discountType', query: true, type: 'text', resizable: true},
+    {label: '结束时间', prop: 'endTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '设备空闲关机倒计时剩余时间(单位秒),开机后从idle_timeout开始每秒减1,见到0关机,关机原因close_type=idle_time(递减过程中按任意功能键,重新开始从idle_timeout递减)', prop: 'idleRemainTime', query: true, type: '', resizable: true},
+    {label: '发票状态:0-待开票 1-已开票 2-已作废(用不上) 3-开票中', prop: 'invoiceStatus', query: true, type: '', resizable: true},
+    {label: '会员折扣比例(0-100,100表示不享受折扣,95表示9.5折优惠)', prop: 'memberDiscount', query: true, type: '', resizable: true},
+    {label: '开机方式:button维护按钮,network网络命令,coin投币,card刷卡', prop: 'openType', query: true, type: 'text', resizable: true},
+    {label: '订单操作剩余操作时间(单位秒),开机后从operation_timeout开始每秒减1,减到0关机,关机原因close_type=operation_timeout', prop: 'operationRemainTime', query: true, type: '', resizable: true},
+    {label: '订单号,和开机命令的order_id相同,如果使用按钮快速开机,order_id是空字符串', prop: 'orderId', query: true, type: 'text', resizable: true},
+    {label: '本机订单号', prop: 'orderIdLocal', query: true, type: 'text', resizable: true},
+    {label: '订单状态:-1:未知,0-开机,1:成功,2:失败,3:取消', prop: 'orderStatus', query: true, type: '', resizable: true},
+    {label: '支付状态:0:未支付,1:已支付', prop: 'payStatus', query: true, type: '', resizable: true},
+    {label: '本次开机的预付金额(单位分,本次开机最大消费金额限制)', prop: 'prepayMoney', query: true, type: '', resizable: true},
+    {label: '产品key', prop: 'productKey', query: true, type: 'text', resizable: true},
+    {label: '开始时间', prop: 'startTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '', prop: 'stationId', query: true, type: 'text', resizable: true},
+    {label: '', prop: 'stopReason', query: true, type: 'text', resizable: true},
+    {label: '', prop: 'updateTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {                label: '操作', prop: 'action', type: 'render', width: 180, align: 'center', fixed: 'right',
+      render: (h: any, row: any) => {
+        return (
+            h('div', null, [
+              proxy.$auth('washOrder.modify') ?
+                  h(ElButton, {
+                    type: 'warning',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      handleRowClick('edit', row)
+                    }
+                  }, () => '编辑') : '',
+              proxy.$auth('washOrder.remove') ?
+                  h(ElButton, {
+                    type: 'danger',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      handleRowDelete(row)
+                    }
+                  }, () => '删除') : '',
+            ])
+        )
+      }
+    }
+  ],
 })
 
 
 // 监听双向绑定 modelValue 的变化
 // watch(
-//         () => state.pageNum,
+//         () => state.pageIndex,
 //         () => {
 //
 //         }
@@ -326,35 +170,36 @@ const state = reactive({
 
 //生命周期钩子
 onBeforeMount(() => {
-})
-
-onMounted(() => {
-  var query = route.query;
-  console.log(route.params, route.query)
-  if (query.connectorId) {
-    state.formQuery.connectorId = query.connectorId;
+  let token = Session.get("token")
+  let encodeToken = encodeURIComponent(token)
+  let exportUrl = `poi/export?type=washOrder&X-Token=${encodeToken}`
+  //导入导出参数配置
+  state.importConfig = {
+    auths: ['washOrder.add'],
+    url: `poi/import?type=washOrder&X-Token=${encodeToken}`,
+    template: `${exportUrl}&isTemplate=true`
   }
 
-  if (query.mobilePhone) {
-    state.formQuery.mobilePhone = query.mobilePhone;
-  }
+  state.exportConfig = {url: exportUrl,}
+
+})
 
+onMounted(() => {
   loadData();
 
-  nextTick(() => {
+  nextTick(()=>{
     let bodyHeight = document.body.clientHeight;
     let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 320
-    // state.tableData.height =300
+    state.tableData.height = bodyHeight - queryHeight - 220
   })
 
-  mittBus.on("chargeOrder.refresh", () => {
+  mittBus.on("washOrder.refresh",()=>{
     loadData();
   })
 });
 
-onBeforeUnmount(() => {
-  mittBus.off("chargeOrder.refresh")
+onBeforeUnmount(()=>{
+  mittBus.off("washOrder.refresh")
 })
 
 
@@ -362,14 +207,13 @@ onBeforeUnmount(() => {
 // 初始化表格数据
 const loadData = (refresh: boolean = false) => {
   if (refresh) {
-    state.pageQuery.pageNum = 1;
+    state.pageQuery.pageIndex = 1;
   }
   state.tableData.loading = true;
-  $get(`/custom/listChargeOrders`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let {list, total, extraData} = res;
-    state.extraData = extraData;
+  $body(`/washOrder/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
+    let {list, count} = res;
     state.tableData.data = list;
-    state.pageQuery.total = total;
+    state.pageQuery.total = count;
     state.tableData.loading = false;
   }).catch(e => {
     console.error(e)
@@ -377,15 +221,14 @@ const loadData = (refresh: boolean = false) => {
   })
 };
 
-// 打开修改用户弹窗
-const onRowClick = (type: string, row: any) => {
-  chargeOrderDialogRef.value.open(type, row);
+// 打开详情页弹窗
+const handleRowClick = (type: string, row: any) => {
+  washOrderDialogRef.value.open(type, row);
 };
-
-// 删除用户
-const onRowDel = (row: any) => {
+// 删除点击
+const handleRowDelete = (row: any) => {
   Msg.confirm(`此操作将永久删除:『${row.name}』,是否继续?`).then(() => {
-    $get(`/chargeOrder/delete/${row.id}`).then(() => {
+    $get(`/washOrder/delete/${row.id}`).then(() => {
       Msg.message("删除成功", 'success')
     }).catch(() => {
       Msg.message("删除失败", 'error')
@@ -393,17 +236,6 @@ const onRowDel = (row: any) => {
   });
 };
 
-const handleTableSelectionChange = (selection: any) => {
-  console.log("handleTableSelectionChange>>", selection)
-  // emit("on-check-change", selection)
-}
-
-const handleTableSortChange = (column, prop, order) => {
-  console.log("handleTableSortChange>>", column, prop, order)
-  // emit("on-sort-change", column)
-}
-
-
 //endregion
 
 
@@ -411,4 +243,4 @@ const handleTableSortChange = (column, prop, order) => {
 // defineExpose({
 //     loadData,
 // });
-</script>
+</script>

+ 0 - 107
admin-web/src/views/admin/security/blackWhite/index.vue

@@ -1,107 +0,0 @@
-<template>
-	<div class="fun-tagsview layout-pd">
-		<NoticeBar
-			text="已删除非当前页 tagsView 演示,后续有时间可以再加回来!,tagsview 支持多标签(参数不同)、单标签共用(参数不同)"
-			background="#ecf5ff"
-			color="#409eff"
-		/>
-		<el-card shadow="hover" header="tagsView 当前页演示" class="mt15">
-			<div class="flex-warp">
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="primary" size="default" @click="refreshCurrentTagsView">
-							<el-icon>
-								<ele-RefreshRight />
-							</el-icon>
-							刷新当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="info" size="default" @click="closeCurrentTagsView">
-							<el-icon>
-								<ele-Close />
-							</el-icon>
-							关闭当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="warning" size="default" @click="closeOtherTagsView">
-							<el-icon>
-								<ele-CircleClose />
-							</el-icon>
-							关闭其它
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="danger" size="default" @click="closeAllTagsView">
-							<el-icon>
-								<ele-FolderDelete />
-							</el-icon>
-							全部关闭
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="success" size="default" @click="openCurrenFullscreen">
-							<el-icon>
-								<ele-FullScreen />
-							</el-icon>
-							当前页全屏
-						</el-button>
-					</div>
-				</div>
-			</div>
-		</el-card>
-	</div>
-</template>
-
-<script setup lang="ts" name="funTagsView">
-import { defineAsyncComponent } from 'vue';
-import { useRoute } from 'vue-router';
-import mittBus from '/@/utils/mitt';
-
-// 引入组件
-const NoticeBar = defineAsyncComponent(() => import('/@/components/noticeBar/index.vue'));
-
-// 定义变量内容
-const route = useRoute();
-
-// 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
-// 1、刷新当前 tagsView
-const refreshCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 0, ...route }));
-};
-// 2、关闭当前 tagsView
-const closeCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
-};
-// 3、关闭其它 tagsView
-const closeOtherTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 2, ...route }));
-};
-// 4、关闭全部 tagsView
-const closeAllTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 3, ...route }));
-};
-// 5、开启当前页面全屏
-const openCurrenFullscreen = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 4, ...route }));
-};
-</script>
-
-<style scoped lang="scss">
-.fun-tagsview {
-	.fun-tagsview-from-item {
-		:deep(.el-form-item__content) {
-			margin-left: 0 !important;
-		}
-	}
-}
-</style>

+ 0 - 107
admin-web/src/views/admin/security/dashboard/index.vue

@@ -1,107 +0,0 @@
-<template>
-	<div class="fun-tagsview layout-pd">
-		<NoticeBar
-			text="已删除非当前页 tagsView 演示,后续有时间可以再加回来!,tagsview 支持多标签(参数不同)、单标签共用(参数不同)"
-			background="#ecf5ff"
-			color="#409eff"
-		/>
-		<el-card shadow="hover" header="tagsView 当前页演示" class="mt15">
-			<div class="flex-warp">
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="primary" size="default" @click="refreshCurrentTagsView">
-							<el-icon>
-								<ele-RefreshRight />
-							</el-icon>
-							刷新当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="info" size="default" @click="closeCurrentTagsView">
-							<el-icon>
-								<ele-Close />
-							</el-icon>
-							关闭当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="warning" size="default" @click="closeOtherTagsView">
-							<el-icon>
-								<ele-CircleClose />
-							</el-icon>
-							关闭其它
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="danger" size="default" @click="closeAllTagsView">
-							<el-icon>
-								<ele-FolderDelete />
-							</el-icon>
-							全部关闭
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="success" size="default" @click="openCurrenFullscreen">
-							<el-icon>
-								<ele-FullScreen />
-							</el-icon>
-							当前页全屏
-						</el-button>
-					</div>
-				</div>
-			</div>
-		</el-card>
-	</div>
-</template>
-
-<script setup lang="ts" name="funTagsView">
-import { defineAsyncComponent } from 'vue';
-import { useRoute } from 'vue-router';
-import mittBus from '/@/utils/mitt';
-
-// 引入组件
-const NoticeBar = defineAsyncComponent(() => import('/@/components/noticeBar/index.vue'));
-
-// 定义变量内容
-const route = useRoute();
-
-// 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
-// 1、刷新当前 tagsView
-const refreshCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 0, ...route }));
-};
-// 2、关闭当前 tagsView
-const closeCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
-};
-// 3、关闭其它 tagsView
-const closeOtherTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 2, ...route }));
-};
-// 4、关闭全部 tagsView
-const closeAllTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 3, ...route }));
-};
-// 5、开启当前页面全屏
-const openCurrenFullscreen = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 4, ...route }));
-};
-</script>
-
-<style scoped lang="scss">
-.fun-tagsview {
-	.fun-tagsview-from-item {
-		:deep(.el-form-item__content) {
-			margin-left: 0 !important;
-		}
-	}
-}
-</style>

+ 0 - 107
admin-web/src/views/admin/security/highIp/index.vue

@@ -1,107 +0,0 @@
-<template>
-	<div class="fun-tagsview layout-pd">
-		<NoticeBar
-			text="已删除非当前页 tagsView 演示,后续有时间可以再加回来!,tagsview 支持多标签(参数不同)、单标签共用(参数不同)"
-			background="#ecf5ff"
-			color="#409eff"
-		/>
-		<el-card shadow="hover" header="tagsView 当前页演示" class="mt15">
-			<div class="flex-warp">
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="primary" size="default" @click="refreshCurrentTagsView">
-							<el-icon>
-								<ele-RefreshRight />
-							</el-icon>
-							刷新当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="info" size="default" @click="closeCurrentTagsView">
-							<el-icon>
-								<ele-Close />
-							</el-icon>
-							关闭当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="warning" size="default" @click="closeOtherTagsView">
-							<el-icon>
-								<ele-CircleClose />
-							</el-icon>
-							关闭其它
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="danger" size="default" @click="closeAllTagsView">
-							<el-icon>
-								<ele-FolderDelete />
-							</el-icon>
-							全部关闭
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="success" size="default" @click="openCurrenFullscreen">
-							<el-icon>
-								<ele-FullScreen />
-							</el-icon>
-							当前页全屏
-						</el-button>
-					</div>
-				</div>
-			</div>
-		</el-card>
-	</div>
-</template>
-
-<script setup lang="ts" name="funTagsView">
-import { defineAsyncComponent } from 'vue';
-import { useRoute } from 'vue-router';
-import mittBus from '/@/utils/mitt';
-
-// 引入组件
-const NoticeBar = defineAsyncComponent(() => import('/@/components/noticeBar/index.vue'));
-
-// 定义变量内容
-const route = useRoute();
-
-// 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
-// 1、刷新当前 tagsView
-const refreshCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 0, ...route }));
-};
-// 2、关闭当前 tagsView
-const closeCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
-};
-// 3、关闭其它 tagsView
-const closeOtherTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 2, ...route }));
-};
-// 4、关闭全部 tagsView
-const closeAllTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 3, ...route }));
-};
-// 5、开启当前页面全屏
-const openCurrenFullscreen = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 4, ...route }));
-};
-</script>
-
-<style scoped lang="scss">
-.fun-tagsview {
-	.fun-tagsview-from-item {
-		:deep(.el-form-item__content) {
-			margin-left: 0 !important;
-		}
-	}
-}
-</style>

+ 0 - 107
admin-web/src/views/admin/security/keyword/index.vue

@@ -1,107 +0,0 @@
-<template>
-	<div class="fun-tagsview layout-pd">
-		<NoticeBar
-			text="已删除非当前页 tagsView 演示,后续有时间可以再加回来!,tagsview 支持多标签(参数不同)、单标签共用(参数不同)"
-			background="#ecf5ff"
-			color="#409eff"
-		/>
-		<el-card shadow="hover" header="tagsView 当前页演示" class="mt15">
-			<div class="flex-warp">
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="primary" size="default" @click="refreshCurrentTagsView">
-							<el-icon>
-								<ele-RefreshRight />
-							</el-icon>
-							刷新当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="info" size="default" @click="closeCurrentTagsView">
-							<el-icon>
-								<ele-Close />
-							</el-icon>
-							关闭当前页
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="warning" size="default" @click="closeOtherTagsView">
-							<el-icon>
-								<ele-CircleClose />
-							</el-icon>
-							关闭其它
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="danger" size="default" @click="closeAllTagsView">
-							<el-icon>
-								<ele-FolderDelete />
-							</el-icon>
-							全部关闭
-						</el-button>
-					</div>
-				</div>
-				<div class="flex-warp-item">
-					<div class="flex-warp-item-box">
-						<el-button type="success" size="default" @click="openCurrenFullscreen">
-							<el-icon>
-								<ele-FullScreen />
-							</el-icon>
-							当前页全屏
-						</el-button>
-					</div>
-				</div>
-			</div>
-		</el-card>
-	</div>
-</template>
-
-<script setup lang="ts" name="funTagsView">
-import { defineAsyncComponent } from 'vue';
-import { useRoute } from 'vue-router';
-import mittBus from '/@/utils/mitt';
-
-// 引入组件
-const NoticeBar = defineAsyncComponent(() => import('/@/components/noticeBar/index.vue'));
-
-// 定义变量内容
-const route = useRoute();
-
-// 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
-// 1、刷新当前 tagsView
-const refreshCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 0, ...route }));
-};
-// 2、关闭当前 tagsView
-const closeCurrentTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
-};
-// 3、关闭其它 tagsView
-const closeOtherTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 2, ...route }));
-};
-// 4、关闭全部 tagsView
-const closeAllTagsView = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 3, ...route }));
-};
-// 5、开启当前页面全屏
-const openCurrenFullscreen = () => {
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 4, ...route }));
-};
-</script>
-
-<style scoped lang="scss">
-.fun-tagsview {
-	.fun-tagsview-from-item {
-		:deep(.el-form-item__content) {
-			margin-left: 0 !important;
-		}
-	}
-}
-</style>

+ 113 - 187
admin-web/src/views/admin/station/endpoint/index.vue

@@ -27,179 +27,122 @@
 <template>
   <div class="system-container layout-padding">
     <el-card shadow="hover" class="layout-padding-auto">
-
-
-      <el-form
-          :model="state.formQuery"
+      <ext-query-form
+          class="page-search"
           ref="queryRef"
-          size="default" label-width="0px" class="mt5 mb5">
-
-        <ext-d-select
-            type="Connector.status"
-            v-model="state.formQuery.status"
-            placeholder="状态"
-            clearable
-            @change="loadData(true)"
-            class="wd150 mr10"/>
-
-        <ext-select
-            v-model="state.formQuery.stationId"
-            placeholder="站点"
-            clearable
-            url="station/listStation"
-            urlMethod="get"
-            data-key=""
-            label-key="stationName"
-            value-key="stationId"
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-
-        </ext-select>
-        <el-input
-            v-model="state.formQuery.equipmentId"
-            placeholder="充电桩编号/序列号"
-            clearable
-            @change="loadData(true)"
-            class="wd150 mr10">
-        </el-input>
-
-
-        <el-button class="ml10" plain size="default" type="success" @click="loadData(true)">
-          <SvgIcon name="ele-Search"/>
-          查询
-        </el-button>
-
-<!--        <el-button class="ml10" plain size="default" type="success" @click="handleUploadVisible">-->
-<!--          <SvgIcon name="ele-Upload"/>-->
-<!--          上传-->
-<!--        </el-button>-->
-      </el-form>
-
-      <el-table
-          border
-          stripe="stripe"
+          v-model="state.formQuery"
+          :columns="state.columns"
+          :import-config="state.importConfig"
+          :export-config="state.exportConfig"
+          @on-change="loadData(true)"
+          @imported="loadData(true)">
+        <!--  <template #extraQuery></template>
+          <template #extraLeft></template>
+          <template #extraRight></template>-->
+      </ext-query-form>
+
+      <ext-table
+          class="page-content"
           :height="state.tableData.height"
-          highlight-current-row
-          current-row-key="id"
-          row-key="id"
-          :data="state.tableData.data"
-          v-loading="state.tableData.loading"
-          @selection-change="handleTableSelectionChange"
-          @sort-change="handleTableSortChange">
-        <template #empty>
-          <el-empty></el-empty>
-        </template>
-        <el-table-column
-            v-for="field in state.tableData.columns"
-            :key="field.prop"
-            :label="field.label"
-            :column-key="field.prop"
-            :width="field.width"
-            :min-width="field.minWidth"
-            :fixed="field.fixed"
-            :sortable="field.sortable"
-            :show-overflow-tooltip="!field.fixed&&field.width>150"
-        >
-          <template #default="{row}">
-            <template v-if="field.prop==='expand'">
-              <p style="padding-left: 2em;" v-html="row[field.prop]"></p>
-            </template>
-            <template v-else-if="'equipmentType'===field.prop">
-              <ext-d-label type="Equipment.type" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'status'===field.prop">
-              <ext-d-label type="Connector.status" v-model="row[field.prop]"/>
-            </template>
-<!--            <template v-else-if="'netStatus'===field.prop">-->
-<!--              <ext-d-label type="Equipment.netStatus" v-model="row[field.prop]"/>-->
-<!--            </template>-->
-            <template v-else-if="'equipmentId'===field.prop">
-              <el-button link type="primary" @click="handleGotoOrder(row)">{{row[field.prop]}} </el-button>
-            </template>
-            <template v-else-if="'shortId'===field.prop">
-              <el-button link type="primary" @click="handleGotoOrder(row)">{{row[field.prop]}} </el-button>
-            </template>
-            <template v-else>
-              <div>{{ row[field.prop] }}</div>
-            </template>
-
-          </template>
-        </el-table-column>
-      </el-table>
+          :data-list="state.tableData.data"
+          :columns="state.columns"
+          :border="true"
+          :loading="state.tableData.loading">
+      </ext-table>
 
       <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
     </el-card>
   </div>
-  <!--  <EquipmentInfoDialog ref="equipmentInfoDialogRef" @refresh="loadData(true)"/>-->
-  <endpoint-upload ref="endpoint_upload_ref"></endpoint-upload>
+  <WashDeviceDialog ref="washDeviceDialogRef" @refresh="loadData(true)"/>
 </template>
 
-<script setup lang="ts" name="EquipmentInfoList">
-import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance, nextTick, onBeforeUnmount} from 'vue';
-import {$body, $get} from "/@/utils/request";
+<script setup lang="ts" name="WashDeviceList">
+import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance,nextTick,onBeforeUnmount} from 'vue';
+import {$body,$get} from "/@/utils/request";
+import u from '/@/utils/u'
+import {Msg} from "/@/utils/message";
+import {Session} from "/@/utils/storage";
 
-import {useRoute} from "vue-router";
+const {proxy}: any = getCurrentInstance();
 
-const route = useRoute();
 import ExtPage from '/@/components/form/ExtPage.vue'
+import ExtQueryForm from "/@/components/form/ExtQueryForm.vue";
+import ExtTable from "/@/components/form/ExtTable.vue";
 
 import mittBus from '/@/utils/mitt';
-import ExtDLabel from "/@/components/form/ExtDLabel.vue";
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtSelect from "/@/components/form/ExtSelect.vue";
 
-import {useRouter} from "vue-router";
-const router = useRouter();
-const EndpointUpload = defineAsyncComponent(() => import("/@/views/admin/station/endpoint/upload.vue"));
+import {ElButton} from 'element-plus'
+
+
+const WashDeviceDialog = defineAsyncComponent(() => import("/@/views/page/WashDeviceDialog.vue"));
 
 //定义引用
 const queryRef = ref();
-const endpoint_upload_ref = ref();
+const washDeviceDialogRef = ref();
 
 //定义变量
 const state = reactive({
-  uploadVisible:false,
-  formQuery: {
-    stationId: ''
-  },
+  formQuery: {},
   pageQuery: {
-    pageNum: 1,
+    pageIndex: 1,
     pageSize: 10,
     total: 0
   },
   tableData: {
-    height: 500,
-    data: [] as Array<any>,
-    loading: false,
-    columns: [
-      {label: '站点ID', prop: 'stationId', resizable: true, width: 100, fixed: 'left'},
-      {label: '站点编号', prop: 'stationNo', resizable: true, width: 100, fixed: 'left'},
-      {label: '站点名称', prop: 'stationName', resizable: true, width: 200, fixed: 'left'},
-      {label: '充电桩编号', prop: 'shortId', resizable: true, width: 110, fixed: 'left'},
-      {label: '车位编号', prop: 'parkingNo', resizable: true, width: 90, fixed: 'left'},
-      {label: '充电桩序列号', prop: 'equipmentId', width: 180, resizable: true},
-      {label: '充电桩接口编号', prop: 'connectorId', width: 180, resizable: true},
-      // {label: '设备型号', prop: 'equipmentModel', width: 150, resizable: true},
-      // {label: '服务状态', prop: 'status', resizable: true, width: 130},
-      // {label: '设备类型', prop: 'equipmentType', resizable: true, width: 130},
-      // {label: '位置坐标', prop: 'location', resizable: true, width: 150},
-      // {label: '网络状态', prop: 'netStatus', resizable: true, width: 130},
-      {label: '状态', prop: 'status', resizable: true, width: 130},
-      // {label: '设备生产商组织机构代码', prop: 'manufacturerId', width: 200, resizable: true},
-      // {label: '设备生产商名称', prop: 'manufacturerName', width: 160, resizable: true},
-      // {label: '设备生产日期', prop: 'productionDate', width: 160, resizable: true},
-      {label: '更新时间', prop: 'updateTime', sortable: 'custom', resizable: true, width: 180},
-      /*{
-        label: '操作', prop: 'action', width: 1, align: 'center', fixed: 'right',
-      }*/
-    ],
+    height:500,
+    data: [] as Array < any >,
+    loading: false
   },
+  importConfig: {},
+  exportConfig: {},
+  columns: [
+    {type: 'selection', width: 60, align: 'center', fixed: 'left'},
+    {label: '', prop: 'createTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '设备名称', prop: 'deviceName', query: true, type: 'text', resizable: true},
+    {label: '故障原因', prop: 'faultReason', query: true, type: 'text', resizable: true},
+    {label: '设备主状态机的当前状态(状态可能增加或减少,仅供调试参考。)', prop: 'fsmState', query: true, type: 'text', resizable: true},
+    {label: '功能', prop: 'functions', query: true, type: 'text', resizable: true},
+    {label: '是否有泡沫:-1不支持或未开启,0无泡沫,1有泡沫', prop: 'hasFoam', query: true, type: '', resizable: true},
+    {label: '是否有水:-1不支持或未开启,0无水,1有水', prop: 'hasWater', query: true, type: '', resizable: true},
+    {label: '产品key', prop: 'productKey', query: true, type: 'text', resizable: true},
+    {label: '状态:init设备正在初始化,idle设备空闲,busy设备忙碌,sleep不在营业时间,maintenance维护模式,fault设备故障', prop: 'state', query: true, type: 'text', resizable: true},
+    {label: '', prop: 'stationId', query: true, type: 'text', resizable: true},
+    {label: '板载温度传感器的温度值', prop: 'temperatureChip', query: true, type: '', resizable: true},
+    {label: '', prop: 'updateTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '本次上电以来的时间戳', prop: 'uptimeMs', query: true, type: 'text', resizable: true},
+    {                label: '操作', prop: 'action', type: 'render', width: 180, align: 'center', fixed: 'right',
+      render: (h: any, row: any) => {
+        return (
+            h('div', null, [
+              proxy.$auth('washDevice.modify') ?
+                  h(ElButton, {
+                    type: 'warning',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      handleRowClick('edit', row)
+                    }
+                  }, () => '编辑') : '',
+              proxy.$auth('washDevice.remove') ?
+                  h(ElButton, {
+                    type: 'danger',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      handleRowDelete(row)
+                    }
+                  }, () => '删除') : '',
+            ])
+        )
+      }
+    }
+  ],
 })
 
 
 // 监听双向绑定 modelValue 的变化
 // watch(
-//         () => state.pageNum,
+//         () => state.pageIndex,
 //         () => {
 //
 //         }
@@ -207,88 +150,71 @@ const state = reactive({
 
 //生命周期钩子
 onBeforeMount(() => {
+  let token = Session.get("token")
+  let encodeToken = encodeURIComponent(token)
+  let exportUrl = `poi/export?type=washDevice&X-Token=${encodeToken}`
+  //导入导出参数配置
+  state.importConfig = {
+    auths: ['washDevice.add'],
+    url: `poi/import?type=washDevice&X-Token=${encodeToken}`,
+    template: `${exportUrl}&isTemplate=true`
+  }
+
+  state.exportConfig = {url: exportUrl,}
+
 })
 
 onMounted(() => {
-  var params = route.params;
-  console.log(route.params, route.query)
-  let {id} = route.params;
-  if (!isNaN(Number(id))) {
-    state.formQuery.stationId = id;
-  }
   loadData();
 
-  nextTick(() => {
+  nextTick(()=>{
     let bodyHeight = document.body.clientHeight;
     let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 320
+    state.tableData.height = bodyHeight - queryHeight - 220
   })
 
-  mittBus.on("equipmentInfo.refresh", () => {
+  mittBus.on("washDevice.refresh",()=>{
     loadData();
   })
 });
 
-onBeforeUnmount(() => {
-  mittBus.off("equipmentInfo.refresh")
+onBeforeUnmount(()=>{
+  mittBus.off("washDevice.refresh")
 })
 
 
 //region 方法区
-const handleGotoOrder =(row:any)=>{
-  router.push(`/ordering?connectorId=${row.equipmentId}`)
-}
-
-
 // 初始化表格数据
 const loadData = (refresh: boolean = false) => {
   if (refresh) {
-    state.pageQuery.pageNum = 1;
+    state.pageQuery.pageIndex = 1;
   }
   state.tableData.loading = true;
-  $get(`/connector/listConnectors`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let {list, total} = res;
+  $body(`/washDevice/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
+    let {list, count} = res;
     state.tableData.data = list;
-    state.pageQuery.total = total;
+    state.pageQuery.total = count;
     state.tableData.loading = false;
   }).catch(e => {
     console.error(e)
     state.tableData.loading = false;
   })
 };
-/*
 
-// 打开修改用户弹窗
-const onRowClick = (type: string, row: any) => {
-  equipmentInfoDialogRef.value.open(type, row);
+// 打开详情页弹窗
+const handleRowClick = (type: string, row: any) => {
+  washDeviceDialogRef.value.open(type, row);
 };
-
-// 删除用户
-const onRowDel = (row: any) => {
+// 删除点击
+const handleRowDelete = (row: any) => {
   Msg.confirm(`此操作将永久删除:『${row.name}』,是否继续?`).then(() => {
-    $get(`/equipmentInfo/delete/${row.id}`).then(() => {
+    $get(`/washDevice/delete/${row.id}`).then(() => {
       Msg.message("删除成功", 'success')
     }).catch(() => {
       Msg.message("删除失败", 'error')
     })
   });
 };
-*/
-
-const handleTableSelectionChange = (selection: any) => {
-  console.log("handleTableSelectionChange>>", selection)
-  // emit("on-check-change", selection)
-}
-
-const handleTableSortChange = (column, prop, order) => {
-  console.log("handleTableSortChange>>", column, prop, order)
-  // emit("on-sort-change", column)
-}
-
-const handleUploadVisible = () => {
-  endpoint_upload_ref.value.open();
-}
-
 
 //endregion
 
@@ -297,4 +223,4 @@ const handleUploadVisible = () => {
 // defineExpose({
 //     loadData,
 // });
-</script>
+</script>

+ 85 - 184
admin-web/src/views/admin/station/list/dialog.vue

@@ -10,255 +10,156 @@
         draggable
         destroy-on-close
         :close-on-click-modal="false"
-        @close="onClose"
         align-center>
       <el-form
           inline
           :model="state.ruleForm"
-          :rules="state.rules"
+          :rules="rules"
+          label-position="top"
           ref="formRef"
           size="default"
-          label-width="125px"
+          label-width="100px"
           class="mt5">
-        <el-form-item label="站点名称" prop="stationName">
-
+        <el-form-item label="地址" prop="address">
           <el-input
-              v-model.trim="state.ruleForm.stationName"
-              placeholder="站点名称"
+              v-model="state.ruleForm.address"
+              placeholder="地址"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="站点照片" prop="pictures" class="w100">
-          <ext-upload
-              v-model="state.ruleForm.pictures"
-              multiple :max="3"></ext-upload>
-          <!--          <el-input
-                        v-model.trim="state.ruleForm.pictures"
-                        placeholder="站点照片"
-                        clearable
-                        class="wd200">
-                    </el-input>-->
-        </el-form-item>
-
-        <el-form-item label="en+充电站id" prop="stationId">
+        <el-form-item label="营业时间描述" prop="businessHours">
           <el-input
-              v-model.trim="state.ruleForm.stationId"
-              placeholder="en+充电站id"
+              v-model="state.ruleForm.businessHours"
+              placeholder="营业时间描述"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="en+运营商id" prop="operatorId">
+        <el-form-item label="公司id" prop="companyId">
           <el-input
-              v-model.trim="state.ruleForm.operatorId"
-              placeholder="en+运营商id"
+              v-model="state.ruleForm.companyId"
+              placeholder="公司id"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="设备机构代码" prop="equipmentOwnerId">
+        <el-form-item label="站点坐标" prop="location">
           <el-input
-              v-model.trim="state.ruleForm.equipmentOwnerId"
-              placeholder="设备所属运营平台组织机构代码"
+              v-model="state.ruleForm.location"
+              placeholder="站点坐标"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-
-        <el-form-item label="充电中国家代码" prop="countryCode">
+        <el-form-item label="停车费描述:eg:洗车费用满10元减免1小时停车费" prop="parkingFee">
           <el-input
-              v-model.trim="state.ruleForm.countryCode"
-              placeholder="充电中国家代码:CN"
+              v-model="state.ruleForm.parkingFee"
+              placeholder="停车费描述:eg:洗车费用满10元减免1小时停车费"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="省市辖区编码" prop="areaCode">
+        <el-form-item label="工位数量" prop="parkingNum">
           <el-input
-              v-model.trim="state.ruleForm.areaCode"
-              placeholder="充电站省市辖区编码"
+              v-model="state.ruleForm.parkingNum"
+              placeholder="工位数量"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="地址" prop="address" class="w100">
+        <el-form-item label="站点照片" prop="pictures">
           <el-input
-              v-model.trim="state.ruleForm.address"
-              placeholder="地址"
+              v-model="state.ruleForm.pictures"
+              placeholder="站点照片"
               clearable
-              class="w100">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="站点电话" prop="stationTel">
+        <el-form-item label="备注" prop="remark">
           <el-input
-              v-model.trim="state.ruleForm.stationTel"
-              placeholder="站点电话"
+              v-model="state.ruleForm.remark"
+              placeholder="备注"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
         <el-form-item label="服务电话" prop="serviceTel">
           <el-input
-              v-model.trim="state.ruleForm.serviceTel"
+              v-model="state.ruleForm.serviceTel"
               placeholder="服务电话"
               clearable
-              class="wd200">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="站点类型" prop="stationType">
-          <ext-d-select
-              type="Station.type"
-              v-model.trim="state.ruleForm.stationType"
-              placeholder="站点类型"
-              clearable
-              class="wd200">
-          </ext-d-select>
-        </el-form-item>
-        <el-form-item label="站点状态" prop="stationStatus">
-          <ext-d-select
-              v-model.trim="state.ruleForm.stationStatus"
-              placeholder="站点状态"
-              type="Station.status"
-              clearable
-              class="wd200">
-          </ext-d-select>
-        </el-form-item>
-        <el-form-item label="充电车位数量" prop="parkingNum">
-          <el-input
-              v-model.trim="state.ruleForm.parkingNum"
-              placeholder="充电车位数量"
-              clearable
-              class="wd200">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="充电桩位置坐标" prop="location">
-          <el-input
-              v-model.trim="state.ruleForm.location"
-              placeholder="充电桩位置坐标"
-              clearable
-              class="wd200">
-          </el-input>
-        </el-form-item>
-
-        <el-form-item label="建设场所" prop="construction">
-          <ext-d-select
-              type="Station.construction"
-              v-model.trim="state.ruleForm.construction"
-              placeholder="建设场所:1:居民区 2:公共机构 3:企事业单位 4:写字楼 5:工业园区 6:交通枢纽 7:大型文体设施 8:城市绿地 9:大型建筑配建停车场 10:路边停车位 11:城际高速服务区 255:其他"
-              clearable
-              class="wd200">
-          </ext-d-select>
-        </el-form-item>
-
-        <el-form-item label="充电费描述" prop="electricityFee">
-          <el-input
-              v-model.trim="state.ruleForm.electricityFee"
-              placeholder="充电费描述"
-              clearable
-              class="wd200">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="服务费率描述" prop="serviceFee">
-          <el-input
-              v-model.trim="state.ruleForm.serviceFee"
-              placeholder="服务费率描述"
-              clearable
-              class="wd200">
-          </el-input>
-        </el-form-item>
-
-
-        <el-form-item label="停车费" prop="parkFee">
-          <el-input
-              v-model.trim="state.ruleForm.parkFee"
-              placeholder="停车费"
-              clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="支付方式" prop="payment">
+        <el-form-item label="站点引导" prop="siteGuide">
           <el-input
-              v-model.trim="state.ruleForm.payment"
-              placeholder="支付方式:刷卡、线上、现金(电子钱包类卡为刷卡、身份鉴权卡、微信/支付宝、APP为线上)"
-              clearable
-              class="wd200">
-          </el-input>
-        </el-form-item>
-        <el-form-item label="是否支持预约" prop="supportOrder">
-          <el-input
-              v-model.trim="state.ruleForm.supportOrder"
-              placeholder="是否支持预约:0:不支持 1:支持"
+              v-model="state.ruleForm.siteGuide"
+              placeholder="站点引导"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="备注" prop="remark">
+        <el-form-item label="站点id" prop="stationId">
           <el-input
-              v-model.trim="state.ruleForm.remark"
-              placeholder="备注"
+              v-model="state.ruleForm.stationId"
+              placeholder="站点id"
               clearable
-              class="wd200">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="站点引导" prop="siteGuide" class="w100">
+        <el-form-item label="站点名称" prop="stationName">
           <el-input
-              v-model.trim="state.ruleForm.siteGuide"
-              placeholder="站点引导"
+              v-model="state.ruleForm.stationName"
+              placeholder="站点名称"
               clearable
-              type="textarea"
-              class="w100">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="营业时间描述" prop="businessHours" class="w100">
+        <el-form-item label="站点状态:Unknown:未知,Normal:正常运营,Offline:关闭下线,Repair:维护中" prop="stationStatus">
           <el-input
-              v-model.trim="state.ruleForm.businessHours"
-              placeholder="营业时间描述"
-              type="textarea"
+              v-model="state.ruleForm.stationStatus"
+              placeholder="站点状态:Unknown:未知,Normal:正常运营,Offline:关闭下线,Repair:维护中"
               clearable
-              class="w100">
+              class="wd350">
           </el-input>
         </el-form-item>
-
-        <el-form-item label="使用车型描述" prop="matchCars" class="w100">
+        <el-form-item label="站点电话" prop="stationTel">
           <el-input
-              v-model.trim="state.ruleForm.matchCars"
-              placeholder="使用车型描述"
+              v-model="state.ruleForm.stationTel"
+              placeholder="站点电话"
               clearable
-              type="textarea"
-              class="w100">
+              class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="楼层及数量描述" prop="parkInfo" class="w100">
+        <el-form-item label="站点类型:Public:公共站 2:Private:内部站(不对外开放)" prop="stationType">
           <el-input
-              v-model.trim="state.ruleForm.parkInfo"
-              placeholder="车位楼层及数量描述"
+              v-model="state.ruleForm.stationType"
+              placeholder="站点类型:Public:公共站 2:Private:内部站(不对外开放)"
               clearable
-              type="textarea"
-              class="w100">
+              class="wd350">
           </el-input>
         </el-form-item>
       </el-form>
 
       <template #footer>
-        <div class="dialog-footer">
-          <el-button @click="onCancel" size="default">取 消</el-button>
-          <el-button :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
-        </div>
+				<span class="dialog-footer">
+					<el-button @click="onCancel" size="default">取 消</el-button>
+					<el-button :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
+				</span>
       </template>
     </el-dialog>
   </div>
 </template>
 
-<script setup lang="ts" name="StationDialog">
+<script setup lang="ts" name="WashStationDialog">
 import {defineAsyncComponent, reactive, onMounted, ref} from 'vue';
 import {Msg} from "/@/utils/message";
 import {$body, $get} from "/@/utils/request";
 import u from '/@/utils/u'
-import ExtDSelect from "/@/components/form/ExtDSelect.vue";
-import ExtUpload from "/@/components/form/ExtUpload.vue";
 
 // 引入组件
+const ExtDetailForm = defineAsyncComponent(() => import('/@/components/form/ExtDetailForm.vue'));
 
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['refresh']);
@@ -284,10 +185,14 @@ const state = reactive(initState());
 
 // 打开弹窗
 const open = (action: string = 'add', row: any) => {
-  state.dialog.title = u.dialog.actions[action].title + "『充电站信息』"
-  state.dialog.submitTxt = u.dialog.actions[action].btn + "『充电站信息』"
+  state.dialog.title = u.dialog.actions[action].title + "『洗车站点表』"
+  state.dialog.submitTxt = u.dialog.actions[action].btn + "『洗车站点表』"
   state.dialog.isShowDialog = true;
-  state.ruleForm = Object.assign(state.ruleForm, row);
+  if (action !== 'add') {
+    loadData(row.id);
+  } else {
+    state.ruleForm = Object.assign(state.ruleForm, row);
+  }
 };
 // 关闭弹窗
 const onClose = () => {
@@ -300,25 +205,21 @@ const onCancel = () => {
 };
 // 提交
 const onSubmit = () => {
-  formRef.value.validate((valid: boolean) => {
-    if (valid) {
+  formRef.value.validate((v: boolean) => {
+    if (v) {
       state.btnLoading = true;
-      const url = state.ruleForm.id > 0 ? "station/modify" : "station/add"
-      let params = {
-        stationId: state.ruleForm.stationId,
-        pictures: state.ruleForm.pictures
-      }
-      $body(url, params).then(() => {
+      const url = state.ruleForm.id > 0 ? "washStation/modify" : "washStation/add"
+      $body(url, state.ruleForm).then(() => {
         state.btnLoading = false;
         Msg.message('操作成功');
         console.log('submit!')
         onClose();
         emit('refresh');
       })
+    } else {
+      state.btnLoading = false;
+      Msg.message('请先完整填写表单', 'error');
     }
-  }).catch(() => {
-    state.btnLoading = false;
-    Msg.message('请先完整填写表单', 'error');
   })
 };
 
@@ -326,12 +227,12 @@ const handleFormChange = (formData: any) => {
   console.log(formData)
 }
 
-// 初始化表格数据
-/*const loadData = (id: number) => {
-  $get(`station/detail/${id}`).then((res: any) => {
+// 初始化数据
+const loadData = (id: number) => {
+  $get(`washStation/detail/${id}`).then((res: any) => {
     state.ruleForm = res;
   })
-}*/
+}
 
 // 暴露变量
 defineExpose({

+ 115 - 200
admin-web/src/views/admin/station/list/index.vue

@@ -27,190 +27,125 @@
 <template>
   <div class="system-container layout-padding">
     <el-card shadow="hover" class="layout-padding-auto">
-
-
-      <el-form
-          :model="state.formQuery"
+      <ext-query-form
+          class="page-search"
           ref="queryRef"
-          size="default" label-width="0px" class="mt5 mb5">
-
-        <ext-select
-            v-model="state.formQuery.stationId"
-            placeholder="站点"
-            clearable
-            url="station/listStation"
-            urlMethod="get"
-            data-key=""
-            label-key="stationName"
-            value-key="stationId"
-            @on-change="loadData(true)"
-            class="wd150 mr10">
-        </ext-select>
-
-        <el-button v-auth="'station.list'"    class="ml10"  plain size="default" type="success" @click="loadData(true)">
-          <SvgIcon name="ele-Search"/>
-          查询
-        </el-button>
-
-<!--        <el-button  v-auth="'station.add'"   size="default" plain  type="success" class="ml10" @click="onRowClick('add',null)">-->
-<!--          <SvgIcon name="ele-FolderAdd"/>-->
-<!--          新增-->
-<!--        </el-button>-->
-
-        <el-button class="ml10" plain size="default" type="success" @click="handleUploadVisible">
-          <SvgIcon name="ele-Upload"/>
-          导入站点
-        </el-button>
-
-      </el-form>
-
-<!--      <el-card class="w100">
-        <div class="order-summary">
-          <span class="ml5">电量:</span>
-          <el-tag type="success">{{state.extraData.totalPower}}Kwh</el-tag>
-          <span class="ml5">实付服务费:</span>
-          <el-tag type="success">{{u.fmt.fmtMoney(state.extraData.serviceMoney)}}元</el-tag>
-        </div>
-
-      </el-card>-->
-
-      <el-table
-          border
-          stripe="stripe"
+          v-model="state.formQuery"
+          :columns="state.columns"
+          :import-config="state.importConfig"
+          :export-config="state.exportConfig"
+          @on-change="loadData(true)"
+          @imported="loadData(true)">
+        <!--  <template #extraQuery></template>
+          <template #extraLeft></template>
+          <template #extraRight></template>-->
+      </ext-query-form>
+
+      <ext-table
+          class="page-content"
           :height="state.tableData.height"
-          highlight-current-row
-          current-row-key="id"
-          row-key="id"
-          :data="state.tableData.data"
-          v-loading="state.tableData.loading"
-          @selection-change="handleTableSelectionChange"
-          @sort-change="handleTableSortChange">
-        <template #empty>
-          <el-empty></el-empty>
-        </template>
-        <el-table-column
-            v-for="field in state.tableData.columns"
-            :key="field.prop"
-            :label="field.label"
-            :column-key="field.prop"
-            :width="field.width"
-            :min-width="field.minWidth"
-            :fixed="field.fixed"
-            :sortable="field.sortable"
-            :show-overflow-tooltip="!field.fixed&&field.width>150"
-        >
-          <template #default="{row}">
-            <template v-if="field.prop==='pictures'">
-              <ext-image :src-list="row[field.prop]?.split(';')" ></ext-image>
-            </template>
-            <template v-else-if="'stationType'===field.prop">
-              <ext-d-label type="Station.type" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'stationStatus'===field.prop">
-              <ext-d-label type="Station.status" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'construction'===field.prop">
-              <ext-d-label type="Station.construction" v-model="row[field.prop]"/>
-            </template>
-            <template v-else-if="'action'===field.prop">
-             <el-button link type="primary" @click="handleGotoEndpoint(row)">查看电桩</el-button>
-              <el-button  size="small" plain type="warning" @click="onRowClick('edit',row)">编辑</el-button>
-            </template>
-            <template v-else>
-              <div>{{row[field.prop]}}</div>
-            </template>
+          :data-list="state.tableData.data"
+          :columns="state.columns"
+          :border="true"
+          :loading="state.tableData.loading">
+      </ext-table>
 
-          </template>
-        </el-table-column>
-      </el-table>
-
-<!--      <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>-->
+      <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
     </el-card>
   </div>
-  <StationDialog ref="stationDialogRef" @refresh="loadData(true)"/>
-  <SettleDialog ref="settleDialogRef" />
-  <upload ref="upload_ref"></upload>
+  <WashStationDialog ref="washStationDialogRef" @refresh="loadData(true)"/>
 </template>
 
-<script setup lang="ts" name="StationList">
-import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance, nextTick, onBeforeUnmount} from 'vue';
+<script setup lang="ts" name="WashStationList">
+import {defineAsyncComponent, reactive, onMounted, onBeforeMount, ref, getCurrentInstance,nextTick,onBeforeUnmount} from 'vue';
 import {$body,$get} from "/@/utils/request";
+import u from '/@/utils/u'
 import {Msg} from "/@/utils/message";
-import u from "/@/utils/u"
+import {Session} from "/@/utils/storage";
+
+const {proxy}: any = getCurrentInstance();
+
 import ExtPage from '/@/components/form/ExtPage.vue'
+import ExtQueryForm from "/@/components/form/ExtQueryForm.vue";
+import ExtTable from "/@/components/form/ExtTable.vue";
 
 import mittBus from '/@/utils/mitt';
-import ExtDLabel from "/@/components/form/ExtDLabel.vue";
-import {useRouter} from "vue-router";
-import ExtImage from "/@/components/form/ExtImage.vue";
-import ExtSelect from "/@/components/form/ExtSelect.vue";
-const router = useRouter();
-const StationDialog = defineAsyncComponent(() => import("/@/views/admin/station/list/dialog.vue"));
-const Upload = defineAsyncComponent(() => import("/@/views/admin/station/list/upload.vue"));
 
+import {ElButton} from 'element-plus'
+
+
+const WashStationDialog = defineAsyncComponent(() => import("/@/views/page/WashStationDialog.vue"));
 
 //定义引用
 const queryRef = ref();
-const stationDialogRef = ref();
-const settleDialogRef = ref();
-const upload_ref = ref();
+const washStationDialogRef = ref();
 
 //定义变量
 const state = reactive({
   formQuery: {},
   pageQuery: {
-    pageNum: 1,
+    pageIndex: 1,
     pageSize: 10,
     total: 0
   },
   tableData: {
-    height: 500,
+    height:500,
     data: [] as Array < any >,
-    loading: false,
-    columns: [
-      {label: '充电站ID', prop: 'stationId',width:160, resizable: true,fixed:'left'},
-      // {label: 'en+运营商id', prop: 'operatorId', resizable: true},
-      // {label: '所属运营平台', prop: 'equipmentOwnerId', width:160,resizable: true,fixed:'left'},
-      {label: '站点名称', prop: 'stationName',width:160, resizable: true},
-      {label: '站点照片', prop: 'pictures',width:120, resizable: true},
-      // {label: '充电中国家代码:CN', prop: 'countryCode', resizable: true},
-      // {label: '充电站省市辖区编码', prop: 'areaCode', resizable: true},
-      {label: '地址', prop: 'address',width:160, resizable: true},
-      {label: '站点电话', prop: 'stationTel', width:120,resizable: true},
-      {label: '服务电话', prop: 'serviceTel', width:140, resizable: true},
-      {label: '站点类型', prop: 'stationType', width:120,resizable: true},
-      {label: '站点状态', prop: 'stationStatus', width:120,resizable: true},
-      {label: '充电车位数量', prop: 'parkingNum',width:160, resizable: true},
-      // {label: '充电桩位置坐标', prop: 'location', resizable: true},
-      // {label: '站点引导', prop: 'siteGuide', resizable: true},
-      {label: '建设场所', prop: 'construction',  width:160, resizable: true},
-      {label: '使用车型描述', prop: 'matchCars', width:160,resizable: true},
-      {label: '车位楼层及数量描述', prop: 'parkInfo',width:160, resizable: true},
-      {label: '营业时间描述', prop: 'businessHours', width:160,resizable: true},
-      {label: '充电费描述', prop: 'electricityFee', width:160, resizable: true},
-      {label: '服务费率描述', prop: 'serviceFee',  width:120,resizable: true},
-      {label: '停车费', prop: 'parkFee', width:120, resizable: true},
-      {label: '支付方式', prop: 'payment',  width:120,resizable: true},
-      {label: '是否支持预约', prop: 'supportOrder',  width:120,resizable: true},
-      {label: '备注', prop: 'remark', width:160,resizable: true},
-      {
-        label: '操作', prop: 'action', width: 180, align: 'center', fixed: 'right',
-      }
-    ],
+    loading: false
   },
-  extraData:{
-    totalOrders:0,
-    totalPower:0,
-    elecMoney:0,
-    serviceMoney:0,
-    totalMoney:0,
-  }
+  importConfig: {},
+  exportConfig: {},
+  columns: [
+    {type: 'selection', width: 60, align: 'center', fixed: 'left'},
+    {label: '地址', prop: 'address', query: true, type: 'text', resizable: true},
+    {label: '营业时间描述', prop: 'businessHours', query: true, type: 'text', resizable: true},
+    {label: '', prop: 'createTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {label: '站点坐标', prop: 'location', query: true, type: '', resizable: true},
+    {label: '停车费描述:eg:洗车费用满10元减免1小时停车费', prop: 'parkingFee', query: true, type: 'text', resizable: true},
+    {label: '工位数量', prop: 'parkingNum', query: true, type: '', resizable: true},
+    {label: '站点照片', prop: 'pictures', query: true, type: 'text', resizable: true},
+    {label: '备注', prop: 'remark', query: true, type: 'text', resizable: true},
+    {label: '服务电话', prop: 'serviceTel', query: true, type: 'text', resizable: true},
+    {label: '站点引导', prop: 'siteGuide', query: true, type: 'text', resizable: true},
+    {label: '站点id', prop: 'stationId', query: true, type: 'text', resizable: true},
+    {label: '站点名称', prop: 'stationName', query: true, type: 'text', resizable: true},
+    {label: '站点状态:Unknown:未知,Normal:正常运营,Offline:关闭下线,Repair:维护中', prop: 'stationStatus', query: true, type: 'text', resizable: true},
+    {label: '站点电话', prop: 'stationTel', query: true, type: 'text', resizable: true},
+    {label: '站点类型:Public:公共站 2:Private:内部站(不对外开放)', prop: 'stationType', query: true, type: 'text', resizable: true},
+    {label: '', prop: 'updateTime', query: true, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDate(val)}},
+    {                label: '操作', prop: 'action', type: 'render', width: 180, align: 'center', fixed: 'right',
+      render: (h: any, row: any) => {
+        return (
+            h('div', null, [
+              proxy.$auth('washStation.modify') ?
+                  h(ElButton, {
+                    type: 'warning',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      handleRowClick('edit', row)
+                    }
+                  }, () => '编辑') : '',
+              proxy.$auth('washStation.remove') ?
+                  h(ElButton, {
+                    type: 'danger',
+                    text: true,
+                    size: 'small',
+                    onClick: () => {
+                      handleRowDelete(row)
+                    }
+                  }, () => '删除') : '',
+            ])
+        )
+      }
+    }
+  ],
 })
 
 
 // 监听双向绑定 modelValue 的变化
 // watch(
-//         () => state.pageNum,
+//         () => state.pageIndex,
 //         () => {
 //
 //         }
@@ -218,50 +153,50 @@ const state = reactive({
 
 //生命周期钩子
 onBeforeMount(() => {
+  let token = Session.get("token")
+  let encodeToken = encodeURIComponent(token)
+  let exportUrl = `poi/export?type=washStation&X-Token=${encodeToken}`
+  //导入导出参数配置
+  state.importConfig = {
+    auths: ['washStation.add'],
+    url: `poi/import?type=washStation&X-Token=${encodeToken}`,
+    template: `${exportUrl}&isTemplate=true`
+  }
+
+  state.exportConfig = {url: exportUrl,}
+
 })
 
 onMounted(() => {
   loadData();
 
-  nextTick(() => {
+  nextTick(()=>{
     let bodyHeight = document.body.clientHeight;
     let queryHeight = queryRef.value.$el.clientHeight;
-    state.tableData.height = bodyHeight - queryHeight - 320
+    state.tableData.height = bodyHeight - queryHeight - 220
   })
 
-  mittBus.on("station.refresh", () => {
+  mittBus.on("washStation.refresh",()=>{
     loadData();
   })
 });
 
-onBeforeUnmount(() => {
-  mittBus.off("station.refresh")
+onBeforeUnmount(()=>{
+  mittBus.off("washStation.refresh")
 })
 
 
-
-
 //region 方法区
-const handleGotoEndpoint = (row:any)=>{
-  let {stationId} = row;
-  if(!stationId){
-    return;
-  }
-  let resolve = router.resolve(`/station/endpoint/${stationId}`);
-  window.open(resolve.href, '_blank');
-}
-
-
 // 初始化表格数据
 const loadData = (refresh: boolean = false) => {
   if (refresh) {
-    state.pageQuery.pageNum = 1;
+    state.pageQuery.pageIndex = 1;
   }
   state.tableData.loading = true;
-  $get(`/station/listStation`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
-    let list= res;
+  $body(`/washStation/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
+    let {list, count} = res;
     state.tableData.data = list;
-    // state.pageQuery.total = count;
+    state.pageQuery.total = count;
     state.tableData.loading = false;
   }).catch(e => {
     console.error(e)
@@ -269,15 +204,14 @@ const loadData = (refresh: boolean = false) => {
   })
 };
 
-// 打开修改用户弹窗
-const onRowClick = (type: string, row: any) => {
-  stationDialogRef.value?.open(type, row);
+// 打开详情页弹窗
+const handleRowClick = (type: string, row: any) => {
+  washStationDialogRef.value.open(type, row);
 };
-
-// 删除用户
-const onRowDel = (row: any) => {
+// 删除点击
+const handleRowDelete = (row: any) => {
   Msg.confirm(`此操作将永久删除:『${row.name}』,是否继续?`).then(() => {
-    $get(`/station/delete/${row.id}`).then(() => {
+    $get(`/washStation/delete/${row.id}`).then(() => {
       Msg.message("删除成功", 'success')
     }).catch(() => {
       Msg.message("删除失败", 'error')
@@ -285,25 +219,6 @@ const onRowDel = (row: any) => {
   });
 };
 
-const handleTableSelectionChange = (selection: any) => {
-  console.log("handleTableSelectionChange>>", selection)
-  // emit("on-check-change", selection)
-}
-
-const handleTableSortChange = (column, prop, order) => {
-  console.log("handleTableSortChange>>", column, prop, order)
-  // emit("on-sort-change", column)
-}
-
-const handleSettleShow = () => {
-  settleDialogRef.value?.open();
-}
-
-const handleUploadVisible = () => {
-  upload_ref.value.open();
-}
-
-
 //endregion
 
 
@@ -311,4 +226,4 @@ const handleUploadVisible = () => {
 // defineExpose({
 //     loadData,
 // });
-</script>
+</script>