Преглед на файлове

优化客户提出问题

jiapu преди 3 месеца
родител
ревизия
5d839bf4b3

+ 4 - 5
code/backend/src/main/java/com/aijiuyi/admin/controller/PlanController.java

@@ -50,16 +50,15 @@ public class PlanController {
     }
 
     /**
-     * 新增方案(保存草稿)
+     * 新增方案(保存草稿或直接发布
      *
      * @param dto 方案信息(含步骤)
-     * @return 操作结果
+     * @return 新增方案ID
      */
     @PostMapping
     @Log(value = "新增方案", module = "方案管理", operationType = OperationType.INSERT)
-    public Result<Void> add(@RequestBody @Valid PlanSaveDTO dto) {
-        planService.addPlan(dto);
-        return Result.success();
+    public Result<Long> add(@RequestBody @Valid PlanSaveDTO dto) {
+        return Result.success(planService.addPlan(dto));
     }
 
     /**

+ 1 - 1
code/backend/src/main/java/com/aijiuyi/admin/controller/dto/PlanSaveDTO.java

@@ -52,7 +52,7 @@ public class PlanSaveDTO {
     /** 创作人名称 */
     private String authorName;
 
-    /** 状态:0=草稿,1=已发布,2=已下架(新增时默认草稿) */
+    /** 状态:0=草稿,1=已发布,2=已下架(新增时为空默认草稿,可传1直接发布) */
     private Integer status;
 
     /** 治疗步骤列表 */

+ 2 - 1
code/backend/src/main/java/com/aijiuyi/admin/service/PlanService.java

@@ -34,8 +34,9 @@ public interface PlanService extends IService<Plan> {
      * 新增方案(含步骤)
      *
      * @param dto 方案信息
+     * @return 新增方案ID
      */
-    void addPlan(PlanSaveDTO dto);
+    Long addPlan(PlanSaveDTO dto);
 
     /**
      * 修改方案(含步骤)

+ 24 - 7
code/backend/src/main/java/com/aijiuyi/admin/service/impl/PlanServiceImpl.java

@@ -97,13 +97,14 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
     }
 
     /**
-     * 新增方案(含步骤),状态默认为草稿
+     * 新增方案(含步骤),支持保存草稿或直接发布
      *
      * @param dto 方案信息
+     * @return 新增方案ID
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void addPlan(PlanSaveDTO dto) {
+    public Long addPlan(PlanSaveDTO dto) {
         // 校验步骤不为空
         if (dto.getSteps() == null || dto.getSteps().isEmpty()) {
             throw new BusinessException(ResultCode.PLAN_STEP_MIN_ERROR);
@@ -120,12 +121,13 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
         applyAddPlanModeRules(plan);
         fillCurrentAuthor(plan);
         plan.setPlanCode(planCode);
-        plan.setStatus(0); // 草稿
+        plan.setStatus(resolveAddPlanStatus(dto.getStatus()));
         plan.setUseCount(0);
         save(plan);
         // 保存步骤
         saveSteps(plan.getId(), dto.getSteps());
         LogUtil.info(PlanServiceImpl.class, "新增方案[{}],编码[{}]", plan.getName(), planCode);
+        return plan.getId();
     }
 
     /**
@@ -202,13 +204,22 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
     }
 
     private void applyAddPlanModeRules(Plan plan) {
-        if (!Integer.valueOf(MODE_TYPE_CUSTOM).equals(plan.getModeType())
-                && !Integer.valueOf(MODE_TYPE_MASTER).equals(plan.getModeType())) {
+        if (!isEditableModeType(plan.getModeType())) {
             throw new BusinessException(ResultCode.PARAM_ERROR);
         }
         plan.setEffectType("");
     }
 
+    private int resolveAddPlanStatus(Integer status) {
+        if (status == null || Integer.valueOf(0).equals(status)) {
+            return 0;
+        }
+        if (Integer.valueOf(1).equals(status)) {
+            return 1;
+        }
+        throw new BusinessException(ResultCode.PARAM_ERROR);
+    }
+
     private void applyUpdatePlanModeRules(Plan plan, String originalPlanCode, String originalName, Integer originalStatus, boolean systemPresetPlan) {
         if (systemPresetPlan) {
             plan.setPlanCode(originalPlanCode);
@@ -223,9 +234,15 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
             plan.setEffectType(getProfessionalPresetEffectType(originalPlanCode));
             return;
         }
-        if (!Integer.valueOf(MODE_TYPE_PROFESSIONAL).equals(plan.getModeType())) {
-            plan.setEffectType("");
+        if (!isEditableModeType(plan.getModeType())) {
+            throw new BusinessException(ResultCode.PARAM_ERROR);
         }
+        plan.setEffectType("");
+    }
+
+    private boolean isEditableModeType(Integer modeType) {
+        return Integer.valueOf(MODE_TYPE_CUSTOM).equals(modeType)
+                || Integer.valueOf(MODE_TYPE_MASTER).equals(modeType);
     }
 
     private boolean isSystemPresetPlan(Plan plan) {

+ 2 - 1
code/frontend/src/api/plan.js

@@ -17,8 +17,9 @@ export function getPlanDetail(id) {
 }
 
 /**
- * 新增方案(保存草稿)
+ * 新增方案(保存草稿或直接发布
  * @param {Object} data 方案信息(含步骤列表)
+ * @returns {Promise<Object>} 返回新增方案ID
  */
 export function addPlan(data) {
   return request.post('/plan', data)

+ 1 - 1
code/frontend/src/layout/index.vue

@@ -171,7 +171,7 @@ async function handleCommand(command) {
     await userStore.logout()
     router.replace('/login')
   } else if (command === 'profile') {
-    router.push('/profile')
+    router.push({ path: '/profile', query: { from: route.fullPath } })
   }
 }
 

+ 16 - 6
code/frontend/src/views/plan/index.vue

@@ -722,7 +722,7 @@ const editableModeTypeOptions = computed(() => {
   if (isProfessionalPresetPlan(formData)) {
     return modeTypeOptions.filter(item => item.value === 2)
   }
-  return modeTypeOptions
+  return addModeTypeOptions
 })
 
 const isModeTypeLocked = computed(() => (
@@ -736,9 +736,6 @@ const isEffectTypeLocked = computed(() => dialogMode.value === 'edit' && isProfe
 const showEffectTypeField = computed(() => formData.modeType === 2 && !isOneClickPresetPlan(formData))
 
 function applyPlanModeRules() {
-  if (dialogMode.value === 'add' && ![3, 4].includes(formData.modeType)) {
-    formData.modeType = 3
-  }
   if (isOneClickPresetPlan(formData)) {
     formData.modeType = 1
     formData.effectType = ''
@@ -749,6 +746,9 @@ function applyPlanModeRules() {
     formData.effectType = getProfessionalPresetEffect(formData)
     return
   }
+  if (![3, 4].includes(formData.modeType)) {
+    formData.modeType = 3
+  }
   if (formData.modeType !== 2) {
     formData.effectType = ''
   }
@@ -829,6 +829,7 @@ async function handleSubmit(publishFlag) {
   applyCurrentAuthor()
   submitLoading.value = true
   try {
+    const shouldPublish = !isSystemPresetPlan(formData) && publishFlag === 1
     const payload = {
       ...formData,
       symptoms: formData.symptomsList.join(','),
@@ -836,10 +837,19 @@ async function handleSubmit(publishFlag) {
     }
     if (formData.id) {
       await updatePlan(payload)
+      if (shouldPublish) {
+        await publishPlan(formData.id)
+      }
     } else {
-      await addPlan(payload)
+      const res = await addPlan(payload)
+      if (shouldPublish) {
+        if (!res.data) {
+          throw new Error('未获取到新增方案ID,无法同步发布')
+        }
+        await publishPlan(res.data)
+      }
     }
-    ElMessage.success('操作成功')
+    ElMessage.success(shouldPublish ? '发布成功' : '操作成功')
     dialogVisible.value = false
     loadData()
   } finally {

+ 57 - 6
code/frontend/src/views/profile/index.vue

@@ -87,6 +87,7 @@
               保存修改
             </el-button>
             <el-button @click="handleReset">重置</el-button>
+            <el-button @click="handleBack">取消</el-button>
           </el-form-item>
         </el-form>
       </div>
@@ -96,8 +97,8 @@
 
 <script setup>
 import { ref, reactive, onMounted } from 'vue'
-import { useRouter } from 'vue-router'
-import { ElMessage } from 'element-plus'
+import { useRoute, useRouter } from 'vue-router'
+import { ElMessage, ElMessageBox } from 'element-plus'
 import { UserFilled, Camera } from '@element-plus/icons-vue'
 import { useUserStore } from '@/store/user'
 import { updateProfile, uploadImage, getUserInfoApi } from '@/api/auth'
@@ -106,11 +107,13 @@ import { updateProfile, uploadImage, getUserInfoApi } from '@/api/auth'
 const defaultAvatar = '/default-avatar.png'
 
 const userStore = useUserStore()
+const route = useRoute()
 const router = useRouter()
 const formRef = ref()
 const fileInput = ref()
 const submitLoading = ref(false)
 const avatarUrl = ref('')
+const savedFormSnapshot = ref('')
 
 const formData = reactive({
   nickname: '',
@@ -121,6 +124,48 @@ const formData = reactive({
   confirmPassword: ''
 })
 
+function createFormSnapshot() {
+  return JSON.stringify({
+    nickname: formData.nickname || '',
+    phone: formData.phone || '',
+    address: formData.address || '',
+    oldPassword: formData.oldPassword || '',
+    password: formData.password || '',
+    confirmPassword: formData.confirmPassword || ''
+  })
+}
+
+function markFormClean() {
+  savedFormSnapshot.value = createFormSnapshot()
+}
+
+function hasUnsavedChanges() {
+  return !!savedFormSnapshot.value && createFormSnapshot() !== savedFormSnapshot.value
+}
+
+async function handleBack() {
+  if (hasUnsavedChanges()) {
+    await ElMessageBox.confirm(
+      '当前个人信息有未保存的修改,返回后这些修改将不会保留,确认返回吗?',
+      '未保存提示',
+      {
+        type: 'warning',
+        confirmButtonText: '确认返回',
+        cancelButtonText: '继续编辑'
+      }
+    )
+  }
+
+  const from = typeof route.query.from === 'string' ? route.query.from : ''
+  if (from && from !== route.path && from !== route.fullPath && from.startsWith('/')) {
+    router.push(from)
+  } else if (window.history.state?.back) {
+    router.back()
+  } else {
+    router.push('/')
+  }
+}
+
 // 表单验证规则
 const formRules = {
   phone: [
@@ -184,6 +229,11 @@ async function loadUserInfo() {
     formData.nickname = info.nickname || ''
     formData.phone = info.phone || ''
     formData.address = info.address || ''
+    formData.oldPassword = ''
+    formData.password = ''
+    formData.confirmPassword = ''
+    markFormClean()
+    formRef.value?.clearValidate()
   } catch (e) {
     // ignore
   }
@@ -244,6 +294,10 @@ async function handleSubmit() {
     await updateProfile(payload)
     // 如果修改了密码,提示后退出登录重新登录
     if (formData.password) {
+      formData.oldPassword = ''
+      formData.password = ''
+      formData.confirmPassword = ''
+      markFormClean()
       ElMessage.success('密码修改成功,请重新登录')
       setTimeout(async () => {
         await userStore.logout()
@@ -258,6 +312,7 @@ async function handleSubmit() {
     formData.oldPassword = ''
     formData.password = ''
     formData.confirmPassword = ''
+    markFormClean()
   } finally {
     submitLoading.value = false
   }
@@ -266,10 +321,6 @@ async function handleSubmit() {
 // 重置表单
 function handleReset() {
   loadUserInfo()
-  formData.oldPassword = ''
-  formData.password = ''
-  formData.confirmPassword = ''
-  formRef.value?.clearValidate()
 }
 
 onMounted(() => {