1268 lines
37 KiB
Plaintext
1268 lines
37 KiB
Plaintext
<template>
|
||
<div class="monthly-payment data-list">
|
||
<div class="filter-container">
|
||
<el-date-picker
|
||
v-model="listQuery.StatisticsDate"
|
||
class="mr"
|
||
type="month"
|
||
value-format="yyyy-MM"
|
||
format="yyyy-MM"
|
||
placeholder="Select Month"
|
||
:picker-options="pickerOption"
|
||
:clearable="false"
|
||
size="small"
|
||
/>
|
||
<el-select v-model="listQuery.Nation" placeholder="Nation" size="small" style="width:120px;margin-right:5px;" clearable>
|
||
<el-option label="CN" value="0" />
|
||
<el-option label="US" value="1" />
|
||
</el-select>
|
||
|
||
<el-input
|
||
v-model="listQuery.KeyWord"
|
||
placeholder="ID or Name"
|
||
style="width:150px;margin-right:5px;"
|
||
class="handle-select"
|
||
size="small"
|
||
/>
|
||
<el-button type="text" size="small" style="margin-left:5px;" @click="handleReset">Reset</el-button>
|
||
<el-button type="primary" size="small" @click="handleSearch">Search</el-button>
|
||
|
||
<el-button
|
||
type="primary"
|
||
:disabled="unlockCount==0||!exchangeRate > 0 || arrID.length == 0"
|
||
size="small"
|
||
:loading="lockLoading"
|
||
@click="handleLock"
|
||
>Lock</el-button>
|
||
<el-button
|
||
type="primary"
|
||
:disabled="arrID.length == 0 || unlockCount==0"
|
||
size="small"
|
||
:loading="calcLoading"
|
||
@click="handleCalculate"
|
||
>Calculate</el-button>
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
:disabled="!exchangeRate > 0 || arrID.length == 0"
|
||
:loading="exportLoading"
|
||
@click="handleExportExcel"
|
||
>Export Summary</el-button>
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
:disabled="!exchangeRate > 0 || arrID.length == 0"
|
||
:loading="exportDetailLoading"
|
||
@click="handleExportDetail"
|
||
>Export Details</el-button>
|
||
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
:disabled="!exchangeRate > 0 || arrID.length == 0"
|
||
:loading="exportPayrollLoading"
|
||
@click="handleExportPayroll"
|
||
>Export Payrolls</el-button>
|
||
|
||
<el-button
|
||
style="margin-left:auto"
|
||
type="primary"
|
||
size="small"
|
||
@click="handleAdjustment"
|
||
>Adjustment</el-button>
|
||
<el-button
|
||
style="margin-left: 5px"
|
||
type="primary"
|
||
size="small"
|
||
@click="handleSetting"
|
||
>Settings</el-button>
|
||
</div>
|
||
<div class="data-table">
|
||
<el-table
|
||
ref="table"
|
||
v-loading="listLoading"
|
||
size="small"
|
||
height="99%"
|
||
:data="list"
|
||
stripe
|
||
:cell-style="cellStyle"
|
||
:summary-method="getSummaries"
|
||
show-summary
|
||
@sort-change="handleSortChange"
|
||
@selection-change="handleSelectChange"
|
||
>
|
||
<el-table-column type="selection" :selectable="handleSelectTable" />
|
||
<el-table-column type="index" width="40" />
|
||
<el-table-column
|
||
prop="LastName"
|
||
label="Name"
|
||
show-overflow-tooltip
|
||
min-width="140"
|
||
sortable="custom"
|
||
>
|
||
<template slot-scope="scope">{{ scope.row.LastName + ' / ' + scope.row.FirstName }}</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="DoctorNameInBank"
|
||
label="Name CN"
|
||
show-overflow-tooltip
|
||
min-width="110"
|
||
sortable="custom"
|
||
>
|
||
<template
|
||
slot-scope="scope"
|
||
>{{ scope.row.DoctorNameInBank?scope.row.DoctorNameInBank:scope.row.ChineseName }}</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="Code"
|
||
label="ID"
|
||
show-overflow-tooltip
|
||
min-width="90"
|
||
sortable="custom"
|
||
/>
|
||
<el-table-column prop="RankName" label="Rank" show-overflow-tooltip min-width="80" />
|
||
<el-table-column prop="IDCard" label="Resident ID" show-overflow-tooltip min-width="100" />
|
||
<el-table-column prop="Phone" label="Phone Number" show-overflow-tooltip min-width="115" />
|
||
|
||
<el-table-column prop="BankName" label="Bank" show-overflow-tooltip min-width="80" />
|
||
<el-table-column
|
||
prop="BankCardNumber"
|
||
label="Account Number"
|
||
show-overflow-tooltip
|
||
min-width="125"
|
||
/>
|
||
<el-table-column
|
||
prop="TotalPaymentUSD"
|
||
label="Payment ($)"
|
||
min-width="130"
|
||
sortable="custom"
|
||
>
|
||
<template slot-scope="scope">
|
||
<el-tooltip class="item" effect="dark" placement="top">
|
||
<div slot="content">
|
||
{{ 'Current month: ' + scope.row.PaymentUSD }}
|
||
<br>
|
||
{{ 'Adjustment: ' + scope.row.AdjustPaymentUSD }}
|
||
</div>
|
||
<div>
|
||
{{
|
||
!scope.row.IDCard || !scope.row.BankCardNumber || !scope.row.RankName
|
||
? 'Setting Needed'
|
||
: scope.row.TotalPaymentUSD.toFixed(2)
|
||
}}
|
||
|
||
<!-- {{
|
||
!scope.row.IDCard || !scope.row.BankCardNumber || !scope.row.RankName
|
||
? 'Setting Needed'
|
||
: scope.row.TotalPaymentUSD
|
||
}} -->
|
||
</div>
|
||
</el-tooltip>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="ExchangeRate" label="Exchange Rate" min-width="110">
|
||
<template slot-scope="scope">
|
||
<span>{{ scope.row.ExchangeRate | rounding }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="TotalPaymentCNY"
|
||
label="Payment(¥)"
|
||
min-width="110"
|
||
sortable="custom"
|
||
:formatter="paymentCNFormatter"
|
||
>
|
||
<template slot-scope="scope">
|
||
<el-tooltip class="item" effect="dark" placement="top">
|
||
<div slot="content">
|
||
{{ 'Current month: ' + scope.row.PaymentCNY }}
|
||
<br>
|
||
{{ 'Adjustment: ' + scope.row.AdjustPaymentCNY }}
|
||
</div>
|
||
<!-- <div>{{ scope.row.ExchangeRate > 0 ? scope.row.TotalPaymentCNY.toFixed(2) : 'Setting Needed' }}</div> -->
|
||
<div>{{ scope.row.ExchangeRate > 0 ? scope.row.TotalPaymentCNY : 'Setting Needed' }}</div>
|
||
</el-tooltip>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="Status" prop="IsLock" sortable="custom">
|
||
<template slot-scope="scope">{{ scope.row.IsLock?'Locked':'Pending' }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="Action" min-width="120">
|
||
<template slot-scope="scope">
|
||
<el-button
|
||
size="small"
|
||
type="text"
|
||
:disabled="!(scope.row.IDCard && scope.row.BankCardNumber)"
|
||
@click="handleDetail(scope.row)"
|
||
>Detail</el-button>
|
||
|
||
<el-button
|
||
v-if="!scope.row.IDCard || !scope.row.BankCardNumber || !scope.row.RankName"
|
||
size="small"
|
||
type="text"
|
||
style="color:red;"
|
||
@click="handleSettingDoctor(scope.row)"
|
||
>Setting</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
<div class="pagination">
|
||
<pagination
|
||
:total="total"
|
||
:page.sync="listQuery.PageIndex"
|
||
:limit.sync="listQuery.PageSize"
|
||
@pagination="getList"
|
||
/>
|
||
</div>
|
||
<el-dialog
|
||
:key="form.DoctorId"
|
||
title="Edit"
|
||
:visible.sync="dialogVisible"
|
||
width="500px"
|
||
:close-on-click-modal="false"
|
||
size="small"
|
||
>
|
||
<el-form ref="reviewerDataForm" label-width="170px" :rules="rules" :model="form" size="small">
|
||
<el-form-item label="Name: ">
|
||
<el-input v-model="form.Name" readonly />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="Name CN: " prop="DoctorNameInBank">
|
||
<el-input v-model="form.DoctorNameInBank" />
|
||
</el-form-item>
|
||
<el-form-item label="ID: " prop="Code">
|
||
<el-input v-model="form.Code" readonly />
|
||
</el-form-item>
|
||
<el-form-item label="Rank: " prop="Rank">
|
||
<el-select v-model="form.RankId" style="width:100%;">
|
||
<el-option
|
||
v-for="(item) in rankList"
|
||
:key="item.Id"
|
||
:label="item.RankName"
|
||
:value="item.Id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="Personal Adjustment ($): " prop="Additional">
|
||
<el-input v-model="form.Additional" type="number" />
|
||
</el-form-item>
|
||
<el-form-item label="Resident ID: " prop="IDCard">
|
||
<el-input v-model="form.IDCard" />
|
||
</el-form-item>
|
||
<el-form-item label="Bank: " prop="BankName">
|
||
<el-input v-model="form.BankName" />
|
||
</el-form-item>
|
||
<el-form-item label="Account Number: " prop="BankCardNumber">
|
||
<el-input v-model="form.BankCardNumber" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button size="small" @click="dialogVisible = false">Cancel</el-button>
|
||
<el-button type="primary" :disabled="btnDisabled" size="small" @click="handleSave">Ok</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
<script>
|
||
import Pagination from '@/components/Pagination'
|
||
import { num2Money } from '@/utils/formatter'
|
||
import floatObj from '@/utils/float-operation'
|
||
import {
|
||
getMonthlyPaymentList,
|
||
lockMonthlyPayment,
|
||
calculateMonthlyPayment,
|
||
addOrUpdateReviewerPayInfo,
|
||
getReviewersPaymentDetailList,
|
||
getMonthlyPayroll
|
||
} from '@/api/financials'
|
||
import store from '@/store'
|
||
import { mapGetters, mapMutations } from 'vuex'
|
||
import Excel from 'exceljs'
|
||
import Zip from 'jszip'
|
||
import { saveAs } from 'file-saver'
|
||
const getListQueryDefault = () => {
|
||
return {
|
||
StatisticsDate: '',
|
||
KeyWord: '',
|
||
PageSize: 20,
|
||
PageIndex: 1,
|
||
Asc: true,
|
||
SortField: ''
|
||
}
|
||
}
|
||
|
||
export default {
|
||
name: 'EnrollmentsStats',
|
||
components: { Pagination },
|
||
filters: {
|
||
rounding(value) {
|
||
// return value ? Number(value).toFixed(2) : value
|
||
return value
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
listQuery: getListQueryDefault(),
|
||
list: [],
|
||
listLoading: false,
|
||
total: 0,
|
||
exchangeRate: '',
|
||
arrID: '',
|
||
excelData: [], // 支付费用详情Excel数据
|
||
excelDataCount: 0,
|
||
excelDataPayroll: [], // 公司单汇总及明细 Excel数据
|
||
excelDataPayrollCount: 0,
|
||
lockLoading: false,
|
||
calcLoading: false,
|
||
exportLoading: false,
|
||
exportDetailLoading: false,
|
||
exportPayrollLoading: false,
|
||
form: {},
|
||
rules: {
|
||
DoctorNameInBank: [
|
||
{ required: true, message: 'Please specify', trigger: 'blur' }
|
||
],
|
||
BankName: [
|
||
{ required: true, message: 'Please specify', trigger: 'blur' }
|
||
],
|
||
BankCardNumber: [
|
||
{ required: true, message: 'Please specify', trigger: 'blur' }
|
||
],
|
||
IDCard: [
|
||
{ required: true, message: 'Please specify', trigger: 'blur' },
|
||
{
|
||
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
|
||
message: 'Incorrect ID card format'
|
||
}
|
||
],
|
||
Rank: [{ required: true, message: 'Please select', trigger: ['blur', 'change'] }]
|
||
},
|
||
btnDisabled: false,
|
||
dialogVisible: false,
|
||
pickerOption: {
|
||
disabledDate: (time) => {
|
||
const _now = Date.now()
|
||
return time.getTime() > _now
|
||
}
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
...mapGetters(['rankList', 'paymentQuery']),
|
||
unlockCount: function() {
|
||
var tempCount = 0
|
||
this.list.forEach((item) => {
|
||
if (this.arrID.indexOf(item.DoctorId) > -1) {
|
||
if (!item.IsLock) {
|
||
tempCount++
|
||
}
|
||
}
|
||
})
|
||
return tempCount
|
||
}
|
||
},
|
||
mounted() {
|
||
this.listQuery.StatisticsDate = new Date(
|
||
new Date().setMonth(new Date().getMonth() - 1)
|
||
).format('yyyy-MM')
|
||
this.paymentQuery ? (this.listQuery = this.paymentQuery) : ''
|
||
this.getList()
|
||
},
|
||
|
||
destroyed() {},
|
||
methods: {
|
||
getList() {
|
||
this.listLoading = true
|
||
this.setQueryParam(this.listQuery)
|
||
getMonthlyPaymentList(this.listQuery)
|
||
.then((res) => {
|
||
this.listLoading = false
|
||
this.list = res.Result.CostList.CurrentPageData
|
||
this.total = res.Result.CostList.TotalCount
|
||
this.exchangeRate = res.Result.ExchangeRate
|
||
})
|
||
.catch(() => {
|
||
this.listLoading = false
|
||
})
|
||
},
|
||
handleSearch() {
|
||
this.listQuery.PageIndex = 1
|
||
this.getList()
|
||
},
|
||
handleReset() {
|
||
this.listQuery = getListQueryDefault()
|
||
this.listQuery.StatisticsDate = new Date(
|
||
new Date().setMonth(new Date().getMonth() - 1)
|
||
).format('yyyy-MM')
|
||
this.getList()
|
||
},
|
||
handleLock() {
|
||
const param = {
|
||
ReviewerIdList: this.arrID,
|
||
Month: this.listQuery.StatisticsDate
|
||
}
|
||
this.lockLoading = true
|
||
lockMonthlyPayment(param)
|
||
.then((res) => {
|
||
this.lockLoading = false
|
||
this.getList()
|
||
this.$message.success('Locked successfully')
|
||
})
|
||
.catch(() => {
|
||
this.lockLoading = false
|
||
})
|
||
},
|
||
handleCalculate() {
|
||
const param = {
|
||
CalculateMonth: this.listQuery.StatisticsDate,
|
||
NeedCalculateReviewers: this.arrID
|
||
}
|
||
this.calcLoading = true
|
||
calculateMonthlyPayment(param)
|
||
.then((res) => {
|
||
this.calcLoading = false
|
||
this.getList()
|
||
this.$message.success('Calculate successfully')
|
||
})
|
||
.catch(() => {
|
||
this.calcLoading = false
|
||
})
|
||
},
|
||
handleAdjustment() {
|
||
this.$router.push({
|
||
name: 'Adjustment',
|
||
query: {
|
||
exchangeRate: this.exchangeRate,
|
||
date: this.listQuery.StatisticsDate
|
||
}
|
||
})
|
||
},
|
||
handleSetting() {
|
||
this.$router.push({ name: 'PaymentSettings' })
|
||
},
|
||
|
||
handleDetail(row) {
|
||
this.$router.push({ name: 'PaymentDetail', query: row })
|
||
},
|
||
handleSettingDoctor(row) {
|
||
store.dispatch('financials/getRank')
|
||
this.form = (({
|
||
FirstName,
|
||
LastName,
|
||
ChineseName,
|
||
Code,
|
||
DoctorId,
|
||
DoctorNameInBank,
|
||
IDCard,
|
||
BankCardNumber,
|
||
BankName,
|
||
RankId,
|
||
Additional
|
||
}) => ({
|
||
FirstName,
|
||
LastName,
|
||
ChineseName,
|
||
Code,
|
||
DoctorId,
|
||
DoctorNameInBank,
|
||
IDCard,
|
||
BankCardNumber,
|
||
BankName,
|
||
RankId,
|
||
Additional
|
||
}))(row)
|
||
this.form.Name = `${row.LastName} / ${row.FirstName}`
|
||
this.form.DoctorNameInBank = this.form.DoctorNameInBank
|
||
? this.form.DoctorNameInBank
|
||
: this.form.ChineseName
|
||
this.dialogVisible = true
|
||
},
|
||
handleSave() {
|
||
this.btnDisabled = true
|
||
const param = (({
|
||
DoctorId,
|
||
DoctorNameInBank,
|
||
IDCard,
|
||
BankCardNumber,
|
||
BankName,
|
||
RankId,
|
||
Additional
|
||
}) => ({
|
||
DoctorId,
|
||
DoctorNameInBank,
|
||
IDCard,
|
||
BankCardNumber,
|
||
BankName,
|
||
RankId,
|
||
Additional
|
||
}))(this.form)
|
||
addOrUpdateReviewerPayInfo(param)
|
||
.then((res) => {
|
||
this.btnDisabled = false
|
||
this.dialogVisible = false
|
||
this.getList()
|
||
this.$message.success('Updated successfully')
|
||
})
|
||
.catch(() => {
|
||
this.btnDisabled = false
|
||
})
|
||
},
|
||
handleSortChange(column) {
|
||
if (column.order === 'ascending') {
|
||
this.listQuery.Asc = true
|
||
} else {
|
||
this.listQuery.Asc = false
|
||
}
|
||
this.listQuery.SortField = column.prop
|
||
this.listQuery.PageIndex = 1
|
||
this.getList()
|
||
},
|
||
handleSelectChange(val) {
|
||
const arr = []
|
||
for (let index = 0; index < val.length; index++) {
|
||
arr.push(val[index].DoctorId)
|
||
}
|
||
this.arrID = arr
|
||
},
|
||
getSummaries(param) {
|
||
const { columns, data } = param
|
||
const sums = []
|
||
// const scope = this
|
||
columns.forEach((column, index) => {
|
||
if (index === 2) {
|
||
sums[index] = 'Total (Current Page)'
|
||
return
|
||
}
|
||
if (column.property === 'TotalPaymentUSD') {
|
||
const values = data.map((item) => Number(item[column.property]))
|
||
if (!values.every((value) => isNaN(value))) {
|
||
sums[index] = values
|
||
.reduce((prev, curr) => {
|
||
const value = Number(curr)
|
||
if (!isNaN(value)) {
|
||
return floatObj.add(prev, curr)
|
||
} else {
|
||
return prev
|
||
}
|
||
}, 0)
|
||
}
|
||
}
|
||
if (column.property === 'TotalPaymentCNY') {
|
||
const values = data.map((item) => Number(item[column.property]))
|
||
if (!values.every((value) => isNaN(value))) {
|
||
sums[index] = values
|
||
.reduce((prev, curr) => {
|
||
const value = Number(curr)
|
||
if (!isNaN(value)) {
|
||
return floatObj.add(prev, curr)
|
||
} else {
|
||
return prev
|
||
}
|
||
}, 0)
|
||
}
|
||
}
|
||
})
|
||
return sums
|
||
},
|
||
addNum(n1, n2) {
|
||
var s1, s2, m
|
||
try {
|
||
s1 = n1.toString().split('.')[1].length
|
||
} catch (e) {
|
||
s1 = 0
|
||
}
|
||
try {
|
||
s2 = n2.toString().split('.')[1].length
|
||
} catch (e) {
|
||
s2 = 0
|
||
}
|
||
m = Math.pow(10, Math.max(s1, s2))
|
||
console.log(n1 + '===' + n2 + '===' + m + '===' + (n1 * m + n2 * m) / m)
|
||
return (n1 * m + n2 * m) / m
|
||
},
|
||
handleSelectTable(row) {
|
||
return !!(row.IDCard && row.BankCardNumber && row.BankName)
|
||
},
|
||
onSelected(e) {
|
||
const obj = this.rankOption.find((item) => {
|
||
return item.Id === e
|
||
})
|
||
this.form.Rank = obj.RankName
|
||
},
|
||
|
||
cellStyle({ row, column, rowIndex, columnIndex }) {
|
||
if (
|
||
(row.TotalPaymentCNY === 0 && columnIndex === 12) ||
|
||
(columnIndex === 10 &&
|
||
(!row.IDCard || !row.BankCardNumber || !row.RankName))
|
||
) {
|
||
return 'color:red'
|
||
}
|
||
},
|
||
paymentCNFormatter(row, column) {
|
||
return row.ExchangeRate > 0
|
||
? num2Money(row.PaymentCNY + row.AdjustPaymentCNY, 2, 0)
|
||
: 'Setting Needed'
|
||
},
|
||
|
||
handleExportDetail() {
|
||
var that = this
|
||
that.excelData = []
|
||
var queryArray = []
|
||
this.list.forEach((item) => {
|
||
if (this.arrID.indexOf(item.DoctorId) > -1) {
|
||
queryArray.push({
|
||
PaymentId: item.Id,
|
||
ReviewerId: item.DoctorId,
|
||
YearMonth: item.YearMonth
|
||
})
|
||
}
|
||
})
|
||
that.exportDetailLoading = true
|
||
getReviewersPaymentDetailList(queryArray)
|
||
.then((res) => {
|
||
that.excelDataCount = res.Result.length
|
||
res.Result.forEach((element) => {
|
||
that.exportDetailExcel(element.DoctorInfo, element.DetailList)
|
||
})
|
||
})
|
||
.catch(() => {
|
||
that.exportDetailLoading = false
|
||
})
|
||
},
|
||
handleExportPayroll() {
|
||
var that = this
|
||
that.excelDataPayroll = []
|
||
var doctorIds = []
|
||
this.list.forEach((item) => {
|
||
if (this.arrID.indexOf(item.DoctorId) > -1) doctorIds.push(item.Id)
|
||
})
|
||
that.exportPayrollLoading = true
|
||
getMonthlyPayroll(doctorIds)
|
||
.then((res) => {
|
||
that.ExportExcelPayroll(res.Result)
|
||
})
|
||
.catch(() => {
|
||
that.exportPayrollLoading = false
|
||
})
|
||
},
|
||
|
||
ExportExcelPayroll(payrollDataList) {
|
||
var workbook = new Excel.Workbook()
|
||
var sheet = workbook.addWorksheet(this.listQuery.StatisticsDate)
|
||
|
||
sheet.properties.defaultRowHeight = 22
|
||
sheet.columns = [
|
||
{ key: 'ChineseName', width: 15 },
|
||
{ key: 'ResidentId', width: 30 },
|
||
{ key: 'Phone', width: 15 },
|
||
{ key: 'AccountNumber', width: 20 },
|
||
{ key: 'Bank', width: 30 },
|
||
{ key: 'PaymentCNY', width: 20 },
|
||
{ key: 'TaxCNY', width: 20 },
|
||
{ key: 'ActuallyPaidCNY', width: 20 }
|
||
]
|
||
var that = this
|
||
|
||
// 处理标题
|
||
sheet.mergeCells('A1', 'H2')
|
||
sheet.getCell('A1').value =
|
||
that.listQuery.StatisticsDate + ' Payroll Summary'
|
||
sheet.getCell('A1').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
sheet.getCell('A1').font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 13,
|
||
bold: true
|
||
}
|
||
sheet.mergeCells('A3', 'H3')
|
||
sheet.getCell('A3').value = 'Month:' + that.listQuery.StatisticsDate
|
||
sheet.getCell('A3').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'right'
|
||
}
|
||
|
||
sheet.getRow(4).values = [
|
||
'Name CN',
|
||
'Resident ID',
|
||
'Phone Number',
|
||
'Account Number',
|
||
'Bank',
|
||
'劳务费总计',
|
||
'应付税额',
|
||
'实付劳务费'
|
||
]
|
||
sheet.getRow(4).font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 11,
|
||
bold: true
|
||
}
|
||
sheet.getRow(4).alignment = { vertical: 'middle', horizontal: 'left' }
|
||
|
||
sheet.addRows(payrollDataList)
|
||
|
||
sheet.getColumn(6).numFmt = '#,##0.00'
|
||
sheet.getColumn(7).numFmt = '#,##0.00'
|
||
sheet.getColumn(8).numFmt = '#,##0.00'
|
||
|
||
sheet.eachRow((row, number) => {
|
||
if (number > 3) {
|
||
row.eachCell((cell, rowNumber) => {
|
||
cell.alignment = { vertical: 'center', horizontal: 'left' }
|
||
cell.border = {
|
||
top: { style: 'thin' },
|
||
left: { style: 'thin' },
|
||
bottom: { style: 'thin' },
|
||
right: { style: 'thin' }
|
||
}
|
||
})
|
||
}
|
||
})
|
||
|
||
workbook.xlsx
|
||
.writeBuffer({
|
||
base64: true
|
||
})
|
||
.then(function(xls64) {
|
||
var data = new Blob([xls64], {
|
||
type:
|
||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
})
|
||
that.excelDataPayrollCount = payrollDataList.length + 1
|
||
that.excelDataPayroll.push({
|
||
data: data,
|
||
fileName:
|
||
'Payroll Summary_' + that.listQuery.StatisticsDate + '.xlsx'
|
||
})
|
||
|
||
payrollDataList.forEach((element) => {
|
||
that.ExportExcelPayrollDeatil(element)
|
||
})
|
||
})
|
||
},
|
||
ExportExcelPayrollDeatil(payrollItem) {
|
||
var that = this
|
||
var workbook = new Excel.Workbook()
|
||
var sheet = workbook.addWorksheet(
|
||
payrollItem.ChineseName + ' ' + this.listQuery.StatisticsDate
|
||
)
|
||
|
||
sheet.properties.defaultRowHeight = 25
|
||
sheet.properties.defaultColWidth = 30
|
||
// 处理标题
|
||
sheet.mergeCells('A1', 'E1')
|
||
sheet.getCell('A1').value = '上海致准信息科技有限公司'
|
||
sheet.getCell('A1').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
sheet.getCell('A1').font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 13,
|
||
bold: true
|
||
}
|
||
sheet.mergeCells('A2', 'E2')
|
||
sheet.getCell('A2').value = '劳务支付单'
|
||
sheet.getCell('A2').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
sheet.getCell('A2').font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 13,
|
||
bold: true
|
||
}
|
||
|
||
sheet.getRow(3).values = ['姓名', '身份证号', '', '工作月份', '发放月份']
|
||
|
||
sheet.mergeCells('B3', 'C3')
|
||
|
||
var myDate = new Date()
|
||
var tYear = myDate.getFullYear()
|
||
var tMonth = myDate.getMonth() + 1
|
||
if (tMonth < 10) tMonth = '0' + tMonth
|
||
|
||
sheet.getRow(4).values = [
|
||
payrollItem.ChineseName,
|
||
payrollItem.ResidentId,
|
||
'',
|
||
payrollItem.YearMonth,
|
||
tYear + '-' + tMonth
|
||
]
|
||
sheet.mergeCells('B4', 'C4')
|
||
|
||
sheet.getRow(5).values = [
|
||
'应付金额',
|
||
'代扣税金',
|
||
'实付金额',
|
||
'银行转账',
|
||
''
|
||
]
|
||
sheet.getRow(6).values = [
|
||
payrollItem.PaymentCNY,
|
||
payrollItem.TaxCNY,
|
||
payrollItem.ActuallyPaidCNY,
|
||
payrollItem.ActuallyPaidCNY,
|
||
''
|
||
]
|
||
sheet.mergeCells('D5', 'E5')
|
||
sheet.mergeCells('D6', 'E6')
|
||
sheet.getRow(7).values = ['审核', '', '经办', '', '']
|
||
sheet.mergeCells('A7', 'B7')
|
||
sheet.mergeCells('C7', 'E7')
|
||
|
||
sheet.eachRow((row, number) => {
|
||
if (number > 2) {
|
||
row.eachCell((cell, rowNumber) => {
|
||
if (number < 7) {
|
||
cell.alignment = { vertical: 'center', horizontal: 'center' }
|
||
}
|
||
cell.numFmt = '#,##0.00'
|
||
cell.border = {
|
||
top: { style: 'thin' },
|
||
left: { style: 'thin' },
|
||
bottom: { style: 'thin' },
|
||
right: { style: 'thin' }
|
||
}
|
||
})
|
||
}
|
||
})
|
||
|
||
workbook.xlsx
|
||
.writeBuffer({
|
||
base64: true
|
||
})
|
||
.then(function(xls64) {
|
||
var data = new Blob([xls64], {
|
||
type:
|
||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
})
|
||
|
||
that.excelDataPayroll.push({
|
||
data: data,
|
||
fileName:
|
||
payrollItem.ChineseName + '_paystub_' + payrollItem.YearMonth + '.xlsx'
|
||
})
|
||
|
||
if (that.excelDataPayrollCount === that.excelDataPayroll.length) {
|
||
var zip = new Zip()
|
||
that.excelDataPayroll.forEach((element) => {
|
||
zip.file(element.fileName, element.data)
|
||
})
|
||
zip.generateAsync({ type: 'blob' }).then(function(content) {
|
||
saveAs(
|
||
content,
|
||
'Monthly Payroll ' + payrollItem.YearMonth + '.zip'
|
||
)
|
||
})
|
||
}
|
||
that.exportPayrollLoading = false
|
||
})
|
||
},
|
||
|
||
exportDetailExcel(basicInfo, list) {
|
||
var workbook = new Excel.Workbook()
|
||
var sheet = workbook.addWorksheet(
|
||
basicInfo.ChineseName + ' ' + basicInfo.YearMonth
|
||
)
|
||
|
||
sheet.properties.defaultRowHeight = 22
|
||
sheet.columns = [
|
||
{ header: 'Project ID', key: 'TrialCode', width: 15 },
|
||
{ header: 'Type', key: 'PaymentType', width: 30 },
|
||
{ header: 'Count', key: 'Count', width: 15 },
|
||
{ header: 'Base Price', key: 'BasePrice', width: 15 },
|
||
{ header: 'Personal Additional', key: 'PersonalAdditional', width: 22 },
|
||
{ header: 'Trial Additional', key: 'TrialAdditional', width: 22 },
|
||
{ header: 'Total Price', key: 'TotalUnitPrice', width: 22 },
|
||
{ header: 'Total Fee', key: 'PaymentUSD', width: 22 },
|
||
{ header: 'Subtotal(¥)', key: 'PaymentCNY', width: 22 }
|
||
]
|
||
|
||
var that = this
|
||
|
||
var tempTotalFee = 0
|
||
var tempTotalFeeInCN = 0
|
||
|
||
list.forEach((element) => {
|
||
tempTotalFee += parseFloat(element.PaymentUSD)
|
||
tempTotalFeeInCN += parseFloat(element.PaymentCNY)
|
||
})
|
||
var rowsCount = Number(list.length + 1)
|
||
|
||
// 处理标题
|
||
var titleRows = 4
|
||
sheet.mergeCells('A1', 'I2')
|
||
sheet.getCell('A1').value = 'Monthly Payment' // that.basicInfo.DoctorChineseName + ' ' + that.date + ' 费用明细'
|
||
sheet.getCell('A1').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
sheet.getCell('A1').font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 13,
|
||
bold: true
|
||
}
|
||
|
||
sheet.mergeCells('A3', 'D3')
|
||
// that.basicInfo.FirstName + ' ' + that.basicInfo.LastName + ' Name CN:'+
|
||
sheet.getCell('A3').value =
|
||
'Name:' + basicInfo.ChineseName + ' ID:' + basicInfo.Code
|
||
sheet.mergeCells('E3', 'I3')
|
||
sheet.getCell('E3').value =
|
||
' Rank:' +
|
||
basicInfo.PayTitle +
|
||
' Month:' +
|
||
basicInfo.YearMonth +
|
||
' Exchange Rate: ' +
|
||
Number(list[0].ExchangeRate).toFixed(2)
|
||
sheet.getCell('A3').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'left'
|
||
}
|
||
sheet.getCell('E3').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'right'
|
||
}
|
||
// heet.mergeCells('A4', 'H4')
|
||
|
||
sheet.getCell('A4').value = 'Project ID'
|
||
sheet.getCell('B4').value = 'Read Type'
|
||
sheet.getCell('C4').value = 'Volume'
|
||
sheet.getCell('D4').value = 'Base Rate($)'
|
||
sheet.getCell('E4').value = 'Personal Adjustment($)'
|
||
sheet.getCell('F4').value = 'Project Adjustment($)'
|
||
sheet.getCell('G4').value = 'Adjusted Rate($)'
|
||
sheet.getCell('H4').value = 'Subtotal($)'
|
||
sheet.getCell('I4').value = 'Subtotal(¥)'
|
||
sheet.getRow(4).font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 11,
|
||
bold: true
|
||
}
|
||
|
||
sheet.addRows(list)
|
||
// 合并项目编号单元格
|
||
var projectCount = Math.floor(Number(list.length / 9)) // 项目个数
|
||
|
||
for (let i = 0; i < projectCount; i++) {
|
||
var tempR1 = 'A' + (10 * i + titleRows + 1)
|
||
var tempR2 = 'A' + (10 * (i + 1) + titleRows)
|
||
if (10 * (i + 1) < rowsCount) {
|
||
sheet.mergeCells(tempR1, tempR2)
|
||
sheet.getCell(tempR1).alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
}
|
||
}
|
||
|
||
// 合并奖励单元格
|
||
|
||
var awardCount = list.filter((t) => t.TrialCode === 'Volume Reward')
|
||
.length
|
||
|
||
var adjustMentCount = list.filter((t) => t.TrialCode === 'Adjustment')
|
||
.length
|
||
|
||
if (awardCount > 0) {
|
||
var R1 = 'A' + (projectCount * 10 + titleRows + 1)
|
||
var R2 = 'A' + (projectCount * 10 + titleRows + awardCount)
|
||
sheet.mergeCells(R1, R2)
|
||
sheet.getCell(R1).alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
}
|
||
|
||
if (adjustMentCount > 0) {
|
||
// 处理调整行列合并
|
||
|
||
var R3 = 'A' + (projectCount * 10 + titleRows + awardCount + 1)
|
||
var R4 = 'A' + (rowsCount + titleRows - 1)
|
||
|
||
sheet.mergeCells(R3, R4)
|
||
sheet.getCell(R3).alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
|
||
// 行合并
|
||
var i = 0
|
||
for (i = 0; i < adjustMentCount; i++) {
|
||
var adjustMentCell1 =
|
||
'B' + (projectCount * 10 + titleRows + awardCount + 1 + i)
|
||
var adjustMentCell2 =
|
||
'C' + (projectCount * 10 + titleRows + awardCount + 1 + i)
|
||
var adjustMentCell3 =
|
||
'G' + (projectCount * 10 + titleRows + awardCount + 1 + i)
|
||
sheet.mergeCells(adjustMentCell2, adjustMentCell3)
|
||
var index = projectCount * 10 + awardCount + i
|
||
|
||
sheet.getCell(adjustMentCell1).value =
|
||
list[index].AdjustmentView.AdjustType
|
||
sheet.getCell(adjustMentCell2).value =
|
||
list[index].AdjustmentView.Note
|
||
}
|
||
}
|
||
|
||
var tempCell = 'A' + (rowsCount + 1 + titleRows - 1)
|
||
var tempCell1 = 'B' + (rowsCount + 1 + titleRows - 1)
|
||
var tempCell2 = 'G' + (rowsCount + 1 + titleRows - 1)
|
||
var tempCell3 = 'H' + (rowsCount + 1 + titleRows - 1)
|
||
var tempCell4 = 'I' + (rowsCount + 1 + titleRows - 1)
|
||
sheet.mergeCells(tempCell1, tempCell2)
|
||
sheet.getCell(tempCell).value = 'Total' // that.date + ' 费用总计: '
|
||
sheet.getCell(tempCell3).value = tempTotalFee
|
||
sheet.getCell(tempCell4).value = tempTotalFeeInCN
|
||
|
||
sheet.getCell(tempCell3).font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 13,
|
||
bold: true
|
||
}
|
||
sheet.getRow(rowsCount + titleRows).font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 13,
|
||
bold: true
|
||
}
|
||
sheet.getColumn(7).numFmt = '#,##0.00'
|
||
sheet.getColumn(8).numFmt = '#,##0.00'
|
||
sheet.getColumn(9).numFmt = '#,##0.00'
|
||
sheet.eachRow((row, number) => {
|
||
if (number > 3) {
|
||
row.eachCell((cell, rowNumber) => {
|
||
cell.border = {
|
||
top: { style: 'thin' },
|
||
left: { style: 'thin' },
|
||
bottom: { style: 'thin' },
|
||
right: { style: 'thin' }
|
||
}
|
||
})
|
||
}
|
||
})
|
||
workbook.xlsx
|
||
.writeBuffer({
|
||
base64: true
|
||
})
|
||
.then(function(xls64) {
|
||
var data = new Blob([xls64], {
|
||
type:
|
||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
})
|
||
|
||
that.excelData.push({
|
||
data: data,
|
||
fileName:
|
||
basicInfo.ChineseName + '_detail_ ' + basicInfo.YearMonth + '.xlsx'
|
||
})
|
||
if (that.excelDataCount === that.excelData.length) {
|
||
var zip = new Zip()
|
||
that.excelData.forEach((element) => {
|
||
zip.file(element.fileName, element.data)
|
||
})
|
||
zip.generateAsync({ type: 'blob' }).then(function(content) {
|
||
saveAs(
|
||
content,
|
||
'Monthly Payment Detail_' + basicInfo.YearMonth + '.zip'
|
||
)
|
||
})
|
||
that.exportDetailLoading = false
|
||
}
|
||
})
|
||
},
|
||
|
||
handleExportExcel() {
|
||
var workbook = new Excel.Workbook()
|
||
var sheet = workbook.addWorksheet(this.listQuery.StatisticsDate)
|
||
|
||
sheet.properties.defaultRowHeight = 22
|
||
sheet.columns = [
|
||
{ key: 'Index', width: 5 },
|
||
{ key: 'LastName', width: 15 },
|
||
{ key: 'FirstName', width: 15 },
|
||
{ key: 'DoctorNameInBank', width: 15 },
|
||
{ key: 'Code', width: 15 },
|
||
{ key: 'IDCard', width: 20 },
|
||
{ key: 'Phone', width: 15 },
|
||
{ key: 'BankCardNumber', width: 25 },
|
||
{ key: 'BankName', width: 30 },
|
||
{ key: 'PaymentUSD', width: 20 },
|
||
{ key: 'ExchangeRate', width: 20 },
|
||
{ key: 'PaymentCNY', width: 20 },
|
||
{ key: 'IsLock', width: 20 }
|
||
]
|
||
var that = this
|
||
var tempTotalFee = 0
|
||
var tempTotalFeeCNY = 0
|
||
let index = 1
|
||
var exportExcelData = this.list.filter(
|
||
(item) => this.arrID.indexOf(item.DoctorId) > -1
|
||
)
|
||
exportExcelData.forEach((element) => {
|
||
element.Index = index
|
||
element.PaymentUSD = element.PaymentUSD + element.AdjustPaymentUSD
|
||
element.PaymentCNY = element.PaymentCNY + element.AdjustPaymentCNY
|
||
tempTotalFee += element.PaymentUSD
|
||
tempTotalFeeCNY += element.PaymentCNY
|
||
element.IsLock = element.IsLock ? 'Locked' : 'Pending'
|
||
index++
|
||
})
|
||
// 处理标题
|
||
sheet.mergeCells('A1', 'M2')
|
||
sheet.getCell('A1').value =
|
||
that.listQuery.StatisticsDate + ' Payment Summary'
|
||
sheet.getCell('A1').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'center'
|
||
}
|
||
sheet.getCell('A1').font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 13,
|
||
bold: true
|
||
}
|
||
sheet.mergeCells('A3', 'M3')
|
||
sheet.getCell('A3').value = 'Month:' + that.listQuery.StatisticsDate
|
||
sheet.getCell('A3').alignment = {
|
||
vertical: 'middle',
|
||
horizontal: 'right'
|
||
}
|
||
|
||
sheet.getRow(4).values = [
|
||
'',
|
||
'Surname',
|
||
'Given Name',
|
||
'Name CN',
|
||
'ID',
|
||
'Resident ID',
|
||
'Phone Number',
|
||
'Account Number',
|
||
'Bank',
|
||
'Payment($)',
|
||
'Exchange Rate',
|
||
'Payment(¥)',
|
||
'Status'
|
||
]
|
||
sheet.getRow(4).font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 11,
|
||
bold: true
|
||
}
|
||
sheet.getRow(4).alignment = { vertical: 'middle', horizontal: 'left' }
|
||
|
||
sheet.addRows(exportExcelData)
|
||
sheet.addRow([
|
||
'',
|
||
'Total',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
tempTotalFee,
|
||
'',
|
||
tempTotalFeeCNY,
|
||
''
|
||
])
|
||
sheet.getRow(exportExcelData.length + 5).font = {
|
||
name: 'SimSun',
|
||
family: 4,
|
||
size: 11,
|
||
bold: true
|
||
}
|
||
|
||
sheet.getColumn(10).numFmt = '#,##0.00'
|
||
sheet.getColumn(11).numFmt = '#,##0.00'
|
||
sheet.getColumn(12).numFmt = '#,##0.00'
|
||
|
||
sheet.eachRow((row, number) => {
|
||
if (number > 3) {
|
||
row.eachCell((cell, rowNumber) => {
|
||
cell.alignment = { vertical: 'center', horizontal: 'left' }
|
||
cell.border = {
|
||
top: { style: 'thin' },
|
||
left: { style: 'thin' },
|
||
bottom: { style: 'thin' },
|
||
right: { style: 'thin' }
|
||
}
|
||
})
|
||
}
|
||
})
|
||
|
||
workbook.xlsx
|
||
.writeBuffer({
|
||
base64: true
|
||
})
|
||
.then(function(xls64) {
|
||
var data = new Blob([xls64], {
|
||
type:
|
||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
})
|
||
|
||
if ('msSaveOrOpenBlob' in navigator) {
|
||
// ie使用的下载方式
|
||
window.navigator.msSaveOrOpenBlob(
|
||
data,
|
||
'Payment Summary_' + that.listQuery.StatisticsDate + '.xlsx'
|
||
)
|
||
} else {
|
||
var a = document.createElement('a')
|
||
|
||
var url = URL.createObjectURL(data)
|
||
a.href = url
|
||
a.download =
|
||
'Payment Summary_' + that.listQuery.StatisticsDate + '.xlsx'
|
||
document.body.appendChild(a)
|
||
a.click()
|
||
setTimeout(function() {
|
||
document.body.removeChild(a)
|
||
window.URL.revokeObjectURL(url)
|
||
}, 0)
|
||
}
|
||
})
|
||
},
|
||
...mapMutations({
|
||
setQueryParam: 'financials/SET_PAYMENTQUERYPARAM'
|
||
})
|
||
}
|
||
}
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
.monthly-payment {
|
||
height: 100%;
|
||
.filter-container {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.mr {
|
||
margin-right: 5px;
|
||
width: 150px;
|
||
}
|
||
.el-table {
|
||
overflow: visible !important;
|
||
}
|
||
.el-table .cell {
|
||
white-space: nowrap;
|
||
}
|
||
.list-container {
|
||
margin-top: 10px;
|
||
height: calc(100% - 100px);
|
||
}
|
||
}
|
||
</style>
|