Browse Source

1

yuhongzhe
于宏哲PHP 11 months ago
parent
commit
0ed8684db6
  1. 31
      admin/src/app/api/reimbursement.ts
  2. 33
      admin/src/app/api/salary.ts
  3. 37
      admin/src/app/lang/zh-cn/reimbursement.reimbursement.json
  4. 60
      admin/src/app/lang/zh-cn/salary.salary.json
  5. 16
      admin/src/app/views/campus_person_role/campus_person_role.vue
  6. 2
      admin/src/app/views/course/components/course-edit.vue
  7. 62
      admin/src/app/views/course/course.vue
  8. 309
      admin/src/app/views/reimbursement/components/reimbursement-edit.vue
  9. 347
      admin/src/app/views/reimbursement/reimbursement.vue
  10. 471
      admin/src/app/views/salary/components/salary-edit.vue
  11. 474
      admin/src/app/views/salary/salary.vue
  12. 12
      niucloud/app/adminapi/controller/reimbursement/Reimbursement.php
  13. 32
      niucloud/app/adminapi/controller/salary/Salary.php
  14. 6
      niucloud/app/adminapi/route/reimbursement.php
  15. 8
      niucloud/app/adminapi/route/salary.php
  16. 80
      niucloud/app/model/reimbursement/Reimbursement.php
  17. 138
      niucloud/app/model/salary/Salary.php
  18. 10
      niucloud/app/service/admin/reimbursement/ReimbursementService.php
  19. 20
      niucloud/app/service/admin/salary/SalaryService.php
  20. 6
      niucloud/app/validate/reimbursement/Reimbursement.php
  21. 10
      niucloud/app/validate/salary/Salary.php

31
admin/src/app/api/reimbursement.ts

