1、调整就餐点名
2、增加中文姓名排序依赖库
This commit is contained in:
parent
8a6cfd58c9
commit
dee7d67bcc
@ -58,6 +58,7 @@
|
||||
"lodash": "4.17.21",
|
||||
"pinia": "2.0.23",
|
||||
"pinia-plugin-persist-uni": "1.2.0",
|
||||
"pinyin-pro": "^3.27.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"uview-plus": "3.1.20",
|
||||
"vconsole": "3.15.1",
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@ -74,6 +74,9 @@ importers:
|
||||
pinia-plugin-persist-uni:
|
||||
specifier: 1.2.0
|
||||
version: 1.2.0(pinia@2.0.23(typescript@4.8.3)(vue@3.2.45))(vue@3.2.45)
|
||||
pinyin-pro:
|
||||
specifier: ^3.27.0
|
||||
version: 3.27.0
|
||||
qrcode:
|
||||
specifier: ^1.5.3
|
||||
version: 1.5.4
|
||||
@ -2965,6 +2968,9 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
pinyin-pro@3.27.0:
|
||||
resolution: {integrity: sha512-Osdgjwe7Rm17N2paDMM47yW+jUIUH3+0RGo8QP39ZTLpTaJVDK0T58hOLaMQJbcMmAebVuK2ePunTEVEx1clNQ==}
|
||||
|
||||
pirates@4.0.7:
|
||||
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -7626,6 +7632,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 4.8.3
|
||||
|
||||
pinyin-pro@3.27.0: {}
|
||||
|
||||
pirates@4.0.7: {}
|
||||
|
||||
pixelmatch@4.0.2:
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
import { get, post } from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 就餐标准分页查询
|
||||
*/
|
||||
export const jcBzFindPageApi = async (params: any) => {
|
||||
return await get('/api/jcBz/findPage', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取就餐标准列表
|
||||
*/
|
||||
@ -8,16 +15,16 @@ export const getJcBzListApi = async (params: any) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取就餐清单列表
|
||||
* 获取就餐清单分页查询
|
||||
*/
|
||||
export const getJcQdListApi = async (params: any) => {
|
||||
export const jcQdFindPageApi = async (params: any) => {
|
||||
return await get('/api/jcQd/findPage', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取就餐点名分页
|
||||
*/
|
||||
export const getJcDmPageApi = async (params: any) => {
|
||||
export const jcDmFindPageApi = async (params: any) => {
|
||||
return await get('/api/jcDm/findPage', params)
|
||||
}
|
||||
|
||||
@ -60,20 +67,6 @@ export const getJcPtListApi = async (params: any) => {
|
||||
return await get('/api/jcPt/findPage', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 【教师端专用】根据班级ID获取学生点名数据
|
||||
* 返回两组学生数据:已缴费和未缴费/未报名
|
||||
*/
|
||||
export const getClassStudentDmDataApi = async (bjId: string, njId: string) => {
|
||||
try {
|
||||
const response = await get('/mobile/js/jc/getClassStudentDmData', { bjId, njId })
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('获取班级学生点名数据失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 【教师端专用】提交就餐点名数据
|
||||
* 包含:点名教师ID、点名时间、学生列表、陪餐教师列表等
|
||||
|
||||
15
src/api/base/xsApi.ts
Normal file
15
src/api/base/xsApi.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { get, post } from "@/utils/request";
|
||||
|
||||
/**
|
||||
* 分页查询未选课的学生
|
||||
*/
|
||||
export function findPageByNoXk(params: any) {
|
||||
return get('/api/xs/findPageByNoXk', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询未报名就餐的学生
|
||||
*/
|
||||
export function findPageByNoJc(params: any) {
|
||||
return get('/api/xs/findPageByNoJc', params);
|
||||
}
|
||||
@ -614,6 +614,12 @@
|
||||
"backgroundColor": "#f4f5f7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/view/routine/jc/bzList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "就餐标准列表"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/view/routine/jc/index",
|
||||
"style": {
|
||||
|
||||
@ -303,7 +303,7 @@ const sections = reactive<Section[]>([
|
||||
text: "就餐点名",
|
||||
show: true,
|
||||
permissionKey: "routine-jcdm", // 就餐点名权限编码
|
||||
path: "/pages/view/routine/jc/index",
|
||||
path: "/pages/view/routine/jc/bzList",
|
||||
},
|
||||
{
|
||||
id: "r9",
|
||||
|
||||
152
src/pages/view/routine/jc/bzList.vue
Normal file
152
src/pages/view/routine/jc/bzList.vue
Normal file
@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<view class="bz-list">
|
||||
<!-- 使用 BasicListLayout 包裹记录列表 -->
|
||||
<BasicListLayout @register="register" :fixed="false" class="flex-1">
|
||||
<template #default="{ data }">
|
||||
<view class="bz-card" @click="goToBz(data)">
|
||||
<view class="card-header">
|
||||
<view class="card-title">{{ data.bzMc }}</view>
|
||||
</view>
|
||||
<view class="divider"></view>
|
||||
<view class="card-content">
|
||||
<view class="info-row">
|
||||
<text class="info-label">年级:</text>
|
||||
<text class="info-value">{{ data.njmc }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">说明:</text>
|
||||
<text class="info-value">{{ data.bzSm }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-footer">
|
||||
<text class="view-detail">前往点名 →</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</BasicListLayout>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
|
||||
import { jcBzFindPageApi } from "@/api/base/jcApi";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { setJcBz } = useDataStore();
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false);
|
||||
const bzList = ref<any>([]);
|
||||
const total = ref<any>(0);
|
||||
|
||||
// 使用 BasicListLayout
|
||||
const [register, { reload, setParam }] = useLayout({
|
||||
api: async (params: any) => {
|
||||
try {
|
||||
const res = await jcBzFindPageApi(params);
|
||||
console.log("API返回数据:", res); // 调试日志
|
||||
|
||||
// 确保数据正确赋值
|
||||
if (res && res.rows) {
|
||||
bzList.value = res.rows;
|
||||
total.value = res.records || res.total || 0;
|
||||
} else {
|
||||
bzList.value = [];
|
||||
total.value = 0;
|
||||
}
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.error("获取数据失败:", error);
|
||||
bzList.value = [];
|
||||
total.value = 0;
|
||||
return { rows: [], total: 0 };
|
||||
}
|
||||
},
|
||||
componentProps: {
|
||||
auto: false,
|
||||
},
|
||||
});
|
||||
|
||||
const goToBz = (bz: any) => {
|
||||
setJcBz(bz);
|
||||
uni.navigateTo({ url: "/pages/view/routine/jc/index"});
|
||||
};
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
// 不自动加载数据,等待用户搜索
|
||||
reload();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bz-list {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.bz-card {
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.card-header {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background-color: #eee;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-weight: normal;
|
||||
flex: 0 0 160rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@ -80,22 +80,22 @@
|
||||
<view class="section" v-if="curBj">
|
||||
<view class="section-title">
|
||||
学生状态列表
|
||||
<text class="refresh-btn" @click="sxXsLb">刷新</text>
|
||||
<text class="refresh-btn" @click="loadXsList">刷新</text>
|
||||
</view>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<view class="stats-container">
|
||||
<view class="stat-item">
|
||||
<text class="stat-number">{{ xsLb.length }}</text>
|
||||
<text class="stat-number">{{ rsData.zrs }}</text>
|
||||
<text class="stat-label">总人数</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number unpaid">{{ hqZtSl('D') }}</text>
|
||||
<text class="stat-label">未缴费</text>
|
||||
<text class="stat-number unregistered">{{ rsData.bmRs }}</text>
|
||||
<text class="stat-label">报名就餐</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number unregistered">{{ hqZtSl('E') }}</text>
|
||||
<text class="stat-label">未报名</text>
|
||||
<text class="stat-number unregistered">{{ rsData.unBmRs }}</text>
|
||||
<text class="stat-label">未报名就餐</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number normal">{{ hqZtSl('A') }}</text>
|
||||
@ -112,36 +112,36 @@
|
||||
</view>
|
||||
|
||||
<!-- 学生列表 - 改为card形式 -->
|
||||
<view class="student-list">
|
||||
<view class="xs-list">
|
||||
<!-- 已缴费学生列表 -->
|
||||
<view v-if="yjfXs.length > 0" class="student-section">
|
||||
<view class="section-subtitle">已缴费学生 ({{ yjfXs.length }}人)</view>
|
||||
<view class="student-grid">
|
||||
<view v-if="bmXsList.length > 0" class="xs-section">
|
||||
<view class="section-subtitle">已报名学生 ({{ bmXsList.length }}人)</view>
|
||||
<view class="xs-grid">
|
||||
<view
|
||||
v-for="student in yjfXs"
|
||||
:key="student.id"
|
||||
class="student-item bg-white r-md p-12"
|
||||
v-for="xs in bmXsList"
|
||||
:key="xs.id"
|
||||
class="xs-item bg-white r-md p-12"
|
||||
>
|
||||
<view class="flex-row items-center">
|
||||
<view class="avatar-container mr-8">
|
||||
<image
|
||||
class="student-avatar"
|
||||
:src="imagUrl(student.xstx) || '/static/images/default-avatar.png'"
|
||||
class="xs-avatar"
|
||||
:src="imagUrl(xs.xstx) || '/static/images/default-avatar.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="student-name mb-8">
|
||||
<text class="font-14 cor-333">{{ student.xm }}</text>
|
||||
<view class="xs-name mb-8">
|
||||
<text class="font-14 cor-333">{{ xs.xm }}</text>
|
||||
</view>
|
||||
<view class="flex-row">
|
||||
<!-- 已缴费学生可以切换状态 -->
|
||||
<view
|
||||
class="status-tag clickable"
|
||||
:class="getStatusClass(student.jcZt)"
|
||||
@click="dkZtXz(student, 'paid')"
|
||||
:class="getStatusClass(xs.jcZt)"
|
||||
@click="dkZtXz(xs, 'paid')"
|
||||
>
|
||||
{{ hqZtWz(student.jcZt) }}
|
||||
{{ hqZtWz(xs.jcZt) }}
|
||||
<text class="status-arrow">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
@ -152,33 +152,33 @@
|
||||
</view>
|
||||
|
||||
<!-- 未缴费/未报名学生列表 -->
|
||||
<view v-if="wjfXs.length > 0" class="student-section">
|
||||
<view class="section-subtitle">未缴费/未报名学生 ({{ wjfXs.length }}人)</view>
|
||||
<view class="student-grid">
|
||||
<view v-if="unBmXsList.length > 0" class="xs-section">
|
||||
<view class="section-subtitle">未报名学生 ({{ unBmXsList.length }}人)</view>
|
||||
<view class="xs-grid">
|
||||
<view
|
||||
v-for="student in wjfXs"
|
||||
:key="student.id"
|
||||
class="student-item bg-white r-md p-12"
|
||||
v-for="xs in unBmXsList"
|
||||
:key="xs.id"
|
||||
class="xs-item bg-white r-md p-12"
|
||||
>
|
||||
<view class="flex-row items-center">
|
||||
<view class="avatar-container mr-8">
|
||||
<image
|
||||
class="student-avatar"
|
||||
:src="imagUrl(student.xstx) || '/static/images/default-avatar.png'"
|
||||
class="xs-avatar"
|
||||
:src="imagUrl(xs.xstx) || '/static/images/default-avatar.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="student-name mb-8">
|
||||
<text class="font-12 cor-333">{{ student.xm }}</text>
|
||||
<view class="xs-name mb-8">
|
||||
<text class="font-12 cor-333">{{ xs.xm }}</text>
|
||||
</view>
|
||||
<view class="flex-row">
|
||||
<!-- 未缴费/未报名学生只显示状态,不能切换 -->
|
||||
<view
|
||||
class="status-tag readonly"
|
||||
:class="getStatusClass(student.jcZt)"
|
||||
:class="getStatusClass(xs.jcZt)"
|
||||
>
|
||||
{{ hqZtWz(student.jcZt) }}
|
||||
{{ hqZtWz(xs.jcZt) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -187,7 +187,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="xsLb.length === 0" class="empty-tip">
|
||||
<view v-if="bmXsList.length === 0 && unBmXsList.length === 0" class="empty-tip">
|
||||
暂无学生数据
|
||||
</view>
|
||||
</view>
|
||||
@ -254,11 +254,14 @@ import { ref, computed } from 'vue'
|
||||
import NjBjPicker from '@/pages/components/NjBjPicker/index.vue'
|
||||
import BasicJsPicker from '@/components/BasicJsPicker/Picker.vue'
|
||||
import DmPsComponent from '@/pages/components/dmPs/index.vue'
|
||||
import { getClassStudentDmDataApi, submitJcDmDataApi } from '@/api/base/jcApi'
|
||||
import { findPageByNoJc } from "@/api/base/xsApi";
|
||||
import { jcQdFindPageApi, submitJcDmDataApi } from '@/api/base/jcApi'
|
||||
import { imagUrl } from "@/utils";
|
||||
import { sortChinese } from "@/utils/pinyinUtil"
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useDataStore } from '@/store/modules/data'
|
||||
const { getJs } = useUserStore()
|
||||
|
||||
const { getJcBz } = useDataStore();
|
||||
/**
|
||||
* 就餐点名组件
|
||||
* 功能:
|
||||
@ -279,10 +282,16 @@ const props = withDefaults(defineProps<{
|
||||
const curNj = ref<any>(null);
|
||||
const curBj = ref<any>(null);
|
||||
|
||||
const xsLb = ref<any[]>([]) // 学生列表
|
||||
const xzJs = ref<any[]>([]) // 选择的教师
|
||||
const jzZt = ref(false) // 加载状态
|
||||
|
||||
// 人数
|
||||
const rsData = ref({
|
||||
zrs: 0,
|
||||
bmRs: 0,
|
||||
unBmRs: 0
|
||||
})
|
||||
|
||||
// 状态选择相关
|
||||
const ztXzK = ref(false) // 状态选择可见
|
||||
const yjfZtXz = ref<Array<{ text: string, value: string }>>([
|
||||
@ -317,25 +326,20 @@ const dmPsRef = ref<any>(null);
|
||||
|
||||
// 计算属性
|
||||
const kTj = computed(() => {
|
||||
return curBj.value && yjfXs.value.length > 0 // 改为检查已缴费学生数量
|
||||
return curBj.value && bmXsList.value.length > 0 // 改为检查已缴费学生数量
|
||||
})
|
||||
|
||||
// 已缴费学生列表(有就餐清单且jfZt为B)
|
||||
const yjfXs = computed(() => {
|
||||
return xsLb.value.filter(student => student.studentType === 'paid')
|
||||
})
|
||||
|
||||
// 未缴费/未报名学生列表
|
||||
const wjfXs = computed(() => {
|
||||
return xsLb.value.filter(student => student.studentType === 'unpaid')
|
||||
})
|
||||
// 已报名学生列表
|
||||
const bmXsList = ref<any>([]);
|
||||
// 未报名学生列表
|
||||
const unBmXsList = ref<any>([]);
|
||||
|
||||
// 方法
|
||||
// 改变了年级班级
|
||||
const changeNjBj = async (nj: any, bj: any) => {
|
||||
curNj.value = nj
|
||||
curBj.value = bj
|
||||
await jzXsLb()
|
||||
await loadXsList()
|
||||
};
|
||||
|
||||
// 处理照片变化
|
||||
@ -435,40 +439,39 @@ const sxJsLb = () => {
|
||||
console.log('刷新教师列表')
|
||||
}
|
||||
|
||||
const jzXsLb = async () => {
|
||||
// 加载学生列表
|
||||
const loadXsList = async () => {
|
||||
if (!curBj.value) return
|
||||
|
||||
jzZt.value = true
|
||||
try {
|
||||
// 使用新的API接口获取班级学生点名数据
|
||||
const response = await getClassStudentDmDataApi(
|
||||
curBj.value.key,
|
||||
curNj.value.key
|
||||
)
|
||||
|
||||
if (response.result) {
|
||||
// 合并已缴费和未缴费学生列表
|
||||
const paidStudents = response.result.paidStudents || []
|
||||
const unpaidStudents = response.result.unpaidStudents || []
|
||||
|
||||
// 为每个学生设置默认就餐状态
|
||||
const allStudents = [
|
||||
...paidStudents.map((student: any) => ({
|
||||
...student,
|
||||
jcZt: 'A', // 已缴费学生默认正常状态
|
||||
studentType: 'paid'
|
||||
})),
|
||||
...unpaidStudents.map((student: any) => ({
|
||||
...student,
|
||||
jcZt: student.hasJcQd ? 'D' : 'E', // 未缴费或未报名
|
||||
studentType: 'unpaid'
|
||||
}))
|
||||
]
|
||||
|
||||
xsLb.value = allStudents
|
||||
} else {
|
||||
xsLb.value = []
|
||||
const params = {
|
||||
bzId: getJcBz.id,
|
||||
bjId: curBj.value.key,
|
||||
njId: curNj.value.key,
|
||||
pageNo: 1,
|
||||
rows: 1000
|
||||
}
|
||||
const resQd = await jcQdFindPageApi(params);
|
||||
bmXsList.value = (resQd.rows || []).map((item: any) => {
|
||||
return {
|
||||
...item,
|
||||
jcZt: 'A',
|
||||
xm: (item.xsxm || item.xm || '').trim()
|
||||
}
|
||||
});
|
||||
bmXsList.value = sortChinese(bmXsList.value, 'xm');
|
||||
console.log('学生清单列表', bmXsList.value);
|
||||
const resUn = await findPageByNoJc(params);
|
||||
unBmXsList.value = resUn.rows || [];
|
||||
unBmXsList.value = sortChinese(unBmXsList.value, 'xm');
|
||||
|
||||
console.log('未报名学生列表', unBmXsList.value);
|
||||
rsData.value = {
|
||||
zrs: (resQd.records || 0) + (resUn.records || 0),
|
||||
bmRs: (resQd.records || 0),
|
||||
unBmRs: (resUn.records || 0),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('加载学生列表失败:', error)
|
||||
uni.showToast({
|
||||
@ -480,10 +483,6 @@ const jzXsLb = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const sxXsLb = () => {
|
||||
jzXsLb()
|
||||
}
|
||||
|
||||
const hqXsZtLx = (status: string) => {
|
||||
switch (status) {
|
||||
case 'A':
|
||||
@ -519,18 +518,7 @@ const hqZtWz = (status: string) => {
|
||||
}
|
||||
|
||||
const hqZtSl = (status: string) => {
|
||||
return xsLb.value.filter(s => s.jcZt === status).length
|
||||
}
|
||||
|
||||
// 获取学生类型文本
|
||||
const hqXsLxWz = (student: any) => {
|
||||
if (student.studentType === 'paid') {
|
||||
return '已缴费'
|
||||
} else if (student.jcZt === 'E') {
|
||||
return '未报名'
|
||||
} else {
|
||||
return '未缴费'
|
||||
}
|
||||
return bmXsList.value.filter((s:any) => s.jcZt === status).length
|
||||
}
|
||||
|
||||
// 获取状态对应的样式类
|
||||
@ -551,21 +539,9 @@ const getStatusClass = (status: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取学生类型对应的样式类
|
||||
const getTypeClass = (studentType: string) => {
|
||||
switch (studentType) {
|
||||
case 'paid':
|
||||
return 'cor-success'
|
||||
case 'unpaid':
|
||||
return 'cor-warning'
|
||||
default:
|
||||
return 'cor-666'
|
||||
}
|
||||
}
|
||||
|
||||
// 打开状态选择器
|
||||
const dkZtXz = (student: any, type: 'paid' | 'unpaid') => {
|
||||
dqXs.value = student
|
||||
const dkZtXz = (xs: any, type: 'paid' | 'unpaid') => {
|
||||
dqXs.value = xs
|
||||
|
||||
// 根据学生类型设置对应的状态选项
|
||||
if (type === 'paid') {
|
||||
@ -575,7 +551,7 @@ const dkZtXz = (student: any, type: 'paid' | 'unpaid') => {
|
||||
}
|
||||
|
||||
// 找到当前状态在选项中的索引
|
||||
const currentIndex = dqZtXz.value.findIndex(option => option.value === student.jcZt)
|
||||
const currentIndex = dqZtXz.value.findIndex(option => option.value === xs.jcZt)
|
||||
mqXz.value = [currentIndex >= 0 ? currentIndex : 0]
|
||||
ztXzK.value = true
|
||||
}
|
||||
@ -596,7 +572,7 @@ const qrXzZt = (e: any) => {
|
||||
}
|
||||
|
||||
const tjDm = async () => {
|
||||
if (!curBj.value || yjfXs.value.length === 0) { // 改为检查已缴费学生数量
|
||||
if (!curBj.value || bmXsList.value.length === 0) { // 改为检查已缴费学生数量
|
||||
uni.showToast({
|
||||
title: '请先选择班级或有已缴费学生',
|
||||
icon: 'none'
|
||||
@ -635,24 +611,28 @@ const tjDm = async () => {
|
||||
bjmc: curBj.value.title,
|
||||
njmc: curNj.value.title,
|
||||
dmJsId: getJs.id || '', // 点名教师ID
|
||||
dmTime: new Date(),
|
||||
jcTime: new Date(),
|
||||
zrs: rsData.value.zrs,
|
||||
sdRs: hqZtSl('A'),
|
||||
qjRs: hqZtSl('B'),
|
||||
qqRs: hqZtSl('C'),
|
||||
// 媒体文件地址
|
||||
zp: photoUrls, // 照片字段,逗号分隔的字符串
|
||||
sp: videoUrls, // 视频字段,逗号分隔的字符串
|
||||
xsList: yjfXs.value.map(student => ({
|
||||
xsId: student.id,
|
||||
xsXm: student.xm, // 传入学生姓名
|
||||
jcZt: student.jcZt || 'A',
|
||||
jcQdId: student.jcQdInfo?.qdId,
|
||||
jcBzId: student.jcQdInfo?.bzId,
|
||||
jzId: student.jcQdInfo?.jzId,
|
||||
tx: student.xstx // 传入学生头像
|
||||
xsList: bmXsList.value.map((qd:any) => ({
|
||||
xsId: qd.xsId,
|
||||
xsXm: qd.xm, // 传入学生姓名
|
||||
jcZt: qd.jcZt || 'A',
|
||||
jcQdId: qd.id,
|
||||
jcBzId: qd.bzId,
|
||||
jzId: qd.jzId,
|
||||
tx: qd.xstx // 传入学生头像
|
||||
})),
|
||||
ptJsList: xzJs.value.map(teacher => ({
|
||||
jsId: teacher.value,
|
||||
jsXm: teacher.label,
|
||||
pcZt: teacher.pcZt || 'A', // 添加陪餐状态
|
||||
tx: teacher.headPic // 传入教师头像
|
||||
ptJsList: xzJs.value.map(js => ({
|
||||
jsId: js.value,
|
||||
jsXm: js.label,
|
||||
pcZt: js.pcZt || 'A', // 添加陪餐状态
|
||||
tx: js.headPic // 传入教师头像
|
||||
}))
|
||||
}
|
||||
|
||||
@ -668,7 +648,8 @@ const tjDm = async () => {
|
||||
// 重置表单
|
||||
curNj.value = null
|
||||
curBj.value = null
|
||||
xsLb.value = []
|
||||
bmXsList.value = [];
|
||||
unBmXsList.value = [];
|
||||
xzJs.value = []
|
||||
mediaData.value = {
|
||||
photoList: [],
|
||||
@ -782,28 +763,28 @@ const tjDm = async () => {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.student-section {
|
||||
.xs-section {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.student-list {
|
||||
.xs-list {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.student-grid {
|
||||
.xs-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.student-item {
|
||||
.xs-item {
|
||||
position: relative;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.student-item:hover {
|
||||
.xs-item:hover {
|
||||
transform: translateY(-2rpx);
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
@ -820,7 +801,7 @@ const tjDm = async () => {
|
||||
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.student-avatar {
|
||||
.xs-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
@ -881,7 +862,7 @@ const tjDm = async () => {
|
||||
color: #eb2f96;
|
||||
}
|
||||
|
||||
.student-type {
|
||||
.xs-type {
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
display: inline-block;
|
||||
|
||||
@ -9,26 +9,18 @@
|
||||
<view class="search-item">
|
||||
<text class="label">班级:</text>
|
||||
<view class="flex-1">
|
||||
<NjBjPicker
|
||||
@change="changeNjBj"
|
||||
icon-arrow="right"
|
||||
:customStyle="{
|
||||
<NjBjPicker @change="changeNjBj" icon-arrow="right" :customStyle="{
|
||||
borderRadius: '0',
|
||||
padding: '0.5rem 0.625rem',
|
||||
}"
|
||||
/>
|
||||
}" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-row">
|
||||
<view class="search-item">
|
||||
<text class="label">时间范围:</text>
|
||||
<uni-datetime-picker
|
||||
type="daterange"
|
||||
:value="[startTime, endTime]"
|
||||
@change="onTimeRangeChange"
|
||||
class="date-picker"
|
||||
>
|
||||
<uni-datetime-picker type="daterange" :value="[startTime, endTime]" @change="onTimeRangeChange"
|
||||
class="date-picker">
|
||||
<view class="picker-text">{{ getTimeRangeText() }}</view>
|
||||
</uni-datetime-picker>
|
||||
</view>
|
||||
@ -45,10 +37,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view
|
||||
v-if="!loading && dmRecords && dmRecords.length === 0 && hasSearched"
|
||||
class="empty-state"
|
||||
>
|
||||
<view v-if="!loading && dmRecords && dmRecords.length === 0 && hasSearched" class="empty-state">
|
||||
<view class="empty-icon">📋</view>
|
||||
<text class="empty-text">暂无点名记录</text>
|
||||
<text class="empty-tip">请选择班级和时间范围进行搜索</text>
|
||||
@ -95,10 +84,10 @@
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
|
||||
import NjBjPicker from "@/pages/components/NjBjPicker/index.vue";
|
||||
import { getJcDmPageApi } from "@/api/base/jcApi";
|
||||
import { jcDmFindPageApi } from "@/api/base/jcApi";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
|
||||
const { setData } = useDataStore();
|
||||
const { setData, getJcBz } = useDataStore();
|
||||
|
||||
// 接收外部传入属性
|
||||
const props = withDefaults(
|
||||
@ -123,7 +112,7 @@ const hasSearched = ref(false);
|
||||
const [register, { reload, setParam }] = useLayout({
|
||||
api: async (params: any) => {
|
||||
try {
|
||||
const res = await getJcDmPageApi(params);
|
||||
const res = await jcDmFindPageApi(params);
|
||||
console.log("API返回数据:", res); // 调试日志
|
||||
|
||||
// 确保数据正确赋值
|
||||
@ -208,6 +197,7 @@ const searchRecords = async () => {
|
||||
|
||||
// 设置搜索参数并重新加载
|
||||
setParam({
|
||||
bzId: getJcBz.id,
|
||||
njId: selectedClass.value.njId,
|
||||
bjId: selectedClass.value.bjId,
|
||||
startTime: startTime.value + " 00:00:00",
|
||||
@ -233,22 +223,6 @@ const goToDetail = (dm: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
const exportRecords = () => {
|
||||
if (dmRecords.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: "暂无数据可导出",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 实现导出逻辑
|
||||
uni.showToast({
|
||||
title: "导出功能开发中",
|
||||
icon: "none",
|
||||
});
|
||||
};
|
||||
|
||||
const formatDate = (dateStr: string) => {
|
||||
if (!dateStr) return "";
|
||||
const date = new Date(dateStr);
|
||||
@ -359,6 +333,7 @@ onMounted(() => {
|
||||
.records-header {
|
||||
padding: 0 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
@ -386,10 +361,6 @@ onMounted(() => {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.card-footer {
|
||||
text-align: right;
|
||||
padding-top: 16rpx;
|
||||
|
||||
@ -68,68 +68,68 @@
|
||||
</view>
|
||||
|
||||
<!-- 学生状态列表 -->
|
||||
<view class="section" v-if="dmDetail.xsList && dmDetail.xsList.length > 0">
|
||||
<view class="section">
|
||||
<view class="section-title">
|
||||
学生状态列表 ({{ dmDetail.xsList.length }}人)
|
||||
学生状态列表 ({{ rsData.zrs }}人)
|
||||
</view>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<view class="stats-container">
|
||||
<view class="stat-item">
|
||||
<text class="stat-number">{{ dmDetail.xsList.length }}</text>
|
||||
<text class="stat-number">{{ rsData.zrs }}</text>
|
||||
<text class="stat-label">总人数</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number normal">{{ getStatusCount('A') }}</text>
|
||||
<text class="stat-number unregistered">{{ rsData.bmRs }}</text>
|
||||
<text class="stat-label">报名就餐</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number unregistered">{{ rsData.unBmRs }}</text>
|
||||
<text class="stat-label">未报名就餐</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number normal">{{ hqZtSl('A') }}</text>
|
||||
<text class="stat-label">正常</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number leave">{{ getStatusCount('B') }}</text>
|
||||
<text class="stat-number leave">{{ hqZtSl('B') }}</text>
|
||||
<text class="stat-label">请假</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number absent">{{ getStatusCount('C') }}</text>
|
||||
<text class="stat-number absent">{{ hqZtSl('C') }}</text>
|
||||
<text class="stat-label">缺勤</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number unpaid">{{ getStatusCount('D') }}</text>
|
||||
<text class="stat-label">未缴费</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-number unregistered">{{ getStatusCount('E') }}</text>
|
||||
<text class="stat-label">未报名</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 学生列表 - 分为两个部分 -->
|
||||
<view class="student-list">
|
||||
<view class="xs-list">
|
||||
<!-- 已缴费学生列表 -->
|
||||
<view v-if="yjfXs.length > 0" class="student-section">
|
||||
<view class="section-subtitle">已缴费学生 ({{ yjfXs.length }}人)</view>
|
||||
<view class="student-grid">
|
||||
<view v-if="dmXsList.length > 0" class="xs-section">
|
||||
<view class="section-subtitle">已报名学生 ({{ dmXsList.length }}人)</view>
|
||||
<view class="xs-grid">
|
||||
<view
|
||||
v-for="student in yjfXs"
|
||||
:key="student.id"
|
||||
class="student-item bg-white r-md p-12"
|
||||
v-for="xs in dmXsList"
|
||||
:key="xs.id"
|
||||
class="xs-item bg-white r-md p-12"
|
||||
>
|
||||
<view class="flex-row items-center">
|
||||
<view class="avatar-container mr-8">
|
||||
<image
|
||||
class="student-avatar"
|
||||
:src="student.tx || '/static/images/default-avatar.png'"
|
||||
class="xs-avatar"
|
||||
:src="imagUrl(xs.tx) || '/static/images/default-avatar.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="student-name mb-8">
|
||||
<text class="font-14 cor-333">{{ student.xsXm }}</text>
|
||||
<view class="xs-name mb-8">
|
||||
<text class="font-14 cor-333">{{ xs.xsXm }}</text>
|
||||
</view>
|
||||
<view class="flex-row">
|
||||
<view
|
||||
class="status-tag readonly"
|
||||
:class="getStatusClass(student.jcZt)"
|
||||
:class="getStatusClass(xs.jcZt)"
|
||||
>
|
||||
{{ getStatusText(student.jcZt) }}
|
||||
{{ getStatusText(xs.jcZt) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -139,32 +139,32 @@
|
||||
</view>
|
||||
|
||||
<!-- 未缴费/未报名学生列表 -->
|
||||
<view v-if="wjfXs.length > 0" class="student-section">
|
||||
<view class="section-subtitle">未缴费/未报名学生 ({{ wjfXs.length }}人)</view>
|
||||
<view class="student-grid">
|
||||
<view v-if="unBmXsList.length > 0" class="xs-section">
|
||||
<view class="section-subtitle">未报名学生 ({{ unBmXsList.length }}人)</view>
|
||||
<view class="xs-grid">
|
||||
<view
|
||||
v-for="student in wjfXs"
|
||||
:key="student.id"
|
||||
class="student-item bg-white r-md p-12"
|
||||
v-for="xs in unBmXsList"
|
||||
:key="xs.id"
|
||||
class="xs-item bg-white r-md p-12"
|
||||
>
|
||||
<view class="flex-row items-center">
|
||||
<view class="avatar-container mr-8">
|
||||
<image
|
||||
class="student-avatar"
|
||||
:src="student.tx || '/static/images/default-avatar.png'"
|
||||
class="xs-avatar"
|
||||
:src="imagUrl(xs.xstx) || '/static/images/default-avatar.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="student-name mb-8">
|
||||
<text class="font-14 cor-333">{{ student.xsXm }}</text>
|
||||
<view class="xs-name mb-8">
|
||||
<text class="font-14 cor-333">{{ xs.xsXm }}</text>
|
||||
</view>
|
||||
<view class="flex-row">
|
||||
<view
|
||||
class="status-tag readonly"
|
||||
:class="getStatusClass(student.jcZt)"
|
||||
:class="getStatusClass(xs.jcZt)"
|
||||
>
|
||||
{{ getStatusText(student.jcZt) }}
|
||||
{{ getStatusText(xs.jcZt) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -173,7 +173,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="dmDetail.xsList.length === 0" class="empty-tip">
|
||||
<view v-if="dmXsList.length === 0" class="empty-tip">
|
||||
暂无学生数据
|
||||
</view>
|
||||
</view>
|
||||
@ -193,6 +193,8 @@
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { getJcDmDetailApi } from '@/api/base/jcApi'
|
||||
import { useDataStore } from '@/store/modules/data'
|
||||
import { imagUrl } from "@/utils";
|
||||
import { sortChinese } from "@/utils/pinyinUtil"
|
||||
const { getData } = useDataStore()
|
||||
|
||||
// 响应式数据
|
||||
@ -200,21 +202,16 @@ const loading = ref(false)
|
||||
const dmDetail = ref<any>(null)
|
||||
const error = ref('')
|
||||
|
||||
// 计算属性
|
||||
// 已缴费学生列表(状态为A、B、C的学生)
|
||||
const yjfXs = computed(() => {
|
||||
if (!dmDetail.value?.xsList) return []
|
||||
return dmDetail.value.xsList.filter((student: any) =>
|
||||
['A', 'B', 'C'].includes(student.jcZt)
|
||||
)
|
||||
})
|
||||
// 点名学生
|
||||
const dmXsList = ref<any>([]);
|
||||
// 未报名学生
|
||||
const unBmXsList = ref<any>([]);
|
||||
|
||||
// 未缴费/未报名学生列表(状态为D、E的学生)
|
||||
const wjfXs = computed(() => {
|
||||
if (!dmDetail.value?.xsList) return []
|
||||
return dmDetail.value.xsList.filter((student: any) =>
|
||||
['D', 'E'].includes(student.jcZt)
|
||||
)
|
||||
// 人数
|
||||
const rsData = ref({
|
||||
zrs: 0,
|
||||
bmRs: 0,
|
||||
unBmRs: 0
|
||||
})
|
||||
|
||||
// 方法
|
||||
@ -228,7 +225,18 @@ const loadDetail = async () => {
|
||||
const response = await getJcDmDetailApi(getData.id)
|
||||
|
||||
if (response.result) {
|
||||
dmDetail.value = response.result
|
||||
dmDetail.value = response.result;
|
||||
dmXsList.value = response.result.dmXsList || [];
|
||||
dmXsList.value = sortChinese(dmXsList.value, 'xsXm');
|
||||
unBmXsList.value = response.result.unBmXsList || [];
|
||||
unBmXsList.value = sortChinese(unBmXsList.value, 'xsxm');
|
||||
|
||||
rsData.value = {
|
||||
zrs: unBmXsList.value.length + dmXsList.value.length,
|
||||
bmRs: dmXsList.value.length,
|
||||
unBmRs: unBmXsList.value.length,
|
||||
}
|
||||
|
||||
} else {
|
||||
error.value = response.message || '获取详情失败'
|
||||
}
|
||||
@ -240,6 +248,10 @@ const loadDetail = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const hqZtSl = (status: string) => {
|
||||
return dmXsList.value.filter((s:any) => s.jcZt === status).length
|
||||
}
|
||||
|
||||
const formatDateTime = (dateStr: string) => {
|
||||
if (!dateStr) return ''
|
||||
const date = new Date(dateStr)
|
||||
@ -252,11 +264,6 @@ const formatDateTime = (dateStr: string) => {
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`
|
||||
}
|
||||
|
||||
const getStatusCount = (status: string) => {
|
||||
if (!dmDetail.value?.xsList) return 0
|
||||
return dmDetail.value.xsList.filter((s: any) => s.jcZt === status).length
|
||||
}
|
||||
|
||||
const getStatusText = (status: string) => {
|
||||
switch (status) {
|
||||
case 'A':
|
||||
@ -383,7 +390,7 @@ onMounted(() => {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.student-section {
|
||||
.xs-section {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
@ -463,24 +470,24 @@ onMounted(() => {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.teacher-list, .student-list {
|
||||
.teacher-list, .xs-list {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.teacher-grid, .student-grid {
|
||||
.teacher-grid, .xs-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.teacher-item, .student-item {
|
||||
.teacher-item, .xs-item {
|
||||
position: relative;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.teacher-item:hover, .student-item:hover {
|
||||
.teacher-item:hover, .xs-item:hover {
|
||||
transform: translateY(-2rpx);
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
@ -497,7 +504,7 @@ onMounted(() => {
|
||||
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.teacher-avatar, .student-avatar {
|
||||
.teacher-avatar, .xs-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
|
||||
@ -9,6 +9,7 @@ export const useDataStore = defineStore({
|
||||
global: {},
|
||||
file: {},
|
||||
xs: {}, // 学生专用
|
||||
jcBz: {}, // 就餐标准
|
||||
}),
|
||||
getters: {
|
||||
getData(): any {
|
||||
@ -28,7 +29,10 @@ export const useDataStore = defineStore({
|
||||
},
|
||||
getXs(): any {
|
||||
return this.xs;
|
||||
}
|
||||
},
|
||||
getJcBz(): any {
|
||||
return this.jcBz;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setData(data: any) {
|
||||
@ -48,6 +52,9 @@ export const useDataStore = defineStore({
|
||||
},
|
||||
setXs(data: any) {
|
||||
this.xs = data;
|
||||
},
|
||||
setJcBz(data: any) {
|
||||
this.jcBz = data;
|
||||
}
|
||||
},
|
||||
persist: {
|
||||
|
||||
50
src/utils/pinyinUtil.ts
Normal file
50
src/utils/pinyinUtil.ts
Normal file
@ -0,0 +1,50 @@
|
||||
// utils/pinyinUtils.ts
|
||||
import { pinyin } from 'pinyin-pro';
|
||||
|
||||
/**
|
||||
* 将汉字转换为拼音
|
||||
* @param text 需要转换的汉字文本
|
||||
* @returns 拼音字符串
|
||||
*/
|
||||
export function chineseToPinyin(text: string): string {
|
||||
try {
|
||||
return pinyin(text, { toneType: 'none', type: 'array', mode: 'surname' }).join('');
|
||||
} catch (error) {
|
||||
console.error('拼音转换失败:', error);
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取汉字首字母
|
||||
* @param text 需要转换的汉字文本
|
||||
* @returns 首字母字符串
|
||||
*/
|
||||
export function getFirstLetter(text: string): string {
|
||||
try {
|
||||
return pinyin(text, { pattern: 'first', toneType: 'none' });
|
||||
} catch (error) {
|
||||
console.error('首字母提取失败:', error);
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 中文排序函数
|
||||
* @param list 需要排序的数组
|
||||
* @param key 排序字段(如果是对象数组)
|
||||
* @returns 排序后的数组
|
||||
*/
|
||||
export function sortChinese(list: any, key?: string) {
|
||||
return list.sort((a:any, b: any) => {
|
||||
const textA = key ? a[key] : a as unknown as string;
|
||||
const textB = key ? b[key] : b as unknown as string;
|
||||
|
||||
const pinyinA = chineseToPinyin(textA);
|
||||
const pinyinB = chineseToPinyin(textB);
|
||||
|
||||
return pinyinA.localeCompare(pinyinB, 'zh-Hans-CN', {
|
||||
sensitivity: 'accent'
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user