销售月评登记批量导入

This commit is contained in:
wuteng 2025-07-29 15:17:13 +08:00
parent 55bc334319
commit e335847635
6 changed files with 356 additions and 6 deletions

Binary file not shown.

View File

@ -77,3 +77,25 @@ export function excelDateToJSDate(excelDate) {
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
/**
* 获取上个月的年月 格式 yyyy-mm
*/
export function getLastMonthYearMonth() {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth();
// 计算上一个月的年月
let lastMonth, lastYear;
if (month === 0) {
// 如果是1月,上一个月是去年12月
lastMonth = 11;
lastYear = year - 1;
} else {
lastMonth = month - 1;
lastYear = year;
}
// 格式化为 YYYY-MM
return `${lastYear}-${String(lastMonth + 1).padStart(2, "0")}`;
}

View File

@ -41,7 +41,6 @@ data() {
},
watch: {
value(newVal) {
console.log('newVal---',newVal)
this.svalue = newVal;
},
svalue(newVal, oldVal) {

View File

@ -22,7 +22,7 @@
</SearchForm>
<XdTable slot="pageContent" slot-scope="slotProps" :height="(slotProps.contentHeight) + 'px'" ref="refTable"
v-loading="loading" border size="mini" :data="list" storageName="emisUser_main" :showSearch.sync="showSearch"
v-loading="loading" border size="mini" :data="list" :showSearch.sync="showSearch"
:total="total" highlight-current-row @queryTable="getList" :queryParams="queryParams"
@selection-change="handleSelectionChange" @sort-change="handleSortChange">

View File

@ -0,0 +1,328 @@
<template>
<XdPageContainer class="app-container">
<div slot="pageHeader"></div>
<XdTable slot="pageContent" slot-scope="slotProps" :height="(slotProps.contentHeight) + 'px'"
storageName="batchWaybillRecord_main" ref="multipleTable" :row-class-name="tableRowClassName"
v-loading="loading" border size="mini" :data="emisQuotePriceList" :showSearch.sync="showSearch"
:queryParams="queryParams" :total="total" @queryTable="getList" @selection-change="handleSelectionChange"
@sort-change="handleSortChange">
<div slot="toolbar">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button plain class="filter-item" size="mini" type="primary" icon="el-icon-upload2"
@click="handleBatchImport">选择文件</el-button>
<el-link type="primary" style="line-height: 28px;font-size:13px;color:blue"
href="/static/tpl/imp_sales_monthly_review.xlsx">下载导入Excel模板</el-link>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain size="mini" @click="handleRealUploadAll">批量新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete">删除</el-button>
</el-col>
</el-row>
</div>
<el-table-column type="selection" width="55" align="center" />
<el-table-column :label="$t('状态')" align="center" prop="uploadStatus" min-width="80"
:show-overflow-tooltip="true">
<template slot-scope="scope">
<el-tag v-if="scope.row.uploadStatus == 1" type="success">下单成功</el-tag>
<el-tag v-if="scope.row.uploadStatus == 0" type="info">待下单</el-tag>
<el-tag v-if="scope.row.uploadStatus == -1" type="danger">下单异常</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('异常信息')" align="center" prop="errorInfo" min-width="300"
:show-overflow-tooltip="true">
<template slot-scope="scope">
<span v-if="scope.row.uploadStatus == -1" style="color:red">{{ scope.row.errorInfo }}</span>
<span v-if="scope.row.uploadStatus == 1">下单成功</span>
<span v-if="scope.row.uploadStatus == 0">待下单</span>
</template>
</el-table-column>
<el-table-column label="员工姓名" align="center" prop="employeeName" width="100">
</el-table-column>
<el-table-column label="所属部门" align="center" prop="department" width="100" />
<el-table-column label="入职日期" align="center" prop="entryDate" width="100" />
<el-table-column label="岗位" align="center" prop="position" width="100" />
<el-table-column label="考核月份" align="center" prop="reviewMonth" width="100" />
<el-table-column label="考核分数" align="center" prop="score" width="100" />
<el-table-column label="备注" align="center" prop="remark" width="100">
</el-table-column>
</XdTable>
<el-dialog title="上传文件" :visible.sync="openUploadForm" width="50%" v-dialogDrag :destroy-on-close="true"
:close-on-click-modal="false" append-to-body>
<el-row :gutter="0">
<el-form ref="form" :model="form" :rules="rules" size="mini" label-width="80px">
<el-col :span="24">
<el-form-item label="选择文件" prop="uploadFile">
<el-upload action="" name="file"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
:show-file-list="true" :limit="1" :file-list="fileList" :tooltip="fileName"
:on-change="fileChange" :before-upload="beforeUpload">
<el-button slot="trigger" plain class="filter-item" size="mini"
type="primary">选择文件</el-button>
<el-link type="primary" style="line-height: 28px;font-size:13px;color:blue"
href="/static/tpl/imp_trans_quote.xls">下载导入Excel模板</el-link>
<div v-if="uploadExcelDataInfo != ''"
style="color: black;font-size: 12px;font-weight: 800;">{{
fileName }} {{ uploadExcelDataInfo }}</div>
</el-upload>
<el-alert title="注意" type="info" description="仅允许导入“xls”或“xlsx”格式文件!" close-text="知道了">
</el-alert>
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="batchImpDataForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</XdPageContainer>
</template>
<script>
import { addSalesMonthlyReviewDraft } from "@/api/emis/salesMonthlyReview";
import { timeDiffTime, excelDateToJSDate } from '@/utils/dateUtils'
import XLSX from 'xlsx'
export default {
name: "BatchWaybillRecord",
data() {
return {
resetRefreshId: null,
// 遮罩层
loading: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 报价列表表格数据
emisQuotePriceList: [],
tmpDataList: [],
selectionList: [],
selectionIndexList: [],
form: {},
rules: {},
openUploadForm: false,
uploadMsg: "",
uploadExcelDataInfo: "",
fileName: "",
fileList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20
},
};
},
methods: {
getUUID() {
return Math.random().toString(36).substring(3, 10);
},
handleBatchImport() {
this.resetRefreshId = "importForm-" + this.getUUID();
this.openUploadForm = true;
this.fileList = [];
this.uploadExcelDataInfo = "";
this.fileName = "";
},
calcDeliveryTime(startData, endDate) {
return timeDiffTime(startData, endDate)
},
//标红table指定行
tableRowClassName(row, index) {
row.row.index = row.rowIndex;
if (row.uploadStatus == '1') {
return 'success-row';
}
else if (row.uploadStatus == '-1') {
return 'warning-row';
}
return '';
},
/** 查询报价列表 */
getList() {
this.loading = true;
},
fileChange(file, fileList) {
this.fileList = fileList;
},
beforeUpload(file) {
this.fileName = file.name;
this.form.batchName = file.name;
this.readerData(file)
return false
},
readerData(rawFile) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = e => {
const data = e.target.result
const workbook = XLSX.read(data, { type: 'array' })
const firstSheetName = workbook.SheetNames[0] // firstSheetName
// if (!excelTypes.includes(firstSheetName)) {
// reject('无法识别当前Excel模板')
// this.$modal.msgError('无法识别当前Excel模板')
// return
// }
const worksheet = workbook.Sheets[firstSheetName]
// const header = this.getHeaderRow(worksheet) // 标题
const results = XLSX.utils.sheet_to_json(worksheet)
this.batchImportData(results);
resolve()
}
reader.readAsArrayBuffer(rawFile)
})
},
getHeaderRow(sheet) {
const headers = []
const range = XLSX.utils.decode_range(sheet['!ref'])
let C
const R = range.s.r
/* start in the first row */
for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
/* find the cell in the first row */
let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
headers.push(hdr)
}
return headers
},
async batchImportData(results) {
const _index = 1
let loadingInstance = this.$loading({
text: '正在解析 ' + _index + ' 数据...'
})
this.emisQuotePriceList = [];
this.tmpDataList = [];
// 组装提交的数据
for (let index = 0; index < results.length; index++) {
const element = results[index]
let data = {
employeeName: element['员工姓名'],
department: element['所属部门'],
entryDate: element['入职日期'],
position: element['岗位'],
reviewMonth: element['考评月份'],
score: element['考核分数'],
remark: element['备注'],
uploadStatus: 0,
errorInfo: ''
}
//转时间格式
if (data.entryDate) {
data.entryDate = excelDateToJSDate(data.entryDate)
}
this.tmpDataList.push(data);
}
this.uploadExcelDataInfo = "总共 " + this.tmpDataList.length + " 条数据。";
loadingInstance.close()
},
handleRealUploadAll() {
if (this.ids && this.ids.length > 0) {
this.$confirm("确认下单吗?", "提示", {
cancelButtonText: "取消",
confirmButtonText: "确认",
type: "warning",
distinguishCancelAndClose: true,
closeOnClickModal: false
}).then(async () => {
if (this.selectionList && this.selectionList.length > 0) {
for (let i = 0; i < this.selectionList.length; i++) {
let orderItem = this.selectionList[i];
let res = await addSalesMonthlyReviewDraft({ ...orderItem })
let rstData = res.data;
if (rstData.result == 'success') {
orderItem.uploadStatus = 1;
orderItem.errorInfo = "下单成功";
}
else {
orderItem.uploadStatus = -1;
orderItem.errorInfo = rstData.msg;
}
}
this.$modal.msgSuccess("上传成功");
}
});
}
},
batchImpDataForm() {
// 判断是否有数据
if (this.tmpDataList.length == 0) {
this.$modal.msgError('表格中没有数据');
return;
}
this.emisQuotePriceList = this.emisQuotePriceList.concat(this.tmpDataList);
this.tmpDataList = [];
this.openUploadForm = false;
},
// 多选框选中数据
handleSelectionChange(selection) {
this.selectionList = selection;
this.ids = selection.map(item => item.id)
this.single = selection.length !== 1
this.multiple = !selection.length
},
// 排序 查询字段是表格中字段名字 动态取值排序顺序
handleSortChange(column) {
this.queryParams.orderByColumn = column.prop;
this.queryParams.isAsc = column.order;
this.getList();
},
cancel() {
this.openUploadForm = false;
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
let that = this;
this.$modal.confirm('是否确认删除').then(function () {
that.selectionList.forEach((item, index) => {
that.emisQuotePriceList.forEach((v, i) => {
if (item.index === v.index) {
that.emisQuotePriceList.splice(i, 1)
}
})
})
that.$refs.multipleTable.clearSelection();
}).then(() => {
this.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
}
};
</script>
<style lang="scss" scoped></style>

View File

@ -30,7 +30,7 @@
</SearchForm>
<XdTable slot="pageContent" slot-scope="slotProps" :height="(slotProps.contentHeight) + 'px'" ref="refTable"
v-loading="loading" border size="mini" :data="list" storageName="emisUser_main" :showSearch.sync="showSearch"
v-loading="loading" border size="mini" :data="list" :showSearch.sync="showSearch"
:total="total" highlight-current-row @queryTable="getList" :queryParams="queryParams"
@selection-change="handleSelectionChange" @sort-change="handleSortChange">
@ -93,6 +93,7 @@ import PostsPicker from "@/views/emis/EmisBaseTools/PostsPicker.vue";
import NumberRangePicker from '@/components/NumberRange/NumberRangePicker';
import EmpNamePicker from '@/views/emis/EmisBaseTools/EmpNamePicker.vue';
import DepartmentPicker from "@/views/emis/EmisBaseTools/DepartmentPicker.vue";
import { getLastMonthYearMonth } from "@/utils/dateUtils";
export default {
name: "SalesMonthlyReview",
components: { SalesMonthlyReviewForm,Treeselect,PostsPicker,NumberRangePicker,EmpNamePicker,DepartmentPicker },
@ -126,7 +127,7 @@ export default {
employeeName:null,
position:null,
department:null,
reviewMonth:null,
reviewMonth:getLastMonthYearMonth(), //默认上个月
params:{
scoreRange:null,
}
@ -264,7 +265,7 @@ export default {
},
getTreeselect() {
treeselect().then(response => {
console.log(response.data)
// console.log(response.data)
this.deptOptions = response.data;
});
},