@ -1,5 +1,13 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- reimbursement // USER_CODE_BEGIN -- reimbursement
/** /**
* *
@ -7,7 +15,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getReimbursementList(params: Record<string, any>) { export function getReimbursementList(params: Record<string, any>) {
return request.get(`reimbursement/reimbursement`, { params }) return request.get(`reimbursement/reimbursement`, {params})
} }
/** /**
@ -16,7 +24,7 @@ export function getReimbursementList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getReimbursementInfo(id: number) { export function getReimbursementInfo(id: number) {
return request.get(`reimbursement/reimbursement/${id}`) return request.get(`reimbursement/reimbursement/${id}`);
} }
/** /**
@ -25,10 +33,7 @@ export function getReimbursementInfo(id: number) {
* @returns * @returns
*/ */
export function addReimbursement(params: Record<string, any>) { export function addReimbursement(params: Record<string, any>) {
return request.post('reimbursement/reimbursement', params, { return request.post('reimbursement/reimbursement', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +43,7 @@ export function addReimbursement(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editReimbursement(params: Record<string, any>) { export function editReimbursement(params: Record<string, any>) {
return request.put(`reimbursement/reimbursement/${params.id}`, params, { return request.put(`reimbursement/reimbursement/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +52,11 @@ export function editReimbursement(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteReimbursement(id: number) { export function deleteReimbursement(id: number) {
return request.delete(`reimbursement/reimbursement/${id}`, { return request.delete(`reimbursement/reimbursement/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithPersonnelList(params: Record<string,any>){
return request.get('reimbursement/personnel_all', {params})
} }
// USER_CODE_END -- reimbursement // USER_CODE_END -- reimbursement

33
admin/src/app/api/salary.ts

@ -1,5 +1,13 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- salary // USER_CODE_BEGIN -- salary
/** /**
* *
@ -7,7 +15,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getSalaryList(params: Record<string, any>) { export function getSalaryList(params: Record<string, any>) {
return request.get(`salary/salary`, { params }) return request.get(`salary/salary`, {params})
} }
/** /**
@ -16,7 +24,7 @@ export function getSalaryList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getSalaryInfo(id: number) { export function getSalaryInfo(id: number) {
return request.get(`salary/salary/${id}`) return request.get(`salary/salary/${id}`);
} }
/** /**
@ -25,10 +33,7 @@ export function getSalaryInfo(id: number) {
* @returns * @returns
*/ */
export function addSalary(params: Record<string, any>) { export function addSalary(params: Record<string, any>) {
return request.post('salary/salary', params, { return request.post('salary/salary', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +43,7 @@ export function addSalary(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editSalary(params: Record<string, any>) { export function editSalary(params: Record<string, any>) {
return request.put(`salary/salary/${params.id}`, params, { return request.put(`salary/salary/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +52,13 @@ export function editSalary(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteSalary(id: number) { export function deleteSalary(id: number) {
return request.delete(`salary/salary/${id}`, { return request.delete(`salary/salary/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithPersonnelList(params: Record<string,any>){
return request.get('salary/personnel_all', {params})
}export function getWithDepartmentsList(params: Record<string,any>){
return request.get('salary/departments_all', {params})
} }
// USER_CODE_END -- salary // USER_CODE_END -- salary

37
admin/src/app/lang/zh-cn/reimbursement.reimbursement.json

@ -1,21 +1,20 @@
{ {
"id": "报销编号", "applicantId":"申请人",
"idPlaceholder": "请输入报销编号", "applicantIdPlaceholder":"请输入申请人",
"applicantId": "申请人ID", "amount":"报销金额",
"applicantIdPlaceholder": "请输入申请人ID", "amountPlaceholder":"请输入报销金额",
"amount": "报销金额", "description":"报销描述",
"amountPlaceholder": "请输入报销金额", "descriptionPlaceholder":"请输入报销描述",
"description": "报销描述", "receiptUrl":"发票或收据",
"descriptionPlaceholder": "请输入报销描述", "receiptUrlPlaceholder":"请输入发票或收据",
"receiptUrl": "发票或收据URL", "status":"状态",
"receiptUrlPlaceholder": "请输入发票或收据URL", "statusPlaceholder":"请输入状态",
"status": "状态", "createdAt":"创建时间",
"statusPlaceholder": "请输入状态", "createdAtPlaceholder":"请输入创建时间",
"processId": "关联的审批流程ID", "updatedAt":"修改时间",
"processIdPlaceholder": "请输入关联的审批流程ID", "addReimbursement":"添加报销记录",
"addReimbursement": "添加报销记录", "updateReimbursement":"编辑报销记录",
"updateReimbursement": "编辑报销记录", "reimbursementDeleteTips":"确定要删除该数据吗?",
"reimbursementDeleteTips": "确定要删除该数据吗?", "startDate":"请选择开始时间",
"startDate": "请选择开始时间", "endDate":"请选择结束时间"
"endDate": "请选择结束时间"
} }

60
admin/src/app/lang/zh-cn/salary.salary.json

@ -1,33 +1,31 @@
{ {
"id": "工资编号", "staffId":"员工",
"idPlaceholder": "请输入工资编号", "staffIdPlaceholder":"全部",
"staffId": "员工ID", "departmentId":"部门",
"staffIdPlaceholder": "请输入员工ID", "departmentIdPlaceholder":"全部",
"baseSalary": "底薪", "baseSalary":"底薪",
"baseSalaryPlaceholder": "请输入底薪", "baseSalaryPlaceholder":"请输入底薪",
"performanceBonus": "绩效", "performanceBonus":"绩效",
"performanceBonusPlaceholder": "请输入绩效", "performanceBonusPlaceholder":"请输入绩效",
"deductions": "扣款", "deductions":"扣款",
"deductionsPlaceholder": "请输入扣款", "deductionsPlaceholder":"请输入扣款",
"otherSubsidies": "其他补贴", "otherSubsidies":"其他补贴",
"otherSubsidiesPlaceholder": "请输入其他补贴", "otherSubsidiesPlaceholder":"请输入其他补贴",
"netSalary": "实发工资", "netSalary":"实发工资",
"netSalaryPlaceholder": "请输入实发工资", "paymentStatus":"发放状态",
"paymentStatus": "发放状态", "paymentStatusPlaceholder":"请输入发放状态",
"paymentStatusPlaceholder": "请输入发放状态", "paymentMethod":"发放方式",
"paymentMethod": "发放方式", "paymentMethodPlaceholder":"请输入发放方式",
"paymentMethodPlaceholder": "请输入发放方式", "remarks":"备注",
"remarks": "备注", "remarksPlaceholder":"请输入备注",
"remarksPlaceholder": "请输入备注", "salaryMonth":"工资月份",
"salaryMonth": "工资月份", "salaryMonthPlaceholder":"请输入工资月份",
"salaryMonthPlaceholder": "请输入工资月份", "createdAt":"创建时间",
"departmentId": "部门ID", "createdAtPlaceholder":"请输入创建时间",
"departmentIdPlaceholder": "请输入部门ID", "updatedAt":"修改时间",
"processId": "关联的审批流程ID", "addSalary":"添加工资",
"processIdPlaceholder": "请输入关联的审批流程ID", "updateSalary":"编辑工资",
"addSalary": "添加工资", "salaryDeleteTips":"确定要删除该数据吗?",
"updateSalary": "编辑工资", "startDate":"请选择开始时间",
"salaryDeleteTips": "确定要删除该数据吗?", "endDate":"请选择结束时间"
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
} }

16
admin/src/app/views/campus_person_role/campus_person_role.vue

@ -65,7 +65,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('deptId')" prop="dept_id"> <!-- <el-form-item :label="t('deptId')" prop="dept_id">
<el-select <el-select
class="w-[280px]" class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.dept_id" v-model="campusPersonRoleTable.searchParam.dept_id"
@ -79,7 +79,7 @@
:value="item['id']" :value="item['id']"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item> -->
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadCampusPersonRoleList()">{{ <el-button type="primary" @click="loadCampusPersonRoleList()">{{
@ -186,7 +186,6 @@ const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
// ?dept_id=1 // ?dept_id=1
const dept_id = pageName == '市场人员列表' ? 1 : 2;
let campusPersonRoleTable = reactive({ let campusPersonRoleTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
@ -197,10 +196,19 @@ let campusPersonRoleTable = reactive({
campus_id: '', campus_id: '',
person_id: '', person_id: '',
role_id: '', role_id: '',
dept_id: dept_id, dept_id: '',
}, },
}) })
if(pageName == '市场人员列表'){
campusPersonRoleTable.searchParam.dept_id = 1;
}else if(pageName == '销售人员列表'){
campusPersonRoleTable.searchParam.dept_id = 2;
}else if(pageName == '教练管理'){
campusPersonRoleTable.searchParam.role_id = 5;
}
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
// //

2
admin/src/app/views/course/components/course-edit.vue

@ -33,7 +33,7 @@
v-for="(item, index) in courseTypeList" v-for="(item, index) in courseTypeList"
:key="index" :key="index"
:label="item.name" :label="item.name"
:value="item.value" :value="item.name"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>

62
admin/src/app/views/course/course.vue

@ -31,56 +31,12 @@
<el-option <el-option
v-for="item in courseTypeList" v-for="item in courseTypeList"
:key="item.value" :key="item.value"
:label="item.label" :label="item.name"
:value="item.value" :value="item.name"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('duration')" prop="duration">
<el-input
v-model="courseTable.searchParam.duration"
:placeholder="t('durationPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('sessionCount')" prop="session_count">
<el-input
v-model="courseTable.searchParam.session_count"
:placeholder="t('sessionCountPlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('singleSessionCount')"
prop="single_session_count"
>
<el-input
v-model="courseTable.searchParam.single_session_count"
:placeholder="t('singleSessionCountPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('price')" prop="price">
<el-input
v-model="courseTable.searchParam.price"
:placeholder="t('pricePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('internalReminder')" prop="internal_reminder">
<el-input
v-model="courseTable.searchParam.internal_reminder"
:placeholder="t('internalReminderPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('customerReminder')" prop="customer_reminder">
<el-input
v-model="courseTable.searchParam.customer_reminder"
:placeholder="t('customerReminderPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input
v-model="courseTable.searchParam.remarks"
:placeholder="t('remarksPlaceholder')"
/>
</el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadCourseList()">{{ <el-button type="primary" @click="loadCourseList()">{{
@ -227,7 +183,17 @@ let courseTable = reactive({
remarks: '', remarks: '',
}, },
}) })
const courseTypeList = useDictionary('course_type') // const courseTypeList = useDictionary('course_type')
const courseTypeList = ref([])
const getcourseTypeList = async () => {
courseTypeList.value = await (
await useDictionary('course_type')
).data.dictionary
}
getcourseTypeList()
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
// //

309
admin/src/app/views/reimbursement/components/reimbursement-edit.vue

@ -1,86 +1,53 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateReimbursement') : t('addReimbursement')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateReimbursement') : t('addReimbursement')" <el-form-item :label="t('applicantId')" prop="applicant_id">
width="50%" <el-select class="input-width" v-model="formData.applicant_id" clearable :placeholder="t('applicantIdPlaceholder')">
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in applicantIdList"
<el-form :key="index"
:model="formData" :label="item['name']"
label-width="120px" :value="item['id']"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('amount')" prop="amount">
<el-form-item :label="t('applicantId')" prop="applicant_id"> <el-input v-model="formData.amount" clearable :placeholder="t('amountPlaceholder')" class="input-width" />
<el-input </el-form-item>
v-model="formData.applicant_id"
clearable <el-form-item :label="t('description')" prop="description">
:placeholder="t('applicantIdPlaceholder')" <el-input v-model="formData.description" clearable :placeholder="t('descriptionPlaceholder')" class="input-width" />
class="input-width" </el-form-item>
/>
</el-form-item> <el-form-item :label="t('receiptUrl')">
<upload-file v-model="formData.receipt_url" />
<el-form-item :label="t('amount')" prop="amount"> </el-form-item>
<el-input
v-model="formData.amount" <el-form-item :label="t('status')" prop="status">
clearable <el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
:placeholder="t('amountPlaceholder')" <el-option label="请选择" value=""></el-option>
class="input-width" <el-option
/> v-for="(item, index) in statusList"
</el-form-item> :key="index"
:label="item.name"
<el-form-item :label="t('description')" prop="description"> :value="item.value"
<el-input />
v-model="formData.description" </el-select>
clearable </el-form-item>
:placeholder="t('descriptionPlaceholder')"
class="input-width" </el-form>
/>
</el-form-item> <template #footer>
<span class="dialog-footer">
<el-form-item :label="t('receiptUrl')"> <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-input <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
v-model="formData.receipt_url" t('confirm')
clearable }}</el-button>
:placeholder="t('receiptUrlPlaceholder')" </span>
class="input-width" </template>
/> </el-dialog>
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-input
v-model="formData.status"
clearable
:placeholder="t('statusPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('processId')" prop="process_id">
<el-input
v-model="formData.process_id"
clearable
:placeholder="t('processIdPlaceholder')"
class="input-width"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
</span>
</template>
</el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -88,11 +55,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { import { addReimbursement, editReimbursement, getReimbursementInfo, getWithPersonnelList } from '@/app/api/reimbursement'
addReimbursement,
editReimbursement,
getReimbursementInfo,
} from '@/app/api/reimbursement'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
@ -101,13 +64,12 @@ const loading = ref(false)
* 表单数据 * 表单数据
*/ */
const initialFormData = { const initialFormData = {
id: '', id: '',
applicant_id: '', applicant_id: '',
amount: '', amount: '',
description: '', description: '',
receipt_url: '', receipt_url: '',
status: '', status: '',
process_id: '',
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -115,26 +77,33 @@ const formRef = ref<FormInstance>()
// //
const formRules = computed(() => { const formRules = computed(() => {
return { return {
applicant_id: [ applicant_id: [
{ required: true, message: t('applicantIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('applicantIdPlaceholder'), trigger: 'blur' },
],
]
,
amount: [ amount: [
{ required: true, message: t('amountPlaceholder'), trigger: 'blur' }, { required: true, message: t('amountPlaceholder'), trigger: 'blur' },
],
]
,
description: [ description: [
{ required: true, message: t('descriptionPlaceholder'), trigger: 'blur' }, { required: true, message: t('descriptionPlaceholder'), trigger: 'blur' },
],
]
,
receipt_url: [ receipt_url: [
{ required: true, message: t('receiptUrlPlaceholder'), trigger: 'blur' }, { required: true, message: t('receiptUrlPlaceholder'), trigger: 'blur' },
],
]
,
status: [ status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' }, { required: true, message: t('statusPlaceholder'), trigger: 'blur' },
],
process_id: [ ]
{ required: true, message: t('processIdPlaceholder'), trigger: 'blur' }, ,
], }
}
}) })
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
@ -144,93 +113,97 @@ const emit = defineEmits(['complete'])
* @param formEl * @param formEl
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
let save = formData.id ? editReimbursement : addReimbursement let save = formData.id ? editReimbursement : addReimbursement
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
let data = formData let data = formData
save(data) save(data).then(res => {
.then((res) => { loading.value = false
loading.value = false showDialog.value = false
showDialog.value = false emit('complete')
emit('complete') }).catch(err => {
}) loading.value = false
.catch((err) => { })
loading.value = false }
}) })
}
})
} }
// //
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('sp_status')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const applicantIdList = ref([] as any[])
const setApplicantIdList = async () => {
applicantIdList.value = await (await getWithPersonnelList({})).data
}
setApplicantIdList()
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if (row) { if(row){
const data = await (await getReimbursementInfo(row.id)).data const data = await (await getReimbursementInfo(row.id)).data
if (data) if (data) Object.keys(formData).forEach((key: string) => {
Object.keys(formData).forEach((key: string) => { if (data[key] != undefined) formData[key] = data[key]
if (data[key] != undefined) formData[key] = data[key] })
}) }
} loading.value = false
loading.value = false
} }
// //
const mobileVerify = (rule: any, value: any, callback: any) => { const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile'))) callback(new Error(t('generateMobile')))
} else { } else {
callback() callback()
} }
} }
// //
const idCardVerify = (rule: any, value: any, callback: any) => { const idCardVerify = (rule: any, value: any, callback: any) => {
if ( if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
value && callback(new Error(t('generateIdCard')))
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test( } else {
value callback()
) }
) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
} }
// //
const emailVerify = (rule: any, value: any, callback: any) => { const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) { if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail'))) callback(new Error(t('generateEmail')))
} else { } else {
callback() callback()
} }
} }
// //
const numberVerify = (rule: any, value: any, callback: any) => { const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) { if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber'))) callback(new Error(t('generateNumber')))
} else { } else {
callback() callback()
} }
} }
defineExpose({ defineExpose({
showDialog, showDialog,
setFormData, setFormData
}) })
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>
<style lang="scss"> <style lang="scss">
.diy-dialog-wrap .el-form-item__label { .diy-dialog-wrap .el-form-item__label{
height: auto !important; height: auto !important;
} }
</style> </style>

