123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- <template>
- <div class="page-container row-container">
- <section class="list-part-container" style="flex: 2">
- <!-- 搜索区 -->
- <el-form
- class="list-search-container"
- :model="queryParams"
- ref="queryRef"
- :inline="true"
- >
- <el-form-item label="工艺文件制作错误次数统计"> </el-form-item>
- <el-form-item>
- <el-button
- v-if="tabname == 'second'"
- type="success"
- @click="handleAdd"
- v-hasPermi="['business:processErrorSatistics:add']"
- >添加</el-button
- >
- <el-button v-if="tabname == 'second'" type="warning" @click="getList"
- >刷新</el-button
- >
- </el-form-item>
- <el-form-item label="年份:" v-if="tabname == 'second'">
- <el-date-picker
- v-model="queryParams.startYear"
- type="year"
- value-format="YYYY"
- :editable="false"
- :clearable="true"
- placeholder="请选择开始年份"
- style="width: 150px"
- />
- <span>To</span>
- <el-date-picker
- v-model="queryParams.endYear"
- type="year"
- value-format="YYYY"
- :editable="false"
- :clearable="true"
- placeholder="请选择结束年份"
- style="width: 150px"
- />
- </el-form-item>
- <el-form-item v-if="tabname == 'second'">
- <el-button type="info" icon="Search" @click="handleQuery"
- >搜索</el-button
- >
- </el-form-item>
- </el-form>
- <!-- 列表区 -->
- <el-tabs
- v-model="activeName"
- class="demo-tabs"
- @tab-click="handleTabClick"
- height="100%"
- style="margin-left: 10px; margin-right: 10px"
- >
- <el-tab-pane label="图表" name="first">
- <div
- style="
- position: relative;
- width: 100%;
- height: 100%;
- overflow-x: auto;
- margin-left: 20px;
- "
- >
- <div
- ref="echartDom"
- id="echartDom"
- :style="{ height: chartHeight, width: chartWidth }"
- />
- </div>
- </el-tab-pane>
- <el-tab-pane label="表格" name="second">
- <el-table
- ref="ErrorStatisticsTable"
- v-loading="loading"
- :data="errorStatisticsList"
- row-key="id"
- height="100%"
- border
- highlight-current-row
- >
- <el-table-column
- label="序号"
- type="index"
- width="50"
- align="center"
- ></el-table-column>
- <el-table-column label="年份" width="110" align="center">
- <template #default="scope">
- <el-date-picker
- v-if="scope.row.editStatus"
- v-model="scope.row.year"
- type="year"
- :clearable="false"
- placeholder="选择年"
- style="width: 100%"
- @change="(arg) => handleRowYearChange(arg, scope.row)"
- />
- <div v-else>{{ scope.row.year }}</div>
- </template>
- </el-table-column>
- <el-table-column label="季度" width="100" align="center">
- <template #default="scope">
- <el-select
- v-model="scope.row.quarter"
- v-if="scope.row.editStatus"
- >
- <el-option label="1" value="1" />
- <el-option label="2" value="2" />
- <el-option label="3" value="3" />
- <el-option label="4" value="4" />
- </el-select>
- <div v-else>{{ scope.row.quarter }}</div>
- </template>
- </el-table-column>
- <el-table-column label="日期" width="120" align="center">
- <template #default="scope">
- <el-date-picker
- v-if="scope.row.editStatus"
- v-model="scope.row.date"
- type="date"
- format="YYYY.M.D"
- :clearable="false"
- value-format="YYYY-MM-DD"
- placeholder="选择日期"
- style="width: 100%"
- />
- <div v-else>{{ scope.row.date }}</div>
- </template>
- </el-table-column>
- <el-table-column label="客户" align="center" width="150">
- <template #default="scope">
- <el-input
- v-model="scope.row.companyAlias"
- placeholder="请选择客户"
- readonly
- v-if="scope.row.editStatus"
- style="width: 120px; margin-left: 8px"
- >
- <template #append>
- <el-button
- icon="Search"
- @click="handleSelectComplany(scope.row, scope.$index)"
- /> </template
- ></el-input>
- <div v-else>{{ scope.row.companyAlias }}</div>
- </template>
- </el-table-column>
- <el-table-column label="规格" width="120" align="center">
- <template #default="scope">
- <div>{{ scope.row.specification }}</div>
- </template>
- </el-table-column>
- <el-table-column label="图号" width="120" align="center">
- <template #default="scope">
- <div>{{ scope.row.drawingNumber }}</div>
- </template>
- </el-table-column>
- <el-table-column label="类型" width="160" align="center">
- <template #default="scope">
- <el-select
- v-model="scope.row.type"
- placeholder="请选择客户类型"
- style="width: 160px"
- v-if="scope.row.editStatus"
- >
- <el-option
- v-for="dict in process_error_company_type"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- ></el-option>
- </el-select>
- <div v-else>
- <dict-tag
- :options="process_error_company_type"
- :value="scope.row.type"
- />
- </div>
- </template>
- </el-table-column>
- <el-table-column label="投诉内容" align="center">
- <template #default="scope">
- <el-input
- v-if="scope.row.editStatus"
- placeholder="请输入投诉内容"
- v-model.trim="scope.row.complaintContent"
- clearable
- />
- <div v-else>{{ scope.row.complaintContent }}</div>
- </template>
- </el-table-column>
- <el-table-column label="工艺错误次数" prop="errorQuantity" width="120" align="center">
- <template #default="scope">
- <el-input-number
- v-if="scope.row.editStatus"
- v-model="scope.row.errorQuantity"
- controls-position="right"
- style="width: 100px"
- @input="(val) => {handleUpdateErrorQuantity(val, scope.row,scope.$index)}"
- :min="0"
- />
- <div v-else>{{ scope.row.errorQuantity }}</div>
- </template>
- </el-table-column>
- <el-table-column label="季度目标(≤)" width="120" prop="quarterTarget" align="center">
- <template #default="scope">
- <el-input-number
- v-if="scope.row.editStatus"
- v-model="scope.row.quarterTarget"
- controls-position="right"
- style="width: 100px"
- @input="(val) => {handleUpdateQuarterTarget(val, scope.row,scope.$index)}"
- :min="0"
- />
- <div v-else>{{ scope.row.quarterTarget }}</div>
- </template>
- </el-table-column>
- <el-table-column label="目标完成情况" width="100" align="center" >
- <template #default="scope">
- <dict-tag :options="process_error_status" :value="scope.row.status" />
- </template>
- </el-table-column>
- <el-table-column label="操作" width="160" align="center">
- <template #default="scope">
- <el-button
- v-if="scope.row.editStatus"
- type="success"
- @click="handleSave(scope.row)"
- >保存</el-button
- >
- <el-button
- v-else
- type="primary"
- @click="() => (scope.row.editStatus = true)"
- v-hasPermi="['business:processErrorSatistics:edit']"
- >编辑</el-button
- >
- <el-button
- v-if="scope.row.editStatus"
- type="danger"
- @click="handleCancel(scope.row, scope.$index)"
- >取消</el-button
- >
- <el-button v-else type="danger" @click="handleDel(scope.row)"
- v-hasPermi="['business:processErrorSatistics:delete']"
- >删除</el-button
- >
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- </el-tabs>
- </section>
- <company-dialog
- ref="companyDialogRef"
- :single-selected="handleSingleSelected"
- />
- </div>
- </template>
- <script setup name="processErrorStatistics">
- import { listProcessErrorStatistics,addProcessErrorStatistics,updateProcessErrorStatistics,delProcessErrorStatistics } from '@/api/business/processErrorStatistics'
- import { ref, onMounted, reactive, computed } from 'vue'
- import companyDialog from './DialogCompany.vue'
- import * as echarts from 'echarts'
- import { markRaw } from "vue"
- const { proxy } = getCurrentInstance();
- const echartInstance = ref(null)
- const echartDom = ref(null)
- const tabname = ref('first')
- const currentIndex = ref(null)
- const chartHeight = ref(`${window.innerHeight - 200}px`)
- const chartWidth = ref(`${window.innerWidth - 200}px`)
- /** 字典 */
- const { process_error_company_type } = proxy.useDict("process_error_company_type");
- const { process_error_status } = proxy.useDict("process_error_status");
- const data = reactive({
- queryParams: {
- startYear:null,
- endYear:null
- }
- })
- const loading = ref(false)
- const errorStatisticsList = ref([])
- const activeName = ref('first')
- const { queryParams } = toRefs(data)
- const getWindowInfo = () => {
- initGrophSize();
- };
- const debounce = (fn, delay) => {
- let timer;
- return function () {
- if (timer) {
- clearTimeout(timer);
- }
- timer = setTimeout(() => {
- fn();
- }, delay);
- }
- };
- const cancalDebounce = debounce(getWindowInfo, 500);
- onUnmounted(() => {
- //移除监听事件
- window.removeEventListener('resize', cancalDebounce);
- })
- //打开客户弹窗
- function handleSelectComplany(row,index) {
- currentIndex.value = index
- proxy.$refs.companyDialogRef.open();
- }
- //input事件
- function handleUpdateErrorQuantity(val,row,index) {
- const errorQuantity = val
- if(row.quarterTarget !=null && errorQuantity !=null) {
- if(row.quarterTarget >= errorQuantity) {
- errorStatisticsList.value[index].status = 0
- } else {
- errorStatisticsList.value[index].status = 1
- }
- }
- }
- function handleUpdateQuarterTarget(val,row,index) {
- const quarterTarget = val
- if(quarterTarget !=null && row.errorQuantity !=null) {
- if(quarterTarget >= row.errorQuantity) {
- errorStatisticsList.value[index].status = 0
- }else {
- errorStatisticsList.value[index].status = 1
- }
- }
- }
- //搜索事件
- function handleQuery() {
- getList()
- }
- //单选带回
- function handleSingleSelected(selection) {
- errorStatisticsList.value[currentIndex.value].companyAlias = selection.companyAlias
- errorStatisticsList.value[currentIndex.value].specification = selection.specification
- errorStatisticsList.value[currentIndex.value].drawingNumber = selection.drawingNumber
- errorStatisticsList.value[currentIndex.value].productionPlanDetailId = selection.id
- }
- function initGrophSize() {
- chartHeight.value = `${window.innerHeight - 200}px`
- chartWidth.value = errorStatisticsList.value.length * 200 + 'px'
- console.log(chartHeight.value, chartWidth.value)
- echartInstance.value.resize()
- }
- function handleDel(row) {
- proxy.$modal
- .confirm("确认删除吗?")
- .then(function () {
- delProcessErrorStatistics(row.id).then(res => {
- if (res.code === 200) {
- proxy.$modal.msgSuccess('删除成功')
- getList()
- }
- })
- })
- }
- function handleCancel(row,index) {
- errorStatisticsList.value[index].editStatus = false
- getList()
- }
- function handleSave(row) {
- console.log(row)
- //验证
- let flag = true
- if(row.year ==null) {
- flag = false
- proxy.$modal.msgError('年份不能为空')
- }
- if(row.quarter ==null) {
- flag = false
- proxy.$modal.msgError('季度不能为空')
- }
- if(row.date ==null) {
- flag = false
- proxy.$modal.msgError('日期不能为空')
- }
- if(row.companyAlias ==null) {
- flag = false
- proxy.$modal.msgError('客户不能为空')
- }
- if(row.errorQuantity ==null) {
- flag = false
- proxy.$modal.msgError('工艺错误次数不能为空')
- }
- if(row.quarterTarget ==null) {
- flag = false
- proxy.$modal.msgError('季度目标不能为空')
- }
- if(row.type ==null) {
- flag = false
- proxy.$modal.msgError('类型不能为空')
- }
- if(flag) {
- if (row.id != null) {
- updateProcessErrorStatistics(row).then(res => {
- if (res.code === 200) {
- proxy.$modal.msgSuccess('修改成功')
- getList()
- }
- })
- } else {
- addProcessErrorStatistics(row).then(res => {
- if (res.code === 200) {
- proxy.$modal.msgSuccess('添加成功')
- getList()
- }
- })
- }
- }
- }
- // 转换季度字符串为数字的映射
- const quarterToNumberMap = { '1': 1, '2': 2, '3': 3, '4': 4 };
- // 去重、转换和排序的方法
- function processMonths(list) {
- // 排序逻辑
- list.sort((a, b) => {
- const yearDiff = a.year - b.year; // 年份降序
- if (yearDiff !== 0) return yearDiff;
- // 季度升序
- const quarterDiff = quarterToNumberMap[a.quarter] - quarterToNumberMap[b.quarter];
- return quarterDiff;
- });
- return list
- };
- //获得日期数据
- function getYearData(data) {
- let yearData = []
- for(let i = 0; i < data.length; i++){
- let errorList = errorStatisticsList.value.filter(item => {
- return item.year == data[i].year +"" && data[i].quarter == item.quarter
- })
- yearData.push({yearQuarter:data[i].year + '年第' + data[i].quarter + '季度',
- totalErrorQuantity:errorList.reduce((acc, item) => acc + parseInt(item.errorQuantity), 0),
- totalQuarterTarget:errorList.reduce((acc, item) => acc + parseInt(item.quarterTarget), 0),
- })
- }
- return yearData
- }
- function initChartData() {
- //横坐标年份季度
- let list = processMonths(errorStatisticsList.value.map(item => ({
- year: parseInt(item.year),
- quarter: item.quarter
- })))
- let yearLabel = Array.from(new Set(list.map(item => item.year + '年第' + item.quarter + '季度')));
- const uniqueList = Array.from(new Set(list.map(item =>
- JSON.stringify({ year: item.year, quarter: item.quarter })
- )));
- // 去重后的数组包含字符串,需要转换回对象
- const dedupedObjects = uniqueList.map(str => JSON.parse(str));
- //展示数据
- let yearData = getYearData(dedupedObjects)
- //y轴对应数据
- let toData = yearData.map(e => e.totalErrorQuantity)
- updateCompleteChart(yearData, yearLabel, toData)
- }
- function updateCompleteChart(yearData, yearLabel, toData) {
- echartInstance.value.setOption({
- title: { text: '工艺文件制作错误次数统计' },
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- },
- formatter: function (params) {
- const data = yearData.find(e => e.yearQuarter == params[0].axisValue)
- return `${params[0].axisValue}:<br/>
- 本季度工艺错误次数${data.totalErrorQuantity};<br/>
- 本季度目标${data.totalQuarterTarget};<br/>
- `
- }
- },
- xAxis: {
- type: 'category',
- data: yearLabel
- },
- yAxis: {
- type: 'value'
- },
- dataset: {
- // 用 dimensions 指定了维度的顺序。直角坐标系中,如果 X 轴 type 为 category,
- // 默认把第一个维度映射到 X 轴上,后面维度映射到 Y 轴上。
- // 如果不指定 dimensions,也可以通过指定 series.encode
- // 完成映射,参见后文。
- dimensions: ['month', 'ratio'],
- source: yearData
- },
- series: [{
- name: '工艺文件制作错误次数',
- type: 'line',
- data: toData
- }]
- });
- // echartInstance.value.on('click', function (params) {
- // console.log(params)
- // }
- // )
- }
- function getList() {
- listProcessErrorStatistics(queryParams.value).then(res => {
- if (res.code === 200) {
- res.rows.forEach(item => {
- item.errorQuantity = parseInt(item.errorQuantity)
- item.quarterTarget = parseInt(item.quarterTarget)
- })
- errorStatisticsList.value = res.rows.map(v => ({ ...v, editStatus: false }))
- initGrophSize()
- initChartData();
- // updateCompleteChart(monthlyData, displayMonths, selectedYear, currentYear);
- }
- })
- }
- function handleTabClick(arg) {
- tabname.value = arg.props.name
- getList()
- }
- function handleAdd() {
- errorStatisticsList.value.unshift({year:null,quarter:null,date:null,companyAlias:null,specification:null,drawingNumber:null,
- type:null,complaintContent:null,errorQuantity:0,quarterTarget:null,status:null, editStatus: true })
- }
- function handleRowYearChange(arg, row) {
- row.year = proxy.moment(arg).format('YYYY')
- }
- function initChart() {
- echartInstance.value = markRaw(echarts.init(echartDom.value));
- }
- onMounted(() => {
- initChart();
- getList();
- });
- </script>
- <style lang="scss">
- .demo-tabs {
- height: 100%;
- display: flex;
- flex-direction: column;
- .el-tabs__content {
- height: 100%;
- #pane-first {
- height: 100%;
- }
- #pane-second {
- height: 100%;
- position: relative;
- }
- }
- }
- </style>
|