1
0
Fork 0
HANYANG_MES/home_dir/www/kadm/auth/auth_manage.php

372 lines
16 KiB
PHP

<?php
if( !$cate_area ) return;
include_once "{$_SERVER['DOCUMENT_ROOT']}/common.inc.php";
include_once _ADM_INC_PATH_ ."/auth_check.php";
include _ADM_INC_PATH_ ."/header.html";
?>
<div id="auth_info_body" v-cloak>
<form method="get" class="sform form-inline">
<i class="bi bi-caret-right-square-fill ml-3 text-info"></i> 조회 :
<label><input type="checkbox" v-model="show_tag.group"> Group </label>,
<label><input type="checkbox" v-model="show_tag.member"> Member </label>
<template v-if="show_tag.member">
<span class="ml-3 mr-3">|</span> <i class="bi bi-caret-right-square-fill text-info"></i> Member 권한 복사 :
<label>
원본
<select class="form-select-sm form-control-sm" :class="[{'bg-light-blue':show_tag.src_mem}]" v-model="show_tag.src_mem">
<option value="">- 없음 -</option>
<template v-for="mem in member_list">
<option :value="mem.member_id">{{mem.member_name}}</option>
</template>
</select>
</label>
<span class="ml-3">=></span>
<label>
대상
<select class="form-select-sm form-control-sm" :class="[{'bg-light-pink':show_tag.tgt_mem}]" v-model="show_tag.tgt_mem">
<option value="">- 없음 -</option>
<template v-for="mem in member_list">
<option :value="mem.member_id">{{mem.member_name}}</option>
</template>
</select>
</label>
<button type="button" class="btn btn-sm btn-primary ml-1" v-if="show_tag.src_mem && show_tag.tgt_mem" @click="copyAuth">Copy</button>
</template>
</form>
<div id="cmd_bar" class="mb-2">
<div class="h4"><i class="bi bi-files-alt"></i> 권한 관리</div>
<div class="text-right">
<button type="button" class="btn btn-primary" @click="setAuth"><i class="bi bi-save"></i> 변경내용 저장</button>
</div>
</div>
<div class="container-fluid mt-3 d-none">
<div class="row">
<div class="col">
<h5 class="d-flex justify-content-between">
<span><i class="bi bi-subtract"></i> 권한 정보 <small class="text-danger">※ 붉은 표시는 사용하지 않는 메뉴</small></span>
</h5>
<div class="mt-3 cont_hfix">
<table class="auth_table table-bordered sticky_table">
<thead class="text-center text-light top_sticky">
<tr>
<th class="bg-dark stk_field_left">기능 / 메뉴</th>
<th class="bg-dark" v-if="show_tag.group">Group</th>
<th class="bg-dark" v-if="show_tag.member">Member</th>
</tr>
</thead>
<tbody>
<tr>
<td class="stk_field_left">
<table class="grid_table sticky_table">
<thead>
<tr>
<th :colspan="menu_max_level+1" class="rowspan2">구분</th>
<th class="rowspan2">Menu_Id</th>
</tr>
</thead>
<tbody>
<template v-for="menu in menu_plist">
<tr :class="{'text-danger':menu.data.cate_use != 'Y'}">
<td :rowspan="menu.mygrpnum||1" class="mnu_title">{{menu.text}}</td>
<td :colspan="menu_max_level - menu.data.level+1" class="mnu_title sptd">&nbsp;</td>
<td class="mnu_title"><small>{{menu.id}}</small></td>
</tr>
</template>
</tbody>
</table>
</td>
<td v-if="show_tag.group">
<table class="grid_table sticky_table chk_table">
<thead>
<tr>
<template v-for="(val, key) in group_list">
<th colspan="3">{{val}}</th>
</template>
</tr>
<tr>
<template v-for="(val, key) in group_list">
<th class="hand" @dblclick="chkall('G',key,'R')"><label>R</label></th>
<th class="hand" @dblclick="chkall('G',key,'W')"><label>W</label></th>
<th class="hand" @dblclick="chkall('G',key,'D')"><label>D</label></th>
</template>
</tr>
</thead>
<tbody>
<template v-for="menu in menu_plist">
<tr>
<template v-for="(val, key) in group_list">
<td :data-menu="menu.text" :data-group="val" data-auth="읽기"><label><input type="checkbox" v-model="auth_list[menu.id]['G'][key]['R']" @change="setUpdate(menu.id,'G',key)"></label></td>
<td :data-menu="menu.text" :data-group="val" data-auth="쓰기"><label><input type="checkbox" v-model="auth_list[menu.id]['G'][key]['W']" @change="setUpdate(menu.id,'G',key)"></label></td>
<td :data-menu="menu.text" :data-group="val" data-auth="삭제"><label><input type="checkbox" v-model="auth_list[menu.id]['G'][key]['D']" @change="setUpdate(menu.id,'G',key)"></label></td>
</template>
</tr>
</template>
</tbody>
</table>
</td>
<td v-if="show_tag.member">
<table class="grid_table sticky_table chk_table">
<thead>
<tr>
<template v-for="mem in member_list.filter( m => show_mem_filter(m.member_id) )">
<th colspan="3" :class="[{'bg-light-blue':show_tag.src_mem==mem.member_id},{'bg-light-pink':show_tag.tgt_mem==mem.member_id}]">{{mem.member_name}}</th>
</template>
</tr>
<tr>
<template v-for="mem in member_list.filter( m => show_mem_filter(m.member_id) )">
<th class="hand" :class="[{'bg-light-blue':show_tag.src_mem==mem.member_id}, {'bg-light-pink':show_tag.tgt_mem==mem.member_id}]" @dblclick="chkall('M',mem.member_id,'R')">R</th>
<th class="hand" :class="[{'bg-light-blue':show_tag.src_mem==mem.member_id}, {'bg-light-pink':show_tag.tgt_mem==mem.member_id}]" @dblclick="chkall('M',mem.member_id,'W')">W</th>
<th class="hand" :class="[{'bg-light-blue':show_tag.src_mem==mem.member_id}, {'bg-light-pink':show_tag.tgt_mem==mem.member_id}]" @dblclick="chkall('M',mem.member_id,'D')">D</th>
</template>
</tr>
</thead>
<tbody>
<template v-for="menu in menu_plist">
<tr>
<template v-for="mem in member_list.filter( m => show_mem_filter(m.member_id) )">
<td><label :data-menu="menu.text" :data-group="mem.member_name" data-auth="읽기" @mouseover="show_info" @mouseleave="hide_info"><input type="checkbox" v-model="auth_list[menu.id]['M'][mem.member_id]['R']" @change="setUpdate(menu.id,'M',mem.member_id)"></label></td>
<td><label :data-menu="menu.text" :data-group="mem.member_name" data-auth="쓰기" @mouseover="show_info" @mouseleave="hide_info"><input type="checkbox" v-model="auth_list[menu.id]['M'][mem.member_id]['W']" @change="setUpdate(menu.id,'M',mem.member_id)"></label></td>
<td><label :data-menu="menu.text" :data-group="mem.member_name" data-auth="삭제" @mouseover="show_info" @mouseleave="hide_info"><input type="checkbox" v-model="auth_list[menu.id]['M'][mem.member_id]['D']" @change="setUpdate(menu.id,'M',mem.member_id)"></label></td>
</template>
</tr>
</template>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php
include _ADM_INC_PATH_ ."/footer.html";
?>
<style>
#viewCellInfo {
position: absolute;
border:solid 2px #333;
border-radius: 10px;
padding: 10px 15px;
background: #333;
z-index: 1000;
}
#viewCellInfo::before {
content: '◆';
color: #333;
z-index: 1;
position: absolute;
left: 8px;
top: -13px;
}
#viewCellInfo .lh-lg {
white-space: nowrap;
color: #FFF;
font-size: 1.1em;
}
</style>
<div id="viewCellInfo" class="d-none"></div>
<!--
<script type="importmap">
{"imports": {
"vue": "https://cdn.jsdelivr.net/npm/vue@3.2.39/dist/vue.esm-browser.js"
}
}
</script>
<script type="module">
import { createApp } from 'vue'
-->
<script>
/*
http://ludo.cubicphuse.nl/jquery-treetable/#usage
*/
const VueAuthManage = createApp({
data() {
return {
ajax_url: './auth.ajax.php',
menu_max_level: 0,
menu_list: [],
group_list: [],
member_list : [],
auth_list : [],
//single_exe: null,
show_tag : {
group: true,
member: true,
src_mem: "",
tgt_mem: "",
}
}
},
mounted() {
let _this = this;
_this.auth_manage();
jQuery(".select2").select2({width:"100px"});
},
updated() {
let _this = this;
// if( _this.single_exe ){
// _this.single_exe.forEach(v=>v.destroy());
// }
// _this.single_exe = tippy(".chk_table td", {
// placement: 'bottom-end',
// allowHTML: true,
// content( tgt ){
// let retval="";
// retval += "<div class='lh-lg px-3'><small>구분</small>| <span class='text-warning'>"+jQuery(tgt).data("menu")+"</span></div>";
// retval += "<div class='lh-lg px-3'><small>대상</small>| <span class='text-info'>"+jQuery(tgt).data("group")+"</span></div>";
// retval += "<div class='lh-lg px-3'><small>권한</small>| <span class='text-danger font-weight-bolder'>"+jQuery(tgt).data("auth")+"</span></div>";
// return retval;
// }
// });
jQuery("#auth_info_body .d-none").removeClass("d-none");
},
computed: {
menu_plist (){
let _this = this;
let new_menu_list = [];
_this.menu_list.forEach( menu => {
let mygrp = _this.menu_list.filter( v => RegExp(`^${menu.data.cate_code}`).test(v.data.cate_code));
menu.mygrpnum = mygrp.length;
new_menu_list.push(menu);
});
return new_menu_list;
}
},
methods: {
auth_manage(){
let _this = this;
ajax_json({
url: _this.ajax_url,
type: "POST",
data: {
cate_area: "<?=$cate_area?>",
mode:'getManages'
},
success: function(data){
if( data.code ){
_this.menu_max_level = data.data.menu_max_level||0;
_this.menu_list = data.data.menu_list||[];
_this.group_list = data.data.group_list||[];
_this.member_list = data.data.member_list||[];
_this.auth_list = data.data.auth_list||[];
}
},
error: function(request, status, error) {
},
complete: function(request, status){
}
});
},
setAuth(){
let _this = this;
ajax_json({
url: _this.ajax_url,
type: "POST",
data: {
cate_area: "<?=$cate_area?>",
mode:'setAuth',
auth_data:JSON.stringify(_this.auth_list),
},
success: function(data){
if( data.code ){
kuls_success("<?=cUtil\Mlang::getText("적용되었습니다.")?>");
}
},
error: function(request, status, error) {
},
complete: function(request, status){
}
})
},
copyAuth(){
let _this = this;
Object.keys(_this.auth_list).forEach(cate_id => {
_this.auth_list[cate_id]['M'][_this.show_tag.tgt_mem] = Object.assign({}, _this.auth_list[cate_id]['M'][_this.show_tag.src_mem]);
});
},
chkall( group, key, auth ){
let _this = this;
let new_state = null;
Object.keys(_this.auth_list).forEach(cate_id => {
if( new_state === null ){
new_state = !_this.auth_list[cate_id][group][key][auth];
}
_this.auth_list[cate_id][group][key][auth] = new_state;
});
},
show_mem_filter( member_id ){
let _this = this;
return !_this.show_tag.src_mem && !_this.show_tag.tgt_mem || [_this.show_tag.src_mem, _this.show_tag.tgt_mem].indexOf(member_id) !== -1
},
show_info( e ){
let _this = this;
let tgt = e.target;
if( tgt.tagName == "LABEL" ){
let retval="";
retval += "<div class='lh-lg px-3'><small>구분</small>| <span class='text-warning'>"+jQuery(tgt).data("menu")+"</span></div>";
retval += "<div class='lh-lg px-3'><small>대상</small>| <span class='text-info'>"+jQuery(tgt).data("group")+"</span></div>";
retval += "<div class='lh-lg px-3'><small>권한</small>| <span class='text-danger font-weight-bolder'>"+jQuery(tgt).data("auth")+"</span></div>";
document.querySelector("#viewCellInfo").innerHTML = retval;
document.querySelector("#viewCellInfo").style.left = (e.pageX - 10)+'px';
document.querySelector("#viewCellInfo").style.top = (e.pageY + 20)+'px';
document.querySelector("#viewCellInfo").classList.remove("d-none");
}
},
hide_info( e ){
let _this = this;
document.querySelector("#viewCellInfo").classList.add("d-none");
},
setUpdate( menu, G, tgt ){
let _this = this;
_this.auth_list[menu][G][tgt]['C'] = 1;
}
}
}).mount('#auth_info_body');
jQuery(".auth_table").on("mouseenter chainenter",".grid_table td", function(e){
let cellIdx = jQuery(this)[0].cellIndex;
let rowIdx = jQuery(this).parent("tr")[0].rowIndex - 2;
if( e.type == "chainenter" ){
jQuery(this).addClass("bg-secondary");
jQuery(this).siblings().addClass("bg-secondary");
}else if( !jQuery(this).hasClass("mnu_title") ){
jQuery(this).addClass("bg-secondary");
jQuery(this).prevAll().addClass("bg-secondary");
jQuery(this).parent("tr").prevAll().find("td:eq("+cellIdx+")").addClass("bg-secondary");
jQuery(this).parents("table:eq(0)").find("thead tr:eq(1) th:eq("+cellIdx+")").addClass("bg-secondary");
}
jQuery(this).parents("td:eq(0)").prevAll().find("tbody tr:eq("+rowIdx+") td:eq(0)").trigger("chainenter");
});
jQuery(".auth_table").on("mouseleave chainleave",".grid_table td", function(e){
let cellIdx = jQuery(this)[0].cellIndex;
let rowIdx = jQuery(this).parent("tr")[0].rowIndex - 2;
if( e.type == "chainleave" ){
jQuery(this).removeClass("bg-secondary");
jQuery(this).siblings().removeClass("bg-secondary");
}else if( !jQuery(this).hasClass("mnu_title") ){
jQuery(this).removeClass("bg-secondary");
jQuery(this).prevAll().removeClass("bg-secondary");
jQuery(this).parent("tr").prevAll().find("td:eq("+cellIdx+")").removeClass("bg-secondary");
jQuery(this).parents("table:eq(0)").find("thead tr:eq(1) th:eq("+cellIdx+")").removeClass("bg-secondary");
}
jQuery(this).parents("td:eq(0)").prevAll().find("tbody tr:eq("+rowIdx+") td:eq(0)").trigger("chainleave");
});
</script>