347
admin/src/app/views/reimbursement/reimbursement.vue

@ -1,182 +1,106 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addReimbursement') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addReimbursement') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="reimbursementTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('status')" prop="status">
:inline="true" <el-select class="w-[280px]" v-model="reimbursementTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
:model="reimbursementTable.searchParam" <el-option label="全部" value=""></el-option>
ref="searchFormRef" <el-option
> v-for="(item, index) in statusList"
<el-form-item :label="t('applicantId')" prop="applicant_id"> :key="index"
<el-input :label="item.name"
v-model="reimbursementTable.searchParam.applicant_id" :value="item.value"
:placeholder="t('applicantIdPlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('amount')" prop="amount">
<el-input <el-form-item :label="t('createdAt')" prop="created_at">
v-model="reimbursementTable.searchParam.amount" <el-date-picker v-model="reimbursementTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:placeholder="t('amountPlaceholder')" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('description')" prop="description"> <el-form-item>
<el-input <el-button type="primary" @click="loadReimbursementList()">{{ t('search') }}</el-button>
v-model="reimbursementTable.searchParam.description" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('descriptionPlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('receiptUrl')" prop="receipt_url">
<el-input <div class="mt-[10px]">
v-model="reimbursementTable.searchParam.receipt_url" <el-table :data="reimbursementTable.data" size="large" v-loading="reimbursementTable.loading">
:placeholder="t('receiptUrlPlaceholder')" <template #empty>
/> <span>{{ !reimbursementTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-form-item :label="t('status')" prop="status"> <el-table-column prop="applicant_id_name" :label="t('applicantId')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="reimbursementTable.searchParam.status" <el-table-column prop="amount" :label="t('amount')" min-width="120" :show-overflow-tooltip="true"/>
:placeholder="t('statusPlaceholder')"
/> <el-table-column prop="description" :label="t('description')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-form-item :label="t('processId')" prop="process_id"> <el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<el-input <template #default="{ row }">
v-model="reimbursementTable.searchParam.process_id" <div v-for="(item, index) in statusList">
:placeholder="t('processIdPlaceholder')" <div v-if="item.value == row.status">{{ item.name }}</div>
/> </div>
</el-form-item> </template>
</el-table-column>
<el-form-item>
<el-button type="primary" @click="loadReimbursementList()">{{ <el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
t('search')
}}</el-button> <el-table-column prop="updated_at" :label="t('updatedAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-button @click="resetForm(searchFormRef)">{{
t('reset') <el-table-column :label="t('operation')" fixed="right" min-width="120">
}}</el-button> <template #default="{ row }">
</el-form-item> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
</el-form> <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</el-card> </template>
</el-table-column>
<div class="mt-[10px]">
<el-table </el-table>
:data="reimbursementTable.data" <div class="mt-[16px] flex justify-end">
size="large" <el-pagination v-model:current-page="reimbursementTable.page" v-model:page-size="reimbursementTable.limit"
v-loading="reimbursementTable.loading" layout="total, sizes, prev, pager, next, jumper" :total="reimbursementTable.total"
> @size-change="loadReimbursementList()" @current-change="loadReimbursementList" />
<template #empty> </div>
<span>{{ !reimbursementTable.loading ? t('emptyData') : '' }}</span> </div>
</template>
<el-table-column <edit ref="editReimbursementDialog" @complete="loadReimbursementList" />
prop="applicant_id" </el-card>
:label="t('applicantId')" </div>
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="amount"
:label="t('amount')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="description"
:label="t('description')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="receipt_url"
:label="t('receiptUrl')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="status"
:label="t('status')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="process_id"
:label="t('processId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="reimbursementTable.page"
v-model:page-size="reimbursementTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="reimbursementTable.total"
@size-change="loadReimbursementList()"
@current-change="loadReimbursementList"
/>
</div>
</div>
<edit ref="editReimbursementDialog" @complete="loadReimbursementList" />
</el-card>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { import { getReimbursementList, deleteReimbursement, getWithPersonnelList } from '@/app/api/reimbursement'
getReimbursementList,
deleteReimbursement,
} from '@/app/api/reimbursement'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/reimbursement/components/reimbursement-edit.vue' import Edit from '@/app/views/reimbursement/components/reimbursement-edit.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title;
let reimbursementTable = reactive({ let reimbursementTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam:{
applicant_id: '', "status":"",
amount: '', "created_at":[]
description: '', }
receipt_url: '',
status: '',
process_id: '',
},
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -185,26 +109,29 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([]) const selectData = ref<any[]>([])
// //
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('sp_status')).data.dictionary
}
statusDictList();
/** /**
* 获取报销记录列表 * 获取报销记录列表
*/ */
const loadReimbursementList = (page: number = 1) => { const loadReimbursementList = (page: number = 1) => {
reimbursementTable.loading = true reimbursementTable.loading = true
reimbursementTable.page = page reimbursementTable.page = page
getReimbursementList({ getReimbursementList({
page: reimbursementTable.page, page: reimbursementTable.page,
limit: reimbursementTable.limit, limit: reimbursementTable.limit,
...reimbursementTable.searchParam, ...reimbursementTable.searchParam
}) }).then(res => {
.then((res) => { reimbursementTable.loading = false
reimbursementTable.loading = false reimbursementTable.data = res.data.data
reimbursementTable.data = res.data.data reimbursementTable.total = res.data.total
reimbursementTable.total = res.data.total }).catch(() => {
}) reimbursementTable.loading = false
.catch(() => {
reimbursementTable.loading = false
}) })
} }
loadReimbursementList() loadReimbursementList()
@ -215,8 +142,8 @@ const editReimbursementDialog: Record<string, any> | null = ref(null)
* 添加报销记录 * 添加报销记录
*/ */
const addEvent = () => { const addEvent = () => {
editReimbursementDialog.value.setFormData() editReimbursementDialog.value.setFormData()
editReimbursementDialog.value.showDialog = true editReimbursementDialog.value.showDialog = true
} }
/** /**
@ -224,42 +151,50 @@ const addEvent = () => {
* @param data * @param data
*/ */
const editEvent = (data: any) => { const editEvent = (data: any) => {
editReimbursementDialog.value.setFormData(data) editReimbursementDialog.value.setFormData(data)
editReimbursementDialog.value.showDialog = true editReimbursementDialog.value.showDialog = true
} }
/** /**
* 删除报销记录 * 删除报销记录
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('reimbursementDeleteTips'), t('warning'), { ElMessageBox.confirm(t('reimbursementDeleteTips'), t('warning'),
confirmButtonText: t('confirm'), {
cancelButtonText: t('cancel'), confirmButtonText: t('confirm'),
type: 'warning', cancelButtonText: t('cancel'),
}).then(() => { type: 'warning',
deleteReimbursement(id) }
.then(() => { ).then(() => {
loadReimbursementList() deleteReimbursement(id).then(() => {
}) loadReimbursementList()
.catch(() => {}) }).catch(() => {
}) })
})
} }
const applicantIdList = ref([])
const setApplicantIdList = async () => {
applicantIdList.value = await (await getWithPersonnelList({})).data
}
setApplicantIdList()
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadReimbursementList() loadReimbursementList()
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 多行超出隐藏 */ /* 多行超出隐藏 */
.multi-hidden { .multi-hidden {
word-break: break-all; word-break: break-all;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
</style> </style>

471
admin/src/app/views/salary/components/salary-edit.vue

@ -1,140 +1,94 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateSalary') : t('addSalary')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateSalary') : t('addSalary')" <el-form-item :label="t('staffId')" prop="staff_id">
width="50%" <el-select class="input-width" v-model="formData.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in staffIdList"
<el-form :key="index"
:model="formData" :label="item['name']"
label-width="120px" :value="item['id']"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('departmentId')" prop="department_id">
<el-form-item :label="t('staffId')" prop="staff_id"> <el-select class="input-width" v-model="formData.department_id" clearable :placeholder="t('departmentIdPlaceholder')">
<el-input <el-option label="请选择" value=""></el-option>
v-model="formData.staff_id" <el-option
clearable v-for="(item, index) in departmentIdList"
:placeholder="t('staffIdPlaceholder')" :key="index"
class="input-width" :label="item['department_name']"
/> :value="item['id']"
</el-form-item> />
</el-select>
<el-form-item :label="t('baseSalary')" prop="base_salary"> </el-form-item>
<el-input
v-model="formData.base_salary" <el-form-item :label="t('baseSalary')" prop="base_salary">
clearable <el-input v-model="formData.base_salary" clearable :placeholder="t('baseSalaryPlaceholder')" class="input-width" />
:placeholder="t('baseSalaryPlaceholder')" </el-form-item>
class="input-width"
/> <el-form-item :label="t('performanceBonus')" prop="performance_bonus">
</el-form-item> <el-input v-model="formData.performance_bonus" clearable :placeholder="t('performanceBonusPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('performanceBonus')" prop="performance_bonus">
<el-input <el-form-item :label="t('deductions')" prop="deductions">
v-model="formData.performance_bonus" <el-input v-model="formData.deductions" clearable :placeholder="t('deductionsPlaceholder')" class="input-width" />
clearable </el-form-item>
:placeholder="t('performanceBonusPlaceholder')"
class="input-width" <el-form-item :label="t('otherSubsidies')" prop="other_subsidies">
/> <el-input v-model="formData.other_subsidies" clearable :placeholder="t('otherSubsidiesPlaceholder')" class="input-width" />
</el-form-item> </el-form-item>
<el-form-item :label="t('deductions')" prop="deductions"> <el-form-item :label="t('paymentStatus')" prop="payment_status">
<el-input <el-select class="input-width" v-model="formData.payment_status" clearable :placeholder="t('paymentStatusPlaceholder')">
v-model="formData.deductions" <el-option label="请选择" value=""></el-option>
clearable <el-option
:placeholder="t('deductionsPlaceholder')" v-for="(item, index) in payment_statusList"
class="input-width" :key="index"
/> :label="item.name"
</el-form-item> :value="item.value"
/>
<el-form-item :label="t('otherSubsidies')"> </el-select>
<el-input </el-form-item>
v-model="formData.other_subsidies"
clearable <el-form-item :label="t('paymentMethod')" prop="payment_method">
:placeholder="t('otherSubsidiesPlaceholder')" <el-select class="input-width" v-model="formData.payment_method" clearable :placeholder="t('paymentMethodPlaceholder')">
class="input-width" <el-option label="请选择" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in payment_methodList"
:key="index"
<el-form-item :label="t('netSalary')"> :label="item.name"
<el-input :value="item.value"
v-model="formData.net_salary" />
clearable </el-select>
:placeholder="t('netSalaryPlaceholder')" </el-form-item>
class="input-width"
/> <el-form-item :label="t('remarks')" >
</el-form-item> <el-input v-model="formData.remarks" type="textarea" rows="4" clearable :placeholder="t('remarksPlaceholder')" class="input-width"/>
</el-form-item>
<el-form-item :label="t('paymentStatus')" prop="payment_status"> <el-form-item :label="t('salaryMonth')" prop="salary_month" class="input-width">
<el-input <el-date-picker
v-model="formData.payment_status" class="flex-1 !flex"
clearable v-model="formData.salary_month"
:placeholder="t('paymentStatusPlaceholder')" clearable
class="input-width" type="date"
/> value-format="YYYY-MM-DD"
</el-form-item> :placeholder="t('salaryMonthPlaceholder')">
</el-date-picker>
<el-form-item :label="t('paymentMethod')"> </el-form-item>
<el-input </el-form>
v-model="formData.payment_method"
clearable <template #footer>
:placeholder="t('paymentMethodPlaceholder')" <span class="dialog-footer">
class="input-width" <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
/> <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
</el-form-item> t('confirm')
}}</el-button>
<el-form-item :label="t('remarks')"> </span>
<el-input </template>
v-model="formData.remarks" </el-dialog>
clearable
:placeholder="t('remarksPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('salaryMonth')" prop="salary_month">
<el-input
v-model="formData.salary_month"
clearable
:placeholder="t('salaryMonthPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('departmentId')">
<el-input
v-model="formData.department_id"
clearable
:placeholder="t('departmentIdPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('processId')">
<el-input
v-model="formData.process_id"
clearable
:placeholder="t('processIdPlaceholder')"
class="input-width"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
</span>
</template>
</el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -142,7 +96,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { addSalary, editSalary, getSalaryInfo } from '@/app/api/salary' import { addSalary, editSalary, getSalaryInfo, getWithPersonnelList, getWithDepartmentsList } from '@/app/api/salary'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
@ -151,19 +105,17 @@ const loading = ref(false)
* 表单数据 * 表单数据
*/ */
const initialFormData = { const initialFormData = {
id: '', id: '',
staff_id: '', staff_id: '',
base_salary: '', department_id: '',
performance_bonus: '', base_salary: '',
deductions: '', performance_bonus: '',
other_subsidies: '', deductions: '',
net_salary: '', other_subsidies: '',
payment_status: '', payment_status: '',
payment_method: '', payment_method: '',
remarks: '', remarks: '',
salary_month: '', salary_month: '',
department_id: '',
process_id: '',
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -171,64 +123,58 @@ const formRef = ref<FormInstance>()
// //
const formRules = computed(() => { const formRules = computed(() => {
return { return {
staff_id: [ staff_id: [
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
],
]
,
department_id: [
{ required: true, message: t('departmentIdPlaceholder'), trigger: 'blur' },
]
,
base_salary: [ base_salary: [
{ required: true, message: t('baseSalaryPlaceholder'), trigger: 'blur' }, { required: true, message: t('baseSalaryPlaceholder'), trigger: 'blur' },
],
]
,
performance_bonus: [ performance_bonus: [
{ { required: true, message: t('performanceBonusPlaceholder'), trigger: 'blur' },
required: true,
message: t('performanceBonusPlaceholder'), ]
trigger: 'blur', ,
},
],
deductions: [ deductions: [
{ required: true, message: t('deductionsPlaceholder'), trigger: 'blur' }, { required: true, message: t('deductionsPlaceholder'), trigger: 'blur' },
],
]
,
other_subsidies: [ other_subsidies: [
{ { required: true, message: t('otherSubsidiesPlaceholder'), trigger: 'blur' },
required: true,
message: t('otherSubsidiesPlaceholder'), ]
trigger: 'blur', ,
},
],
net_salary: [
{ required: true, message: t('netSalaryPlaceholder'), trigger: 'blur' },
],
payment_status: [ payment_status: [
{ { required: true, message: t('paymentStatusPlaceholder'), trigger: 'blur' },
required: true,
message: t('paymentStatusPlaceholder'), ]
trigger: 'blur', ,
},
],
payment_method: [ payment_method: [
{ { required: true, message: t('paymentMethodPlaceholder'), trigger: 'blur' },
required: true,
message: t('paymentMethodPlaceholder'), ]
trigger: 'blur', ,
},
],
remarks: [ remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' }, { required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
],
]
,
salary_month: [ salary_month: [
{ required: true, message: t('salaryMonthPlaceholder'), trigger: 'blur' }, { required: true, message: t('salaryMonthPlaceholder'), trigger: 'blur' },
],
department_id: [ ]
{ ,
required: true, }
message: t('departmentIdPlaceholder'),
trigger: 'blur',
},
],
process_id: [
{ required: true, message: t('processIdPlaceholder'), trigger: 'blur' },
],
}
}) })
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
@ -238,93 +184,108 @@ const emit = defineEmits(['complete'])
* @param formEl * @param formEl
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
let save = formData.id ? editSalary : addSalary let save = formData.id ? editSalary : addSalary
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
let data = formData let data = formData
save(data) save(data).then(res => {
.then((res) => { loading.value = false
loading.value = false showDialog.value = false
showDialog.value = false emit('complete')
emit('complete') }).catch(err => {
}) loading.value = false
.catch((err) => { })
loading.value = false }
}) })
}
})
} }
// //
let payment_statusList = ref([])
const payment_statusDictList = async () => {
payment_statusList.value = await (await useDictionary('payment_status')).data.dictionary
}
payment_statusDictList();
watch(() => payment_statusList.value, () => { formData.payment_status = payment_statusList.value[0].value })
let payment_methodList = ref([])
const payment_methodDictList = async () => {
payment_methodList.value = await (await useDictionary('payment_method')).data.dictionary
}
payment_methodDictList();
watch(() => payment_methodList.value, () => { formData.payment_method = payment_methodList.value[0].value })
const staffIdList = ref([] as any[])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const departmentIdList = ref([] as any[])
const setDepartmentIdList = async () => {
departmentIdList.value = await (await getWithDepartmentsList({})).data
}
setDepartmentIdList()
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if (row) { if(row){
const data = await (await getSalaryInfo(row.id)).data const data = await (await getSalaryInfo(row.id)).data
if (data) if (data) Object.keys(formData).forEach((key: string) => {
Object.keys(formData).forEach((key: string) => { if (data[key] != undefined) formData[key] = data[key]
if (data[key] != undefined) formData[key] = data[key] })
}) }
} loading.value = false
loading.value = false
} }
// //
const mobileVerify = (rule: any, value: any, callback: any) => { const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile'))) callback(new Error(t('generateMobile')))
} else { } else {
callback() callback()
} }
} }
// //
const idCardVerify = (rule: any, value: any, callback: any) => { const idCardVerify = (rule: any, value: any, callback: any) => {
if ( if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
value && callback(new Error(t('generateIdCard')))
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test( } else {
value callback()
) }
) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
} }
// //
const emailVerify = (rule: any, value: any, callback: any) => { const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) { if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail'))) callback(new Error(t('generateEmail')))
} else { } else {
callback() callback()
} }
} }
// //
const numberVerify = (rule: any, value: any, callback: any) => { const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) { if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber'))) callback(new Error(t('generateNumber')))
} else { } else {
callback() callback()
} }
} }
defineExpose({ defineExpose({
showDialog, showDialog,
setFormData, setFormData
}) })
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>
<style lang="scss"> <style lang="scss">
.diy-dialog-wrap .el-form-item__label { .diy-dialog-wrap .el-form-item__label{
height: auto !important; height: auto !important;
} }
</style> </style>

