| | |
| | | <div class="user-name">{{ userStore.name }}</div> |
| | | <div class="user-role">{{ userStore.roleName }}</div> |
| | | <div class="user-meta"> |
| | | <span>{{ userStore.phoneNumber || '123456789' }}</span> |
| | | <span>{{ userStore.phonenumber || '123456789' }}</span> |
| | | <span class="sep">|</span> |
| | | <span>{{ userStore.deptName || '组织架构' }}</span> |
| | | <span>{{ userStore.currentFactoryName || '组织架构' }}</span> |
| | | <span class="sep">|</span> |
| | | <span>{{ userStore.postName || '岗位名' }}</span> |
| | | <span>{{ userStore.remark || '岗位名' }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- |
| | | <div class="data-cards"> |
| | | <div class="data-card sales"> |
| | | <div class="data-title">销售数据</div> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | --> |
| | | <!-- 右:待办事项 --> |
| | | <!-- |
| | | <div class="todo-panel"> |
| | | <div class="section-title">待办事项</div> |
| | | <ul class="todo-list" v-if="todoList.length > 0"> |
| | |
| | | 暂无数据 |
| | | </div> |
| | | </div> |
| | | --> |
| | | </div> |
| | | <!-- |
| | | <div class="dashboard-row"> |
| | | <div class="main-panel process-panel"> |
| | | <div class="process-panel__header"> |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 工序选择弹窗 --> |
| | | <el-dialog v-model="processDialogVisible" title="选择工序" width="500px" append-to-body> |
| | | <div class="process-selection-wrapper"> |
| | | <el-checkbox-group v-model="tempProcessIds"> |
| | |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 中部横向两栏 --> |
| | | --> |
| | | <!-- 中部:客户合同金额分析 --> |
| | | <div class="dashboard-row"> |
| | | <div class="main-panel"> |
| | | <div class="main-panel contract-panel"> |
| | | <div class="section-title">客户合同金额分析</div> |
| | | <div class="contract-summary"> |
| | | <div class="contract-info"> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div |
| | | style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 180px;margin-top: 20px"> |
| | | <div> |
| | | <Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie" :series="materialPieSeries" |
| | | <div class="contract-chart-wrapper"> |
| | | <div class="chart-container"> |
| | | <Echarts ref="chart" :legend="pieLegend" :chartStyle="{ width: '100%', height: '280px' }" :series="materialPieSeries" |
| | | :tooltip="pieTooltip"></Echarts> |
| | | </div> |
| | | <ul class="contract-list"> |
| | | <li v-for="item in materialPieSeries[0].data" :key="item.name"> |
| | | <div style="display: flex;align-items: center;justify-content: space-between;width: 100%"> |
| | | <div class="line" :style="{ color: item.itemStyle.color }">●{{ item.name }}</div> |
| | | <div style="width: 70px">{{ item.rate }}%</div> |
| | | <div>¥{{ item.value }}</div> |
| | | <div class="contract-item"> |
| | | <span class="contract-dot" :style="{ background: item.itemStyle?.color || '#999' }"></span> |
| | | <span class="contract-name">{{ item.name }}</span> |
| | | <span class="contract-rate">{{ item.rate }}%</span> |
| | | <span class="contract-value">¥{{ item.value }}</span> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | </div> |
| | | <div class="main-panel"> |
| | | <div style="display: flex;justify-content: space-between;"> |
| | | <div class="section-title">应收应付统计</div> |
| | | <!-- <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable">--> |
| | | <!-- <el-radio-button label="按周" :value="1" />--> |
| | | <!-- <el-radio-button label="按月" :value="2" />--> |
| | | <!-- <el-radio-button label="按季度" :value="3" />--> |
| | | <!-- </el-radio-group>--> |
| | | </div> |
| | | <Echarts ref="chart" :color="barColors2" :chartStyle="chartStyle" :grid="grid" :series="barSeries" |
| | | :tooltip="tooltip" :xAxis="xAxis" :yAxis="yAxis" style="height: 260px"></Echarts> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 底部横向两栏 --> |
| | | <!-- |
| | | <div class="dashboard-row"> |
| | | <div class="main-panel"> |
| | | <div style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 10px;"> |
| | |
| | | :tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" style="height: 270px;" /> |
| | | </div> |
| | | </div> |
| | | --> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | ]) |
| | | const chartStyle = { |
| | | width: '100%', |
| | | height: '100%' // 设置图表容器的高度 |
| | | height: '100%' |
| | | } |
| | | const chartStylePie = { |
| | | width: '140%', |
| | | height: '140%' // 设置图表容器的高度 |
| | | height: '140%' |
| | | } |
| | | const grid = { |
| | | left: '3%', |
| | |
| | | const pieTooltip = reactive({ |
| | | trigger: 'item', |
| | | formatter: function (params) { |
| | | // 动态生成提示信息,基于数据项的 name 属性 |
| | | const description = params.name === '本月回款金额' ? '本月回款金额' : '应收款金额'; |
| | | return `${description} ${formatNumber(params.value)}元 ${params.percent}%`; |
| | | }, |
| | |
| | | label: { |
| | | show: true |
| | | }, |
| | | showSymbol: true, // 显示圆点 |
| | | showSymbol: true, |
| | | }, |
| | | ]) |
| | | const tooltipLine = { |
| | |
| | | } |
| | | ]) |
| | | |
| | | // 待办事项 |
| | | const todoList = ref([]) |
| | | const radio1 = ref(1) |
| | | const qualityRange = ref(1) |
| | | |
| | | // 图表引用 |
| | | const barChart = ref(null) |
| | | const lineChart = ref(null) |
| | | const barColors2 = ['#5181DB', '#D369E0', '#F2CA6D', '#60CCA8'] |
| | | |
| | | // 随机颜色生成函数 |
| | | const getRandomColor = () => { |
| | | return '#' + Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0'); |
| | | } |
| | |
| | | getAmountHalfYearNum() |
| | | getProcessList() |
| | | }) |
| | | // 数据统计 |
| | | |
| | | const getBusinessData = () => { |
| | | getBusiness().then((res) => { |
| | | businessInfo.value = { ...res.data } |
| | | }) |
| | | } |
| | | // 合同金额 |
| | | |
| | | const analysisCustomer = () => { |
| | | analysisCustomerContractAmounts().then((res) => { |
| | | sum.value = res.data.sum |
| | | yny.value = res.data.yny |
| | | chain.value = res.data.chain |
| | | // 为每个数据项分配随机颜色 |
| | | materialPieSeries.value[0].data = res.data.item.map(item => ({ |
| | | ...item, |
| | | itemStyle: { color: getRandomColor() } |
| | | })) |
| | | }) |
| | | } |
| | | // 待办事项 |
| | | |
| | | const todoInfoS = () => { |
| | | homeTodos().then((res) => { |
| | | todoList.value = res.data |
| | | }) |
| | | } |
| | | // 获取工序列表 |
| | | |
| | | const getProcessList = () => { |
| | | list().then(res => { |
| | | processOptions.value = res.data.records |
| | |
| | | activeProcessIndex.value = params.dataIndex |
| | | } |
| | | } |
| | | // 应付应收统计 |
| | | |
| | | const statisticsReceivable = () => { |
| | | statisticsReceivablePayable({ type: radio1.value }).then((res) => { |
| | | barSeries.value[0].data = [ |
| | | // { value: res.data.prepayMoney, itemStyle: { color: barColors2[0] } }, |
| | | { value: res.data.payableMoney, itemStyle: { color: barColors2[0] } }, |
| | | // { value: res.data.advanceMoney, itemStyle: { color: barColors2[2] } }, |
| | | { value: res.data.receivableMoney, itemStyle: { color: barColors2[1] } } |
| | | ] |
| | | }) |
| | | } |
| | | // 质检统计 |
| | | |
| | | const qualityStatisticsInfo = () => { |
| | | qualityInspectionStatistics({ type: qualityRange.value }).then((res) => { |
| | | xAxis1.value[0].data = [] |
| | |
| | | qualityStatisticsObject.value.factoryNum = res.data.factoryNum |
| | | }) |
| | | } |
| | | |
| | | const getAmountHalfYearNum = async () => { |
| | | const res = await getAmountHalfYear() |
| | | console.log(res) |
| | | const monthName = [] |
| | | const receiptAmount = [] |
| | | const invoiceAmount = [] |
| | |
| | | receiptAmount.push(item.receiptAmount) |
| | | invoiceAmount.push(item.invoiceAmount) |
| | | }) |
| | | // 正确响应式赋值:创建新的 xAxis 和 series 对象 |
| | | xAxis2.value[0].data = monthName |
| | | xAxis2.value[0].data = monthName.map(item => item.replace(/~/g, '\n~')); |
| | | lineSeries.value = [ |
| | |
| | | ] |
| | | } |
| | | |
| | | // 工序数据生产统计明细(假数据 + 图表) |
| | | const processRange = ref(1) |
| | | const processChartData = ref([]) |
| | | |
| | |
| | | const processYAxis = ref([ |
| | | { |
| | | type: 'category', |
| | | axisTick: { show: false }, |
| | | axisLabel: { color: 'rgba(0,0,0,0.35)', fontSize: 12 }, |
| | | axisLine: { show: false }, |
| | | axisLabel: { color: 'rgba(0,0,0,0.45)' }, |
| | | axisTick: { show: false }, |
| | | data: [], |
| | | }, |
| | | ]) |
| | | |
| | | const processGrid = reactive({ left: 0, right: 100, top: 30, bottom: 20, containLabel: true }) |
| | | |
| | | const processTooltip = reactive({ |
| | | const processTooltip = ref({ |
| | | trigger: 'axis', |
| | | axisPointer: { type: 'shadow' }, |
| | | formatter: (params) => { |
| | | const name = params?.[0]?.name ?? '' |
| | | const list = Array.isArray(params) ? params : [] |
| | | const lines = list |
| | | .map((p) => { |
| | | const colorBox = `<span style="display:inline-block;margin-right:6px;border-radius:2px;width:10px;height:10px;background:${p.color}"></span>` |
| | | return `${colorBox}${p.seriesName} <b style="float:right;">${Number(p.value || 0).toFixed(2)}</b>` |
| | | }) |
| | | .join('<br/>') |
| | | return `<div style="min-width:140px;"><div style="font-weight:700;margin-bottom:6px;">${name}</div>${lines}</div>` |
| | | }, |
| | | }) |
| | | |
| | | const processSeries = computed(() => { |
| | | const input = processChartData.value.map((i) => i.input) |
| | | const scrap = processChartData.value.map((i) => i.scrap) |
| | | const output = processChartData.value.map((i) => i.output) |
| | | const processSeries = ref([ |
| | | { |
| | | name: '投入量', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 16, |
| | | itemStyle: { color: '#2D99FF', borderRadius: [0, 4, 4, 0] }, |
| | | data: [], |
| | | }, |
| | | { |
| | | name: '报废量', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 16, |
| | | itemStyle: { color: '#F2CA6D', borderRadius: [0, 4, 4, 0] }, |
| | | data: [], |
| | | }, |
| | | { |
| | | name: '产出量', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 16, |
| | | itemStyle: { color: '#5EE9C0', borderRadius: [0, 4, 4, 0] }, |
| | | data: [], |
| | | }, |
| | | ]) |
| | | |
| | | return [ |
| | | { |
| | | name: '投入量', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 22, |
| | | itemStyle: { color: '#1E5BFF', borderRadius: [6, 0, 0, 6] }, |
| | | data: input, |
| | | }, |
| | | { |
| | | name: '报废量', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 22, |
| | | itemStyle: { color: '#F7B500' }, |
| | | data: scrap, |
| | | }, |
| | | { |
| | | name: '产出量', |
| | | type: 'bar', |
| | | stack: 'total', |
| | | barWidth: 22, |
| | | itemStyle: { color: '#19C6C6', borderRadius: [0, 6, 6, 0] }, |
| | | data: output, |
| | | }, |
| | | ] |
| | | const processGrid = ref({ |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | top: '3%', |
| | | containLabel: true, |
| | | }) |
| | | |
| | | const processAside = computed(() => { |
| | | const list = processChartData.value |
| | | const item = list[activeProcessIndex.value] || {} |
| | | const idx = activeProcessIndex.value |
| | | const item = processChartData.value[idx] || {} |
| | | return { |
| | | processName: item.name || '暂无数据', |
| | | totalInput: item.input || 0, |
| | | totalScrap: item.scrap || 0, |
| | | totalOutput: item.output || 0, |
| | | processName: item.processName || '-', |
| | | totalInput: item.inputNum || 0, |
| | | totalScrap: item.scrapNum || 0, |
| | | totalOutput: item.outputNum || 0, |
| | | } |
| | | }) |
| | | |
| | | const formatAmount = (n) => { |
| | | const num = Number(n || 0) |
| | | return num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) |
| | | const refreshProcessStats = async () => { |
| | | const params = { type: processRange.value } |
| | | if (selectedProcessIds.value.length > 0) { |
| | | params.processIds = selectedProcessIds.value.join(',') |
| | | } |
| | | const res = await processDataProductionStatistics(params) |
| | | const list = res.data || [] |
| | | processChartData.value = list |
| | | processYAxis.value[0].data = list.map(i => i.processName) |
| | | processSeries.value[0].data = list.map(i => i.inputNum) |
| | | processSeries.value[1].data = list.map(i => i.scrapNum) |
| | | processSeries.value[2].data = list.map(i => i.outputNum) |
| | | activeProcessIndex.value = 0 |
| | | } |
| | | |
| | | const refreshProcessStats = () => { |
| | | processDataProductionStatistics({ |
| | | type: processRange.value, |
| | | processIds: selectedProcessIds.value.length > 0 ? selectedProcessIds.value.join(',') : null |
| | | }).then(res => { |
| | | processChartData.value = res.data.map(item => ({ |
| | | name: item.processName, |
| | | input: item.totalInput, |
| | | scrap: item.totalScrap, |
| | | output: item.totalOutput |
| | | })) |
| | | processYAxis.value[0].data = processChartData.value.map((i) => i.name) |
| | | activeProcessIndex.value = 0 |
| | | }) |
| | | const formatAmount = (num) => { |
| | | if (!num && num !== 0) return '-' |
| | | return Number(num).toLocaleString() |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getBusinessData() |
| | | analysisCustomer() |
| | | todoInfoS() |
| | | statisticsReceivable() |
| | | qualityStatisticsInfo() |
| | | getAmountHalfYearNum() |
| | | refreshProcessStats() |
| | | }) |
| | | const formatNumber = (num) => { |
| | | if (!num) return '0' |
| | | return num.toLocaleString() |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | <style lang="scss" scoped> |
| | | .dashboard { |
| | | min-height: 100vh; |
| | | padding: 20px; |
| | | box-sizing: border-box; |
| | | background: #f5f7fa; |
| | | } |
| | | |
| | | .dashboard-top { |
| | | display: flex; |
| | | display: grid; |
| | | grid-template-columns: 2fr 1fr; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | align-items: flex-start; |
| | | justify-content: space-evenly; |
| | | } |
| | | |
| | | .company-info { |
| | | padding: 0; |
| | | overflow: hidden; |
| | | border-radius: 12px; |
| | | background: #fff; |
| | | height: 100%; |
| | | } |
| | | |
| | | .welcome-banner { |
| | | padding: 10px 10px; |
| | | background: linear-gradient(135deg, rgba(229, 240, 255, 0.9), rgba(214, 232, 255, 0.7), rgba(207, 236, 255, 0.9)); |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 18px; |
| | | font-weight: 700; |
| | | color: #222; |
| | | line-height: 1.3; |
| | | } |
| | | |
| | | .welcome-user { |
| | | margin-right: 6px; |
| | | } |
| | | |
| | | .welcome-time { |
| | | margin-top: 10px; |
| | | font-size: 16px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | } |
| | | |
| | | .user-card { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | padding: 18px 22px; |
| | | } |
| | | |
| | | .user-card-main { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 5px; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .user-name { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #111; |
| | | letter-spacing: 1px; |
| | | } |
| | | |
| | | .user-role { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 20px; |
| | | padding: 5px 10px; |
| | | background: rgba(245, 246, 248, 1); |
| | | color: #333; |
| | | width: fit-content; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .user-meta { |
| | | font-size: 12px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .user-meta .sep { |
| | | margin: 0 10px; |
| | | color: rgba(0, 0, 0, 0.25); |
| | | } |
| | | |
| | | .avatar { |
| | | width: 90px; |
| | | height: 90px; |
| | | border-radius: 50%; |
| | | object-fit: cover; |
| | | flex: 0 0 auto; |
| | | } |
| | | |
| | | .data-cards { |
| | | width: 50%; |
| | | display: flex; |
| | | gap: 16px; |
| | | justify-content: flex-start; |
| | | background: #ffffff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .data-title { |
| | | font-weight: 700; |
| | | font-size: 26px; |
| | | color: #FFFFFF; |
| | | } |
| | | |
| | | .data-num { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .data-card { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 14px 10px 10px 10px; |
| | | min-width: 160px; |
| | | box-shadow: 0 2px 8px #eee; |
| | | display: flex; |
| | | flex-direction: column; |
| | | width: 32%; |
| | | height: 140px; |
| | | } |
| | | |
| | | .data-card.sales { |
| | | background-image: url("../assets/images/xioashoushuju.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | .data-card.purchase { |
| | | background-image: url("../assets/images/caigou.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | .data-card.inventory { |
| | | background-image: url("../assets/images/kucun.png"); |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | |
| | | .data-desc { |
| | | font-weight: 500; |
| | | font-size: 13px; |
| | | color: #FFFFFF; |
| | | } |
| | | |
| | | .data-value { |
| | | font-size: 18px; |
| | | font-weight: 500; |
| | | margin: 10px 0; |
| | | color: #FFFFFF; |
| | | } |
| | | |
| | | .top-left { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | height: 180px; |
| | | width: 20%; |
| | | } |
| | | |
| | | .company-info { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .welcome-banner { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | padding-bottom: 16px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 18px; |
| | | color: #303133; |
| | | |
| | | .welcome-user { |
| | | font-weight: 600; |
| | | color: var(--el-color-primary); |
| | | } |
| | | } |
| | | |
| | | .welcome-time { |
| | | font-size: 13px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .user-card { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .avatar { |
| | | width: 64px; |
| | | height: 64px; |
| | | border-radius: 50%; |
| | | object-fit: cover; |
| | | border: 3px solid var(--el-color-primary-light-8); |
| | | } |
| | | |
| | | .user-card-main { |
| | | .user-name { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .user-role { |
| | | font-size: 13px; |
| | | color: var(--el-color-primary); |
| | | background: var(--el-color-primary-light-9); |
| | | padding: 2px 10px; |
| | | border-radius: 4px; |
| | | display: inline-block; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .user-meta { |
| | | font-size: 13px; |
| | | color: #606266; |
| | | |
| | | .sep { |
| | | margin: 0 8px; |
| | | color: #dcdfe6; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .data-cards { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 16px; |
| | | } |
| | | |
| | | .data-card { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 16px; |
| | | |
| | | .data-title { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .data-num { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .data-desc { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .data-value { |
| | | font-size: 20px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | .todo-panel { |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | height: 180px; |
| | | width: 30%; |
| | | } |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 16px; |
| | | position: relative; |
| | | padding-left: 12px; |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 4px; |
| | | height: 16px; |
| | | background: var(--el-color-primary); |
| | | border-radius: 2px; |
| | | } |
| | | } |
| | | |
| | | .todo-list { |
| | | height: 100px; |
| | | list-style: none; |
| | | padding: 0; |
| | | margin: 0; |
| | | font-size: 15px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .todo-list li { |
| | | border-radius: 8px; |
| | | margin-bottom: 12px; |
| | | padding: 8px 20px; |
| | | height: 74px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | background: rgba(225, 227, 250, 0.62); |
| | | } |
| | | li { |
| | | padding: 12px 0; |
| | | border-bottom: 1px solid #ebeef5; |
| | | |
| | | .todo-title { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | position: relative; |
| | | } |
| | | |
| | | .todo-title::before { |
| | | content: ''; |
| | | /* 必需,表示这里有一个内容 */ |
| | | position: absolute; |
| | | left: -10px; |
| | | /* 定位到左侧 */ |
| | | top: 50%; |
| | | /* 垂直居中 */ |
| | | transform: translateY(-50%); |
| | | /* 微调垂直居中 */ |
| | | width: 6px; |
| | | /* 圆的直径 */ |
| | | height: 6px; |
| | | /* 圆的直径 */ |
| | | background: #498CEB; |
| | | border-radius: 50%; |
| | | /* 让其变成圆形 */ |
| | | } |
| | | |
| | | .todo-division { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | } |
| | | |
| | | .todo-time { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #000000; |
| | | } |
| | | |
| | | .todo-meta { |
| | | color: #888; |
| | | font-size: 13px; |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .dashboard-row { |
| | | display: flex; |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | } |
| | |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | padding: 20px; |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .section-title { |
| | | position: relative; |
| | | font-size: 18px; |
| | | color: #333; |
| | | padding-left: 10px; |
| | | margin-bottom: 10px; |
| | | font-weight: 700; |
| | | .contract-panel { |
| | | grid-column: 1 / -1; |
| | | } |
| | | |
| | | .section-title::before { |
| | | position: absolute; |
| | | left: 0; |
| | | top: 4px; |
| | | content: ''; |
| | | width: 4px; |
| | | height: 18px; |
| | | background-color: #002FA7; |
| | | border-radius: 2px; |
| | | .contract-summary { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .contract-info { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20px; |
| | | height: 90px; |
| | | background: rgba(245, 245, 245, 0.59); |
| | | width: 100%; |
| | | border-radius: 10px; |
| | | padding: 10px 30px; |
| | | } |
| | | |
| | | .contract-summary { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 30px; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .contract-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | .contract-name { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .contract-meta { |
| | | .main-amount { |
| | | font-size: 28px; |
| | | font-weight: 700; |
| | | color: #303133; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .up { |
| | | color: #67c23a; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .contract-name { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #050505; |
| | | } |
| | | |
| | | .contract-meta { |
| | | .contract-chart-wrapper { |
| | | display: flex; |
| | | align-items: center; |
| | | width: 100%; |
| | | gap: 80px; |
| | | gap: 40px; |
| | | justify-content: center; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .main-amount { |
| | | font-size: 24px; |
| | | color: rgba(51, 50, 50, 0.85); |
| | | } |
| | | |
| | | .up { |
| | | color: #e57373; |
| | | .chart-container { |
| | | width: 320px; |
| | | height: 280px; |
| | | } |
| | | |
| | | .contract-list { |
| | | margin-top: 16px; |
| | | font-size: 14px; |
| | | color: #666; |
| | | list-style: none; |
| | | padding: 0; |
| | | height: 190px; |
| | | overflow-y: auto; |
| | | width: 460px; |
| | | } |
| | | margin: 0; |
| | | min-width: 300px; |
| | | |
| | | .line { |
| | | position: relative; |
| | | width: 230px; |
| | | } |
| | | li { |
| | | margin-bottom: 12px; |
| | | |
| | | .line::after { |
| | | content: ''; |
| | | position: absolute; |
| | | right: 2px; |
| | | top: 0; |
| | | bottom: 0; |
| | | width: 1px; |
| | | background-color: #C9C5C5; |
| | | border-radius: 2px; |
| | | } |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .contract-list li { |
| | | margin-top: 10px; |
| | | } |
| | | .contract-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | padding: 10px 16px; |
| | | background: #f5f7fa; |
| | | border-radius: 8px; |
| | | |
| | | .quality-cards { |
| | | display: flex; |
| | | gap: 12px; |
| | | margin-bottom: 12px; |
| | | } |
| | | .contract-dot { |
| | | width: 10px; |
| | | height: 10px; |
| | | border-radius: 50%; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .quality-card { |
| | | border-radius: 8px; |
| | | padding: 15px 10px 10px 50px; |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: rgba(0, 0, 0, 0.67); |
| | | width: 236px; |
| | | height: 49px; |
| | | background-size: cover; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | } |
| | | .contract-name { |
| | | flex: 1; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | } |
| | | |
| | | .quality-card.one { |
| | | background-image: url("../assets/images/yuancailiao.png"); |
| | | } |
| | | .contract-rate { |
| | | font-size: 13px; |
| | | color: #909399; |
| | | min-width: 50px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .quality-card.two { |
| | | background-image: url("../assets/images/guocheng.png"); |
| | | } |
| | | |
| | | .quality-card.three { |
| | | background-image: url("../assets/images/chuchang.png"); |
| | | |
| | | } |
| | | |
| | | .quality-card span { |
| | | color: #4fc3f7; |
| | | font-weight: bold; |
| | | margin-left: 6px; |
| | | } |
| | | |
| | | .chart { |
| | | width: 100%; |
| | | height: 220px; |
| | | margin-top: 10px; |
| | | .contract-value { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | min-width: 100px; |
| | | text-align: right; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .process-panel { |
| | | padding-bottom: 10px; |
| | | grid-column: 1 / -1; |
| | | } |
| | | |
| | | .process-panel__header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .process-panel__body { |
| | | display: flex; |
| | | gap: 24px; |
| | | align-items: stretch; |
| | | margin-top: 10px; |
| | | display: grid; |
| | | grid-template-columns: 1fr 280px; |
| | | gap: 20px; |
| | | height: 300px; |
| | | } |
| | | |
| | | .process-panel__chart { |
| | | flex: 1; |
| | | min-width: 0; |
| | | padding: 6px 0; |
| | | height: 100%; |
| | | } |
| | | |
| | | .process-panel__aside { |
| | | width: 260px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | |
| | | |
| | | .process-legend { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | align-items: flex-start; |
| | | padding: 8px 6px; |
| | | gap: 16px; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .process-legend__item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | gap: 6px; |
| | | font-size: 13px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | } |
| | | color: #606266; |
| | | |
| | | .dot { |
| | | width: 10px; |
| | | height: 10px; |
| | | border-radius: 2px; |
| | | display: inline-block; |
| | | } |
| | | .dot { |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | |
| | | .dot-blue { |
| | | background: #1E5BFF; |
| | | } |
| | | &.dot-blue { |
| | | background: #2D99FF; |
| | | } |
| | | |
| | | .dot-yellow { |
| | | background: #F7B500; |
| | | } |
| | | &.dot-yellow { |
| | | background: #F2CA6D; |
| | | } |
| | | |
| | | .dot-teal { |
| | | background: #19C6C6; |
| | | &.dot-teal { |
| | | background: #5EE9C0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .process-card { |
| | | background: rgba(245, 247, 250, 0.9); |
| | | border-radius: 10px; |
| | | padding: 16px 16px; |
| | | background: #f5f7fa; |
| | | border-radius: 8px; |
| | | padding: 12px 16px; |
| | | |
| | | &--name { |
| | | font-weight: 600; |
| | | color: #303133; |
| | | background: var(--el-color-primary-light-9); |
| | | } |
| | | |
| | | &__label { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | &__value { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | .process-card--name { |
| | | background: rgba(235, 242, 255, 1); |
| | | color: #1E5BFF; |
| | | font-weight: 800; |
| | | font-size: 14px; |
| | | .quality-cards { |
| | | display: flex; |
| | | gap: 12px; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .process-card__label { |
| | | .quality-card { |
| | | flex: 1; |
| | | background: #f5f7fa; |
| | | border-radius: 8px; |
| | | padding: 12px; |
| | | font-size: 13px; |
| | | color: rgba(0, 0, 0, 0.55); |
| | | margin-bottom: 10px; |
| | | } |
| | | color: #606266; |
| | | |
| | | .process-card__value { |
| | | font-size: 24px; |
| | | font-weight: 800; |
| | | color: rgba(0, 0, 0, 0.8); |
| | | } |
| | | |
| | | .process-card__value .unit { |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | color: rgba(0, 0, 0, 0.45); |
| | | margin-left: 6px; |
| | | } |
| | | |
| | | @media (max-width: 1200px) { |
| | | .process-panel__body { |
| | | flex-direction: column; |
| | | span { |
| | | display: block; |
| | | font-size: 20px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-top: 4px; |
| | | } |
| | | |
| | | .process-panel__aside { |
| | | width: 100%; |
| | | flex-direction: row; |
| | | flex-wrap: wrap; |
| | | &.one { |
| | | background: #e6f7ff; |
| | | color: #1890ff; |
| | | |
| | | span { |
| | | color: #1890ff; |
| | | } |
| | | } |
| | | |
| | | .process-card { |
| | | flex: 1; |
| | | min-width: 220px; |
| | | &.two { |
| | | background: #f6ffed; |
| | | color: #52c41a; |
| | | |
| | | span { |
| | | color: #52c41a; |
| | | } |
| | | } |
| | | |
| | | &.three { |
| | | background: #fff7e6; |
| | | color: #fa8c16; |
| | | |
| | | span { |
| | | color: #fa8c16; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .process-selection-wrapper { |
| | | max-height: 400px; |
| | | overflow-y: auto; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .process-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); |
| | | grid-template-columns: repeat(2, 1fr); |
| | | gap: 12px; |
| | | } |
| | | |
| | | :deep(.el-checkbox.is-bordered) { |
| | | margin-left: 0 !important; |
| | | width: 100%; |
| | | } |
| | | </style> |
| | | </style> |