Просмотр исходного кода

Merge branches 'master' and 'master' of http://49.234.186.218:9000/root/ieplus

jinxia.mo 1 месяц назад
Родитель
Сommit
3b5e548942

+ 3 - 0
back-ui/src/assets/styles/index.scss

@@ -123,6 +123,9 @@ aside {
 //main-container全局样式
 .app-container {
   padding: 20px;
+  box-sizing: border-box;
+  height: 100%;
+  overflow: auto;
 }
 
 .components-container {

+ 0 - 24
back-ui/src/assets/styles/ruoyi.scss

@@ -232,30 +232,6 @@
   color: #1ab394;
 }
 
-.text-primary {
-  color: inherit;
-}
-
-.text-success {
-  color: #1c84c6;
-}
-
-.text-info {
-  color: #23c6c8;
-}
-
-.text-warning {
-  color: #f8ac59;
-}
-
-.text-danger {
-  color: #ed5565;
-}
-
-.text-muted {
-  color: #888888;
-}
-
 /* image */
 .img-circle {
   border-radius: 50%;

+ 11 - 1
back-ui/src/common/enum.js

@@ -7,4 +7,14 @@ export const CARD_STATUS = [
     label: '已激活',
     value: 30,
   },
-];
+];
+
+/**
+ * 卡类型枚举
+ */
+export const EnumCardType = {
+  EXPERIENCE: 9,
+  VIP: 1,
+  VIP_PLATFORM: 6,
+  VIP_INSTITUTION: 2,
+}

+ 3 - 3
back-ui/src/hooks/useSchool.js

