785 lines
28 KiB
Vue
785 lines
28 KiB
Vue
<template>
|
|
<div class="plannings">
|
|
<div class="row justify-content-center">
|
|
<div class="col-1 text-center actions_col">
|
|
<a class="sticky-top btn btn-primary mt-5" @click="goToPlanning(false)">←</a>
|
|
</div>
|
|
|
|
<div class="col-10">
|
|
<table class="table table-bordered align-middle text-center schedules_table">
|
|
<thead>
|
|
<tr>
|
|
<th rowspan="2" >
|
|
|
|
</th>
|
|
<th :colspan="showWeekends ? 7:5" v-for="item in weeksCells" class="Mon Fri" :key="item.num">
|
|
S {{item.num}} - {{item.month}} {{item.year}}
|
|
</th>
|
|
</tr>
|
|
<tr>
|
|
<th v-for="day in days" :class="'day '+day.eday" :key="day.num">
|
|
{{day.day}} {{day.num}}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<template v-for="(user,index) in schedules">
|
|
<tr v-for="(slot,key) in user" :key="index + '' + key">
|
|
<td :rowspan="daySlots" class="resource_ident" v-if="key == 1">
|
|
{{users[index].name}}
|
|
</td>
|
|
<td v-for="day in days" :class="'dynCell day '+user[key][day.key].type.value+ ' ' +day.eday" :key="day.key">
|
|
<div :class="'cellsizer '+ (user[key][day.key].type.value ? user[key][day.key].type.value : 'empty')">
|
|
<b v-if="user[key][day.key]['model_lie']['value']">
|
|
<a target="_blank" class="text-light bg-dark"
|
|
:href="getCellObjectInfo(user[key][day.key]).url">
|
|
{{user[key][day.key]['id_lie']['label']}}
|
|
</a>
|
|
</b><br/>
|
|
{{user[key][day.key]['text']}}
|
|
|
|
<button class="btn btn-edit" type="button" data-bs-toggle="modal"
|
|
data-bs-target="#editModal" @click="setModalData(index,key,day.key,user[key][day.key]['id'])">✎</button>
|
|
<button :class="'btn btn-paste '+(!clipBoard.set ? 'hide' : '') " type="button"
|
|
@click="pasteCell(index,key,day.key,user[key][day.key]['id'])">📋</button>
|
|
<button class="btn btn-copy" type="button"
|
|
@click="copyCell(index,key,day.key,user[key][day.key]['id'])">
|
|
<span style="font-size: .875em; margin-right: .125em; position: relative; top: -.25em; left: -.125em">
|
|
📄<span style="position: absolute; top: .25em; left: .25em">📄</span>
|
|
</span></button>
|
|
<button :class="'btn btn-clear '+(!user[key][day.key]['id'] ? 'hide' : '')" @click="eraseCell(index,key,day.key,user[key][day.key]['id'])">⌫</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="col-1 text-center actions_col">
|
|
<a class="sticky-top btn btn-primary mt-5" @click="goToPlanning(true)">→</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal -->
|
|
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="modalLabel" aria-hidden="true" >
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="modalLabel" ref="modalLabel">{{modale.title}}</h5>
|
|
<button ref="close" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" ></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="container">
|
|
<div class="row justify-content-center">
|
|
<div v-if="error" class="alert alert-danger" role="alert">
|
|
{{ error }}
|
|
</div>
|
|
<div class="col-8">
|
|
<div class="form-group mb-3">
|
|
<label for="categorie" class="col-form-label text-md-right ms-5">Categorie</label>
|
|
<select id="categorie" ref="type" class="form-select" aria-label="Sélectionnez une catégorie">
|
|
<option value="" >Sélectionnez une catégorie</option>
|
|
<option v-for="activity in activities" :key="activity.value" :value="activity.value"
|
|
:selected="modale.activity.value == activity.value"
|
|
:class="activity.value">{{ activity.label }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group mb-3">
|
|
<label for="morph" class="col-form-label text-md-right ms-5">Type d'élément lié</label>
|
|
<select id="morph" ref="morph" class="form-select" @change="selectChange" aria-label="Sélectionnez un élément à lier">
|
|
<option value="">Sélectionnez un type d'objet à lier</option>
|
|
<option v-for="model in models" :key="model.value" :value="model.value"
|
|
:selected="modale.model_lie.value == model.value"
|
|
>{{ model.label }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group mb-3" v-if="modale.dDisplay">
|
|
<label for="select_id_lie" class="col-form-label text-md-right ms-5">Élément lié</label>
|
|
<v-select
|
|
id="select_id_lie"
|
|
ref="select"
|
|
:loading="loading"
|
|
v-model="value"
|
|
:clearable="false"
|
|
label="label"
|
|
:options='data'
|
|
@search="search"
|
|
:disabled="dReadonly||dDisabled"
|
|
:filterable="true"
|
|
:searchable="true"
|
|
@input="setSelected">
|
|
<li slot="list-footer" class="pagination">
|
|
<button
|
|
@click="$event.preventDefault(); page -= 1"
|
|
:disabled="!hasPrevPage"
|
|
class="btn btn-sm btn-primary mt-2 mb-2 ms-2 me-2">Précédent</button>
|
|
<button
|
|
@click="$event.preventDefault(); page += 1"
|
|
:disabled="!hasNextPage"
|
|
class="btn btn-sm btn-primary mt-2 mb-2">Suivant</button>
|
|
</li>
|
|
</v-select>
|
|
</div>
|
|
<div class="form-group mb-3">
|
|
<label for="text" class="col-form-label text-md-right ms-5">Description courte</label>
|
|
<textarea ref="text" class="form-control" name="text"
|
|
id="text" rows="2" placeholder="" @keydown="limitLines($event)" v-model="modale.text"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row justify-content-center">
|
|
<div class="col-8 text-center">
|
|
<button class="btn btn-primary me-3" @click="saveCell()">Valider</button>
|
|
<button class="btn btn-danger" @click="$refs.close.click()">Fermer</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Toastify from 'toastify-js'
|
|
export default {
|
|
mounted() {
|
|
window.Toastify = Toastify
|
|
|
|
let data = JSON.parse(this.$parent.$options.json)
|
|
this.daySlots = Number.parseInt(data.daySlots) !== NaN ? Number.parseInt(data.daySlots) : 4
|
|
this.showWeekends = data.daySlots == 'true' ? true : false
|
|
this.currentDate = data.browseDate ?? new Date()
|
|
this.weeksCells = data.weeks
|
|
this.numweeks = this.weeksCells.length
|
|
this.days = this.prepareDays();
|
|
this.users = data.users
|
|
this.schedules = this.prepareSched(data.schedules)
|
|
this.activities = data.activities
|
|
this.models = data.models
|
|
},
|
|
data() {
|
|
return {
|
|
showWeekends: false,
|
|
daySlots: 4,
|
|
currentDate: null,
|
|
weeksCells: [],
|
|
days: [],
|
|
users:[],
|
|
schedules: [],
|
|
activities: [],
|
|
models: [],
|
|
error: '',
|
|
modale:{
|
|
id: null,
|
|
userid: 0,
|
|
slot: 0,
|
|
day: '01/01/1900',
|
|
title: 0,
|
|
dDisplay: false,
|
|
text: '',
|
|
activity: {
|
|
label: '',
|
|
value: '',
|
|
},
|
|
model_lie: {
|
|
label: '',
|
|
value: '',
|
|
},
|
|
id_lie: {
|
|
label: '',
|
|
value: '',
|
|
},
|
|
},
|
|
//v-select de ses morts
|
|
dDisabled : false,
|
|
dReadonly : false,
|
|
loading: false,
|
|
value: {
|
|
label: null,
|
|
value: null
|
|
},
|
|
searchText: '',
|
|
data: [],
|
|
page: 1,
|
|
perPage: 15,
|
|
hasNextPage: true,
|
|
hasPrevPage: false,
|
|
emptyCell: {
|
|
"type": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"text":"",
|
|
"id_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"model_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"id":null
|
|
},
|
|
clipBoard: {
|
|
"set": false,
|
|
"type": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"text":"",
|
|
"id_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"model_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"id":null
|
|
},
|
|
};
|
|
},
|
|
watch: {
|
|
page() {
|
|
if(this.page < 1) {
|
|
this.page = 1
|
|
}
|
|
if(this.page > 1) {
|
|
this.hasPrevPage = true
|
|
} else {
|
|
this.hasPrevPage = false
|
|
}
|
|
this.search()
|
|
},
|
|
data() {
|
|
if(this.data.length == this.perPage) {
|
|
this.hasNextPage = true
|
|
} else {
|
|
this.hasNextPage = false
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
sendToast(message) {
|
|
Toastify({
|
|
text: message,
|
|
duration: 3000,
|
|
gravity: "top",
|
|
position: "right",
|
|
offset: {
|
|
x: '2rem',
|
|
y: '3rem'
|
|
},
|
|
style: {
|
|
background: "linear-gradient(to right, #00317d, #0058ca)",
|
|
}
|
|
}).showToast();
|
|
},
|
|
goToPlanning(forward) {
|
|
// console.log(forward);
|
|
let date = this.moment(this.currentDate).startOf('week').subtract(7, 'day');
|
|
if(forward) {
|
|
date = this.moment(this.currentDate).add(7, 'day')
|
|
}
|
|
let url = new URL(this.route('schedule.index'))
|
|
location = url.origin+ url.pathname + '?p='+date.format('DD/MM/YYYY')
|
|
},
|
|
prepareDays() {
|
|
let mydays = [];
|
|
for(let i=0; i < this.numweeks * 7; i++) {
|
|
let date = this.moment(this.currentDate).add(i, 'day');
|
|
let obj = {
|
|
day: date.format('ddd'),
|
|
num: date.format('DD'),
|
|
eday: date.locale("en").format('ddd'),
|
|
key: date.format('DD/MM/YYYY'),
|
|
}
|
|
mydays.push(obj);
|
|
if(!this.showWeekends) {
|
|
if(date.day() == 5) {
|
|
i+=2;
|
|
}
|
|
}
|
|
}
|
|
return mydays;
|
|
},
|
|
prepareSched(dbscheds) {
|
|
var templateObj = {
|
|
"type": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"text":"",
|
|
"id_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"model_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"id":null}
|
|
//we need to make missing users
|
|
Object.keys(this.users).forEach(id => {
|
|
if(dbscheds[id] === undefined) {
|
|
dbscheds[id] = {};
|
|
}
|
|
});
|
|
Object.keys(dbscheds).forEach(userid => {
|
|
//what if we missing a slot for the whole period ?
|
|
//we need to make missing slots too
|
|
for(let i=1; i < this.daySlots+1; i++) {
|
|
if(dbscheds[userid][i] === undefined) {
|
|
dbscheds[userid][i] = {};
|
|
}
|
|
}
|
|
Object.keys(dbscheds[userid]).forEach(slotkey => {
|
|
this.days.forEach(day => {
|
|
if(dbscheds[userid][slotkey][day.key] === undefined) {
|
|
//console.log('need ' + day.key + ' for slot ' + slotkey + ' for user ' + userid);
|
|
dbscheds[userid][slotkey][day.key] = templateObj;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
return dbscheds;
|
|
},
|
|
getCellObjectInfo(cellData) {
|
|
for(let model of this.models) {
|
|
if(cellData['model_lie'].value === model.value && model.value == 'tickets') {
|
|
return {
|
|
'url': this.route('ticket.show', { TICKET: cellData['id_lie'].value }),
|
|
'text': cellData['model_lie'].label
|
|
}
|
|
}
|
|
if(cellData['model_lie'].value === model.value && model.value == 'sites') {
|
|
return {
|
|
'url': this.route('sites.show', { SITE: cellData['id_lie'].value}),
|
|
'text': cellData['model_lie'].label
|
|
}
|
|
}
|
|
if(cellData['model_lie'].value === model.value && model.value == 'projects') {
|
|
return {
|
|
'url': this.route('projects.show', { PROJECT: cellData['id_lie'].value}),
|
|
'text': cellData['model_lie'].label
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
},
|
|
resetModalFields() {
|
|
this.$set(this, 'currentType' , null)
|
|
this.$set(this, 'value' , {
|
|
label: null,
|
|
value: null
|
|
})
|
|
this.$refs.type.value = ''
|
|
this.$refs.morph.value = ''
|
|
},
|
|
setModalData(userid,slotkey,day,id) {
|
|
let text = this.schedules[userid][slotkey][day]['text'];
|
|
let activity = this.schedules[userid][slotkey][day]['type'];
|
|
let model = this.schedules[userid][slotkey][day]['model_lie'];
|
|
let enumobject = {
|
|
label: '',
|
|
value: '',
|
|
};
|
|
let currentModale = {
|
|
id: this.schedules[userid][slotkey][day]['id'],
|
|
userid: userid,
|
|
slot: slotkey,
|
|
day: day,
|
|
title: id,
|
|
dDisplay: false,
|
|
text: text,
|
|
activity: activity,
|
|
model_lie: model ?? enumobject,
|
|
id_lie: this.schedules[userid][slotkey][day]['id_lie'],
|
|
}
|
|
this.modale = currentModale;
|
|
this.$nextTick(() => {
|
|
let route = null
|
|
switch(this.modale.model_lie.value) {
|
|
case 'tickets':
|
|
this.dDisplay = true
|
|
route = this.route('ticket.show', {
|
|
TICKET: this.modale.id_lie
|
|
})
|
|
break
|
|
case 'projects':
|
|
this.dDisplay = true
|
|
route = this.route('projects.show', {
|
|
PROJECT: this.modale.id_lie
|
|
})
|
|
break
|
|
case 'sites':
|
|
this.dDisplay = true
|
|
route = this.route('sites.show', {
|
|
SITE: this.modale.id_lie
|
|
})
|
|
break
|
|
default: this.dDisplay = false
|
|
}
|
|
this.selectChange();
|
|
this.value = this.schedules[userid][slotkey][day]['id_lie'];
|
|
})
|
|
},
|
|
pasteCell(userid,slotkey,day,id) {
|
|
//this.eraseCell(userid,slotkey,day,id)
|
|
const data = {
|
|
'id': id,
|
|
'user_id': userid,
|
|
'date': day,
|
|
'activity': this.clipBoard.activity.value,
|
|
'slot': slotkey,
|
|
'model_lie': this.clipBoard.model_lie.value,
|
|
'id_lie': this.clipBoard.id_lie.value,
|
|
'description': this.clipBoard.description,
|
|
}
|
|
this.saveCellOnServer(data)
|
|
//do not clear clipboard
|
|
//this.clearClipBoard()
|
|
this.sendToast('Cellule collée')
|
|
},
|
|
clearClipBoard() {
|
|
this.clipBoard = {
|
|
"set": false,
|
|
"type": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"text":"",
|
|
"id_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"model_lie": {
|
|
"label":"",
|
|
"value":""
|
|
},
|
|
"id":null
|
|
}
|
|
},
|
|
copyCell(userid,slotkey,day,id) {
|
|
this.clipBoard = {
|
|
'set' : true,
|
|
'id': id,
|
|
'user_id': userid,
|
|
'date': day,
|
|
'activity': this.schedules[userid][slotkey][day].type,
|
|
'slot': slotkey,
|
|
'model_lie': this.schedules[userid][slotkey][day].model_lie,
|
|
'id_lie': this.schedules[userid][slotkey][day].id_lie,
|
|
'description': this.schedules[userid][slotkey][day].text,
|
|
}
|
|
this.sendToast('Cellule copiée')
|
|
},
|
|
setSelected(value) {
|
|
this.modale.id_lie = value;
|
|
},
|
|
search (search = null) {
|
|
this.$nextTick(() => {
|
|
this.error = null
|
|
let route;
|
|
switch(this.$refs.morph.value) {
|
|
case 'tickets':
|
|
route = this.route('ticket.index')
|
|
break
|
|
case 'projects':
|
|
route = this.route('projects.index')
|
|
break
|
|
case 'sites':
|
|
route = this.route('sites.index')
|
|
break
|
|
default: return
|
|
}
|
|
if(search !== false && search !== null) {
|
|
this.searchText = search
|
|
}
|
|
let init = search === false ? true : false
|
|
route += '?page='+this.page
|
|
route += '&s='+this.searchText
|
|
this.loading = true
|
|
axios.get(route)
|
|
.then(response => {
|
|
this.data = response.data
|
|
})
|
|
.catch(error => {
|
|
if(error.response.status === 429) {
|
|
location.reload()
|
|
}
|
|
this.error = error
|
|
}).then(() => {
|
|
this.loading = false
|
|
})
|
|
});
|
|
},
|
|
saveCell() {
|
|
this.error = false
|
|
const data = {
|
|
'id': this.modale.id,
|
|
'user_id': this.modale.userid,
|
|
'date': this.modale.day,
|
|
'activity': this.$refs.type.value,
|
|
'slot': this.modale.slot,
|
|
'model_lie': this.$refs.morph.value,
|
|
'id_lie': this.value.value,
|
|
'description': this.$refs.text.value,
|
|
}
|
|
this.saveCellOnServer(data)
|
|
},
|
|
saveCellOnServer(data) {
|
|
this.error = false
|
|
axios.post(this.route('schedule.setCellContent'), data)
|
|
.then(response => {
|
|
if(response.data.status) {
|
|
let sched = response.data.sched;
|
|
// sched.date = Date.parse(sched.date)
|
|
// sched.date = this.moment(sched.date).format('DD/MM/YYYY');
|
|
let cellData = {
|
|
"type": sched.activity,
|
|
"text": sched.description,
|
|
"id_lie": sched.id_lie,
|
|
"model_lie": sched.model_lie,
|
|
"id": sched.id
|
|
};
|
|
this.$set(this.schedules[sched.user_id][sched.slot], sched.date, cellData);
|
|
this.$refs.close.click()
|
|
} else {
|
|
this.error = 'Réponse inconnue';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.log(error);
|
|
if(error.response.status === 429) {
|
|
location.reload()
|
|
}
|
|
if(error.response.status === 422) {
|
|
if(error.response.data.errors) {
|
|
this.error = ''
|
|
for(let id in error.response.data.errors) {
|
|
let field = error.response.data.errors[id]
|
|
this.error += field.join('\n') + '\n'
|
|
}
|
|
return
|
|
} else if(error.response.data.message) {
|
|
this.error = error.response.data.message
|
|
return
|
|
}
|
|
}
|
|
this.error = error
|
|
})
|
|
},
|
|
eraseCell(userid,slotkey,day,id) {
|
|
const data = {
|
|
'id': id,
|
|
}
|
|
axios.post(this.route('schedule.eraseCellContent'), data)
|
|
.then(response => {
|
|
if(response.data.status) {
|
|
this.$set(this.schedules[userid][slotkey], day, this.emptyCell);
|
|
} else {
|
|
console.error('Unknown response')
|
|
}
|
|
})
|
|
.catch(error => {
|
|
if(error.response.status === 429) {
|
|
location.reload()
|
|
}
|
|
console.error(error)
|
|
})
|
|
},
|
|
selectChange() {
|
|
this.value = {
|
|
label: null,
|
|
value: null
|
|
}
|
|
switch(this.$refs.morph.value) {
|
|
case 'tickets':
|
|
case 'projects':
|
|
case 'sites':
|
|
this.modale.dDisplay = true
|
|
this.search(false)
|
|
break
|
|
default: this.modale.dDisplay = false
|
|
}
|
|
},
|
|
limitLines(e) {
|
|
let keynum, lines = this.$refs.text.value.split('\n').length;
|
|
// IE
|
|
if(window.event) {
|
|
keynum = e.keyCode;
|
|
// Netscape/Firefox/Opera
|
|
} else if(e.which) {
|
|
keynum = e.which;
|
|
}
|
|
if(keynum != 8 && this.$refs.text.value.length >= this.textLimit) {
|
|
e.preventDefault()
|
|
return false;
|
|
}
|
|
if(keynum == 13 && lines == this.$refs.text.rows) {
|
|
e.preventDefault()
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "vue-select/src/scss/vue-select.scss";
|
|
|
|
.actions_col {
|
|
width: 45px;
|
|
padding: 0;
|
|
}
|
|
|
|
.plannings {
|
|
.sticky-top {
|
|
top: 20rem !important;
|
|
}
|
|
}
|
|
|
|
table {
|
|
.Mon {
|
|
border-left: 4px solid;
|
|
}
|
|
// .Fri {
|
|
// border-right: 4px solid;
|
|
// }
|
|
}
|
|
|
|
table.schedules_table {
|
|
table-layout: fixed;
|
|
|
|
.resource_ident {
|
|
font-weight: bold;
|
|
width: 150px;
|
|
}
|
|
|
|
.cellsizer {
|
|
height: 50px;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
b {
|
|
width: 90%;
|
|
}
|
|
}
|
|
}
|
|
|
|
.dynCell{
|
|
position: relative;
|
|
&.day {
|
|
//position: relative;
|
|
&:hover .btn {
|
|
opacity: 1;
|
|
}
|
|
&:hover .cellsizer{
|
|
height: 140px;
|
|
padding-top: 2rem;
|
|
position: absolute;
|
|
width: 200%;
|
|
left: -50%;
|
|
top: -55%;
|
|
z-index: 20;
|
|
border: 1px solid;
|
|
}
|
|
$buttonBgColor: #4d4d4d;
|
|
|
|
// Reset button Style to nice one
|
|
button {
|
|
display: inline;
|
|
border: none;
|
|
padding: 0.6rem 3rem;
|
|
margin: 0;
|
|
text-decoration: none;
|
|
background: $buttonBgColor;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
text-align: center;
|
|
transition: background 250ms ease-in-out, transform 150ms ease;
|
|
-webkit-appearance: none;
|
|
-moz-appearance: none;
|
|
}
|
|
|
|
button:disabled,
|
|
button[disabled] {
|
|
color: #aaa;
|
|
}
|
|
|
|
button:hover,
|
|
button:focus {
|
|
background: darken($buttonBgColor, 10%);
|
|
}
|
|
|
|
button:focus {
|
|
outline: 1px solid #fff;
|
|
outline-offset: -4px;
|
|
}
|
|
|
|
button:active {
|
|
transform: scale(0.99);
|
|
}
|
|
|
|
.btn {
|
|
position: absolute;
|
|
top: 0.1rem;
|
|
left: 0.1rem;
|
|
padding: 0;
|
|
width: 1.8rem;
|
|
height: 1.8rem;
|
|
margin: 0;
|
|
background-color: $buttonBgColor;
|
|
opacity: 0;
|
|
&.hide {
|
|
opacity: 0 !important;
|
|
}
|
|
&:hover,
|
|
&:focus {
|
|
background-color: darken($buttonBgColor, 10%);
|
|
}
|
|
&.btn-clear {
|
|
color: darken($color: #fff, $amount: 5);
|
|
}
|
|
&:nth-last-child(2) {
|
|
top: 0.1rem;
|
|
right: inherit;
|
|
left: 2.1rem;
|
|
}
|
|
&:nth-last-child(3) {
|
|
right: inherit;
|
|
top: 0.1rem;
|
|
left: 4.1rem;
|
|
}
|
|
&:nth-last-child(1) {
|
|
top: 0.1rem;
|
|
left: calc(100% - 1.9rem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@import "toastify-js/src/toastify.css";
|
|
@import "vue-select/src/scss/vue-select.scss";
|
|
.planning {
|
|
overflow: auto;
|
|
|
|
td {
|
|
height: 50px;
|
|
}
|
|
|
|
#text {
|
|
height: 5.5rem;
|
|
padding: 1rem 2rem;
|
|
resize: none;
|
|
width: 37rem;
|
|
margin: 0 auto;
|
|
}
|
|
}
|
|
</style>
|