接口调试

This commit is contained in:
BianLzhaoMin 2025-12-09 10:42:45 +08:00
parent 9f6c55c54b
commit 7c8526254b
7 changed files with 365 additions and 74 deletions

View File

@ -24,21 +24,26 @@
<view class="ranking-table">
<view class="table-header">
<text class="header-cell">排名</text>
<text class="header-cell">姓名</text>
<text class="header-cell">{{ activeTab === 'personal' ? '姓名' : '分公司' }}</text>
<text class="header-cell">应履职</text>
<text class="header-cell">已履职</text>
<text class="header-cell">履职进度</text>
<text class="header-cell">{{
activeTab === 'personal' ? '履职进度' : '履职率'
}}</text>
</view>
<view class="table-body">
<view v-if="currentData.length === 0" class="empty-state">
<view v-if="loading" class="empty-state">
<text class="empty-text">加载中...</text>
</view>
<view v-else-if="currentData.length === 0" class="empty-state">
<text class="empty-text">暂无数据</text>
</view>
<view v-else v-for="(item, index) in currentData" :key="index" class="table-row">
<text class="body-cell">{{ item.rank }}</text>
<text class="body-cell">{{ item.name }}</text>
<text class="body-cell">{{ item.required }}</text>
<text class="body-cell">{{ item.completed }}</text>
<text class="body-cell progress-cell">{{ item.progress }}%</text>
<text class="body-cell">{{ item.pm || item.ranking || index + 1 }}</text>
<text class="body-cell">{{ getDisplayName(item) }}</text>
<text class="body-cell">{{ getRequiredValue(item) }}</text>
<text class="body-cell">{{ getCompletedValue(item) }}</text>
<text class="body-cell progress-cell">{{ getRateValue(item) }}%</text>
</view>
</view>
</view>
@ -46,7 +51,12 @@
</template>
<script setup>
import { computed } from 'vue'
import { ref, computed, watch, onMounted } from 'vue'
import dayjs from 'dayjs'
import {
getPerformanceRankingPersonalApi,
getPerformanceRankingUnitApi,
} from '@/services/leader/home'
/**
* 履职排名组件
@ -56,34 +66,40 @@ import { computed } from 'vue'
* 2. 表格形式展示排名数据包含排名姓名应履职已履职履职进度
* 3. 空状态提示提升用户体验
* 4. 绿色下划线标识当前选中的标签
* 5. 组件内部管理数据根据tab和日期自动调用接口
*/
const props = defineProps({
//
rankingData: {
type: Object,
required: true,
default: () => ({
personal: [],
unit: [],
}),
},
//
activeTab: {
type: String,
required: true,
default: 'personal',
},
// YYYY-MM
selectedDate: {
type: String,
required: true,
},
})
const emit = defineEmits(['tab-change'])
//
const rankingData = ref({
personal: [],
unit: [],
})
//
const loading = ref(false)
/**
* 当前显示的数据
* 业务背景根据选中的标签显示对应的排名数据
*/
const currentData = computed(() => {
return props.rankingData[props.activeTab] || []
return rankingData.value[props.activeTab] || []
})
/**
@ -92,6 +108,114 @@ const currentData = computed(() => {
*/
const handleTabClick = (tab) => {
emit('tab-change', tab)
// tab
if (!rankingData.value[tab] || rankingData.value[tab].length === 0) {
loadRankingData(tab)
}
}
/**
* 加载履职排名数据
* 业务背景根据选中的月份和标签类型获取履职排名数据
* @param {String} tab - 标签类型'personal' | 'unit'
*/
const loadRankingData = async (tab) => {
try {
loading.value = true
const date = props.selectedDate // YYYY-MM
const [year, month] = date.split('-')
//
const api =
tab === 'personal' ? getPerformanceRankingPersonalApi : getPerformanceRankingUnitApi
const res = await api({
year,
month,
})
// 使
const data = res?.rows || res?.data || []
rankingData.value[tab] = data
} catch (error) {
console.error('加载履职排名数据失败:', error)
uni.showToast({
title: error?.data?.msg || '加载排名数据失败',
icon: 'none',
})
//
rankingData.value[tab] = []
} finally {
loading.value = false
}
}
//
watch(
() => props.selectedDate,
() => {
loadRankingData(props.activeTab)
},
)
// tab
watch(
() => props.activeTab,
(newTab) => {
if (!rankingData.value[newTab] || rankingData.value[newTab].length === 0) {
loadRankingData(newTab)
}
},
)
//
onMounted(() => {
loadRankingData(props.activeTab)
})
/**
* 获取显示名称
* 业务背景根据tab类型返回对应的名称字段
*/
const getDisplayName = (item) => {
if (props.activeTab === 'personal') {
return item.nickName || item.userName || item.nickName || '--'
} else {
return item.postName || item.branchName || item.name || '--'
}
}
/**
* 获取应履职值
*/
const getRequiredValue = (item) => {
return item.lzNum || item.lzTotal || item.requiredDays || item.shouldPerformDuty || '--'
}
/**
* 获取已履职值
*/
const getCompletedValue = (item) => {
return (
item.realLzNum ||
item.alreadyPerform ||
item.completedDays ||
item.alreadyPerformDuty ||
'--'
)
}
/**
* 获取履职进度/履职率值
*/
const getRateValue = (item) => {
let rate
if (props.activeTab === 'personal') {
rate = item.lzBfb || item.progressRate || item.rate
} else {
rate = item.lzBfb || item.performRate || item.progressRate
}
return rate !== undefined && rate !== null && rate !== '' ? `${rate}%` : '--'
}
</script>