474
admin/src/app/views/salary/salary.vue

@ -1,263 +1,142 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addSalary') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addSalary') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="salaryTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('staffId')" prop="staff_id">
:inline="true" <el-select class="w-[280px]" v-model="salaryTable.searchParam.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
:model="salaryTable.searchParam" <el-option
ref="searchFormRef" v-for="(item, index) in staffIdList"
> :key="index"
<el-form-item :label="t('staffId')" prop="staff_id"> :label="item['name']"
<el-input :value="item['id']"
v-model="salaryTable.searchParam.staff_id" />
:placeholder="t('staffIdPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('baseSalary')" prop="base_salary">
<el-input <el-form-item :label="t('departmentId')" prop="department_id">
v-model="salaryTable.searchParam.base_salary" <el-select class="w-[280px]" v-model="salaryTable.searchParam.department_id" clearable :placeholder="t('departmentIdPlaceholder')">
:placeholder="t('baseSalaryPlaceholder')" <el-option
/> v-for="(item, index) in departmentIdList"
</el-form-item> :key="index"
<el-form-item :label="t('performanceBonus')" prop="performance_bonus"> :label="item['department_name']"
<el-input :value="item['id']"
v-model="salaryTable.searchParam.performance_bonus" />
:placeholder="t('performanceBonusPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('deductions')" prop="deductions">
<el-input <el-form-item :label="t('paymentStatus')" prop="payment_status">
v-model="salaryTable.searchParam.deductions" <el-select class="w-[280px]" v-model="salaryTable.searchParam.payment_status" clearable :placeholder="t('paymentStatusPlaceholder')">
:placeholder="t('deductionsPlaceholder')" <el-option label="全部" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in payment_statusList"
<el-form-item :label="t('otherSubsidies')" prop="other_subsidies"> :key="index"
<el-input :label="item.name"
v-model="salaryTable.searchParam.other_subsidies" :value="item.value"
:placeholder="t('otherSubsidiesPlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('netSalary')" prop="net_salary">
<el-input <el-form-item :label="t('createdAt')" prop="created_at">
v-model="salaryTable.searchParam.net_salary" <el-date-picker v-model="salaryTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:placeholder="t('netSalaryPlaceholder')" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('paymentStatus')" prop="payment_status"> <el-form-item>
<el-input <el-button type="primary" @click="loadSalaryList()">{{ t('search') }}</el-button>
v-model="salaryTable.searchParam.payment_status" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('paymentStatusPlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('paymentMethod')" prop="payment_method">
<el-input <div class="mt-[10px]">
v-model="salaryTable.searchParam.payment_method" <el-table :data="salaryTable.data" size="large" v-loading="salaryTable.loading">
:placeholder="t('paymentMethodPlaceholder')" <template #empty>
/> <span>{{ !salaryTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-form-item :label="t('remarks')" prop="remarks"> <el-table-column prop="staff_id_name" :label="t('staffId')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="salaryTable.searchParam.remarks" <el-table-column prop="department_id_name" :label="t('departmentId')" min-width="120" :show-overflow-tooltip="true"/>
:placeholder="t('remarksPlaceholder')"
/> <el-table-column prop="net_salary" :label="t('netSalary')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-form-item :label="t('salaryMonth')" prop="salary_month"> <el-table-column :label="t('paymentStatus')" min-width="180" align="center" :show-overflow-tooltip="true">
<el-input <template #default="{ row }">
v-model="salaryTable.searchParam.salary_month" <div v-for="(item, index) in payment_statusList">
:placeholder="t('salaryMonthPlaceholder')" <div v-if="item.value == row.payment_status">{{ item.name }}</div>
/> </div>
</el-form-item> </template>
<el-form-item :label="t('departmentId')" prop="department_id"> </el-table-column>
<el-input
v-model="salaryTable.searchParam.department_id" <el-table-column :label="t('paymentMethod')" min-width="180" align="center" :show-overflow-tooltip="true">
:placeholder="t('departmentIdPlaceholder')" <template #default="{ row }">
/> <div v-for="(item, index) in payment_methodList">
</el-form-item> <div v-if="item.value == row.payment_method">{{ item.name }}</div>
<el-form-item :label="t('processId')" prop="process_id"> </div>
<el-input </template>
v-model="salaryTable.searchParam.process_id" </el-table-column>
:placeholder="t('processIdPlaceholder')"
/> <el-table-column prop="salary_month" :label="t('salaryMonth')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item>
<el-button type="primary" @click="loadSalaryList()">{{ <el-table-column prop="updated_at" :label="t('updatedAt')" min-width="120" :show-overflow-tooltip="true"/>
t('search')
}}</el-button> <el-table-column :label="t('operation')" fixed="right" min-width="120">
<el-button @click="resetForm(searchFormRef)">{{ <template #default="{ row }">
t('reset') <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
}}</el-button> <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</el-form-item> </template>
</el-form> </el-table-column>
</el-card>
</el-table>
<div class="mt-[10px]"> <div class="mt-[16px] flex justify-end">
<el-table <el-pagination v-model:current-page="salaryTable.page" v-model:page-size="salaryTable.limit"
:data="salaryTable.data" layout="total, sizes, prev, pager, next, jumper" :total="salaryTable.total"
size="large" @size-change="loadSalaryList()" @current-change="loadSalaryList" />
v-loading="salaryTable.loading" </div>
> </div>
<template #empty>
<span>{{ !salaryTable.loading ? t('emptyData') : '' }}</span> <edit ref="editSalaryDialog" @complete="loadSalaryList" />
</template> </el-card>
<el-table-column </div>
prop="staff_id"
:label="t('staffId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="base_salary"
:label="t('baseSalary')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="performance_bonus"
:label="t('performanceBonus')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="deductions"
:label="t('deductions')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="other_subsidies"
:label="t('otherSubsidies')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="net_salary"
:label="t('netSalary')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="payment_status"
:label="t('paymentStatus')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="payment_method"
:label="t('paymentMethod')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="remarks"
:label="t('remarks')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="salary_month"
:label="t('salaryMonth')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="department_id"
:label="t('departmentId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="process_id"
:label="t('processId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="salaryTable.page"
v-model:page-size="salaryTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="salaryTable.total"
@size-change="loadSalaryList()"
@current-change="loadSalaryList"
/>
</div>
</div>
<edit ref="editSalaryDialog" @complete="loadSalaryList" />
</el-card>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { getSalaryList, deleteSalary } from '@/app/api/salary' import { getSalaryList, deleteSalary, getWithPersonnelList, getWithDepartmentsList } from '@/app/api/salary'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/salary/components/salary-edit.vue' import Edit from '@/app/views/salary/components/salary-edit.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title;
let salaryTable = reactive({ let salaryTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam:{
staff_id: '', "staff_id":"",
base_salary: '', "department_id":"",
performance_bonus: '', "payment_status":"",
deductions: '', "created_at":[]
other_subsidies: '', }
net_salary: '',
payment_status: '',
payment_method: '',
remarks: '',
salary_month: '',
department_id: '',
process_id: '',
},
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -266,26 +145,34 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([]) const selectData = ref<any[]>([])
// //
const payment_statusList = ref([] as any[])
const payment_statusDictList = async () => {
payment_statusList.value = await (await useDictionary('payment_status')).data.dictionary
}
payment_statusDictList();
const payment_methodList = ref([] as any[])
const payment_methodDictList = async () => {
payment_methodList.value = await (await useDictionary('payment_method')).data.dictionary
}
payment_methodDictList();
/** /**
* 获取工资列表 * 获取工资列表
*/ */
const loadSalaryList = (page: number = 1) => { const loadSalaryList = (page: number = 1) => {
salaryTable.loading = true salaryTable.loading = true
salaryTable.page = page salaryTable.page = page
getSalaryList({ getSalaryList({
page: salaryTable.page, page: salaryTable.page,
limit: salaryTable.limit, limit: salaryTable.limit,
...salaryTable.searchParam, ...salaryTable.searchParam
}) }).then(res => {
.then((res) => { salaryTable.loading = false
salaryTable.loading = false salaryTable.data = res.data.data
salaryTable.data = res.data.data salaryTable.total = res.data.total
salaryTable.total = res.data.total }).catch(() => {
}) salaryTable.loading = false
.catch(() => {
salaryTable.loading = false
}) })
} }
loadSalaryList() loadSalaryList()
@ -296,8 +183,8 @@ const editSalaryDialog: Record<string, any> | null = ref(null)
* 添加工资 * 添加工资
*/ */
const addEvent = () => { const addEvent = () => {
editSalaryDialog.value.setFormData() editSalaryDialog.value.setFormData()
editSalaryDialog.value.showDialog = true editSalaryDialog.value.showDialog = true
} }
/** /**
@ -305,42 +192,55 @@ const addEvent = () => {
* @param data * @param data
*/ */
const editEvent = (data: any) => { const editEvent = (data: any) => {
editSalaryDialog.value.setFormData(data) editSalaryDialog.value.setFormData(data)
editSalaryDialog.value.showDialog = true editSalaryDialog.value.showDialog = true
} }
/** /**
* 删除工资 * 删除工资
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('salaryDeleteTips'), t('warning'), { ElMessageBox.confirm(t('salaryDeleteTips'), t('warning'),
confirmButtonText: t('confirm'), {
cancelButtonText: t('cancel'), confirmButtonText: t('confirm'),
type: 'warning', cancelButtonText: t('cancel'),
}).then(() => { type: 'warning',
deleteSalary(id) }
.then(() => { ).then(() => {
loadSalaryList() deleteSalary(id).then(() => {
}) loadSalaryList()
.catch(() => {}) }).catch(() => {
}) })
})
} }
const staffIdList = ref([])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const departmentIdList = ref([])
const setDepartmentIdList = async () => {
departmentIdList.value = await (await getWithDepartmentsList({})).data
}
setDepartmentIdList()
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadSalaryList() loadSalaryList()
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 多行超出隐藏 */ /* 多行超出隐藏 */
.multi-hidden { .multi-hidden {
word-break: break-all; word-break: break-all;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
</style> </style>

12
niucloud/app/adminapi/controller/reimbursement/Reimbursement.php

@ -28,12 +28,8 @@ class Reimbursement extends BaseAdminController
*/ */
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["applicant_id",""],
["amount",""],
["description",""],
["receipt_url",""],
["status",""], ["status",""],
["process_id",""] ["created_at",["",""]]
]); ]);
return success((new ReimbursementService())->getPage($data)); return success((new ReimbursementService())->getPage($data));
} }
@ -58,7 +54,6 @@ class Reimbursement extends BaseAdminController
["description",""], ["description",""],
["receipt_url",""], ["receipt_url",""],
["status",""], ["status",""],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\reimbursement\Reimbursement.add'); $this->validate($data, 'app\validate\reimbursement\Reimbursement.add');
@ -78,7 +73,6 @@ class Reimbursement extends BaseAdminController
["description",""], ["description",""],
["receipt_url",""], ["receipt_url",""],
["status",""], ["status",""],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\reimbursement\Reimbursement.edit'); $this->validate($data, 'app\validate\reimbursement\Reimbursement.edit');
@ -97,4 +91,8 @@ class Reimbursement extends BaseAdminController
} }
public function getPersonnelAll(){
return success(( new ReimbursementService())->getPersonnelAll());
}
} }

