Bläddra i källkod

display is ok

abpcoder 23 timmar sedan
förälder
incheckning
ac7e0a7230

+ 48 - 24
src/pagesOther/pages/university/detail/components/plan-enroll-list.vue

@@ -5,30 +5,49 @@
             <template #top>
                 <view class="flex items-center gap-20 px-30 py-20">
                     <ie-picker v-model="queryParams.year" :list="years" width="w-fit" icon="arrow-down"
+                               placeholder="年份"
                                custom-class="px-30 py-10 bg-primary-100 rounded" @change="handleYearChange"/>
                     <ie-picker v-model="queryParams.level" :list="levels" width="w-fit" icon="arrow-down"
+                               placeholder="级别"
                                custom-class="px-30 py-10 bg-primary-100 rounded" @change="handleLevelChange"/>
                     <ie-picker v-model="queryParams.group" :list="groups" width="w-fit" icon="arrow-down"
+                               placeholder="专业组"
                                custom-class="px-30 py-10 bg-primary-100 rounded" @change="handleGroupChange"/>
                 </view>
             </template>
-            <view v-for="([label, values], idx) in groupedResults" class="fx-col px-30">
+            <view v-for="([label, values], idx) in groupedResults" :key="label" class="px-30">
                 <uv-divider v-if="idx>0"/>
-                <view v-if="label" class="text-primary font-bold mb-20">{{ label }}</view>
-                <view v-for="(item,i) in values" class="px-20 fx-col">
-                    <view class="font-bold text-main">
-                        {{ item.majorName }}
-                        <template v-if="item.groupName">({{ item.groupName }})</template>
-                        <template v-if="item.specialProject">({{ item.specialProject }})</template>
+                <view class="flex flex-col gap-20">
+                    <view v-for="(item,i) in values" :key="i" class="bg-back-light p-24 rounded-xl">
+                        <view class="text-fore-title">
+                            <text class="font-bold text-30">{{ item.majorName }}</text>
+                            <text v-if="item.specialProject" class="text-24">({{ item.specialProject }})</text>
+                        </view>
+                        <view v-if="item.marjorDirection" class="text-primary text-24">
+                            {{ item.marjorDirection }}
+                        </view>
+                        <view v-if="mode=='plan'" class="mt-12 text-22 flex gap-30">
+                            <view v-if="item.majorGroup" class="font-bold">{{ item.majorGroup }}</view>
+                            <view>
+                                学费
+                                <text class="font-bold">{{ item.fee || '-' }}</text>
+                                /年
+                            </view>
+                            <view>
+                                学制
+                                <text class="font-bold">{{ item.xueZhi || '-' }}</text>
+                                年
+                            </view>
+                        </view>
+                        <view v-if="mode=='enroll'&&item.majorGroup" class="mt-12 text-22 flex gap-30">
+                            <view v-if="item.majorGroup" class="font-bold">{{ item.majorGroup }}</view>
+                        </view>
+                        <view class="mt-20 grid gap-20" :class="`grid-cols-`+descriptors.length">
+                            <plan-enroll-descriptor v-for="d in descriptors" :key="d.title" :title="d.title"
+                                                    :value="item[d.prop]" :title-only="d.titleOnly"
+                                                    @click="handleRuleClick(d, item)"/>
+                        </view>
                     </view>
-                    <view v-if="item.marjorDirection" class="font-[PingFang] text-2xs text-content">
-                        {{ item.marjorDirection }}
-                    </view>
-                    <view class="mt-10 grid gap-20" :class="`grid-cols-`+descriptors.length">
-                        <plan-enroll-descriptor v-for="d in descriptors" :title="d.title" :value="item[d.key]"
-                                                :title-only="d.titleOnly" @click="handleRuleClick(d, item)"/>
-                    </view>
-                    <uv-divider v-if="i<values.length-1" dashed/>
                 </view>
             </view>
         </z-paging>
@@ -54,13 +73,13 @@ const paging = ref<ZPagingInstance>()
 const isCultural = ref(false) // 河南文化类遗留结构
 const tag = computed(() => isCultural.value && '') // examMajorName 河南文化类遗留结构
 const descriptors = computed<IPlanEnrollDescriptor[]>(() => {
-    const enrollShared = [{title: '录取', key: 'realNum'}, {title: '最低分', key: 'minScore'}]
+    const enrollShared = [{title: '录取', prop: 'realNum'}, {title: '最低分', prop: 'minScore'}]
     const cols: IPlanEnrollDescriptor[] = props.mode == 'plan'
-        ? [{title: '计划', key: 'planNum'}, {title: '学制', key: 'xueZhi'}, {title: '学费', key: 'fee'}]
+        ? [{title: '计划', prop: 'planNum'}, {title: '招录比', prop: 'acceptanceRate'}]
         : isCultural.value
-            ? [...enrollShared, {title: '最低位', key: 'minSeat'}]
+            ? [...enrollShared, {title: '最低位', prop: 'minSeat'}]
             : [...enrollShared]
-    if (!isCultural.value) cols.push({title: '录取规则', key: '', titleOnly: true})
+    if (!isCultural.value) cols.push({title: '录取规则', prop: '', titleOnly: true})
     return cols
 })
 