View File

@ -17,17 +17,15 @@
<view class="standard-cards">
<view class="standard-card">
<text class="card-label">现场履职</text>
<text class="card-value">实到: {{ standardData.onSitePerformance.actual }}</text>
<text class="card-value">实到: {{ standardDataInfo.real_xclz_num }}</text>
</view>
<view class="standard-card">
<text class="card-label">班组履职</text>
<text class="card-value">实到: {{ standardData.teamPerformance.actual }}</text>
<text class="card-value">实到: {{ standardDataInfo.real_bzlz_num }}</text>
</view>
<view class="standard-card problem-card" @tap="handleProblemClick">
<text class="card-label">发现问题</text>
<text class="card-value problem-value"
>{{ standardData.problemsFound.count }}</text
>
<text class="card-value problem-value">{{ standardDataInfo.problemNum }}</text>
</view>
</view>
@ -38,9 +36,10 @@
</template>
<script setup>
import { computed } from 'vue'
import { computed, ref } from 'vue'
import dayjs from 'dayjs'
import DatePicker from '@/components/DatePicker/index.vue'
import { getHomeStatisticsApi } from '@/services/leader/home'
/**
* 履职标准组件
@ -52,6 +51,14 @@ import DatePicker from '@/components/DatePicker/index.vue'
* 4. 底部显示说明文字解释统计规则
*/
const standardDataInfo = ref({
bzlz_unit_type: '次',
problemNum: 0,
real_bzlz_num: 0,
real_xclz_num: 0,
xclz_unit_type: '次',
})
const props = defineProps({
// YYYY-MM
selectedDate: {
@ -87,6 +94,7 @@ const dateTimestamp = computed(() => {
*/
const handleDateChange = (timestamp) => {
emit('date-change', timestamp)
getPerformanceStandardData()
}
/**
@ -96,6 +104,18 @@ const handleDateChange = (timestamp) => {
const handleProblemClick = () => {
emit('problem-click')
}
//
const getPerformanceStandardData = async () => {
const res = await getHomeStatisticsApi({
yyyyMM: props.selectedDate.split('-').join(''),
})
if (res.code === 200) {
standardDataInfo.value = res.data
}
}
getPerformanceStandardData()
</script>
<style lang="scss" scoped>

View File

@ -25,7 +25,7 @@
<!-- 履职排名 -->
<PerformanceRanking
:rankingData="rankingData"
:selectedDate="selectedDate"
:activeTab="activeTab"
@tab-change="handleTabChange"
/>
@ -128,10 +128,6 @@ const standardData = ref({
//
const activeTab = ref('personal') // 'personal' | 'unit'
const rankingData = ref({
personal: [],
unit: [],
})
//
const routeMap = {
@ -169,12 +165,11 @@ const handleModuleClick = (type) => {
* 处理日期变更
* @param {Number} timestamp - 时间戳
* 业务背景切换月份后需要重新加载该月份的履职数据
* 设计决策更新选中日期并重新请求数据
* 设计决策更新选中日期子组件会自动监听日期变化并重新加载数据
*/
const handleDateChange = (timestamp) => {
selectedDate.value = dayjs(timestamp).format('YYYY-MM')
loadStandardData()
loadRankingData()
}
/**
@ -199,11 +194,10 @@ const handleProblemClick = () => {
* 处理排名标签切换
* @param {String} tab - 标签类型'personal' | 'unit'
* 业务背景用户可以在个人排名和单位排名之间切换
* 设计决策切换标签后重新加载对应维度的排名数据
* 设计决策切换标签子组件会自动处理数据加载
*/
const handleTabChange = (tab) => {
activeTab.value = tab
loadRankingData()
}
/**
@ -235,23 +229,6 @@ const loadStandardData = async () => {
}
}
/**
* 加载履职排名数据
* 业务背景根据选中的月份和标签类型获取履职排名数据
* 设计决策调用接口获取数据如果接口未实现则使用模拟数据
*/
const loadRankingData = async () => {
try {
// TODO:
// const res = await getPerformanceRankingApi(selectedDate.value, activeTab.value)
// rankingData.value[activeTab.value] = res.data
//
rankingData.value[activeTab.value] = []
} catch (error) {
console.error('加载履职排名数据失败:', error)
}
}
const handleBack = () => {
uni.navigateBack()
}
@ -259,7 +236,6 @@ const handleBack = () => {
onLoad(() => {
console.log('领导履职系统首页加载')
loadStandardData()
loadRankingData()
})
</script>

View File

@ -190,8 +190,8 @@
{{ item.dateRange || '暂无日期' }}
</text>
</view>
<text class="record-days" v-if="item.leaveCnt">
{{ item.leaveCnt }}
<text class="record-days" v-if="item.leaveDays || item.leaveCnt">
{{ item.leaveDays || item.leaveCnt }}
</text>
</view>
@ -212,30 +212,48 @@
</view>
<view class="record-actions">
<template v-if="item.canEdit">
<!-- 请假审批tab显示同意和拒绝按钮 -->
<template v-if="activeTab === 'approval'">
<up-button
text="修改"
text="同意"
size="small"
type="primary"
plain
@tap.stop="handleModify(item)"
@tap.stop="handleApprove(item)"
/>
<up-button
text="撤销"
text="拒绝"
size="small"
type="warning"
plain
@tap.stop="handleRevoke(item)"
type="error"
@tap.stop="handleReject(item)"
/>
</template>
<!-- 请假记录tab显示修改撤销或结束按钮 -->
<template v-else>
<template v-if="item.canEdit">
<up-button
text="修改"
size="small"
type="primary"
plain
@tap.stop="handleModify(item)"
/>
<up-button
text="撤销"
size="small"
type="warning"
plain
@tap.stop="handleRevoke(item)"
/>
</template>
<up-button
v-else
text="结束"
size="small"
type="success"
plain
@tap.stop="handleFinish(item)"
/>
</template>
<up-button
v-else
text="结束"
size="small"
type="success"
plain
@tap.stop="handleFinish(item)"
/>
</view>
</view>
</view>
@ -312,6 +330,8 @@ import {
getPersonPerformanceDaysApi,
checkHasUnfinishedLeaveApi,
endLeaveRequestApi,
approveLeaveRequestApi,
rejectLeaveRequestApi,
} from '@/services/leader/leave-request'
/**
@ -917,13 +937,13 @@ const normalizeStartEnd = (item) => {
* 加载记录列表
* 业务背景根据时间范围与页码获取请假记录/审批列表
* 设计决策请求参数使用 startTime/endTime移除 pageSize前端保留分页 pageNum
* 注意请假审批和请假记录使用同一个接口
*/
const loadRecordList = async () => {
try {
loading.value = true
const api = activeTab.value === 'record' ? getMyLeaveRecordListApi : getLeaveApprovalListApi
const res = await api({
// 使
const res = await getMyLeaveRecordListApi({
pageNum: queryParams.value.pageNum,
startTime: computedRecordRange.value.startTime,
endTime: computedRecordRange.value.endTime,
@ -1137,12 +1157,104 @@ const handleFinish = async (item) => {
} catch (error) {
console.error('检查未结束请假失败:', error)
uni.showToast({
title: error?.message || '检查失败,请稍后重试',
title: error?.data?.msg || '检查失败,请稍后重试',
icon: 'none',
})
}
}
/**
* 处理审批同意
* 业务背景审批人同意请假申请
*/
const handleApprove = async (item) => {
if (!item.id) {
uni.showToast({
title: '数据异常,无法审批',
icon: 'none',
})
return
}
uni.showModal({
title: '确认审批',
content: '确认同意该请假申请吗?',
cancelText: '再想想',
confirmText: '确认',
confirmColor: '#07c160',
success: async (res) => {
if (!res.confirm) return
try {
await approveLeaveRequestApi({
id: item.id,
approverComment: '同意',
approverStatus: 1,
})
uni.showToast({
title: '审批成功',
icon: 'success',
})
//
queryParams.value.pageNum = 1
recordList.value = []
await loadRecordList()
} catch (error) {
console.error('审批失败:', error)
uni.showToast({
title: error?.data?.msg || '审批失败,请重试',
icon: 'none',
})
}
},
})
}
/**
* 处理审批拒绝
* 业务背景审批人拒绝请假申请
*/
const handleReject = async (item) => {
if (!item.id) {
uni.showToast({
title: '数据异常,无法审批',
icon: 'none',
})
return
}
uni.showModal({
title: '确认拒绝',
content: '确认拒绝该请假申请吗?',
cancelText: '再想想',
confirmText: '确认拒绝',
confirmColor: '#ff4d4f',
success: async (res) => {
if (!res.confirm) return
try {
await rejectLeaveRequestApi({
id: item.id,
approverComment: '不同意',
approverStatus: 2,
})
uni.showToast({
title: '已拒绝',
icon: 'success',
})
//
queryParams.value.pageNum = 1
recordList.value = []
await loadRecordList()
} catch (error) {
console.error('拒绝失败:', error)
uni.showToast({
title: error?.msg || '操作失败,请重试',
icon: 'none',
})
}
},
})
}
const handleBack = () => {
uni.navigateBack()
}

View File

@ -0,0 +1,28 @@
import { http } from '@/utils/http'
// 获取首页统计数据
export const getHomeStatisticsApi = (data) => {
return http({
url: '/perform_set/user/info',
method: 'GET',
data,
})
}
// 获取履职排名个人数据
export const getPerformanceRankingPersonalApi = (data) => {
return http({
url: '/report/perform_log/userRank',
method: 'GET',
data,
})
}
// 获取履职排名单位数据
export const getPerformanceRankingUnitApi = (data) => {
return http({
url: '/report/perform_log/deptRank',
method: 'GET',
data,
})
}

View File

@ -129,3 +129,32 @@ export const getLeaveDetailApi = (data) => {
data,
})
}
/**
* 审批请假申请同意
* 业务背景审批人同意请假申请
* @param {String|Number} id - 请假申请ID
* @returns {Promise} 返回审批结果
*/
export const approveLeaveRequestApi = (data) => {
return http({
url: '/leave_log/approve_leave',
method: 'PUT',
data,
})
}
/**
* 审批请假申请拒绝
* 业务背景审批人拒绝请假申请
* @param {String|Number} id - 请假申请ID
* @param {String} reason - 拒绝原因可选
* @returns {Promise} 返回审批结果
*/
export const rejectLeaveRequestApi = (data) => {
return http({
url: '/leave_log/approve_leave',
method: 'PUT',
data,
})
}

View File

@ -6,6 +6,8 @@ import uni from '@dcloudio/vite-plugin-uni'
export default defineConfig({
plugins: [uni(), removeConsole()],
server: {
// 自动打开浏览器
open: true,
proxy: {
// 在此处编写代理规则
'/api': {