32
niucloud/app/adminapi/controller/salary/Salary.php

@ -29,17 +29,9 @@ class Salary extends BaseAdminController
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["staff_id",""], ["staff_id",""],
["base_salary",""],
["performance_bonus",""],
["deductions",""],
["other_subsidies",""],
["net_salary",""],
["payment_status",""],
["payment_method",""],
["remarks",""],
["salary_month",""],
["department_id",""], ["department_id",""],
["process_id",""] ["payment_status",""],
["created_at",["",""]]
]); ]);
return success((new SalaryService())->getPage($data)); return success((new SalaryService())->getPage($data));
} }
@ -60,17 +52,15 @@ class Salary extends BaseAdminController
public function add(){ public function add(){
$data = $this->request->params([ $data = $this->request->params([
["staff_id",0], ["staff_id",0],
["department_id",0],
["base_salary",0.00], ["base_salary",0.00],
["performance_bonus",0.00], ["performance_bonus",0.00],
["deductions",0.00], ["deductions",0.00],
["other_subsidies",0.00], ["other_subsidies",0.00],
["net_salary",0.00],
["payment_status",""], ["payment_status",""],
["payment_method",""], ["payment_method",""],
["remarks",""], ["remarks",""],
["salary_month","2025-05-16 17:53:32"], ["salary_month","2025-05-22 18:20:42"],
["department_id",0],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\salary\Salary.add'); $this->validate($data, 'app\validate\salary\Salary.add');
@ -86,17 +76,15 @@ class Salary extends BaseAdminController
public function edit(int $id){ public function edit(int $id){
$data = $this->request->params([ $data = $this->request->params([
["staff_id",0], ["staff_id",0],
["department_id",0],
["base_salary",0.00], ["base_salary",0.00],
["performance_bonus",0.00], ["performance_bonus",0.00],
["deductions",0.00], ["deductions",0.00],
["other_subsidies",0.00], ["other_subsidies",0.00],
["net_salary",0.00],
["payment_status",""], ["payment_status",""],
["payment_method",""], ["payment_method",""],
["remarks",""], ["remarks",""],
["salary_month","2025-05-16 17:53:32"], ["salary_month","2025-05-22 18:20:42"],
["department_id",0],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\salary\Salary.edit'); $this->validate($data, 'app\validate\salary\Salary.edit');
@ -115,4 +103,12 @@ class Salary extends BaseAdminController
} }
public function getPersonnelAll(){
return success(( new SalaryService())->getPersonnelAll());
}
public function getDepartmentsAll(){
return success(( new SalaryService())->getDepartmentsAll());
}
} }

6
niucloud/app/adminapi/route/reimbursement.php

@ -14,6 +14,10 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole; use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- reimbursement // USER_CODE_BEGIN -- reimbursement
Route::group('reimbursement', function () { Route::group('reimbursement', function () {
@ -29,6 +33,8 @@ Route::group('reimbursement', function () {
//删除报销记录 //删除报销记录
Route::delete('reimbursement/:id', 'reimbursement.Reimbursement/del'); Route::delete('reimbursement/:id', 'reimbursement.Reimbursement/del');
Route::get('personnel_all','reimbursement.Reimbursement/getPersonnelAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

8
niucloud/app/adminapi/route/salary.php

@ -14,6 +14,10 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole; use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- salary // USER_CODE_BEGIN -- salary
Route::group('salary', function () { Route::group('salary', function () {
@ -29,6 +33,10 @@ Route::group('salary', function () {
//删除工资 //删除工资
Route::delete('salary/:id', 'salary.Salary/del'); Route::delete('salary/:id', 'salary.Salary/del');
Route::get('personnel_all','salary.Salary/getPersonnelAll');
Route::get('departments_all','salary.Salary/getDepartmentsAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

80
niucloud/app/model/reimbursement/Reimbursement.php

@ -16,6 +16,8 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\personnel\Personnel;
/** /**
* 报销记录模型 * 报销记录模型
* Class Reimbursement * Class Reimbursement
@ -42,66 +44,6 @@ class Reimbursement extends BaseModel
/**
* 搜索器:报销记录报销编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:报销记录申请人ID
* @param $value
* @param $data
*/
public function searchApplicantIdAttr($query, $value, $data)
{
if ($value) {
$query->where("applicant_id", $value);
}
}
/**
* 搜索器:报销记录报销金额
* @param $value
* @param $data
*/
public function searchAmountAttr($query, $value, $data)
{
if ($value) {
$query->where("amount", $value);
}
}
/**
* 搜索器:报销记录报销描述
* @param $value
* @param $data
*/
public function searchDescriptionAttr($query, $value, $data)
{
if ($value) {
$query->where("description", $value);
}
}
/**
* 搜索器:报销记录发票或收据URL
* @param $value
* @param $data
*/
public function searchReceiptUrlAttr($query, $value, $data)
{
if ($value) {
$query->where("receipt_url", $value);
}
}
/** /**
* 搜索器:报销记录状态 * 搜索器:报销记录状态
* @param $value * @param $value
@ -115,14 +57,20 @@ class Reimbursement extends BaseModel
} }
/** /**
* 搜索器:报销记录关联的审批流程ID * 搜索器:报销记录创建时间
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchProcessIdAttr($query, $value, $data) public function searchCreatedAtAttr($query, $value, $data)
{ {
if ($value) { $start = empty($value[0]) ? 0 : strtotime($value[0]);
$query->where("process_id", $value); $end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
} }
} }
@ -131,4 +79,8 @@ class Reimbursement extends BaseModel
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'applicant_id')->joinType('left')->withField('name,id')->bind(['applicant_id_name'=>'name']);
}
} }

138
niucloud/app/model/salary/Salary.php

@ -16,6 +16,10 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\personnel\Personnel;
use app\model\departments\Departments;
/** /**
* 工资模型 * 工资模型
* Class Salary * Class Salary
@ -43,19 +47,7 @@ class Salary extends BaseModel
/** /**
* 搜索器:工资工资编号 * 搜索器:工资员工
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:工资员工ID
* @param $value * @param $value
* @param $data * @param $data
*/ */
@ -67,62 +59,14 @@ class Salary extends BaseModel
} }
/** /**
* 搜索器:工资底薪 * 搜索器:工资部门
* @param $value
* @param $data
*/
public function searchBaseSalaryAttr($query, $value, $data)
{
if ($value) {
$query->where("base_salary", $value);
}
}
/**
* 搜索器:工资绩效
* @param $value
* @param $data
*/
public function searchPerformanceBonusAttr($query, $value, $data)
{
if ($value) {
$query->where("performance_bonus", $value);
}
}
/**
* 搜索器:工资扣款
* @param $value
* @param $data
*/
public function searchDeductionsAttr($query, $value, $data)
{
if ($value) {
$query->where("deductions", $value);
}
}
/**
* 搜索器:工资其他补贴
* @param $value
* @param $data
*/
public function searchOtherSubsidiesAttr($query, $value, $data)
{
if ($value) {
$query->where("other_subsidies", $value);
}
}
/**
* 搜索器:工资实发工资
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchNetSalaryAttr($query, $value, $data) public function searchDepartmentIdAttr($query, $value, $data)
{ {
if ($value) { if ($value) {
$query->where("net_salary", $value); $query->where("department_id", $value);
} }
} }
@ -139,68 +83,34 @@ class Salary extends BaseModel
} }
/** /**
* 搜索器:工资发放方式 * 搜索器:工资创建时间
* @param $value
* @param $data
*/
public function searchPaymentMethodAttr($query, $value, $data)
{
if ($value) {
$query->where("payment_method", $value);
}
}
/**
* 搜索器:工资备注
* @param $value
* @param $data
*/
public function searchRemarksAttr($query, $value, $data)
{
if ($value) {
$query->where("remarks", $value);
}
}
/**
* 搜索器:工资工资月份
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchSalaryMonthAttr($query, $value, $data) public function searchCreatedAtAttr($query, $value, $data)
{ {
if ($value) { $start = empty($value[0]) ? 0 : strtotime($value[0]);
$query->where("salary_month", $value); $end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
} }
} }
/**
* 搜索器:工资部门ID
* @param $value
* @param $data
*/
public function searchDepartmentIdAttr($query, $value, $data)
{
if ($value) {
$query->where("department_id", $value);
}
}
/**
* 搜索器:工资关联的审批流程ID
* @param $value
* @param $data
*/
public function searchProcessIdAttr($query, $value, $data)
{
if ($value) {
$query->where("process_id", $value);
}
}
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'staff_id')->joinType('left')->withField('name,id')->bind(['staff_id_name'=>'name']);
}
public function departments(){
return $this->hasOne(Departments::class, 'id', 'department_id')->joinType('left')->withField('department_name,id')->bind(['department_id_name'=>'department_name']);
}
} }

10
niucloud/app/service/admin/reimbursement/ReimbursementService.php

@ -12,6 +12,7 @@
namespace app\service\admin\reimbursement; namespace app\service\admin\reimbursement;
use app\model\reimbursement\Reimbursement; use app\model\reimbursement\Reimbursement;
use app\model\personnel\Personnel;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -39,7 +40,7 @@ class ReimbursementService extends BaseAdminService
$field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at'; $field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","applicant_id","amount","description","receipt_url","status","process_id"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["status","created_at"], $where)->with(['personnel'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -53,7 +54,7 @@ class ReimbursementService extends BaseAdminService
{ {
$field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at'; $field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel'])->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -95,5 +96,10 @@ class ReimbursementService extends BaseAdminService
} }
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
} }

20
niucloud/app/service/admin/salary/SalaryService.php

@ -12,6 +12,8 @@
namespace app\service\admin\salary; namespace app\service\admin\salary;
use app\model\salary\Salary; use app\model\salary\Salary;
use app\model\personnel\Personnel;
use app\model\departments\Departments;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -36,10 +38,10 @@ class SalaryService extends BaseAdminService
*/ */
public function getPage(array $where = []) public function getPage(array $where = [])
{ {
$field = 'id,staff_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,department_id,process_id,created_at,updated_at'; $field = 'id,staff_id,department_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,process_id,created_at,updated_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","staff_id","base_salary","performance_bonus","deductions","other_subsidies","net_salary","payment_status","payment_method","remarks","salary_month","department_id","process_id"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["staff_id","department_id","payment_status","created_at"], $where)->with(['personnel','departments'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -51,9 +53,9 @@ class SalaryService extends BaseAdminService
*/ */
public function getInfo(int $id) public function getInfo(int $id)
{ {
$field = 'id,staff_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,department_id,process_id,created_at,updated_at'; $field = 'id,staff_id,department_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,process_id,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel','departments'])->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -95,5 +97,15 @@ class SalaryService extends BaseAdminService
} }
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
public function getDepartmentsAll(){
$departmentsModel = new Departments();
return $departmentsModel->select()->toArray();
}
} }

6
niucloud/app/validate/reimbursement/Reimbursement.php

@ -24,7 +24,6 @@ class Reimbursement extends BaseValidate
'amount' => 'require', 'amount' => 'require',
'description' => 'require', 'description' => 'require',
'status' => 'require', 'status' => 'require',
'process_id' => 'require',
]; ];
protected $message = [ protected $message = [
@ -32,12 +31,11 @@ class Reimbursement extends BaseValidate
'amount.require' => ['common_validate.require', ['amount']], 'amount.require' => ['common_validate.require', ['amount']],
'description.require' => ['common_validate.require', ['description']], 'description.require' => ['common_validate.require', ['description']],
'status.require' => ['common_validate.require', ['status']], 'status.require' => ['common_validate.require', ['status']],
'process_id.require' => ['common_validate.require', ['process_id']],
]; ];
protected $scene = [ protected $scene = [
"add" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status', 'process_id'], "add" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status'],
"edit" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status', 'process_id'] "edit" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status']
]; ];
} }

10
niucloud/app/validate/salary/Salary.php

@ -21,25 +21,31 @@ class Salary extends BaseValidate
protected $rule = [ protected $rule = [
'staff_id' => 'require', 'staff_id' => 'require',
'department_id' => 'require',
'base_salary' => 'require', 'base_salary' => 'require',
'performance_bonus' => 'require', 'performance_bonus' => 'require',
'deductions' => 'require', 'deductions' => 'require',
'other_subsidies' => 'require',
'payment_status' => 'require', 'payment_status' => 'require',
'payment_method' => 'require',
'salary_month' => 'require', 'salary_month' => 'require',
]; ];
protected $message = [ protected $message = [
'staff_id.require' => ['common_validate.require', ['staff_id']], 'staff_id.require' => ['common_validate.require', ['staff_id']],
'department_id.require' => ['common_validate.require', ['department_id']],
'base_salary.require' => ['common_validate.require', ['base_salary']], 'base_salary.require' => ['common_validate.require', ['base_salary']],
'performance_bonus.require' => ['common_validate.require', ['performance_bonus']], 'performance_bonus.require' => ['common_validate.require', ['performance_bonus']],
'deductions.require' => ['common_validate.require', ['deductions']], 'deductions.require' => ['common_validate.require', ['deductions']],
'other_subsidies.require' => ['common_validate.require', ['other_subsidies']],
'payment_status.require' => ['common_validate.require', ['payment_status']], 'payment_status.require' => ['common_validate.require', ['payment_status']],
'payment_method.require' => ['common_validate.require', ['payment_method']],
'salary_month.require' => ['common_validate.require', ['salary_month']], 'salary_month.require' => ['common_validate.require', ['salary_month']],
]; ];
protected $scene = [ protected $scene = [
"add" => ['staff_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'net_salary', 'payment_status', 'payment_method', 'remarks', 'salary_month', 'department_id', 'process_id'], "add" => ['staff_id', 'department_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'payment_status', 'payment_method', 'remarks', 'salary_month'],
"edit" => ['staff_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'net_salary', 'payment_status', 'payment_method', 'remarks', 'salary_month', 'department_id', 'process_id'] "edit" => ['staff_id', 'department_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'payment_status', 'payment_method', 'remarks', 'salary_month']
]; ];
} }

Loading…
Cancel
Save