Explorar el Código

voluntary list - fit api

abpcoder hace 3 días
padre
commit
89e7bc5c02

+ 2 - 1
src/pagesMain/pages/me/components/me-menu.vue

@@ -50,6 +50,7 @@
 <script lang="ts" setup>
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { useUserStore } from '@/store/userStore';
+import {routes} from "@/common/routes";
 const { transferTo } = useTransferPage();
 const userStore = useUserStore();
 
@@ -75,7 +76,7 @@ const menus = [
   {
     name: '我的志愿表',
     icon: '/static/personal/my_simulated.png',
-    pagePath: '/pagesOther/pages/ie/entry-ai-list/entry-ai-list',
+    pagePath: routes.voluntaryList,
   },
   {
     name: '绑定会员卡',

+ 8 - 2
src/pagesOther/pages/voluntary/list/components/voluntary-item.vue

@@ -10,7 +10,7 @@
                 <view class="text-30 font-bold text-fore-title flex-1">{{ data.universityName }}</view>
                 <uv-icon name="more-dot-fill" size="20" @click="$emit('more')"/>
             </view>
-            <voluntary-majors-draggable v-model:majors="data.majors" />
+            <voluntary-majors-draggable v-model:majors="data.majors" @update:majors="handleSortUpdate" />
         </view>
     </view>
 </template>
@@ -18,12 +18,13 @@
 <script lang="ts" setup>
 import {VoluntaryRecord} from "@/types/voluntary";
 import VoluntaryMajorsDraggable from "@/pagesOther/pages/voluntary/list/components/voluntary-majors-draggable.vue";
+import {sortVoluntaryByMajor} from "@/api/modules/voluntary";
 
 const props = defineProps<{
     index: number;
     data: VoluntaryRecord;
 }>()
-const emits = defineEmits(['more'])
+const emits = defineEmits(['more', 'error'])
 
 const indexOptions = [{
     text: '第一志愿',
@@ -33,6 +34,11 @@ const indexOptions = [{
     clazz: 'bg-primary-100 text-primary'
 }]
 const showIndex = computed(() => indexOptions[props.index])
+
+const handleSortUpdate = () => {
+    sortVoluntaryByMajor(props.data.universityId, props.data.majors.map(m => m.majorId))
+        .catch((e: any) => emits('error', e))
+}
 </script>
 
 <style scoped>

+ 112 - 3
src/pagesOther/pages/voluntary/list/list.vue

@@ -10,22 +10,70 @@
                 目前志愿计划为2025年,排序前两个为第一、二志愿,可通过修改排序重新选择第一、二志愿
             </view>
             <view class="p-28 flex flex-col gap-28">
-                <voluntary-item v-for="(item,i) in list" :key="i" :data="item" :index="i"/>
+                <voluntary-item v-for="(item,i) in list" :key="i" :data="item" :index="i"
+                                @more="showActions(item)" @error="handleError"/>
             </view>
         </z-paging>
+        <uv-action-sheet ref="actionSheet" :actions="moreActions" safe-area-inset-bottom close-on-click-overlay
+                         cancel-text="取消" @select="handleActionSelect"/>
     </ie-page>
 </template>
 
 <script setup lang="ts">
 import {VoluntaryRecord} from "@/types/voluntary";
 import VoluntaryItem from "@/pagesOther/pages/voluntary/list/components/voluntary-item.vue";
-import {ApiResponseList} from "@/types";
 import {VOLUNTARY_SORTING} from "@/types/injectionSymbols";
-import {getVoluntaryList} from "@/api/modules/voluntary";
+import {getVoluntaryList, removeVoluntaryByUniversity, sortVoluntaryByUniversity} from "@/api/modules/voluntary";
+import UvActionSheet from "@/uni_modules/uv-action-sheet/components/uv-action-sheet/uv-action-sheet.vue";
+
+interface ActionItem {
+    id: string;
+    name: string;
+    icon?: string;
+    color?: string;
+    iconColor?: string;
+    disabled?: boolean;
+}
 
 const list = ref<VoluntaryRecord[]>([])
 const paging = ref<ZPagingInstance>()
 const isSorting = ref<boolean>(false)
+const actionSheet = ref<InstanceType<typeof UvActionSheet>>()
+const actionRecord = ref<VoluntaryRecord>()
+const moreActions = computed<ActionItem[]>(() => {
+    const records = list.value
+    const current = actionRecord.value
+    const idx = current ? records.indexOf(current) : -1
+    const enableTop = records.length > 1 && idx > 0
+    const enableUp = records.length > 1 && idx > 0
+    const enableDown = records.length > 1 && idx < records.length - 1
+    return [{
+        id: 'top',
+        name: '置顶',
+        icon: 'pushpin-fill',
+        color: 'var(--primary-color)',
+        iconColor: enableTop ? 'primary' : 'info',
+        disabled: !enableTop
+    }, {
+        id: 'up',
+        name: '上移',
+        icon: 'arrow-upward',
+        iconColor: enableUp ? '' : 'info',
+        disabled: !enableUp
+    }, {
+        id: 'down',
+        name: '下移',
+        icon: 'arrow-downward',
+        iconColor: enableDown ? '' : 'info',
+        disabled: !enableDown
+    }, {
+        id: 'delete',
+        name: '删除',
+        icon: 'trash',
+        color: 'var(--danger)',
+        iconColor: 'error'
+    }]
+})
 
 const handleQuery = () => {
     getVoluntaryList().then(res => {
@@ -33,6 +81,67 @@ const handleQuery = () => {
     }).catch(e => paging.value?.completeByError(e))
 }
 
+const showActions = (record: VoluntaryRecord) => {
+    actionRecord.value = record
+    actionSheet.value?.open()
+}
+
+const handleActionSelect = async (e: ActionItem) => {
+    const record = actionRecord.value
+    const recordList = list.value
+    if (!record) return
+    const idx = recordList.findIndex(r => r == record)
+    if (['top', 'up', 'down'].includes(e.id)) {
+        try {
+            switch (e.id) {
+                case 'top':
+                    if (idx > 0) {
+                        recordList.splice(idx, 1)
+                        recordList.unshift(record)
+                        await sortVoluntaryByUniversity(recordList.map(r => r.universityId))
+                        uni.$ie.showSuccess('保存成功')
+                    }
+                    break;
+                case 'up':
+                    if (idx > 0) {
+                        recordList.splice(idx, 1)
+                        recordList.splice(idx - 1, 0, record)
+                        await sortVoluntaryByUniversity(recordList.map(r => r.universityId))
+                        uni.$ie.showSuccess('保存成功')
+                    }
+                    break;
+                case 'down':
+                    if (idx < recordList.length - 1) {
+                        recordList.splice(idx, 1)
+                        recordList.splice(idx + 1, 0, record)
+                        await sortVoluntaryByUniversity(recordList.map(r => r.universityId))
+                        uni.$ie.showSuccess('保存成功')
+                    }
+                    break;
+            }
+        } catch (e) {
+            console.log('action ex', e)
+            paging.value?.reload() // 发生异常时,重新加载列表
+        }
+    } else if (e.id === 'delete') {
+        await uni.$ie.showConfirm({
+            title: '志愿删除提醒',
+            content: `删除'${record.universityName}',将同时删除该院校下所有意向专业。\n确认删除?!`
+        })
+        recordList.splice(idx, 1)
+        removeVoluntaryByUniversity(record.universityId)
+            .then(() => uni.$ie.showSuccess('删除成功'))
+            .catch(() => paging.value?.reload())
+    } else {
+        throw new Error('Unsupported action id: ' + e.id)
+    }
+}
+
+const handleError = () => {
+    // 内部异常,重新取数
+    paging.value?.reload()
+}
+
 provide(VOLUNTARY_SORTING, isSorting)
 </script>
 

+ 1 - 1
src/uni_modules/uv-action-sheet/components/uv-action-sheet/uv-action-sheet.vue

@@ -70,7 +70,7 @@
                                         :style="[itemStyle(index)]"
                                     >
                                         {{ item.name }}
-                                        <uv-icon v-if="item.icon" :name="item.icon"/>
+                                        <uv-icon v-if="item.icon" :name="item.icon" :color="item.iconColor"/>
                                     </view>
                                     <text
                                         v-if="item.subname"

+ 27 - 0
src/utils/uni-tool.ts

@@ -67,6 +67,14 @@ export interface IeTool {
    */
   showModal(params: IModalOptions): Promise<boolean>;
 
+  /*
+  * 显示模态对话框, 与showModal的差异在于,确认时命中resolve, 取消时命中reject.
+  * // NOTE: 没有直接在showModal里改,是因为使用的地方太多,避免直接修改影响太广 2026.1.8
+  * @param params - 模态框配置选项
+  * @returns Promise<boolean> - 用户点击确认返回 true,点击取消返回 false
+  * */
+  showConfirm(params: IModalOptions): Promise<boolean>;
+
   /**
    * 复制内容
    * @param content - 要复制的内容
@@ -164,6 +172,25 @@ const tool: IeTool = {
       });
     });
   },
+  showConfirm(params: IModalOptions) {
+    const { title, content, showCancel, confirmText, cancelText, cancelColor, confirmColor } = Object.assign(defaultModalOptions, params);
+    return new Promise((resolve, reject) => {
+      uni.showModal({
+        title,
+        content,
+        showCancel,
+        confirmText,
+        cancelText,
+        cancelColor,
+        confirmColor,
+        success: (res) => {
+          if (res.confirm) resolve(res.confirm)
+          else reject(res.confirm)
+        },
+        fail: reject
+      });
+    });
+  },
   copy(content: string) {
     uni.setClipboardData({
       data: content,