Commit 5815b208 authored by daywrite's avatar daywrite

添加考勤记录模块

parent 0fd0ae69
...@@ -73,6 +73,12 @@ ...@@ -73,6 +73,12 @@
"title": "服务目录", "title": "服务目录",
"appName": 'services', "appName": 'services',
"url": "/service" "url": "/service"
}, {
"icon": "fa-home",
"isRouteShow": 1,
"title": "考勤记录",
"appName": 'punch',
"url": "/punch"
}], }],
homePage: { homePage: {
appName: 'reimbursement', appName: 'reimbursement',
......
...@@ -7,6 +7,7 @@ import SupplierApi from './apis/supplier.js' ...@@ -7,6 +7,7 @@ import SupplierApi from './apis/supplier.js'
import AccountApi from './apis/account.js' import AccountApi from './apis/account.js'
import ProfileApi from './apis/profile.js' import ProfileApi from './apis/profile.js'
import ServiceApi from './apis/service.js' import ServiceApi from './apis/service.js'
import PunchApi from './apis/punch.js'
const API_HOST = process.env.API_HOST const API_HOST = process.env.API_HOST
const API_PORT = process.env.API_PORT const API_PORT = process.env.API_PORT
...@@ -40,6 +41,7 @@ apis = Object.assign(apis, SupplierApi) ...@@ -40,6 +41,7 @@ apis = Object.assign(apis, SupplierApi)
apis = Object.assign(apis, AccountApi) apis = Object.assign(apis, AccountApi)
apis = Object.assign(apis, ProfileApi) apis = Object.assign(apis, ProfileApi)
apis = Object.assign(apis, ServiceApi) apis = Object.assign(apis, ServiceApi)
apis = Object.assign(apis, PunchApi)
export default { export default {
option, option,
......
const type = 'punch'
export default {
[`get${type}Filter`]: {
url: `/vue/${type}/get-filter`
},
[`get${type}List`]: {
url: `/vue/${type}/list`
},
[`get${type}New`]: {
url: `/vue/${type}/get-new`
},
[`save${type}New`]: {
url: `/vue/${type}/save-new`
},
[`get${type}Edit`]: {
url: `/vue/${type}/get-edit`
},
[`save${type}Edit`]: {
url: `/vue/${type}/save-edit`
},
[`delete${type}`]: {
url: `/vue/${type}/delete`
}
}
...@@ -7,3 +7,4 @@ ...@@ -7,3 +7,4 @@
@import './account-app.scss'; @import './account-app.scss';
@import './profile-app.scss'; @import './profile-app.scss';
@import './service-app.scss'; @import './service-app.scss';
@import './punch-app.scss';
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<el-button slot="append" type="primary" @click.stop.prevent="searchKeyword">搜索</el-button> <el-button slot="append" type="primary" @click.stop.prevent="searchKeyword">搜索</el-button>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item v-if="searchKey"> <el-form-item v-if="searchKey || addTitle">
<el-button type="primary" size="mini" @click.stop.prevent="addNew"> <el-button type="primary" size="mini" @click.stop.prevent="addNew">
<i class="fa fa-plus faa-pulse animated"></i> {{addTitle}} <i class="fa fa-plus faa-pulse animated"></i> {{addTitle}}
</el-button> </el-button>
......
<template>
<section class="obear-countArr-section">
<div class="obear-countArr-row">
<div class="obear-countArr-row__col" v-for="item in list" :key="item.key">
<div class="obear-countArr-option" :style="{'background-color': item.color}">
<span class="obear-countArr-option__label">{{ item.name }}</span>
<span class="obear-countArr-option__number">{{ item.value }}</span>
<span class="obear-countArr-option__unit"></span>
</div>
</div>
</div>
</section>
</template>
<script>
export default {
name: 'countArr',
props: {
list: Array
}
}
</script>
<style lang="scss" scoped>
@include c('countArr-section'){
background-color:white;
}
@include c('countArr-row'){
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
justify-content:center;
align-items:center;
@include e('col'){
position: relative;
width: 100%;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
-ms-flex-preferred-size: 0;
flex-basis: 0;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
}
}
@include c('countArr-option'){
position: relative;
margin-top: 15px;
margin-bottom: 15px;
color: #FFF;
padding: 0 0 6px;
text-align: center;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
background-color:#98c450;
@include e('label'){
display: block;
color: #fff;
font-size: 14px;
padding: 3px 0;
margin-bottom: 3px;
border-bottom: 1px solid #FFF;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
@include e('number'){
font-size: 22px;
}
}
@include c('report-link'){
color: #FFF;
position: absolute;
bottom: 6px;
right: 6px;
}
</style>
<template>
<section>
<div class="content">
<search-header
ref="searchHeader"
:title="'考勤记录'"
:add-title="'导出考勤记录'"
@update:headerSearch="search => searchKeyword(search)"
@update:headerAdd="() => addSch()"
@update:headerClear="() => searchClear()">
</search-header>
<search-form
ref="clientForm"
:filter="filter"
@update:clientList="form =>{ updateForm(form) }">
</search-form>
<div class="page-body-content">
<div class="mb10">
<countArr
:list="result.countList">
</countArr>
</div>
<Item
v-for="item in result.list"
:item="item"
:key="item.id">
<span slot="opearate" class="obear-opearate-button">
<el-button
type="primary"
size="mini"
@click.prevent.stop="leaveMessageSch(item)">
<span class="badge" v-if="item.commentCount.comment">
{{ item.commentCount.comment ? item.commentCount.comment : '' }}
</span>
<i class="fa fa-commenting"></i>留言
</el-button>
<el-button
type="primary"
size="mini"
@click.prevent.stop="editSch(item)"
:disabled="item.can_update">
<i class="fa fa-edit animated"></i>说明
</el-button>
</span>
</Item>
<leave-message
v-click-outside="lmClose"
ref="leaveMessage"
:lmTemplate="lmTemplate"
:type="9">
</leave-message>
<Pagenation
@update:pager="pager => {updatePage(pager)}"
:total="result.pagenation.totalcount">
</Pagenation>
</div>
</div>
<FormModal ref="formModal"></FormModal>
</section>
</template>
<script>
import SearchHeader from '../common/searchHeader'
import SearchForm from '../common/SearchForm'
import Item from './punchItem'
import LeaveMessage from '../common/leaveMessage'
import Pagenation from './punchPagenation'
import clickOutside from '@/lib/bind'
import SetParams from '../common/setParams'
import singleRadioTool from '../common/singleRadioTool'
import countArr from './countArr'
import {
requestAPI,
api
} from '@/lib/commonMixin'
export default {
name: 'accountHome',
mixins: [SetParams],
components: {
SearchHeader,
SearchForm,
Item,
LeaveMessage,
Pagenation,
singleRadioTool,
countArr
},
directives: {
clickOutside
},
data () {
return {
currKey: 'punch',
lmTemplate: [
{
name: '客户名称',
value: 'client.name',
default: '未设置'
},
{
name: '内容',
value: 'description'
},
{
name: '待办时间',
value: 'schedule_week_display'
},
{
name: '状态',
value: 'schedule_status_display'
},
{
name: '开始时间',
value: 'start_at'
},
{
name: '结束时间',
value: 'end_at'
},
{
name: '重复',
value: 'repeat_type_display'
},
{
name: '负责人',
value: 'scheduleCreator.name'
},
{
name: '创建时间',
value: 'created_at'
}
],
filter: [],
form: {
'ClientSearch[keyword]': ''
},
pagenation: {
thispage: 1,
pagesize: 10
},
type: 'all',
navArray: [],
result: {
list: [],
countList: [],
pagenation: {
totalcount: 1,
thispage: 1,
pagesize: 10
},
thisUser: {
id: '',
name: '',
sex: ''
}
}
}
},
mounted () {
this.init()
this.getList({})
},
methods: {
init () {
this.getFilter()
},
// 1.查询条件
getFilter () {
requestAPI(api[`get${this.currKey}Filter`]).then(res => {
this.filter = res
})
},
// 2.列表数据
getList (ret) {
requestAPI(api[`get${this.currKey}List`], ret).then((res) => {
const {
list = [],
countList = [],
pagenation = {},
thisUser = {}
} = res
this.result.list = list
this.result.countList = countList
this.result.pagenation = pagenation
this.result.thisUser = thisUser
})
},
// 3.1关键字搜索
searchKeyword (search) {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, search)
this.getList(ret)
},
// 3.2关键字后面的重置
searchClear () {
this.clearParams()
this.$refs.timeSearchForm.resetForm()
this._reload()
},
// 4.重新加载
_reload () {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, {})
this.getList(ret)
},
// 5.1查询条件
updateForm (search) {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, search)
this.getList(ret)
},
// 5.2分页查询
updatePage (pager) {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, {page: pager.thispage})
this.getList(ret)
},
// 5.3 TimeSearchForm
timeSearchForm (search) {
let ret = this.setParams({
...this.form,
page: this.pagenation.thispage
}, search)
this.getList(ret)
},
// 6.1新增
addSch () {
this.$refs.formModal.show()
},
// 6.2编辑
editEvent (item) {
this.$refs.formModal.show(item)
},
// 7.操作
// 修改密码
changePasswordEvent () {},
// 删除
deleteEvent (id) {
let deleteTip = '删除账户'
this.$confirm(`${deleteTip}?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
requestAPI(api[`delete${this.type}`], { id })
.then((res) => {
this.$message.success(`${deleteTip}成功`)
this._reload()
})
}).catch(() => {
this.$message.info(`取消${deleteTip}`)
})
},
// 8.留言
leaveMessageSch (item) {
this.$refs.leaveMessage.isShow(item)
},
lmClose () {
this.$refs.leaveMessage &&
this.$refs.leaveMessage.isClose()
}
}
}
</script>
<style scoped lang="scss">
@include c('opearate-button') {
> .el-button {
margin-right:0px;
}
& .btn-primary .badge {
color: #333744;
background-color: #fff;
}
& .badge {
position: relative;
top: 0px;
left: -5px;
display: inline-block;
padding: 0px 5px;
font-size: 12px;
font-weight: 700;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: .25rem;
background:white;
color:#333744;
}
i {
display: inline-block;
padding-right: 3px;
}
}
</style>
<template>
<section class="obear-schedule-item">
<el-row class="obear-schedule-row">
<el-col :span="4" :xs="24" class="obear-schedule-left" :style="{background: item.bgcolor}">
<el-row :gutter="10">
<el-col :span="24">
<i class="fa fa-fw fa-calendar-check-o" aria-hidden="true"></i>{{ item.edate }} {{ item.week }}
</el-col>
<el-col :span="24" style="padding-left: 3px;">
<span>
<img class="user-avatar rounded-circle" :src="item.user.avatar.name">{{ item.user.name }}
</span>
</el-col>
<el-col :span="24">
</el-col>
</el-row>
</el-col>
<el-col :span="20" :xs="24" class="obear-schedule-right">
<el-row :gutter="10">
<el-col :span="6" :xs="24">
<span>考勤状态:</span>
</el-col>
<el-col :span="6" :xs="24">
<span>打卡设备:</span>
</el-col>
<el-col :span="6" :xs="24">
<span>情况说明:</span><span>{{ item.id_number }}</span>
</el-col>
<el-col :span="6" :xs="24">
<span>图片:</span><span>{{ item.native_place }}</span>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6" :xs="24">
<div>
<span>上班:</span><span>{{ item.in_at }}</span>
</div>
<div>
<span>下班:</span><span>{{ item.out_at }}</span>
</div>
</el-col>
<el-col :span="6" :xs="24">
<div>
<span>{{ item.in_device_display }}</span>
</div>
<div>
<span>{{ item.out_device_display }}</span>
</div>
</el-col>
<el-col :span="6" :xs="24">
<div>
<span>签到:</span><span>{{ item.in_description }}</span>
</div>
<div>
<span>签退:</span><span>{{ item.out_description }}</span>
</div>
</el-col>
<el-col :span="6" :xs="24">
<slot name="opearate">
</slot>
</el-col>
</el-row>
</el-col>
</el-row>
</section>
</template>
<script>
export default {
name: 'documentItem',
props: {
item: Object
},
data () {
return {
}
},
computed: {
userRolesText () {
return this.item.userRoles.map(item => item.display_name) || []
}
},
mounted () {
},
methods: {
}
}
</script>
<style scoped lang="scss">
$lightBlue: #20a0ff;
$lightRed: #dc3545;
.colRed {
color: red;
border: 1px solid red;
}
.colGreen {
color: green;
border: 1px solid green;
}
.colWhite {
color: white;
}
.collightBlue {
color: #649FD7;
}
.colBlue {
color: #0056b3;
}
.rounded-circle {
border-radius: 50% !important;
}
.user-avatar {
width: 16px;
max-width: 16px;
height: 16px;
max-height: 16px;
}
@include c('schedule-item') {
margin-bottom: 10px;
font-size: 12px;
}
@include c('schedule-item:first-child') {
.obear-schedule-left {
border-radius: 5px 0 0 0;
}
}
@include c('schedule-row') {
// min-height:100px;
background-color:white;
display: flex;
flex-wrap: wrap;
}
@include c('schedule-left') {
background-color: #EB7567;
color: white;
min-height: 100%;
padding: 10px 15px 6px;
> .el-row {
> .el-col {
margin-bottom: 4px;
}
}
.el-row div:first-child, .el-row div:first-child a{
color: white;
}
@include e('checkbox') {
display:block;
font-size: 12px;
background:white;
border-radius:2px;
color: $lightBlue;
padding: 0 2px 0 2px;
}
.el-checkbox {
margin-right: 10px;
}
span {
// display: inline-block;
// padding-left: 5px;
}
i {
display:inline-block;
padding-right:5px;
}
img {
display:inline-block;
margin-right:3px;
}
@include e('private') {
display: inline-block;
padding-left: 5px;
border-radius:5px;
border: 1px solid white;
width:35px;
height:17px;
}
}
@include c('schedule-right') {
height:100%;
padding: 10px 15px 6px;
> .el-row {
> .el-col {
margin-bottom: 4px;
.el-button {
margin: 0 2px;
padding: 7px;
}
.date-time {
color: #649FD7;
}
}
}
.badge {
border-radius: 2px;
color: #333744;
background: #ffffff;
vertical-align: baseline;
display: inline;
padding: 2px 6px;
}
span.badge-unread {
&:hover {
border-color: #de321d
}
color: #fff;
background-color: #e54c3a;
border-color: #a32516
}y: flex;
@include e('item') {
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 5px 0 5px 5px;
flex:1;
}
@include e('status') {
color: red;
}
@include e('content') {
display: inline-block;
border-radius:2px;
border: 1px solid;
padding: 0 2px 0 2px;
}
}
</style>
...@@ -9,6 +9,7 @@ import SupplierRoute from './routes/supplier' ...@@ -9,6 +9,7 @@ import SupplierRoute from './routes/supplier'
import AccountRoute from './routes/account' import AccountRoute from './routes/account'
import ProfileRoute from './routes/profile' import ProfileRoute from './routes/profile'
import ServiceRoute from './routes/service' import ServiceRoute from './routes/service'
import PunchRoute from './routes/punch'
let routes = [] let routes = []
let reimRoutes = [] let reimRoutes = []
...@@ -19,6 +20,8 @@ let supplierRoute = [] ...@@ -19,6 +20,8 @@ let supplierRoute = []
let accountRoute = [] let accountRoute = []
let profileRoute = [] let profileRoute = []
let serviceRoute = [] let serviceRoute = []
let punchRoute = []
const appName = 'schedule' const appName = 'schedule'
routes = [].concat(ScheduleRoute) routes = [].concat(ScheduleRoute)
...@@ -30,6 +33,7 @@ supplierRoute = [].concat(SupplierRoute) ...@@ -30,6 +33,7 @@ supplierRoute = [].concat(SupplierRoute)
accountRoute = [].concat(AccountRoute) accountRoute = [].concat(AccountRoute)
profileRoute = [].concat(ProfileRoute) profileRoute = [].concat(ProfileRoute)
serviceRoute = [].concat(ServiceRoute) serviceRoute = [].concat(ServiceRoute)
punchRoute = [].concat(PunchRoute)
let RouterInit = () => { let RouterInit = () => {
portal.createApp(appName, {}, app => { portal.createApp(appName, {}, app => {
...@@ -59,6 +63,9 @@ let RouterInit = () => { ...@@ -59,6 +63,9 @@ let RouterInit = () => {
portal.createApp('services', {}, app => { portal.createApp('services', {}, app => {
app.mapRoute(serviceRoute) app.mapRoute(serviceRoute)
}) })
portal.createApp('punch', {}, app => {
app.mapRoute(punchRoute)
})
// portal.createApp('client', {}, app => { // portal.createApp('client', {}, app => {
// app.mapRoute([ // app.mapRoute([
// { // {
......
import PunchHome from '../components/punch_list/punchHome'
const routes = [{
path: '/punch',
name: 'punchHome',
component: PunchHome
}]
export default routes
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment