Bläddra i källkod

添加职业库列表

shmily1213 2 veckor sedan
förälder
incheckning
6767db804d

+ 12 - 0
src/api/modules/career.ts

@@ -0,0 +1,12 @@
+import flyio from "../flyio";
+import { ApiResponse, ApiResponseList } from "@/types";
+import { Career } from "@/types";
+
+/**
+ * 获取职业树
+ * @param params 
+ * @returns 
+ */
+export function getCareerTree(params: Career.CareerTreeQueryDTO) {
+  return flyio.get('/front/vocational/getAllVocation', params) as Promise<ApiResponse<Career.CareerItem[]>>;
+}

+ 0 - 293
src/components/ie-tree/ie-tree-node.vue

@@ -1,293 +0,0 @@
-<template>
-  <view class="ie-tree-node">
-    <!-- 节点内容 -->
-    <view @click.stop="handleClick">
-      <slot :node="nodeData" :parent="parentData">
-        <!-- 默认节点内容 -->
-        <view class="ie-tree-node__default">
-          <uv-icon 
-            v-if="!isLeafNode" 
-            name="arrow-right" 
-            size="14" 
-            color="#888"
-            :custom-class="['ie-tree-node__expand-icon', isExpanded ? 'ie-tree-node__expand-icon--expanded' : '']"
-          />
-          <text class="ie-tree-node__label">{{ nodeLabel }}</text>
-        </view>
-      </slot>
-    </view>
-
-    <!-- 子节点容器 -->
-    <view 
-      v-if="hasChildren" 
-      ref="childrenRef" 
-      class="ie-tree-node__children"
-      :id="`ie-tree-children-${nodeKey}`"
-      :class="['ie-tree-node__children', { 'ie-tree-node__children--measuring': isMeasuringHeight }]"
-      :style="childrenStyle"
-    >
-      <ie-tree-node 
-        v-for="child in childrenData" 
-        :key="getNodeKey(child)"
-        :node-data="child"
-        :parent-data="nodeData"
-        :tree-props="treeProps"
-        @node-click="handleChildNodeClick"
-      >
-        <template #default="slotProps: { node: any; parent: any }">
-          <slot :node="slotProps.node" :parent="slotProps.parent"></slot>
-        </template>
-      </ie-tree-node>
-    </view>
-  </view>
-</template>
-
-<script lang="ts" setup>
-import { getCurrentInstance, computed, ref, nextTick } from 'vue';
-import IeTreeNode from './ie-tree-node.vue';
-import type { TreeProps } from '@/types';
-
-defineOptions({
-  name: 'ie-tree-node',
-  options: {
-    virtualHost: true
-  }
-});
-
-const instance = getCurrentInstance();
-
-// Props
-const props = defineProps<{
-  nodeData: any; // 节点数据
-  parentData?: any; // 父节点数据
-  treeProps: TreeProps; // 树配置项
-}>();
-
-// Emits
-const emit = defineEmits<{
-  (e: 'node-click', data: { node: any; parent: any | null }): void;
-}>();
-
-// Slots
-defineSlots<{
-  default(props: { node: any; parent: any }): any;
-}>();
-
-// 默认配置
-const defaultTreeProps: Required<TreeProps> = {
-  children: 'children',
-  label: 'name',
-  nodeKey: 'id',
-  isLeaf: 'isLeaf',
-  disabled: 'disabled',
-  isExpanded: 'isExpanded'
-};
-
-// 合并配置
-const mergedProps = computed(() => ({
-  ...defaultTreeProps,
-  ...props.treeProps
-}));
-
-// 获取节点属性值
-const getNodeProp = (node: any, prop: string, defaultValue?: any) => {
-  return node?.[prop] ?? defaultValue;
-};
-
-// 获取节点唯一标识
-const getNodeKey = (node: any): string | number => {
-  const key = mergedProps.value.nodeKey;
-  return getNodeProp(node, key, node?.value ?? node?.id ?? '');
-};
-
-// 获取节点标签
-const nodeLabel = computed(() => {
-  return getNodeProp(props.nodeData, mergedProps.value.label, '');
-});
-
-// 获取子节点数据
-const childrenData = computed(() => {
-  const childrenProp = mergedProps.value.children;
-  return getNodeProp(props.nodeData, childrenProp, []) || [];
-});
-
-// 是否有子节点
-const hasChildren = computed(() => {
-  return childrenData.value && childrenData.value.length > 0;
-});
-
-// 判断是否为叶子节点
-const isLeafNode = computed(() => {
-  const isLeafProp = mergedProps.value.isLeaf;
-  const isLeaf = getNodeProp(props.nodeData, isLeafProp);
-  if (isLeaf !== undefined) {
-    return isLeaf;
-  }
-  // 如果没有 isLeaf 属性,根据是否有子节点判断
-  return !hasChildren.value;
-});
-
-// 是否展开
-const isExpanded = computed(() => {
-  const expandedProp = mergedProps.value.isExpanded;
-  return getNodeProp(props.nodeData, expandedProp, false);
-});
-
-// 节点唯一标识
-const nodeKey = computed(() => getNodeKey(props.nodeData));
-
-// 高度测量相关
-const isMeasuringHeight = ref(false);
-const childrenRef = ref();
-const measuredHeight = ref<number | string>(0);
-const isAnimating = ref(false);
-
-// 子节点容器样式
-const childrenStyle = computed(() => {
-  if (isMeasuringHeight.value) {
-    return { height: 'auto' };
-  }
-  const heightValue = typeof measuredHeight.value === 'number' ? `${measuredHeight.value}px` : measuredHeight.value;
-  return { height: heightValue };
-});
-
-// 获取元素尺寸
-const getRect = (selector: string) => {
-  return new Promise<{ top: number; height: number }>((resolve) => {
-    const query = uni.createSelectorQuery().in(instance?.proxy);
-    query.select(selector).boundingClientRect((rect) => {
-      resolve(rect as { top: number; height: number });
-    }).exec();
-  });
-};
-
-// 测量子节点高度
-const measureHeight = () => {
-  if (!hasChildren.value) return Promise.resolve(0);
-  
-  return new Promise<number>((resolve) => {
-    // 如果节点已经展开,说明子节点已经显示,可以直接测量,不需要隐藏
-    const needHiding = !isExpanded.value;
-    
-    if (needHiding) {
-      isMeasuringHeight.value = true;
-    }
-    
-    setTimeout(() => {
-      nextTick(() => {
-        getRect(`#ie-tree-children-${nodeKey.value}`).then((res) => {
-          if (needHiding) {
-            isMeasuringHeight.value = false;
-          }
-          const height = res?.height ?? 0;
-          resolve(height);
-        });
-      });
-    }, 50);
-  });
-};
-
-// 处理节点点击
-const handleClick = async () => {
-  // 切换展开状态
-  const expandedProp = mergedProps.value.isExpanded;
-  const newExpandedState = !isExpanded.value;
-  
-  if (newExpandedState) {
-    // 展开流程:
-    // 1. 先设置高度为 0(起始状态)
-    measuredHeight.value = 0;
-    
-    // 2. 更新展开状态,让子节点容器渲染
-    props.nodeData[expandedProp] = newExpandedState;
-    
-    // 3. 等待 DOM 更新,确保子节点容器已经渲染出来
-    await nextTick();
-    
-    // 4. 测量目标高度(此时子节点已经渲染,但高度是 0)
-    const height = await measureHeight();
-    
-    // 5. 再等一帧,确保浏览器已经渲染了高度为 0 的状态
-    await nextTick();
-    
-    // 6. 设置目标高度,触发 CSS 动画(0 → height)
-    setTimeout(() => {
-      measuredHeight.value = height;
-    }, 0)
-    
-    // 7. 动画完成后(350ms)设置为 auto
-    setTimeout(() => {
-      if (isExpanded.value && props.nodeData[expandedProp]) {
-        measuredHeight.value = 'auto';
-      }
-    }, 350);
-    
-  } else {
-    // 收起流程:
-    // 1. 如果当前是 auto,先测量实际高度并设置为固定值
-    if (measuredHeight.value === 'auto') {
-      const height = await measureHeight();
-      measuredHeight.value = height;
-      await nextTick();
-    }
-    
-    // 2. 等待一帧,确保浏览器已经应用了固定高度
-    await nextTick();
-    
-    // 3. 设置为 0,触发收起动画
-    measuredHeight.value = 0;
-    
-    // 4. 更新展开状态
-    props.nodeData[expandedProp] = newExpandedState;
-  }
-  
-  // 触发节点点击事件
-  // emit('node-click', {
-  //   node: props.nodeData,
-  //   parent: props.parentData || null
-  // });
-};
-
-// 处理子节点点击事件
-const handleChildNodeClick = (data: { node: any; parent: any | null }) => {
-  emit('node-click', data);
-};
-</script>
-
-<style lang="scss" scoped>
-.ie-tree-node {
-  &__default {
-    display: flex;
-    align-items: center;
-    padding: 10px 0;
-  }
-
-  &__expand-icon {
-    margin-right: 8px;
-    transition: transform 0.3s;
-    
-    &--expanded {
-      transform: rotate(90deg);
-    }
-  }
-
-  &__label {
-    flex: 1;
-  }
-
-  &__children {
-    padding-left: 20px;
-    overflow: hidden;
-    transition: height 0.3s ease-in-out;
-    will-change: height;
-    
-    &--measuring {
-      opacity: 0;
-      position: fixed;
-      z-index: -1000;
-      transform: translateX(0);
-      height: auto !important;
-    }
-  }
-}
-</style>

