| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902 |
- <template>
- <view class="dept-profile-page">
- <view class="page-header">
- <view class="header-title">
- <view class="title-main">班组综合信息展示</view>
- <view class="header-right">
- <view class="current-time">{{ currentTime }}</view>
- </view>
- </view>
- <view class="time-filter">
- <scroll-view scroll-x class="time-scroll">
- <view class="time-tags">
- <view v-for="(tag, index) in timeTags" :key="index"
- :class="['time-tag', { active: selectedTimeTag === index }]" @click="onTimeTagClick(index)">
- {{ tag }}
- </view>
- </view>
- </scroll-view>
- <view v-if="selectedTimeTag === 4" class="date-range-picker">
- <picker mode="date" :value="startDate" @change="onStartDateChange">
- <view class="date-input" :class="{ filled: startDate }">
- {{ startDate || '开始日期' }}
- </view>
- </picker>
- <text class="date-separator">至</text>
- <picker mode="date" :value="endDate" @change="onEndDateChange">
- <view class="date-input" :class="{ filled: endDate }">
- {{ endDate || '结束日期' }}
- </view>
- </picker>
- </view>
- </view>
- <view class="dept-selector">
- <view class="dept-select-trigger" :class="{ 'dept-select-trigger-disabled': !isBrigade()&&!isStationMaster() }"
- @click="chooseDept">
- <u-icon name="list" color="#A78BFA" size="16"></u-icon>
- <text class="dept-name-text">{{ selectedDeptName || '请选择班组' }}</text>
- <u-icon name="arrow-down" color="#A78BFA" size="14"></u-icon>
- </view>
- </view>
- <view class="tab-nav">
- <view class="tab-item" :class="{ active: activeTab === 'profile' }" @click="activeTab = 'profile'">
- 能力画像
- </view>
- <view class="tab-item" :class="{ active: activeTab === 'data' }" @click="activeTab = 'data'">
- 运行数据
- </view>
- </view>
- </view>
- <view class="page-content">
- <SectionTitle title="部门概况">
- <DeptStats :statsData="deptStatsData" />
- </SectionTitle>
- <view v-if="activeTab === 'profile'">
- <SectionTitle title="七维得分一览">
- <ProfileRadar :chartsData="radarData" />
- </SectionTitle>
- <SectionTitle title="团队成员">
- <TeamMemberTable :chartsData="teamMemberData" />
- </SectionTitle>
- <SectionTitle title="成员基本情况分布">
- <MemberBasicDistribution :chartsData="memberBasicData" />
- </SectionTitle>
- <SectionTitle title="成员职位情况分布">
- <MemberPositionDistribution :chartsData="memberPositionData" />
- </SectionTitle>
- </view>
- <view v-if="activeTab === 'data'">
- <SectionTitle title="通道高峰过检率">
- <PassengerChart :chartsData="passengerData" />
- </SectionTitle>
- <SectionTitle title="查获信息展示">
- <SeizureInfo :chartsData="seizureInfoData" />
- </SectionTitle>
- <SectionTitle title="查获物品分布">
- <ItemDistribution :chartsData="itemDistributionData" />
- </SectionTitle>
- <SectionTitle title="每日查获数量(总表)">
- <SeizedNumAll :chartsData="dailySeizureTotalData" />
- </SectionTitle>
- <SectionTitle title="每日查获数量">
- <DailySeizureChart :chartsData="dailySeizureData" :title="'小组对比'"/>
- </SectionTitle>
- <SectionTitle title="查获工作区域分布">
- <AreaDistribution :chartsData="areaDistributionData" />
- </SectionTitle>
- <SectionTitle title="不安全事件物品分布">
- <UnsafeItemsChart :chartsData="unsafeItemsData" />
- </SectionTitle>
- <SectionTitle title="不安全事件类型分布">
- <UnsafeTypesChart :chartsData="unsafeTypesData" />
- </SectionTitle>
- <SectionTitle title="不安全事件岗位分布">
- <UnsafePositionChart :chartsData="unsafePositionData" />
- </SectionTitle>
- <SecurityTestCharts :chartsData="securityTestData" />
- <SectionTitle title="各岗位监察问题分布">
- <SupervisionDistribution :chartsData="supervisionData" />
- </SectionTitle>
- <SectionTitle title="实时质控拦截物品分布">
- <InterceptionDistribution :chartsData="interceptionData" />
- </SectionTitle>
- </view>
- </view>
- <DeptSelector :show.sync="showDeptPicker" v-model="selectedDeptId" :options="deptList" :loading="deptLoading"
- @change="onDeptSelectChange" title="班组" />
- </view>
- </template>
- <script>
- import SectionTitle from '@/components/SectionTitle.vue'
- import TeamMemberTable from '../components/TeamMemberTable.vue'
- import MemberBasicDistribution from '../components/MemberBasicDistribution.vue'
- import MemberPositionDistribution from '../components/MemberPositionDistribution.vue'
- import PassengerChart from '../components/PassengerChart.vue'
- import SeizureInfo from '../components/SeizureInfo.vue'
- import ItemDistribution from '../components/ItemDistribution.vue'
- import DailySeizureChart from '../components/DailySeizureChart.vue'
- import AreaDistribution from '../components/AreaDistribution.vue'
- import UnsafeItemsChart from '../components/UnsafeItemsChart.vue'
- import UnsafeTypesChart from '../components/UnsafeTypesChart.vue'
- import UnsafePositionChart from '../components/UnsafePositionChart.vue'
- import SecurityTestCharts from '../components/SecurityTestCharts.vue'
- import ProfileRadar from '../components/ProfileRadar.vue'
- import SeizedNumAll from '../components/SeizedNumAll.vue'
- import SupervisionDistribution from '../components/SupervisionDistribution.vue'
- import InterceptionDistribution from '../components/InterceptionDistribution.vue'
- import DeptStats from '../components/DeptStats.vue'
- import DeptSelector from '../components/DeptSelector.vue'
- import {
- countStationTeamStats,
- getDeptMemberDistribution,
- getDeptPositionDistribution,
- countStationHourlyThroughput,
- countSeizureInfoItem,
- countSeizeSubjectCategoryQuantity,
- countSeizureTotalQuantity,
- countSeizureSingleQuantity,
- countSeizeAreaQuantity,
- countSeizureStatsItem,
- countSeizureStatsType,
- countSeizureStatsPost,
- securityTestItemClassification,
- securityTestPassingStatus,
- securityTestRegion,
- getDimensionScoreOverview,
- countLanePeakThroughput,
- realtimeInterceptionItem,
- supervisionProblemPosition,
- countDeptTeamStats
- } from '@/api/portraitManagement/portraitManagement'
- import { getDeptUserTree } from '@/api/system/user'
- const itemColors = ['#60A5FA', '#34D399', '#FBBF24', '#EF4444', '#9CA3AF', '#A78BFA', '#F472B6', '#6EE7B7']
- export default {
- name: 'DeptProfile',
- components: {
- SectionTitle,
- TeamMemberTable,
- MemberBasicDistribution,
- MemberPositionDistribution,
- PassengerChart,
- SeizureInfo,
- ItemDistribution,
- DailySeizureChart,
- AreaDistribution,
- UnsafeItemsChart,
- UnsafeTypesChart,
- UnsafePositionChart,
- SecurityTestCharts,
- ProfileRadar,
- SeizedNumAll,
- SupervisionDistribution,
- InterceptionDistribution,
- DeptStats,
- DeptSelector
- },
- data() {
- return {
- activeTab: 'profile',
- selectedTimeTag: 3,
- timeTags: ['近一周', '近一月', '近三月', '近一年', '自定义时间范围'],
- currentTime: '',
- timer: null,
- startDate: '',
- endDate: '',
- // 部门选择相关
- selectedDeptId: null,
- selectedDeptName: '',
- showDeptPicker: false,
- deptList: [],
- deptLoading: false,
- radarData: [],
- teamMemberData: [],
- memberBasicData: {
- gender: { labels: [], data: [] },
- ethnicity: { labels: [], data: [] },
- political: { labels: [], data: [] }
- },
- memberPositionData: {
- qualification: { labels: [], data: [] },
- experience: { labels: [], data: [] },
- position: { labels: [], data: [] }
- },
- passengerData: {
- labels: [],
- areas: {},
- totalFlow: []
- },
- seizureInfoData: {
- total: 0,
- depts: {
- labels: [],
- data: []
- }
- },
- itemDistributionData: {
- items: []
- },
- dailySeizureTotalData: [],
- dailySeizureData: {
- total: {
- labels: [],
- data: []
- },
- dept: {
- labels: [],
- data: {}
- }
- },
- areaDistributionData: {
- labels: [],
- data: []
- },
- unsafeItemsData: {
- items: []
- },
- unsafeTypesData: {
- types: []
- },
- unsafePositionData: {
- total: 0,
- positions: {
- labels: [],
- data: []
- }
- },
- securityTestData: {
- items: {
- labels: [],
- data: []
- },
- results: {
- labels: [],
- data: []
- },
- areas: {
- labels: [],
- data: []
- }
- },
- supervisionData: [],
- interceptionData: [],
- deptStatsData: {}
- }
- },
- computed: {
- currentDate() {
- const now = new Date()
- const year = now.getFullYear()
- const month = String(now.getMonth() + 1).padStart(2, '0')
- const day = String(now.getDate()).padStart(2, '0')
- const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
- const weekDay = weekDays[now.getDay()]
- return `${year}年${month}月${day}日 ${weekDay}`
- }
- },
- mounted() {
- this.updateTime()
- this.timer = setInterval(() => {
- this.updateTime()
- }, 1000)
- this.fetchDeptList()
- },
- beforeDestroy() {
- if (this.timer) {
- clearInterval(this.timer)
- }
- },
- methods: {
- updateTime() {
- const now = new Date()
- const hours = String(now.getHours()).padStart(2, '0')
- const minutes = String(now.getMinutes()).padStart(2, '0')
- const seconds = String(now.getSeconds()).padStart(2, '0')
- this.currentTime = `${hours}:${minutes}:${seconds}`
- },
- // 部门选择改变
- onDeptSelectChange(item) {
- this.selectedDeptId = item.deptId
- this.selectedDeptName = item.deptName
- // 重新请求数据
- const params = this.buildTimeParams()
- this.fetchAllData(params)
- },
- getUserRoles() {
- const userInfo = this.$store.state.user
- return userInfo && userInfo.roles ? userInfo.roles : []
- },
- //站长
- isStationMaster() {
- const roles = this.getUserRoles()
- return roles.includes('test') || roles.includes('zhijianke')
- },
- //部门经理
- isBrigade() {
- const roles = this.getUserRoles()
- return roles.includes('bumenjingli')
- },
- //班组长
- // isManager() {
- // const roles = this.getUserRoles()
- // return roles.includes('banzuzhang')
- // },
- chooseDept() {
- if (this.isStationMaster() || this.isBrigade()) {
- this.showDeptPicker = true
- }
- },
- fetchDeptList() {
- this.deptLoading = true
- const userInfo = this.$store.state.user?.userInfo;
- let params = this.isBrigade() ? { deptId: userInfo.deptId } : { deptId: userInfo.deptId }
- getDeptUserTree(params).then(res => {
- if (res.code === 200) {
- let allDepts = this.flattenDeptTree(res.data || [])
- this.deptList = allDepts.filter(d => d.deptType === 'MANAGER')
- if (userInfo && userInfo.deptId) {
- const dept = this.deptList.find(d => d.deptId === userInfo.deptId)
- if (dept) {
- this.selectedDeptId = dept.deptId
- this.selectedDeptName = dept.deptName
- } else if (this.deptList.length > 0) {
- this.selectedDeptId = this.deptList[0].deptId
- this.selectedDeptName = this.deptList[0].deptName
- }
- } else if (this.deptList.length > 0) {
- this.selectedDeptId = this.deptList[0].deptId
- this.selectedDeptName = this.deptList[0].deptName
- }
- // 选择完部门后请求数据
- this.onTimeTagClick(3)
- }
- }).catch(() => {
- }).finally(() => {
- this.deptLoading = false
- })
- },
- flattenDeptTree(tree) {
- const result = []
- const traverse = (nodes) => {
- nodes.forEach(node => {
- if (node.id) {
- result.push({
- deptId: node.id,
- deptName: node.label,
- deptType: node.deptType
- })
- }
- if (node.children && node.children.length > 0) {
- traverse(node.children)
- }
- })
- }
- traverse(tree)
- return result
- },
- fetchAllData(params) {
- this.fetchDeptStats(params)
- this.fetchRadarData(params)
- this.fetchTeamData(params)
- this.fetchMemberDistribution(params)
- this.fetchPositionDistribution(params)
- const copyParams = { ...params }
- delete copyParams.deptId
- this.fetchPassengerData(copyParams)
- this.fetchSeizureInfo(copyParams)
- this.fetchItemDistribution(copyParams)
- this.fetchDailySeizure(copyParams)
- this.fetchAreaDistribution(copyParams)
- this.fetchUnsafeItems(copyParams)
- this.fetchUnsafeTypes(copyParams)
- this.fetchUnsafePosition(copyParams)
- this.fetchSecurityTestData(copyParams)
- this.fetchSupervisionData(copyParams)
- this.fetchInterceptionData(copyParams)
- },
- buildTimeParams() {
- const now = new Date()
- const today = this.formatDate(now)
- const deptId = this.selectedDeptId;
- const teamId = this.selectedDeptId;
- if(!this.selectedDeptId){
- return
-
- }
- if (this.selectedTimeTag === 4) {
- if (this.startDate && this.endDate) {
- return { startDate: this.startDate, endDate: this.endDate, deptId, teamId }
- }
- return { deptId, teamId }
- }
- let startDate
- switch (this.selectedTimeTag) {
- case 0:
- startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
- break
- case 1:
- startDate = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate())
- break
- case 2:
- startDate = new Date(now.getFullYear(), now.getMonth() - 3, now.getDate())
- break
- case 3:
- startDate = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate())
- break
- default:
- return { deptId, teamId }
- }
- return { startDate: this.formatDate(startDate), endDate: today, deptId, teamId }
- },
- formatDate(date) {
- const y = date.getFullYear()
- const m = String(date.getMonth() + 1).padStart(2, '0')
- const d = String(date.getDate()).padStart(2, '0')
- return `${y}-${m}-${d}`
- },
- onTimeTagClick(index) {
- this.selectedTimeTag = index
- if (index === 4) {
- this.startDate = ''
- this.endDate = ''
- return
- }
- const params = this.buildTimeParams()
- this.fetchAllData(params)
- },
- onStartDateChange(e) {
- this.startDate = e.detail.value
- if (this.startDate && this.endDate) {
- this.fetchAllData(this.buildTimeParams())
- }
- },
- onEndDateChange(e) {
- this.endDate = e.detail.value
- if (this.startDate && this.endDate) {
- this.fetchAllData(this.buildTimeParams())
- }
- },
- fetchDeptStats(params) {
- countDeptTeamStats(params).then(res => {
- if (res.code === 200 && res.data) {
- this.deptStatsData = res.data
- }
- }).catch(() => { })
- },
- fetchRadarData(params) {
- getDimensionScoreOverview(params).then(res => {
- if (res.code === 200 && res.data) {
- // 支持两种数据结构
- if (res.data.dimensions && Array.isArray(res.data.dimensions)) {
- this.radarData = res.data.dimensions
- } else {
- this.radarData = []
- }
- }
- }).catch(() => {
- this.radarData = []
- })
- },
- fetchTeamData(params) {
- countStationTeamStats(params).then(res => {
- if (res.code === 200 && res.data) {
- this.teamMemberData = (res.data || []).map(item => ({
- department: item.deptName,
- employeeCount: item.employeeCount,
- partyMemberCount: item.partyMemberCount,
- avgAge: item.avgAge,
- avgTenure: item.avgWorkYears,
- certificateCount: item.qualificationLevel,
- machineYears: item.avgXrayOperatorYears,
- comprehensiveScore: item.totalScore
- }))
- }
- }).catch(() => { })
- },
- fetchMemberDistribution(params) {
- getDeptMemberDistribution(params).then(res => {
- if (res.code === 200 && res.data) {
- this.memberBasicData = {
- gender: {
- labels: (res.data.sexDistribution || []).map(item => item.name),
- data: (res.data.sexDistribution || []).map(item => item.count)
- },
- ethnicity: {
- labels: (res.data.nationDistribution || []).map(item => item.name),
- data: (res.data.nationDistribution || []).map(item => item.count)
- },
- political: {
- labels: (res.data.politicalDistribution || []).map(item => item.name),
- data: (res.data.politicalDistribution || []).map(item => item.count)
- }
- }
- }
- }).catch(() => { })
- },
- fetchPositionDistribution(params) {
- getDeptPositionDistribution(params).then(res => {
- if (res.code === 200 && res.data) {
- this.memberPositionData = {
- qualification: {
- labels: (res.data.qualificationDistribution || []).map(item => item.name),
- data: (res.data.qualificationDistribution || []).map(item => item.count)
- },
- experience: {
- labels: (res.data.xrayYearDistribution || []).map(item => item.name),
- data: (res.data.xrayYearDistribution || []).map(item => item.count)
- },
- position: {
- labels: (res.data.positionDistribution || []).map(item => item.name),
- data: (res.data.positionDistribution || []).map(item => item.count)
- }
- }
- }
- }).catch(() => { })
- },
- fetchPassengerData(params) {
- countLanePeakThroughput(params).then(res => {
- if (res.code === 200 && res.data) {
- const rawData = res.data || []
- const hours = [...new Set(rawData.map(item => item.hour))]
- const areaMap = {}
- rawData.forEach(item => {
- (item.laneList || []).forEach(lane => {
- if (!areaMap[lane.laneName]) {
- areaMap[lane.laneName] = []
- }
- areaMap[lane.laneName].push(lane.throughputRate)
- })
- })
- this.passengerData = {
- labels: hours,
- areas: areaMap,
- totalFlow: rawData.map(item => item.totalLaneThroughput)
- }
- }
- }).catch(() => { })
- },
- fetchSeizureInfo(params) {
- countSeizureInfoItem(params).then(res => {
- if (res.code === 200 && res.data) {
- const itemList = res.data.itemList || []
- this.seizureInfoData = {
- total: res.data.totalSeizeNum || 0,
- depts: {
- labels: itemList.map(item => item.name),
- data: itemList.map(item => item.seizeNum)
- }
- }
- }
- }).catch(() => { })
- },
- fetchItemDistribution(params) {
- countSeizeSubjectCategoryQuantity(params).then(res => {
- if (res.code === 200 && res.data) {
- const items = (res.data || []).map((item, index) => ({
- name: item.itemName,
- value: item.itemNum,
- color: itemColors[index % itemColors.length]
- }))
- this.itemDistributionData = { items }
- }
- }).catch(() => { })
- },
- fetchDailySeizure(params) {
- countSeizureTotalQuantity(params).then(res => {
- if (res.code === 200 && res.data) {
- this.dailySeizureTotalData = res.data || []
- this.dailySeizureData.total = {
- labels: (res.data || []).map(item => item.recordDate),
- data: (res.data || []).map(item => item.seizeQuantity)
- }
- }
- }).catch(() => { })
- countSeizureSingleQuantity(params).then(res => {
- if (res.code === 200 && res.data) {
- const rawData = res.data || []
- const dates = rawData.map(item => item.recordDate)
- const deptMap = {}
- rawData.forEach(dayItem => {
- (dayItem.items || []).forEach(subItem => {
- if (!deptMap[subItem.groupName]) {
- deptMap[subItem.groupName] = []
- }
- deptMap[subItem.groupName].push(subItem.seizeQuantity)
- })
- })
- this.dailySeizureData.dept = {
- labels: dates,
- deptData: Object.keys(deptMap).map(name => ({
- name,
- data: deptMap[name]
- }))
- }
- }
- }).catch(() => { })
- },
- fetchAreaDistribution(params) {
- countSeizeAreaQuantity(params).then(res => {
- if (res.code === 200 && res.data) {
- const data = res.data || []
- this.areaDistributionData = {
- labels: data.map(item => item.workArea),
- data: data.map(item => item.areaSeizeNum)
- }
- }
- }).catch(() => { })
- },
- fetchUnsafeItems(params) {
- countSeizureStatsItem(params).then(res => {
- if (res.code === 200 && res.data) {
- const data = res.data || []
- this.unsafeItemsData = {
- items: data.map(item => ({
- name: item.itemName,
- value: item.itemNum
- }))
- }
- }
- }).catch(() => { })
- },
- fetchUnsafeTypes(params) {
- countSeizureStatsType(params).then(res => {
- if (res.code === 200 && res.data) {
- const data = res.data || []
- this.unsafeTypesData = {
- types: data.map(item => ({
- name: item.eventType,
- value: item.eventTypeNum
- }))
- }
- }
- }).catch(() => { })
- },
- fetchUnsafePosition(params) {
- countSeizureStatsPost(params).then(res => {
- if (res.code === 200 && res.data) {
- const data = res.data || []
- const total = data.reduce((sum, item) => sum + (item.count || 0), 0)
- this.unsafePositionData = {
- total: total,
- positions: {
- labels: data.map(item => item.positionName),
- data: data.map(item => item.positionNum)
- }
- }
- }
- }).catch(() => { })
- },
- fetchSecurityTestData(params) {
- securityTestItemClassification(params).then(res => {
- if (res.code === 200 && res.data) {
- const data = res.data || []
- this.securityTestData.items = {
- labels: data.map(item => item.name),
- data: data.map(item => item.total)
- }
- }
- }).catch(() => { })
- securityTestPassingStatus(params).then(res => {
- if (res.code === 200 && res.data) {
- const data = res.data || []
- this.securityTestData.results = {
- labels: data.map(item => item.name),
- data: data.map(item => item.total)
- }
- }
- }).catch(() => { })
- securityTestRegion(params).then(res => {
- if (res.code === 200 && res.data) {
- const data = res.data || []
- this.securityTestData.areas = {
- labels: data.map(item => item.name),
- data: data.map(item => item.total)
- }
- }
- }).catch(() => { })
- },
- fetchSupervisionData(params) {
- supervisionProblemPosition(params).then(res => {
- if (res.code === 200 && res.data) {
- this.supervisionData = (res.data || []).map(item => ({
- num: item.total,
- name: item.name
- }))
- }
- }).catch(() => { })
- },
- fetchInterceptionData(params) {
- realtimeInterceptionItem(params).then(res => {
- if (res.code === 200 && res.data) {
- this.interceptionData = (res.data || []).map(item => ({
- num: item.total,
- name: item.name
- }))
- }
- }).catch(() => { })
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .dept-selector {
- padding: 16rpx 32rpx;
- background: #fff;
- }
- .dept-select-trigger {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 12rpx;
- padding: 16rpx 24rpx;
- background: #f5f5f5;
- border: 1rpx solid #e0e0e0;
- border-radius: 50rpx;
- }
- .dept-select-trigger-disabled {
- opacity: 0.5;
- pointer-events: none;
- }
- .dept-name-text {
- font-size: 26rpx;
- color: #333;
- }
- .dept-profile-page {
- min-height: 100vh;
- background: #fff;
- padding-bottom: 40rpx;
- }
- .page-header {
- position: sticky;
- top: 0;
- z-index: 100;
- background: #fff;
- backdrop-filter: blur(10px);
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
- }
- .header-title {
- padding: 24rpx 32rpx;
- display: flex;
- justify-content: space-between;
- align-items: center;
- .title-main {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- }
- }
- .header-right {
- display: flex;
- align-items: center;
- gap: 16rpx;
- .current-time {
- font-size: 24rpx;
- color: #999;
- }
- }
- .time-filter {
- padding: 16rpx 32rpx;
- background: #fff;
- }
- .time-scroll {
- width: 100%;
- }
- .time-tags {
- display: flex;
- gap: 16rpx;
- white-space: nowrap;
- }
- .time-tag {
- padding: 8rpx 10rpx;
- border-radius: 50rpx;
- background: #f0f0f0;
- font-size: 24rpx;
- color: #666;
- transition: all 0.3s;
- &.active {
- background: #60A5FA;
- color: #fff;
- font-weight: 500;
- }
- }
- .date-range-picker {
- display: flex;
- align-items: center;
- gap: 16rpx;
- margin-top: 16rpx;
- padding-top: 16rpx;
- border-top: 1rpx solid #e0e0e0;
- }
- .date-input {
- flex: 1;
- padding: 12rpx 24rpx;
- border-radius: 12rpx;
- background: #f5f5f5;
- font-size: 24rpx;
- color: #999;
- text-align: center;
- &.filled {
- color: #333;
- }
- }
- .date-separator {
- font-size: 24rpx;
- color: #999;
- flex-shrink: 0;
- }
- .tab-nav {
- padding: 16rpx 32rpx;
- display: flex;
- justify-content: center;
- gap: 64rpx;
- }
- .tab-item {
- font-size: 28rpx;
- color: #999;
- padding-bottom: 8rpx;
- border-bottom: 2rpx solid transparent;
- transition: all 0.3s;
- &.active {
- color: #333;
- border-bottom-color: #333;
- }
- }
- .page-content {
- padding: 32rpx;
- display: flex;
- flex-direction: column;
- }
- </style>
|