master
lion 1 year ago
parent 1867103c2a
commit 4bbc6e3833

@ -37,6 +37,7 @@
"vue-grid-layout": "^2.4.0",
"vue-router": "3.0.6",
"vuex": "3.1.0",
"vxe-pc-ui": "^3.1.0",
"vxe-table": "^3.8.22",
"wujie-vue2": "^1.0.22"
},

@ -38,6 +38,10 @@ Vue.prototype.$moment = moment
Vue.use(ElementUI)
// vxetable
import { VxeUI, VxeUpload, VxeDatePicker } from 'vxe-pc-ui'
import 'vxe-pc-ui/lib/style.css'
Vue.use(VxeUpload)
Vue.use(VxeDatePicker)
import { VxeIcon, VxeTable, VxeColumn, VxeColgroup, VxeTableEditModule, VxeTableValidatorModule, VxeModal, VxeToolbar } from 'vxe-table'
// import vxeTable from 'vxe-table'
import 'vxe-table/styles/index.scss'
@ -49,6 +53,8 @@ Vue.use(VxeColumn)
Vue.use(VxeColgroup)
Vue.use(VxeModal)
Vue.use(VxeToolbar)
// Vue.use(vxeTable)
import domZIndex from 'dom-zindex'
domZIndex.setCurrent(2000)