+ 0 - 154
src/components/ie-tree/ie-tree.vue

@@ -1,154 +0,0 @@
-<template>
-  <view class="ie-tree">
-    <ie-tree-node 
-      v-for="item in initializedData" 
-      :key="getNodeKey(item)"
-      :node-data="item"
-      :tree-props="mergedProps"
-      @node-click="handleNodeClick"
-    >
-      <template #default="slotProps: { node: any; parent: any }">
-        <slot :node="slotProps.node" :parent="slotProps.parent"></slot>
-      </template>
-    </ie-tree-node>
-  </view>
-</template>
-
-<script lang="ts" setup>
-import { ref, watch, computed } from 'vue';
-import type { TreeProps } from '@/types';
-import IeTreeNode from './ie-tree-node.vue';
-
-defineOptions({
-  name: 'ie-tree',
-  options: {
-    virtualHost: true
-  }
-});
-
-// Props
-const props = defineProps<{
-  /** 树形数据 */
-  data: any[];
-  /** 树配置项(参考 Element UI el-tree 的 props) */
-  props?: Partial<TreeProps>;
-  /** 默认展开所有节点 */
-  defaultExpandAll?: boolean;
-  /** 默认展开的节点 key 数组 */
-  defaultExpandedKeys?: (string | number)[];
-}>();
-
-// Emits
-const emit = defineEmits<{
-  (e: 'node-click', data: { node: any; parent: any | null }): void;
-}>();
-
-// 默认配置
-const defaultTreeProps: Required<TreeProps> = {
-  children: 'children',
-  label: 'name',
-  nodeKey: 'id',
-  isLeaf: 'isLeaf',
-  disabled: 'disabled',
-  isExpanded: 'isExpanded'
-};
-
-// 合并配置
-const mergedProps = computed(() => ({
-  ...defaultTreeProps,
-  ...props.props
-}));
-
-// 获取节点唯一标识
-const getNodeKey = (node: any): string | number => {
-  const key = mergedProps.value.nodeKey;
-  return node?.[key] ?? node?.value ?? node?.id ?? '';
-};
-
-// 获取节点属性值
-const getNodeProp = (node: any, prop: string, defaultValue?: any) => {
-  return node?.[prop] ?? defaultValue;
-};
-
-// 初始化后的数据
-const initializedData = ref<any[]>([]);
-
-// 初始化数据
-const initializeData = (sourceData: any[]): any[] => {
-  if (!sourceData || !Array.isArray(sourceData)) return [];
-  
-  return sourceData.map((item, index) => {
-    const oldItem = initializedData.value[index];
-    const childrenProp = mergedProps.value.children;
-    const expandedProp = mergedProps.value.isExpanded;
-    const isLeafProp = mergedProps.value.isLeaf;
-    
-    // 递归处理子节点
-    const children = getNodeProp(item, childrenProp, []);
-    const processedChildren = children && children.length > 0 
-      ? initializeData(children) 
-      : [];
-    
-    // 判断是否为叶子节点
-    const isLeaf = getNodeProp(item, isLeafProp);
-    const computedIsLeaf = isLeaf !== undefined 
-      ? isLeaf 
-      : (!children || children.length === 0);
-    
-    // 判断是否展开
-    let isExpanded = false;
-    if (props.defaultExpandAll) {
-      isExpanded = !computedIsLeaf;
-    } else if (props.defaultExpandedKeys) {
-      const nodeKey = getNodeKey(item);
-      isExpanded = props.defaultExpandedKeys.includes(nodeKey);
-    } else if (oldItem && getNodeKey(oldItem) === getNodeKey(item)) {
-      // 保持之前的展开状态
-      isExpanded = getNodeProp(oldItem, expandedProp, false);
-    } else {
-      isExpanded = getNodeProp(item, expandedProp, false);
-    }
-    
-    return {
-      ...item,
-      [childrenProp]: processedChildren,
-      [isLeafProp]: computedIsLeaf,
-      [expandedProp]: isExpanded
-    };
-  });
-};
-
-// 处理节点点击事件
-const handleNodeClick = (data: { node: any; parent: any | null }) => {
-  emit('node-click', data);
-};
-
-// 监听 props.data 变化,重新初始化数据
-watch(
-  () => props.data,
-  (newData) => {
-    initializedData.value = initializeData(newData || []);
-  },
-  {
-    immediate: true,
-    deep: true
-  }
-);
-
-// 监听配置项变化,重新初始化数据
-watch(
-  () => props.props,
-  () => {
-    initializedData.value = initializeData(props.data || []);
-  },
-  {
-    deep: true
-  }
-);
-</script>
-
-<style lang="scss" scoped>
-.ie-tree {
-  width: 100%;
-}
-</style>