@@ -71,8 +90,11 @@ const years = computed(() => _.orderBy(_.uniq(_.map(props.list, i => i.year)), [
     .map(i => ({label: i, value: i})))
 const levels = computed(() => _.uniq(_.map(props.list.filter(i => i.year == queryParams.value.year), i => i.level))
     .map(i => ({label: i, value: i})))
-const groups = computed(() => _.uniq(_.map(props.list.filter(i => i.year == queryParams.value.year && i.level == queryParams.value.level), i => i.majorGroup))
-    .map(g => ({label: g, value: g})))
+const groups = computed(() => [{
+    label: '不限',
+    value: ''
+}, ..._.uniq(_.map(props.list.filter(i => i.year == queryParams.value.year && i.level == queryParams.value.level), i => i.majorGroup))
+    .map(g => ({label: g, value: g}))])
 
 const listOfYear = computed(() => queryParams.value.year ? props.list.filter(i => i.year == queryParams.value.year) : [])
 const listOfLevel = computed(() => queryParams.value.level ? listOfYear.value.filter(i => i.level == queryParams.value.level) : [])
@@ -91,6 +113,7 @@ const handleGroupChange = () => {
 }
 
 const handleQuery = () => {
+    console.log('plan enroll list: query', queryParams.value)
     // 到这里时listOfLevel应该已经动态计算完毕了
     // onSearch, results结构都是多余的,这里只是为了实验z-paging的虚拟列表
     paging.value?.completeByNoMore(listOfGroup.value, true)
@@ -100,13 +123,14 @@ const handleRuleClick = (descriptor: IPlanEnrollDescriptor, history: IPlanEnroll
     if (descriptor.titleOnly) emits('rule', history.totalRule)
 }
 
-watch(props.list, (list) => {
+watch(props.list, async (list) => {
+    console.log('plan enroll list: watch', list)
     if (list.length) {
         queryParams.value.year = years.value[0].value
         queryParams.value.level = levels.value[0].value
     }
-    paging.value?.reload()
-})
+    setTimeout(() => paging.value?.reload(), 500) // paging还没有初始化好
+}, {immediate: true})
 </script>
 
 <style scoped>

+ 7 - 4
src/pagesOther/pages/university/detail/components/plus/plan-enroll-descriptor.vue

@@ -1,10 +1,13 @@
 <template>
-    <view class="fx-col fx-cen-cen rounded-lg bg-slate-100 py-10">
+    <view class="flex flex-col justify-center items-center rounded-lg bg-white py-10">
         <template v-if="!titleOnly">
-            <text class="text-main text-sm">{{ value || '-' }}</text>
-            <text class="text-tips text-3xs">{{ title }}</text>
+            <text class="text-fore-title text-30 font-bold">{{ value || '-' }}</text>
+            <text class="text-fore-tip text-24">{{ title }}</text>
+        </template>
+        <template v-else>
+            <text class="text-fore-title text-30 font-bold">查看</text>
+            <text class="text-fore-tip text-24">{{ title }}</text>
         </template>
-        <text v-else class="text-primary text-sm">{{ title }}</text>
     </view>
 </template>
 

+ 11 - 4
src/pagesOther/pages/voluntary/list/components/voluntary-item.vue

@@ -10,21 +10,21 @@
                 <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" @change="handleSortUpdate" />
+            <voluntary-majors-draggable v-model:majors="data.majors" @change="handleSortUpdate" @delete="handleDelete" />
         </view>
     </view>
 </template>
 
 <script lang="ts" setup>
-import {VoluntaryRecord} from "@/types/voluntary";
+import {VoluntaryMajorItem, VoluntaryRecord} from "@/types/voluntary";
 import VoluntaryMajorsDraggable from "@/pagesOther/pages/voluntary/list/components/voluntary-majors-draggable.vue";
-import {sortVoluntaryByMajor} from "@/api/modules/voluntary";
+import {removeVoluntaryByMajor, sortVoluntaryByMajor} from "@/api/modules/voluntary";
 
 const props = defineProps<{
     index: number;
     data: VoluntaryRecord;
 }>()
-const emits = defineEmits(['more', 'error'])
+const emits = defineEmits(['more', 'error', 'deleted'])
 
 const indexOptions = [{
     text: '第一志愿',
@@ -39,6 +39,13 @@ const handleSortUpdate = () => {
     sortVoluntaryByMajor(props.data.universityId, props.data.majors.map(m => m.majorId))
         .catch((e: any) => emits('error', e))
 }
+
+const handleDelete = async (m: VoluntaryMajorItem) => {
+    await uni.$ie.showConfirm({title: '删除提醒', content: `确定删除该专业?!`})
+    await removeVoluntaryByMajor(m.majorId)
+    uni.$ie.showSuccess('删除成功')
+    emits('deleted')
+}
 </script>
 
 <style scoped>

+ 3 - 2
src/pagesOther/pages/voluntary/list/components/voluntary-majors-draggable.vue

@@ -11,7 +11,7 @@
             <view class="text-32 text-fore-placeholder font-bold">{{ toFixedLen(i) }}</view>
             <view class="flex-1 w-0 text-28 text-fore-title font-bold truncate">{{ m.majorName }}</view>
 
-            <uv-icon name="trash" size="18" color="error"/>
+            <uv-icon name="trash" size="18" color="error" @click="$emit('delete', m)"/>
 
             <!-- 拖拽手柄:Sortable handle -->
             <view class="drag-handle">
@@ -46,7 +46,7 @@
                 <view class="flex-1 flex items-center gap-20" @touchstart.stop @touchmove.stop>
                     <view class="text-32 text-fore-placeholder font-bold">{{ toFixedLen(i) }}</view>
                     <view class="flex-1 w-0 text-28 text-fore-title font-bold truncate">{{ m.majorName }}</view>
-                    <uv-icon name="trash" size="18" color="error" />
+                    <uv-icon name="trash" size="18" color="error" @click="$emit('delete', m)" />
                 </view>
 
                 <!-- 手柄:不 stop / prevent -->
@@ -71,6 +71,7 @@ const props = defineProps<{
 }>();
 
 const emits = defineEmits<{
+    (e: "delete", major: VoluntaryMajorItem): void;
     (e: "update:majors", majors: VoluntaryMajorItem[]): void;
     (e: "change", majors: VoluntaryMajorItem[]): void;
 }>();

+ 139 - 135
src/pagesOther/pages/voluntary/list/list.vue

@@ -1,172 +1,176 @@
 <template>
-  <ie-page>
-    <z-paging ref="paging" v-model="list" bg-color="#F6F8FA" safe-area-inset-bottom :scrollable="!isSorting"
-      :refresher-enabled="!isSorting" @query="handleQuery">
-      <template #top>
-        <ie-navbar title="志愿表" />
-      </template>
-      <view class="mt-20 bg-warning-light p-28 text-23 leading-38 text-fore-title">
-        <text class="font-bold">说明:</text>
-        目前志愿计划为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" @more="showActions(item)"
-          @error="handleError" />
-      </view>
-    </z-paging>
-    <ie-safe-toolbar :height="84" :shadow="false">
-      <view class="px-30 py-16">
-        <ie-button @click="handleAdd">添加志愿</ie-button>
-      </view>
-    </ie-safe-toolbar>
-    <uv-action-sheet ref="actionSheet" :actions="moreActions" safe-area-inset-bottom close-on-click-overlay
-      cancel-text="取消" @select="handleActionSelect" />
-  </ie-page>
+    <ie-page>
+        <z-paging ref="paging" v-model="list" bg-color="#F6F8FA" safe-area-inset-bottom :scrollable="!isSorting"
+                  :refresher-enabled="!isSorting" @query="handleQuery">
+            <template #top>
+                <ie-navbar title="志愿表"/>
+            </template>
+            <view class="mt-20 bg-warning-light p-28 text-23 leading-38 text-fore-title">
+                <text class="font-bold">说明:</text>
+                目前志愿计划为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" @more="showActions(item)"
+                                @error="handleError" @deleted="handleDeleted"/>
+            </view>
+        </z-paging>
+        <ie-safe-toolbar :height="84" :shadow="false">
+            <view class="px-30 py-16">
+                <ie-button @click="handleAdd">添加志愿</ie-button>
+            </view>
+        </ie-safe-toolbar>
+        <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 { SelectedUniversityMajor, VoluntaryRecord } from "@/types/voluntary";
+import {SelectedUniversityMajor, VoluntaryRecord} from "@/types/voluntary";
 import VoluntaryItem from "@/pagesOther/pages/voluntary/list/components/voluntary-item.vue";
-import { VOLUNTARY_SORTING } from "@/types/injectionSymbols";
+import {VOLUNTARY_SORTING} from "@/types/injectionSymbols";
 import {
-  addVoluntary,
-  getVoluntaryList,
-  removeVoluntaryByUniversity,
-  sortVoluntaryByUniversity
+    addVoluntary,
+    getVoluntaryList,
+    removeVoluntaryByUniversity,
+    sortVoluntaryByUniversity
 } from "@/api/modules/voluntary";
 import UvActionSheet from "@/uni_modules/uv-action-sheet/components/uv-action-sheet/uv-action-sheet.vue";
-import { useTransferPage } from "@/hooks/useTransferPage";
-import { UniversityPickerPageOptions } from "@/types/transfer";
-import { routes } from "@/common/routes";
+import {useTransferPage} from "@/hooks/useTransferPage";
+import {UniversityPickerPageOptions} from "@/types/transfer";
+import {routes} from "@/common/routes";
 
 interface ActionItem {
-  id: string;
-  name: string;
-  icon?: string;
-  color?: string;
-  iconColor?: string;
-  disabled?: boolean;
+    id: string;
+    name: string;
+    icon?: string;
+    color?: string;
+    iconColor?: string;
+    disabled?: boolean;
 }
 
-const { transferTo } = useTransferPage()
+const {transferTo} = useTransferPage()
 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 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 => {
-    paging.value?.completeByNoMore(res.data, true)
-  }).catch(e => paging.value?.completeByError(e))
+    getVoluntaryList().then(res => {
+        paging.value?.completeByNoMore(res.data, true)
+    }).catch(e => paging.value?.completeByError(e))
 }
 
 const showActions = (record: VoluntaryRecord) => {
-  actionRecord.value = record
-  actionSheet.value?.open()
+    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() // 发生异常时,重新加载列表
+    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') {
+        const confirm = await uni.$ie.showConfirm({
+            title: '志愿删除提醒',
+            content: `删除'${record.universityName}',将同时删除该院校下所有意向专业。\n确认删除?!`
+        })
+        if (confirm) {
+            await removeVoluntaryByUniversity(record.universityId)
+            uni.$ie.showSuccess('删除成功')
+            paging.value?.reload()
+        }
+    } else {
+        throw new Error('Unsupported action id: ' + e.id)
     }
-  } else if (e.id === 'delete') {
-    const confirm = await uni.$ie.showConfirm({
-      title: '志愿删除提醒',
-      content: `删除'${record.universityName}',将同时删除该院校下所有意向专业。\n确认删除?!`
-    })
-    if (confirm) {
-      await removeVoluntaryByUniversity(record.universityId)
-      uni.$ie.showSuccess('删除成功')
-      paging.value?.reload()
-    }
-  } else {
-    throw new Error('Unsupported action id: ' + e.id)
-  }
 }
 
 const handleError = () => {
-  // 内部异常,重新取数
-  paging.value?.reload()
+    // 内部异常,重新取数
+    paging.value?.reload()
+}
+
+const handleDeleted = () => {
+    paging.value?.reload()
 }
 
 const handleAdd = async () => {
-  const option: UniversityPickerPageOptions = {
-    title: '选择你的意向院校专业',
-    fromVoluntary: true
-  }
-  const picked = await transferTo(routes.targetPicker, { data: option })
-  if (!picked) return
-  await addVoluntary(picked)
-  uni.$ie.showSuccess('保存成功')
-  paging.value?.reload()
+    const option: UniversityPickerPageOptions = {
+        title: '选择你的意向院校专业',
+        fromVoluntary: true
+    }
+    const picked = await transferTo(routes.targetPicker, {data: option})
+    if (!picked) return
+    await addVoluntary(picked)
+    uni.$ie.showSuccess('保存成功')
+    paging.value?.reload()
 }
 
 provide(VOLUNTARY_SORTING, isSorting)

+ 3 - 2
src/types/university.ts

@@ -91,6 +91,7 @@ export interface UniversityPlanHistory extends IPlanEnrollHistory {
     "planNum": number|null;
     "fee": string;
     "xueZhi": string;
+    "acceptanceRate": string;
 }
 
 export interface UniversityEnrollHistory extends IPlanEnrollHistory {
@@ -100,9 +101,9 @@ export interface UniversityEnrollHistory extends IPlanEnrollHistory {
 }
 
 export interface IPlanEnrollDescriptor {
-    key?: string;
+    prop?: string;
     title?: string;
-    value?: string;
+    value?: string|number;
     titleOnly?: boolean;
 }