接口调试
This commit is contained in:
parent
9f6c55c54b
commit
7c8526254b
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import uni from '@dcloudio/vite-plugin-uni'
|
|||
export default defineConfig({
|
||||
plugins: [uni(), removeConsole()],
|
||||
server: {
|
||||
// 自动打开浏览器
|
||||
open: true,
|
||||
proxy: {
|
||||
// 在此处编写代理规则
|
||||
'/api': {
|
||||
|
|
|
|||
Loading…
Reference in New Issue