@@ -56,7 +56,7 @@ const useSchool = (options = {}) => {
       ? selectedArea.value?.[selectedArea.value.length - 1]
       : selectedArea.value;
     const res = await listSchool({
-      pro: areaId,
+      areaCode: areaId,
       pageNo: 1,
       pageSize: 100000,
     });
@@ -80,7 +80,7 @@ const useSchool = (options = {}) => {
       ? selectedArea.value?.[selectedArea.value.length - 1]
       : selectedArea.value;
     const res = await listCampus({
-      pro: areaId,
+      areaCode: areaId,
     });
     campusList.value = res.rows;
     return res.rows;
@@ -199,7 +199,7 @@ const useSchool = (options = {}) => {
     schoolList,
     selectedSchool,
     selectedAssignSchool,
-    
+
     classList,
     selectedClass,
     getClassList,

+ 4 - 4
back-ui/src/views/dz/cards/components/CardTable.vue

@@ -93,7 +93,7 @@
         </el-table-column>
         <el-table-column label="结算状态" prop="isSettlement" align="center" min-width="100">
           <template #default="scope">
-            <dict-tag :options="bool_values" :value="scope.row.isSettlement" />
+            <dict-tag :options="card_settlement_status" :value="scope.row.isSettlement" />
           </template>
         </el-table-column>
         <el-table-column label="分配时间" prop="distributeTime" align="center" min-width="120">
@@ -111,7 +111,7 @@
             <span>{{ scope.row.outDate ? parseTime(scope.row.outDate, '{y}-{m}-{d}') : '-' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="缴费时间" prop="payTime" align="center" min-width="120">
+        <el-table-column label="缴费时间" prop="payTime" align="center" min-width="120" :fixed="hideActions ? 'right' : undefined">
           <template #default="scope">
             <span>{{ scope.row.payTime ? parseTime(scope.row.payTime, '{y}-{m}-{d}') : '-' }}</span>
           </template>
@@ -129,8 +129,8 @@
 import DictTag from '@/components/DictTag/index.vue';
 import { getCurrentInstance } from 'vue';
 const { proxy } = getCurrentInstance();
-const { card_type, exam_type, card_distribute_status, card_status, bool_values, card_time_status, card_pay_status } = 
-proxy.useDict("card_type", "exam_type", "card_distribute_status", "card_status", "bool_values", "card_time_status", "card_pay_status");
+const { card_type, exam_type, card_distribute_status, card_status, card_settlement_status, card_time_status, card_pay_status } = 
+proxy.useDict("card_type", "exam_type", "card_distribute_status", "card_status", "card_settlement_status", "card_time_status", "card_pay_status");
 const props = defineProps({
   data: {
     type: Array,

+ 37 - 18
back-ui/src/views/dz/cards/components/EditDialog.vue

@@ -80,20 +80,27 @@
           <el-form-item label="目标院校" prop="targetCollege">
             <div class="w-full flex items-center gap-x-2 ">
               <div class="flex-1 flex flex-col gap-2">
-                <div
-                  class="flex items-center gap-x-2 border-1 border-solid border-[#e5e5e5] rounded-[4px] px-2 py-2 relative"
-                  v-for="(item, index) in form.directionStudy" :key="item.id">
-                  <div class="text-[13px] leading-[13px] font-bold">{{ item.universityName }}</div>
-                  <div
-                    class="text-[11px] text-[#5692fa] leading-[11px] border-1 border-solid border-[#5692fa] rounded-[4px] px-1 py-1">
-                    {{ item.majorName }}</div>
-                  <div class="text-[11px] text-[#999] leading-[11px]">{{ item.majorAncestors }}</div>
-                  <div class="absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer">
-                    <el-icon @click="handleRemoveTargetCollege(index)" color="#ff4949">
-                      <Close />
-                    </el-icon>
-                  </div>
-                </div>
+                <draggable v-model="form.directionStudy" item-key="id" handle=".drag-handle" animation="200"
+                  class="flex flex-col gap-2" ghost-class="ghost-class" chosen-class="chosen-class">
+                  <template #item="{ element, index }">
+                    <div
+                      class="flex items-center gap-x-2 border-1 border-solid border-[#e5e5e5] rounded-[4px] px-2 py-2 relative bg-white">
+                      <el-icon class="cursor-move drag-handle mr-1" color="#909399">
+                        <Rank />
+                      </el-icon>
+                      <div class="text-[13px] leading-[13px] font-bold">{{ element.universityName }}</div>
+                      <div
+                        class="text-[11px] text-[#5692fa] leading-[11px] border-1 border-solid border-[#5692fa] rounded-[4px] px-1 py-1">
+                        {{ element.majorName }}</div>
+                      <div class="text-[11px] text-[#999] leading-[11px]">{{ element.majorAncestors }}</div>
+                      <div class="absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer">
+                        <el-icon @click="handleRemoveTargetCollege(index)" color="#ff4949">
+                          <Close />
+                        </el-icon>
+                      </div>
+                    </div>
+                  </template>
+                </draggable>
               </div>
               <el-button type="primary" :disabled="form.directionStudy.length >= 3" icon="plus" plain
                 @click="handleAddTargetCollege">添加</el-button>
@@ -113,12 +120,13 @@ import IeUniversitySelect from '@/components/IeUniversitySelect/index.vue';
 import DirectionDialog from './DirectionDialog.vue';
 import { updateCardUser, getUserByCardId } from '@/api/dz/cards';
 import { getCurrentInstance, nextTick, watch, watchEffect } from 'vue';
+import draggable from 'vuedraggable';
+import { Rank } from '@element-plus/icons-vue';
 
 const { proxy } = getCurrentInstance();
 
 const modalRef = ref(null);
 const formRef = ref(null);
-const userInfo = ref({});
 const form = ref({
   scores: {},
   directionStudy: []
@@ -185,12 +193,12 @@ const close = () => {
 const getUserInfo = (cardInfo) => {
   const { cardId, location, nickName, outDate } = cardInfo;
   getUserByCardId(cardId).then(async res => {
-    userInfo.value = { ...res.data };
     form.value = {
       ...res.data,
       location,
       nickName,
-      outDate
+      outDate,
+      directionStudy: res.data.directionStudy || []
     };
     const areaList = await getAreaList();
     const area = areaList.find(item => item.areaName === location + '省');
@@ -238,4 +246,15 @@ defineExpose({
   close
 })
 </script>
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+:deep(.ghost-class) {
+  opacity: 1 !important;
+  background: #fff !important;
+  border: 1px solid #e5e5e5 !important;
+}
+
+:deep(.chosen-class) {
+  background: #fff !important;
+  border: 1px solid var(--el-color-primary) !important;
+}
+</style>

+ 1 - 1
back-ui/src/views/dz/cards/components/MajorTable.vue

@@ -69,7 +69,7 @@ const getList = () => {
     nextTick(() => {
       // 恢复选中状态:根据 props.selection 中的 id 找到对应的 row 并选中
       props.selection.forEach(selectedItem => {
-        const row = data.value.find(dataItem => dataItem.id === selectedItem.majorId);
+        const row = data.value.find(dataItem => String(dataItem.id) === String(selectedItem.majorId));
         if (row) {
           tableRef.value.toggleRowSelection(row, true);
         }

+ 35 - 13
back-ui/src/views/dz/cards/index.vue

@@ -42,8 +42,8 @@
         </div>
       </el-form-item>
       <el-form-item label="卡分配日期" prop="assignTimeRange">
-        <el-date-picker v-model="queryParams.assignTimeRange" type="daterange" range-separator="至" start-placeholder="开始日期"
-          end-placeholder="结束日期" value-format="YYYY-MM-DD" class="w-[282px]!" />
+        <el-date-picker v-model="queryParams.assignTimeRange" type="daterange" range-separator="至"
+          start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" class="w-[282px]!" />
       </el-form-item>
       <el-form-item label="平台机构" prop="deptId">
         <ie-institution-select v-model="queryParams.deptId" class="w-[180px]!" clearable />
@@ -65,7 +65,10 @@
       <el-form-item label="过期状态" prop="timeStatus">
         <ie-select v-model="queryParams.timeStatus" :options="card_time_status" class="w-[180px]!" clearable />
       </el-form-item>
-      <el-form-item label="结算状态" prop="payStatus">
+      <el-form-item label="结算状态" prop="isSettlement">
+        <ie-select v-model="queryParams.isSettlement" :options="card_settlement_status" class="w-[180px]!" clearable />
+      </el-form-item>
+      <el-form-item label="缴费状态" prop="payStatus">
         <ie-select v-model="queryParams.payStatus" :options="card_pay_status" class="w-[180px]!" clearable />
       </el-form-item>
       <el-form-item>
@@ -105,17 +108,17 @@
         直接开卡
       </CustomButton>
       <CustomButton icon="delete" color="#F56C6C" v-hasPermi="['dz:cards:remove']" :disabled="batchDisabled"
-        @click="handleDeleteBatch">
+        @click="handleDeleteBatch" v-if="false">
         删除
       </CustomButton>
       <CustomButton color="#FFC107" :disabled="batchDisabled" @click="handleSettle">
         <svg-icon icon-class="chart" class="mr-1" style="font-size: 12px" />
         结算
       </CustomButton>
-      <CustomButton color="#009688" :disabled="batchDisabled" @click="handleRenew">
+      <!-- <CustomButton color="#009688" :disabled="batchDisabled" @click="handleRenew">
         <svg-icon icon-class="time" class="mr-1" style="font-size: 14px" />
         续期
-      </CustomButton>
+      </CustomButton> -->
       <CustomButton color="#673AB7" :disabled="editDisabled" @click="handleEdit">
         <svg-icon icon-class="edit" class="mr-1" style="font-size: 12px" />
         修改
@@ -126,7 +129,8 @@
       </CustomButton>
       <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
-    <card-table :data="cardList" :loading="loading" @selectionChange="handleSelectionChange" @delete="handleDelete" />
+    <card-table :data="cardList" :loading="loading" :hide-actions="true" @selectionChange="handleSelectionChange"
+      @delete="handleDelete" />
     <div class="flex justify-end">
       <Pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
         @pagination="getList" />
@@ -153,7 +157,7 @@ import AssignDialog from './components/AssignDialog.vue';
 import EditDialog from './components/EditDialog.vue';
 import RelateDialog from './components/RelateDialog.vue';
 import { listCards, delCards, payCard, closeCard, reopenCard, refundCard, settleCard, renewCard } from '@/api/dz/cards';
-import { CARD_STATUS } from '@/common/enum';
+import { CARD_STATUS, EnumCardType } from '@/common/enum';
 import { getCurrentInstance, nextTick } from 'vue';
 
 const { proxy } = getCurrentInstance();
@@ -173,19 +177,19 @@ const {
 } = useSchool({ loadCampus: true, loadCampusClass: true, loadClass: true });
 const {
   exam_type,
-  card_status,
   card_distribute_status,
   card_time_status,
-  bool_values,
+  card_settlement_status,
   card_pay_status,
   card_type,
-} = proxy.useDict("exam_type", "card_status", "card_distribute_status", "card_time_status", "bool_values", "card_pay_status", "card_type");
+} = proxy.useDict("exam_type", "card_distribute_status", "card_time_status", "card_settlement_status", "card_pay_status", "card_type");
 const cascaderProps = {
   label: "areaName",
   value: "areaId",
   checkStrictly: true,
 }
 const queryParams = ref({
+  pageNum: 1,
   pageSize: 20
 })
 const showSearch = ref(true)
@@ -214,12 +218,13 @@ watchEffect(() => {
 })
 
 const handleQuery = () => {
-  queryParams.page = 1;
+  queryParams.pageNum = 1;
   getList();
 }
 
 const resetQuery = () => {
   queryParams.value = {
+    pageNum: 1,
     pageSize: 20
   };
   reset();
@@ -233,7 +238,6 @@ const getList = () => {
     assignTimeEnd: queryParams.value.assignTimeRange?.[1],
   };
   delete params.assignTimeRange;
-  console.log(params)
   listCards(params).then(res => {
     cardList.value = res.rows;
     total.value = res.total;
@@ -280,6 +284,12 @@ const handleOpenCard = () => {
 }
 
 const handlePay = () => {
+  // 体验卡禁止缴费
+  const isExperienceCard = selectedRows.value.some(item => item.type === EnumCardType.EXPERIENCE);
+  if (isExperienceCard) {
+    proxy.$modal.msgError('体验卡禁止缴费');
+    return;
+  }
   proxy.$modal.confirm(`是否确认缴费所选数据 (${ids.value.length}项) ?`).then(() => {
     payCard(ids.value).then(() => {
       proxy.$modal.msgSuccess('缴费成功')
@@ -307,6 +317,12 @@ const handleReopen = () => {
 }
 
 const handleRefund = () => {
+  // 体验卡禁止退费
+  const isExperienceCard = selectedRows.value.some(item => item.type === EnumCardType.EXPERIENCE);
+  if (isExperienceCard) {
+    proxy.$modal.msgError('体验卡禁止退费');
+    return;
+  }
   proxy.$modal.confirm(`是否确认退费所选数据 (${ids.value.length}项) ?`).then(() => {
     refundCard(ids.value).then(() => {
       proxy.$modal.msgSuccess('退费成功')
@@ -316,6 +332,12 @@ const handleRefund = () => {
 }
 
 const handleSettle = () => {
+  // 体验卡禁止结算
+  const isExperienceCard = selectedRows.value.some(item => item.type === EnumCardType.EXPERIENCE);
+  if (isExperienceCard) {
+    proxy.$modal.msgError('体验卡禁止结算');
+    return;
+  }
   proxy.$modal.confirm(`是否确认结算所选数据 (${ids.value.length}项) ?`).then(() => {
     settleCard(ids.value).then(() => {
       proxy.$modal.msgSuccess('结算成功')

+ 1 - 1
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzCardsController.java

@@ -228,7 +228,7 @@ public class DzCardsController extends BaseController
     public AjaxResult changeCard(@ApiParam("操作") @RequestParam CardAction action, @ApiParam("卡ID") @RequestParam Long[] cardIds)
     {
         dzCardsService.changeCard(action, cardIds);
-        if (CardAction.Close.equals(action) && ArrayUtils.isNotEmpty(cardIds)) {
+        if ((CardAction.Close.equals(action) || CardAction.Refund.equals(action)) && ArrayUtils.isNotEmpty(cardIds)) {
             sysLoginService.resetTokens(sysUserService.selectUserByCardIds(Arrays.asList(cardIds)));
         } else if (CardAction.ReOpen.equals(action) && ArrayUtils.isNotEmpty(cardIds)) {
             List<SysUser> sysUsers = sysUserService.selectUserByCardIds(Arrays.asList(cardIds));

+ 9 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzSchoolController.java

@@ -71,6 +71,15 @@ public class DzSchoolController extends BaseController
 //            dzSchool.setCampus(false);
 //        }
         dzSchool.setCampus(false);
+        if (StringUtils.isNotBlank(dzSchool.getAreaCode())) {
+            if (dzSchool.getAreaCode().endsWith("0000")) {
+                dzSchool.setPro(Long.parseLong(dzSchool.getAreaCode()));
+            } else if (dzSchool.getAreaCode().endsWith("00")) {
+                dzSchool.setCity(Long.parseLong(dzSchool.getAreaCode()));
+            } else {
+                dzSchool.setArea(Long.parseLong(dzSchool.getAreaCode()));
+            }
+        }
         startPage();
         List<DzSchool> list= dzSchoolService.selectDzSchoolList(dzSchool);
         //处理省市区

+ 6 - 0
ie-admin/src/main/java/com/ruoyi/web/domain/CardUserBody.java

@@ -1,11 +1,14 @@
 package com.ruoyi.web.domain;
 
 import com.alibaba.fastjson2.JSONArray;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.common.core.domain.model.RegisterBody;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.util.Date;
+
 @Data
 @ApiModel("卡用户信息")
 public class CardUserBody extends RegisterBody {
@@ -13,4 +16,7 @@ public class CardUserBody extends RegisterBody {
     Long cardId;
     @ApiModelProperty(value = "目标院校", example = "")
     JSONArray directionStudy;
+    @ApiModelProperty(value = "到期日期", example = "2028-08-08")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    Date outDate;
 }

+ 5 - 3
ie-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java

@@ -171,8 +171,10 @@ public class SysRegisterService
         upUser.setScores(cardUserBody.getScores());
         upUser.setSchoolId(cardUserBody.getSchoolId());
         upUser.setClassId(cardUserBody.getClassId());
-
-
+        upUser.setPhonenumber(cardUserBody.getMobile());
+        if (!userService.checkPhoneUnique(upUser)) {
+            throw new ValidationException("保存用户'" + upUser.getNickName() + "'失败,注册手机已存在" + cardUserBody.getMobile());
+        }
         JSONObject directed = cardUserBody.getDirectionStudy().getJSONObject(0);
         Long planId = directed.getLongValue("majorId");
         Long universityId = directed.getLongValue("universityId");
@@ -186,7 +188,7 @@ public class SysRegisterService
         upCard.setClassId(cardUserBody.getClassId());
         upCard.setCampusId(cardUserBody.getCampusSchoolId());
         upCard.setCampusClassId(cardUserBody.getCampusClassId());
-
+        upCard.setOutDate(cardUserBody.getOutDate());
         userService.updateUserInfo(upUser);
         cardsService.updateDzCards(upCard);
     }

+ 10 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzSchool.java

@@ -54,6 +54,8 @@ public class DzSchool extends BaseEntity
 
     String proCityAreaName ;
 
+    String areaCode;
+
     /** 状态(0:无效,1:有效) */
     @Excel(name = "状态(0:无效,1:有效)")
     private Integer status;
@@ -182,6 +184,14 @@ public class DzSchool extends BaseEntity
         this.campus = campus;
     }
 
+    public String getAreaCode() {
+        return areaCode;
+    }
+
+    public void setAreaCode(String areaCode) {
+        this.areaCode = areaCode;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

+ 1 - 1
ie-system/src/main/java/com/ruoyi/dz/service/impl/DzCardsServiceImpl.java

@@ -378,7 +378,7 @@ public class DzCardsServiceImpl implements IDzCardsService
         List<DzCards> cards = dzCardsMapper.selectCardsByCardIds(cardIds);
         DzCards up = new DzCards();
         if(CardAction.Pay.equals(action)) {
-            if(cards.stream().filter(t -> !t.getPayStatus().equals(PayStatus.UnPay.getVal())).count() > 0) {
+            if(cards.stream().filter(t -> t.getPayStatus().equals(PayStatus.Paid.getVal())).count() > 0) {
                 throw new ValidationException("重复支付已支付卡: " + StringUtils.join(cardIds, ","));
             }
             up.setPayStatus(PayStatus.Paid.getVal());

+ 2 - 1
ie-system/src/main/resources/mapper/dz/DzCardsMapper.xml

@@ -109,7 +109,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <where>
             <if test="cardNo != null  and cardNo != ''"> and c.card_no = #{cardNo}</if>
             <if test="password != null  and password != ''"> and c.password = #{password}</if>
-            <if test="type != null "> and c.type = #{type}</if>
+            <if test="type != null and type == 1 "> and c.type in (6, 2) </if>
+            <if test="type != null and type != 1 "> and c.type = #{type}</if>
             <if test="status != null "> and c.status = #{status}</if>
             <if test="distributeStatus != null "> and distribute_status = #{distributeStatus}</if>
             <if test="timeStatus != null "> and time_status = #{timeStatus}</if>