+ 5 - 0
src/main.ts

@@ -84,6 +84,11 @@ export function createApp() {
         disableHover: {
           default: false
         }
+      },
+      collapseItem: {
+        padding: {
+          default: '12px 15px;'
+        }
       }
     }
   })

+ 2 - 1
src/manifest.json

@@ -57,7 +57,8 @@
         "optimization" : {
             "subPackages" : true
         },
-        "mergeVirtualHostAttributes" : true
+        "mergeVirtualHostAttributes" : true,
+        "slotMultipleInstance" : true
     },
     "mp-alipay" : {
         "usingComponents" : true

+ 54 - 0
src/pagesOther/pages/career/index/components/career-list.vue

@@ -0,0 +1,54 @@
+<template>
+  <view>
+    <view v-if="searchMode">
+      <uv-cell-group :border="false">
+        <uv-cell v-for="(item, index) in data" :key="item.id" icon="" :title="item.name" :isLink="true" :border="false"
+          arrow-direction="right" @click="handleNodeClick(item)"></uv-cell>
+      </uv-cell-group>
+    </view>
+    <template v-else>
+      <view v-for="(item, index) in data" :key="index">
+        <view class="px-30 py-20 text-30 font-bold">{{ item.name }}</view>
+        <uv-collapse :border="false">
+          <uv-collapse-item v-for="(child, index) in item.children" :key="child.id" :border="true" :padding="0">
+            <template #title="{ expanded }">
+              <view class="flex items-center justify-between">
+                <view class="flex items-center gap-10">
+                  <uv-icon name="arrow-right" size="14" color="#888" custom-class="transition-transform duration-300"
+                    :class="{ 'rotate-90': expanded }" />
+                  <view>{{ child.name }}</view>
+                </view>
+                <view class="text-24 text-gray-500">{{ child.children?.length }}个专业</view>
+              </view>
+            </template>
+            <template #right-icon>
+              <view></view>
+            </template>
+            <view class="bg-back-light">
+              <uv-cell-group :border="false">
+                <uv-cell v-for="(grandchild, index) in child.children" :key="grandchild.id" icon=""
+                  :title="grandchild.name" :isLink="true" :border="false" arrow-direction="right"
+                  @click="handleNodeClick(child)"></uv-cell>
+              </uv-cell-group>
+            </view>
+          </uv-collapse-item>
+        </uv-collapse>
+      </view>
+    </template>
+  </view>
+
+</template>
+<script lang="ts" setup>
+import { Career } from '@/types';
+import { TreeProps } from '@/types/tree';
+
+const props = defineProps<{
+  data: Career.CareerItem[];
+  searchMode: boolean;
+}>();
+
+const handleNodeClick = (item: Career.CareerItem) => {
+  console.log(item);
+}
+</script>
+<style lang="scss" scoped></style>

+ 29 - 214
src/pagesOther/pages/career/index/index.vue

@@ -1,222 +1,37 @@
 <template>
-  <ie-page title="职业测试">
-    <view class="p-20">
-      <!-- 默认节点样式测试 -->
-      <view class="mb-40">
-        <view class="text-32 font-bold mb-20">默认样式树</view>
-        <ie-tree 
-          :data="treeData1"
-          @node-click="handleNodeClick"
-        />
+  <ie-page>
+    <z-paging ref="paging" v-model="list" :safe-area-inset-bottom="true" @query="loadData">
+      <template #top>
+        <ie-navbar title="职业库" />
+        <ie-search v-model="keyword" placeholder="输入职业名称" @search="handleSearch" @clear="handleSearch" />
+      </template>
+      <view class="">
+        <career-list :data="list" :search-mode="searchMode" />
       </view>
-
-      <!-- 自定义配置测试 -->
-      <view class="mb-40">
-        <view class="text-32 font-bold mb-20">自定义配置树(不同字段名)</view>
-        <ie-tree 
-          :data="treeData2"
-          :props="customProps"
-          @node-click="handleNodeClick"
-        />
-      </view>
-
-      <!-- 自定义节点样式测试 -->
-      <view class="mb-40">
-        <view class="text-32 font-bold mb-20">自定义节点样式</view>
-        <ie-tree 
-          :data="treeData3"
-          @node-click="handleNodeClick"
-        >
-          <template #default="slotProps: { node: any; parent: any }">
-            <view class="flex items-center justify-between py-20 px-20 border-0 border-b border-solid border-[#E6E6E6]">
-              <view class="flex items-center">
-                <view 
-                  class="w-40 h-40 rounded-full flex items-center justify-center mr-16"
-                  :class="slotProps.node.isLeaf ? 'bg-[#E8F5FF]' : 'bg-[#FFF7E6]'"
-                >
-                  <text class="text-24">{{ slotProps.node.isLeaf ? '📄' : '📁' }}</text>
-                </view>
-                <view>
-                  <view class="text-28 font-bold text-fore-title">{{ slotProps.node.name }}</view>
-                  <view v-if="slotProps.node.desc" class="text-24 text-fore-light mt-4">{{ slotProps.node.desc }}</view>
-                </view>
-              </view>
-              <view v-if="slotProps.node.count !== undefined" class="text-24 text-primary">
-                {{ slotProps.node.count }} 个
-              </view>
-            </view>
-          </template>
-        </ie-tree>
-      </view>
-
-      <!-- 默认展开所有节点 -->
-      <view class="mb-40">
-        <view class="text-32 font-bold mb-20">默认展开所有</view>
-        <ie-tree 
-          :data="treeData4"
-          :default-expand-all="true"
-          @node-click="handleNodeClick"
-        />
-      </view>
-    </view>
+    </z-paging>
   </ie-page>
 </template>
 
 <script lang="ts" setup>
-defineOptions({
-  name: 'career-index'
-});
-
-// 测试数据1:默认配置(children, name, id)
-const treeData1 = ref([
-  {
-    id: 1,
-    name: '计算机类',
-    children: [
-      {
-        id: 11,
-        name: '软件开发',
-        children: [
-          { id: 111, name: '前端工程师' },
-          { id: 112, name: '后端工程师' },
-          { id: 113, name: '全栈工程师' }
-        ]
-      },
-      {
-        id: 12,
-        name: '人工智能',
-        children: [
-          { id: 121, name: '机器学习工程师' },
-          { id: 122, name: '算法工程师' }
-        ]
-      }
-    ]
-  },
-  {
-    id: 2,
-    name: '医疗类',
-    children: [
-      { id: 21, name: '临床医生' },
-      { id: 22, name: '护士' },
-      { id: 23, name: '药剂师' }
-    ]
-  }
-]);
-
-// 测试数据2:自定义字段名
-const treeData2 = ref([
-  {
-    code: 'A1',
-    title: '互联网行业',
-    subList: [
-      {
-        code: 'A11',
-        title: '产品设计',
-        subList: [
-          { code: 'A111', title: '产品经理' },
-          { code: 'A112', title: 'UI设计师' },
-          { code: 'A113', title: 'UX设计师' }
-        ]
-      },
-      {
-        code: 'A12',
-        title: '运营推广',
-        subList: [
-          { code: 'A121', title: '内容运营' },
-          { code: 'A122', title: '用户运营' }
-        ]
-      }
-    ]
-  }
-]);
-
-// 自定义配置
-const customProps = {
-  children: 'subList',
-  label: 'title',
-  nodeKey: 'code'
-};
-
-// 测试数据3:带描述和计数
-const treeData3 = ref([
-  {
-    id: 1,
-    name: '制造业',
-    desc: '实体经济核心',
-    count: 5,
-    children: [
-      {
-        id: 11,
-        name: '机械制造',
-        desc: '传统优势产业',
-        count: 3,
-        children: [
-          { id: 111, name: '机械工程师', desc: '设计制造机械设备' },
-          { id: 112, name: '质量工程师', desc: '产品质量控制' },
-          { id: 113, name: '工艺工程师', desc: '生产工艺优化' }
-        ]
-      },
-      {
-        id: 12,
-        name: '电子制造',
-        desc: '高新技术产业',
-        count: 2,
-        children: [
-          { id: 121, name: '电子工程师', desc: '电路设计与开发' },
-          { id: 122, name: '测试工程师', desc: '产品测试验证' }
-        ]
-      }
-    ]
-  },
-  {
-    id: 2,
-    name: '金融业',
-    desc: '现代服务业',
-    count: 3,
-    children: [
-      { id: 21, name: '银行职员', desc: '银行业务办理' },
-      { id: 22, name: '证券分析师', desc: '投资分析咨询' },
-      { id: 23, name: '保险代理人', desc: '保险产品销售' }
-    ]
-  }
-]);
-
-// 测试数据4:默认展开测试
-const treeData4 = ref([
-  {
-    id: 1,
-    name: '教育培训',
-    children: [
-      {
-        id: 11,
-        name: '学前教育',
-        children: [
-          { id: 111, name: '幼儿园教师' },
-          { id: 112, name: '早教老师' }
-        ]
-      },
-      {
-        id: 12,
-        name: '基础教育',
-        children: [
-          { id: 121, name: '小学教师' },
-          { id: 122, name: '中学教师' }
-        ]
-      }
-    ]
-  }
-]);
-
-// 处理节点点击
-const handleNodeClick = (data: { node: any; parent: any | null }) => {
-  console.log('节点点击:', data);
-  uni.showToast({
-    title: `点击: ${data.node.name || data.node.title}`,
-    icon: 'none',
-    duration: 1500
-  });
-};
+import { Career } from '@/types';
+import CareerList from './components/career-list.vue';
+import { getCareerTree } from '@/api/modules/career';
+
+const list = ref<Career.CareerItem[]>([]);
+const keyword = ref('');
+const searchMode = ref(false);
+const paging = ref<ZPagingInstance>();
+const loadData = (page: number, size: number) => {
+  uni.$ie.showLoading();
+  getCareerTree({ name: keyword.value }).then(res => {
+    searchMode.value = keyword.value.trim() !== '';
+    paging.value?.completeByNoMore(res.data, true);
+  }).catch(() => paging.value?.complete(false))
+    .finally(() => uni.$ie.hideLoading());
+}
+const handleSearch = () => {
+  paging.value?.reload();
+}
 </script>
 
-<style lang="scss" scoped>
-</style>
+<style lang="scss" scoped></style>

+ 152 - 0
src/types/career.ts

@@ -0,0 +1,152 @@
+/**
+ * 职业项接口
+ */
+export interface CareerItem {
+  id: number;
+  name: string;
+  type: string;
+  level: number;
+  code: string;
+  childCount: number;
+  children: CareerItem[];
+  learnYearArab: string;
+  grandchildCount: number;
+}
+
+/**
+ * 职业树查询参数
+ */
+export interface CareerTreeQueryDTO {
+  name?: string;
+  level?: number;
+}
+
+/**
+ * 专业详情接口
+ */
+export interface MajorOverview {
+  /** 接续高职本科专业举例 */
+  benMajors: string;
+  /** 大类名称 */
+  bigName: string;
+  /** 子级数量 */
+  childCount: number;
+  /** 专业代码 */
+  code: string;
+  /** 代码列表 */
+  codes: string[] | null;
+  /** 创建人 */
+  createBy: string | null;
+  /** 创建时间 */
+  createTime: string | null;
+  /** 学位 */
+  degree: string;
+  /** 教育层次:zhuan-专科,ben-本科 */
+  eduLevel: string;
+  /** 培养目标 */
+  eduObjective: string;
+  /** 培养要求 */
+  eduRequirement: string;
+  /** 就业热度 */
+  employmentHeat: number;
+  /** 知名学者 */
+  famousScholar: string;
+  /** 女性比例 */
+  femaleRatio: number;
+  /** 女性比例文本 */
+  femaleRatioText: string;
+  /** 点击量 */
+  hits: number;
+  /** 专业ID */
+  id: number;
+  /** 实习描述 */
+  internshipDesc: string;
+  /** 专业介绍 */
+  introduction: string;
+  /** 是否收藏 */
+  isCollect: boolean;
+  /** 就业方向 */
+  jobDirection: string;
+  /** 就业文本 */
+  jobText: string | null;
+  /** 学制(数字) */
+  learnYear: string;
+  /** 学制(阿拉伯数字文本) */
+  learnYearArab: string;
+  /** 学制(中文文本) */
+  learnYearZh: string;
+  /** 层级 */
+  level: number;
+  /** 理科比例 */
+  lkRatio: number;
+  /** 理科比例文本 */
+  lkRatiotext: string;
+  /** 知识与能力 */
+  loreAndAbility: string;
+  /** 主要课程 */
+  mainCourse: string;
+  /** 男性比例 */
+  maleRatio: number;
+  /** 男性比例文本 */
+  maleRatioText: string;
+  /** 专业ID(另一个字段) */
+  marjorId: number;
+  /** 中类名称 */
+  middleName: string;
+  /** 专业名称 */
+  name: string;
+  /** 开设院校数量 */
+  openCollegeCount: number;
+  /** 资格证书 */
+  qualification: string;
+  /** 相关专业 */
+  relationMajors: string;
+  /** 备注 */
+  remark: string | null;
+  /** 薪资 */
+  salary: number | null;
+  /** 学习方向 */
+  studyDirection: string | null;
+  /** 选科要求 */
+  subjectRequirement: string;
+  /** 摘要 */
+  summary: string | null;
+  /** 更新人 */
+  updateBy: string | null;
+  /** 更新时间 */
+  updateTime: string | null;
+  /** 文科比例 */
+  wkRatio: number;
+  /** 文科比例文本 */
+  wkRatioText: string;
+  /** 接续中职专业 */
+  zhongzhiMajors: string;
+  /** 专升本方向 */
+  zhuanToBenOrient: string;
+}
+
+export interface UniversityQueryDTO {
+  code: string;
+  pageNum: number;
+  pageSize: number;
+}
+export interface University {
+  address: string;
+  area: number;
+  bxLevel: string;
+  cityName: string;
+  code: string;
+  collect: boolean;
+  comScore: string;
+  enrollLocation: string;
+  features: string;
+  hits: number;
+  id: number;
+  location: string;
+  logo: string;
+  name: string;
+  natureTypeCN: string;
+  star: string;
+  type: string;
+  webSite: string;
+}

+ 3 - 27
src/types/index.ts

@@ -4,6 +4,8 @@ import * as News from "./news";
 import * as Transfer from "./transfer";
 import * as System from './system';
 import * as Major from "./major";
+import * as Career from "./career";
+import * as Tree from "./tree";
 import { VipCardInfo } from "./user";
 import { EnumExamMode, EnumExamType, EnumReviewMode } from "@/common/enum";
 
@@ -40,32 +42,6 @@ export interface ApiResponseList<T> {
   total: number;
 }
 
-export interface TreeData {
-  name: string;
-  value: number;
-  children?: TreeData[];
-  isExpanded?: boolean;
-  isLeaf?: boolean;
-  [key: string]: any; // 允许其他字段
-}
-
-/**
- * 树组件配置项(参考 Element UI el-tree 的 props)
- */
-export interface TreeProps {
-  /** 指定子树为节点对象的某个属性值,默认 'children' */
-  children?: string;
-  /** 指定节点标签为节点对象的某个属性值,默认 'name' */
-  label?: string;
-  /** 指定节点标识为节点对象的某个属性值,默认 'id' */
-  nodeKey?: string;
-  /** 指定节点是否为叶子节点,默认 'isLeaf' */
-  isLeaf?: string;
-  /** 指定节点是否禁用,默认 'disabled' */
-  disabled?: string;
-  /** 指定节点是否展开,默认 'isExpanded' */
-  isExpanded?: string;
-}
 
 export interface TableConfig {
   border?: boolean;
@@ -154,4 +130,4 @@ export interface SwiperTabItem {
 
 
 
-export { Study, User, News, Transfer, System, Major };
+export { Study, User, News, Transfer, System, Major, Career, Tree };

+ 18 - 0
src/types/tree.ts

@@ -0,0 +1,18 @@
+export interface TreeData<T> {
+  label: string;
+  children?: TreeData<T>[];
+  isExpanded?: boolean;
+  data: T;
+}
+
+/**
+ * 树组件配置项(参考 Element UI el-tree 的 props)
+ */
+export interface TreeProps {
+  /** 指定子树为节点对象的某个属性值,默认 'children' */
+  children?: string;
+  /** 指定节点标签为节点对象的某个属性值,默认 'name' */
+  label?: string;
+  /** 指定节点标识为节点对象的某个属性值,默认 'id' */
+  nodeKey?: string;
+}

+ 11 - 10
src/uni_modules/uv-collapse/components/uv-collapse-item/uv-collapse-item.vue

@@ -7,26 +7,26 @@
 			:icon="icon"
 			:isLink="isLink"
 			:clickable="clickable"
-			:border="parentData.border && showBorder"
+			:border="false"
 			@click="clickHandler"
 			:arrowDirection="expanded ? 'up' : 'down'"
 			:disabled="disabled"
 		>
-			<!-- #ifndef MP-WEIXIN -->
-			<!-- 微信小程序不支持,因为微信中不支持 <slot name="title" slot="title" />的写法 -->
-			<template slot="title">
-				<slot name="title"></slot>
+			<!-- Vue 3 插槽语法,支持所有平台包括微信小程序 -->
+			<template v-slot:title>
+				<view>
+					<slot name="title" :expanded="expanded"></slot>
+				</view>
 			</template>
-			<template slot="icon">
+			<template v-slot:icon>
 				<slot name="icon"></slot>
 			</template>
-			<template slot="value">
+			<template v-slot:value>
 				<slot name="value"></slot>
 			</template>
-			<template slot="right-icon">
+			<template v-slot:right-icon>
 				<slot name="right-icon"></slot>
 			</template>
-			<!-- #endif -->
 		</uv-cell>
 		<view
 			class="uv-collapse-item__content"
@@ -35,11 +35,12 @@
 		>
 			<view
 				class="uv-collapse-item__content__text content-class"
+        :style="{padding}"
 				:id="elId"
 				:ref="elId"
 			><slot /></view>
 		</view>
-		<uv-line v-if="parentData.border"></uv-line>
+		<uv-line v-if="border"></uv-line>
 	</view>
 </template>