@ -15,7 +15,7 @@
</el-select>
</div>
<div>
<el-select style="width:250px" v-model="modalSelect.searchDepartmentId" placeholder="请选择科室">
<el-select @change="changeDepartment" style="width:250px" v-model="modalSelect.searchDepartmentId" placeholder="请选择科室">
<el-option v-for="item in departments" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
@ -229,7 +229,7 @@
}],
changeSelect:false,
dateRange: '',
pickerOptions: {
shortcuts: [{
@ -318,8 +318,11 @@
async getChartOverallList() {
try {
this.loading = true
this.list = []
this.total = 0
if(this.changeSelect){
this.list = []
this.total = 0
this.modalSelect.page = 1
}
const res = await axios.get(`${process.env.VUE_APP_BASE_API}/api/oa/chart/overall-list`, {
headers: {
'Authorization': `Bearer ${getToken()}`
@ -337,6 +340,7 @@
console.log("res",res)
this.table = this.tableList[this.modalSelect.searchTag]
this.changeSelect = false
let list = res.data.data.data
this.total = res.data.data.total
if(this.modalSelect.searchTag==='yongche'){
@ -351,6 +355,7 @@
}
})
this.list = carList
this.total = carList.length
}else{
this.list = list
}
@ -370,15 +375,23 @@
console.log("e", e)
if (e) {
this.modalSelect.start_date = e[0] + ' 00:00:00'
this.modalSelect.end_date = e[1] + ' 23:59:59'
this.modalSelect.end_date = e[1] + ' 23:59:59'
this.changeSelect = true
} else {
this.modalSelect.start_date = ''
this.modalSelect.end_date = ''
}
},
changeDepartment(e){
if(e || e==''){
this.changeSelect = true
this.modalSelect.department_id = e
}
},
changeTag(e){
this.tagList.map(item=>{
if(item.id==e){
this.changeSelect = true
this.modalSelect.type = item.type
}
})

@ -40,6 +40,24 @@
<el-form-item label="职位" prop="position">
<el-input v-model="form.position" clearable />
</el-form-item>
<el-upload
class="avatar-uploader"
list-type="picture-card"
accept="image/*"
:headers="{
'Authorization': `Bearer ${getToken()}`
}"
:limit="1"
:action="action"
:show-file-list="true"
:file-list="imgUrl ? [{url: imgUrl}] : []"
:on-success="uploadSuccess"
:on-remove="uploadRemove"
:before-upload="beforeAvatarUpload"
>
<!-- <img v-if="imgUrl" :src="imgUrl" alt="" style="width: 146px;height: 146px;object-fit: contain;display: block;border-radius: 6px;">-->
<i class="el-icon-plus" />
</el-upload>
<el-form-item label="排序" prop="sortnumber">
<el-input-number v-model="form.sortnumber" controls-position="right" :precision="0" />
</el-form-item>
@ -54,6 +72,9 @@
<script>
import { save } from '@/api/user'
import {
getToken
} from '@/utils/auth'
export default {
props: {
isShow: {
@ -69,6 +90,8 @@ export default {
data() {
return {
loading: false,
action: process.env.VUE_APP_UPLOAD_API,
imgUrl: '',
form: {
name: '',
username: '',
@ -79,6 +102,7 @@ export default {
year_holiday: '',
department_id: '',
position: '',
sign_id: '',
sortnumber: 0
},
rules: {
@ -117,6 +141,27 @@ export default {
},
computed: {},
methods: {
getToken,
uploadRemove(file, fileList) {
this.form.sign_id = ''
this.imgUrl = ''
},
uploadSuccess(res, file) {
if (!res.code) {
this.imgUrl = res.data.url
this.form.sign_id = res.data.id
} else {
this.$message.warning(res.msg)
}
},
beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) {
this.$message.error('上传图片大小不能超过 2MB!')
}
return isLt2M
},
submit() {
this.$refs['elForm'].validate(async valid => {
if (valid) {

@ -1,286 +1,337 @@
<template>
<div>
<card-container>
<vxe-toolbar>
<template #buttons>
<el-select v-model="select.department_id" style="max-width: 200px;margin-right: 10px;" size="small" placeholder="请选择部门" clearable >
<el-option v-for="item in departments" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
<el-input v-model="select.keyword" style="max-width: 200px;margin-right: 10px;" size="small" placeholder="请输入关键词" />
<el-button icon="el-icon-plus" type="primary" size="small" @click="isShowAdd = true">新增</el-button>
<el-button icon="el-icon-search" type="primary" plain size="small" @click="select.page = 1,getList()">搜索</el-button>
</template>
</vxe-toolbar>
<vxe-table
ref="table"
stripe
style="margin-top: 10px;"
:loading="loading"
keep-source
show-overflow
:column-config="{ resizable: true }"
:edit-rules="validRules"
:edit-config="{ trigger: 'manual', mode: 'row', showStatus: true, isHover: true, autoClear: false }"
:align="allAlign"
:data="tableData"
>
<vxe-column type="seq" width="58" align="center" />
<vxe-column field="name" width="140" title="姓名" :edit-render="{ name: 'input', attrs: { type: 'text'} }" />
<vxe-column field="username" width="160" title="用户名" :edit-render="{ name: 'input', attrs: { type: 'text'} }" />
<vxe-column field="password" width="160" title="密码" :edit-render="{ name: 'input', attrs: { type: 'password'} }">
<template #default>
<span>***</span>
</template>
</vxe-column>
<vxe-column field="department.name" width="160" align="center" title="部门" :edit-render="{}">
<template #edit="{ row }">
<el-select v-model="row.department_id" size="small">
<el-option v-for="item in departments" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</template>
</vxe-column>
<vxe-column field="position" width="140" title="职位" align="center" :edit-render="{ name: 'input', attrs: { type: 'text'} }" />
<vxe-column field="attendance_closed" width="130" align="center" title="是否关闭打卡" :edit-render="{ name: 'select', options: [{ value: 1, label: '' },{ value: 0, label: '' }] }" />
<vxe-column field="mobile" width="140" align="center" title="手机号" :edit-render="{ name: 'input', attrs: { type: 'text' } }" />
<vxe-column field="start_work_date" title="参加工作时间" width="140" align="center" :edit-render="{}">
<template #edit="{ row }">
<el-date-picker v-model="row.start_work_date" size="small" style="width: 100%;" type="month" value-format="yyyy-MM" />
</template>
</vxe-column>
<vxe-column field="year_holiday" width="140" title="年假天数" align="center" :edit-render="{ name: 'input', attrs: { type: 'number'} }" />
<vxe-column field="roles" title="角色" min-width="200" show-overflow="tooltip">
<template #default="{ row }">
<div>
<el-tag v-for="item in row.roles" :key="item.id">{{ item.name }}</el-tag>
</div>
</template>
</vxe-column>
<vxe-column field="sortnumber" width="80" title="排序" align="center" :edit-render="{ name: 'input', attrs: { type: 'number' } }" />
<vxe-column field="operate" title="操作" min-width="240">
<template #default="{ row }">
<template v-if="isActiveStatus(row)">
<el-button size="small" type="primary" @click="saveRowEvent(row)"></el-button>
<el-button size="small" type="primary" plain @click="cancelRowEvent(row)"></el-button>
</template>
<template v-else>
<el-button size="small" type="success" @click="bind(row)"></el-button>
<el-button size="small" type="warning" @click="editRowEvent(row)"></el-button>
<el-button size="small" type="danger" @click="destroyRowEvent(row)"></el-button>
</template>
</template>
</vxe-column>
</vxe-table>
<el-pagination
style="margin-top: 10px;"
:current-page.sync="select.page"
:page-sizes="[20, 30, 40, 50]"
:page-size.sync="select.rows"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="e => {
select.rows = e;
select.page = 1;
getList();
}"
@current-change="e => {
select.page = e;
getList();
}"
/>
</card-container>
<AddUser :is-show.sync="isShowAdd" :departments="departments" @refresh="getList" />
<BindRoles ref="BindRoles" :is-show.sync="isShowBind" @refresh="getList" />
</div>
</template>
<script>
import BindRoles from './components/BindRoles.vue'
import AddUser from './components/AddUser.vue'
import { deepCopy } from '@/utils'
import { index, save, destroy } from '@/api/user'
import { index as departmentIndex } from '@/api/department'
export default {
components: {
AddUser,
BindRoles
},
data() {
return {
isShowBind: false,
isShowAdd: false,
select: {
page: 1,
rows: 20,
keyword: '',
department_id: ''
},
loading: false,
total: 0,
allAlign: null,
tableData: [],
validRules: {
name: [
{ required: true, message: '请输入姓名' }
],
username: [
{ required: true, message: '请输入用户名' }
],
password: [
{
validator: ({ cellValue }) => {
return new Promise((resolve, reject) => {
const reg = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,20}')
if (cellValue === undefined || reg.test(cellValue)) {
resolve()
} else {
reject(new Error('您的密码复杂度太低(密码中必须包含字母、数字、特殊字符)!'))
}
})
}
<template>
<div>
<card-container>
<vxe-toolbar>
<template #buttons>
<el-select v-model="select.department_id" style="max-width: 200px;margin-right: 10px;" size="small"
placeholder="请选择部门" clearable>
<el-option v-for="item in departments" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
<el-input v-model="select.keyword" style="max-width: 200px;margin-right: 10px;" size="small"
placeholder="请输入关键词" />
<el-button icon="el-icon-plus" type="primary" size="small" @click="isShowAdd = true">新增</el-button>
<el-button icon="el-icon-search" type="primary" plain size="small"
@click="select.page = 1,getList()">搜索</el-button>
</template>
</vxe-toolbar>
<vxe-table ref="table" stripe style="margin-top: 10px;" :loading="loading" keep-source show-overflow
:column-config="{ resizable: true }" :edit-rules="validRules"
:edit-config="{ trigger: 'manual', mode: 'row', showStatus: true, isHover: true, autoClear: false }"
:align="allAlign" :data="tableData">
<vxe-column type="seq" width="58" align="center" />
<vxe-column field="name" width="140" title="姓名" :edit-render="{ name: 'input', attrs: { type: 'text'} }" />
<vxe-column field="username" width="160" title="用户名" :edit-render="{ name: 'input', attrs: { type: 'text'} }" />
<vxe-column field="password" width="160" title="密码"
:edit-render="{ name: 'input', attrs: { type: 'password'} }">
<template #default>
<span>***</span>
</template>
</vxe-column>
<vxe-column field="department.name" width="160" align="center" title="部门" :edit-render="{}">
<template #edit="{ row }">
<el-select v-model="row.department_id" size="small">
<el-option v-for="item in departments" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</template>
</vxe-column>
<vxe-column field="position" width="140" title="职位" align="center"
:edit-render="{ name: 'input', attrs: { type: 'text'} }" />
<vxe-column field="attendance_closed" width="130" align="center" title="是否关闭打卡"
:edit-render="{ name: 'select', options: [{ value: 1, label: '是' },{ value: 0, label: '否' }] }" />
<vxe-column field="mobile" width="140" align="center" title="手机号"
:edit-render="{ name: 'input', attrs: { type: 'text' } }" />
<vxe-column field="start_work_date" title="参加工作时间" width="140" align="center" :edit-render="{}">
<template #edit="{ row }">
<el-date-picker v-model="row.start_work_date" size="small" style="width: 100%;" type="month"
value-format="yyyy-MM" />
</template>
</vxe-column>
<vxe-column field="year_holiday" width="140" title="年假天数" align="center"
:edit-render="{ name: 'input', attrs: { type: 'number'} }" />
<vxe-column field="roles" title="角色" min-width="200" show-overflow="tooltip">
<template #default="{ row }">
<div>
<el-tag v-for="item in row.roles" :key="item.id">{{ item.name }}</el-tag>
</div>
</template>
</vxe-column>
<vxe-column field="sign_id" min-width="180" title="签名" header-align="center" align="left" :edit-render="{}">
<template #default="{ row }">
<vxe-upload v-model="row['sign']" name-field="original_name" readonly progress-text="{percent}%"
:more-config="{ maxCount: 1, layout: 'horizontal' }" :show-button-text="false" />
</template>
<template #edit="{ row }">
<vxe-upload v-model="row['sign']" name-field="original_name" progress-text="{percent}%"
:more-config="{ maxCount: 1, layout: 'horizontal' }" :show-button-text="false"
:upload-method="({file}) => uploadMethod(file)" />
</template>
</vxe-column>
<vxe-column field="sortnumber" width="80" title="排序" align="center"
:edit-render="{ name: 'input', attrs: { type: 'number' } }" />
<vxe-column field="operate" title="操作" min-width="240">
<template #default="{ row }">
<template v-if="isActiveStatus(row)">
<el-button size="small" type="primary" @click="saveRowEvent(row)"></el-button>
<el-button size="small" type="primary" plain @click="cancelRowEvent(row)"></el-button>
</template>
<template v-else>
<el-button size="small" type="success" @click="bind(row)"></el-button>
<el-button size="small" type="warning" @click="editRowEvent(row)"></el-button>
<el-button size="small" type="danger" @click="destroyRowEvent(row)"></el-button>
</template>
</template>
</vxe-column>
</vxe-table>
<el-pagination style="margin-top: 10px;" :current-page.sync="select.page" :page-sizes="[20, 30, 40, 50]"
:page-size.sync="select.rows" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="e => {
select.rows = e;
select.page = 1;
getList();
}" @current-change="e => {
select.page = e;
getList();
}" />
</card-container>
<AddUser :is-show.sync="isShowAdd" :departments="departments" @refresh="getList" />
<BindRoles ref="BindRoles" :is-show.sync="isShowBind" @refresh="getList" />
</div>
</template>
<script>
import BindRoles from './components/BindRoles.vue'
import AddUser from './components/AddUser.vue'
import {
deepCopy
} from '@/utils'
import {
index,
save,
destroy
} from '@/api/user'
import {
index as departmentIndex
} from '@/api/department'
import {
getToken
} from '@/utils/auth'
import axios from 'axios'
export default {
components: {
AddUser,
BindRoles
},
data() {
return {
isShowBind: false,
isShowAdd: false,
select: {
page: 1,
rows: 20,
keyword: '',
department_id: ''
},
loading: false,
total: 0,
allAlign: null,
tableData: [],
validRules: {
name: [{
required: true,
message: '请输入姓名'
}],
username: [{
required: true,
message: '请输入用户名'
}],
password: [{
validator: ({
cellValue
}) => {
return new Promise((resolve, reject) => {
const reg = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,20}')
if (cellValue === undefined || reg.test(cellValue)) {
resolve()
} else {
reject(new Error('您的密码复杂度太低(密码中必须包含字母、数字、特殊字符)!'))
}
})
}
}],
mobile: [{
validator: ({
cellValue
}) => {
return new Promise((resolve, reject) => {
if (!cellValue || /^1[3456789]\d{9}$/.test(cellValue)) {
resolve()
} else {
reject(new Error('手机号格式错误!'))
}
})
}
}]
},
form: {
id: '',
name: '',
username: '',
password: '',
department_id: '',
start_work_date: '',
year_holiday: '',
position: '',
mobile: '',
sortnumber: 0
},
departments: []
}
},
computed: {
isActiveStatus() {
return function(row) {
if (this.$refs['table']) {
return this.$refs['table'].isEditByRow(row)
}
}
}
},
created() {
this.getDepartments()
this.getList()
},
methods: {
bind(row) {
this.isShowBind = true
this.$refs['BindRoles'].setForm(['id', 'role_id'], [row.id, row.roles?.map(i => i.id) || []])
},
editRowEvent(row) {
if (this.$refs['table']) {
this.$refs['table'].setEditRow(row)
}
},
cancelRowEvent(row) {
if (this.$refs['table']) {
this.$refs['table'].clearEdit().then(() => {
//
this.$refs['table'].revertData(row)
})
}
},
async getList() {
this.loading = true
try {
const res = await index(this.select)
this.tableData = res.data
this.total = res.total
console.log(res)
this.loading = false
} catch (err) {
console.error(err)
this.loading = false
}
},
uploadMethod(file) {
console.log("file",file)
const formData = new FormData()
formData.append('file', file)
window.$_uploading = true
return axios.post(process.env.VUE_APP_UPLOAD_API, formData, {
headers: {
Authorization: `Bearer ${getToken()}`
}
}).then((response) => {
window.$_uploading = false
if (response.status === 200 && !response.data.code) {
return {
response: response.data.data,
name: response.data.data.original_name,
url: response.data.data.url
}
} else {
this.$message.error('上传失败')
}
}).catch(_ => {
window.$_uploading = false
})
},
async saveRowEvent(row) {
if (window.$_uploading) {
this.$message.warning('文件正在上传中')
return
}
try {
const errMap = await this.$refs['table'].validate()
if (errMap) {
throw new Error(errMap)
}
await this.$confirm('确认保存?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消'
})
await this.$refs['table'].clearEdit()
const form = deepCopy(this.form)
for (const key in form) {
form[key] = row[key]
}
],
mobile: [
{
validator: ({ cellValue }) => {
return new Promise((resolve, reject) => {
if (!cellValue || /^1[3456789]\d{9}$/.test(cellValue)) {
resolve()
} else {
reject(new Error('手机号格式错误!'))
}
})
}
}
]
},
form: {
id: '',
name: '',
username: '',
password: '',
department_id: '',
start_work_date: '',
year_holiday: '',
position: '',
mobile: '',
sortnumber: 0
},
departments: []
}
},
computed: {
isActiveStatus() {
return function(row) {
if (this.$refs['table']) {
return this.$refs['table'].isEditByRow(row)
}
}
}
},
created() {
this.getDepartments()
this.getList()
},
methods: {
bind(row) {
this.isShowBind = true
this.$refs['BindRoles'].setForm(['id', 'role_id'], [row.id, row.roles?.map(i => i.id) || []])
},
editRowEvent(row) {
if (this.$refs['table']) {
this.$refs['table'].setEditRow(row)
}
},
cancelRowEvent(row) {
if (this.$refs['table']) {
this.$refs['table'].clearEdit().then(() => {
//
this.$refs['table'].revertData(row)
})
}
},
async getList() {
this.loading = true
try {
const res = await index(this.select)
this.tableData = res.data
this.total = res.total
console.log(res)
this.loading = false
} catch (err) {
console.error(err)
this.loading = false
}
},
async saveRowEvent(row) {
try {
const errMap = await this.$refs['table'].validate()
if (errMap) {
throw new Error(errMap)
}
await this.$confirm('确认保存?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消'
})
await this.$refs['table'].clearEdit()
const form = deepCopy(this.form)
for (const key in form) {
form[key] = row[key]
}
this.loading = true
await save(form)
await this.getList()
this.loading = false
} catch (err) {
this.loading = false
}
},
async destroyRowEvent(row) {
try {
await this.$confirm('确认删除?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消'
})
this.loading = true
if (row.id) {
await destroy({
id: row.id
})
await this.getList()
} else {
this.tableData.splice(this.tableData.findIndex(i => i._X_ROW_KEY === row._X_ROW_KEY), 1)
}
this.loading = false
} catch (err) {
this.loading = false
}
},
async getDepartments() {
try {
this.departments = await departmentIndex({
is_tree: 0
})
} catch (err) {
console.error(err)
}
}
}
}
</script>
<style scoped lang="scss">
.total {
color: #666;
text-align: right;
line-height: 3;
}
::v-deep .el-tag + .el-tag {
margin-left: 4px;
}
console.log("row",row)
if (Array.isArray(row['sign']) && row['sign'].length > 0) {
form['sign_id'] = row['sign'][0]?.response?.id ?? ''
}
this.loading = true
await save(form)
await this.getList()
this.loading = false
} catch (err) {
this.loading = false
}
},
async destroyRowEvent(row) {
try {
await this.$confirm('确认删除?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消'
})
this.loading = true
if (row.id) {
await destroy({
id: row.id
})
await this.getList()
} else {
this.tableData.splice(this.tableData.findIndex(i => i._X_ROW_KEY === row._X_ROW_KEY), 1)
}
this.loading = false
} catch (err) {
this.loading = false
}
},
async getDepartments() {
try {
this.departments = await departmentIndex({
is_tree: 0
})
} catch (err) {
console.error(err)
}
}
}
}
</script>
<style scoped lang="scss">
.total {
color: #666;
text-align: right;
line-height: 3;
}
::v-deep .el-tag+.el-tag {
margin-left: 4px;
}
</style>

Loading…
Cancel
Save