Commit 0206c002e2e1a6eda0671ade974f621e3372b075

Authored by 함상기
1 parent 5b5ab7e5

2024-04-15

Showing 42 changed files with 1903 additions and 1218 deletions   Show diff stats
prestige-vue-4.0.0/src/layout/AppFooter.vue
1 1 <template>
2 2 <div class="layout-footer">
3 3 <div class="grid">
4   - <div class="col-12 md:col-6 lg:col-3">
5   - <span class="logo">Prestige</span>
6   - <p>PrimeVue Premium Template</p>
7   - </div>
8   - <div class="col-12 md:col-6 lg:col-3">
9   - <span>LATEST TEMPLATES</span>
10   - <div class="grid templates">
11   - <ul>
12   - <li><a href="https://primefaces.org/prestige-vue/" target="_blank" rel="noopener noreferrer">Prestige</a></li>
13   - <li><a href="https://primefaces.org/roma-vue/" target="_blank" rel="noopener noreferrer">Roma</a></li>
14   - <li><a href="https://primefaces.org/babylon-vue/" target="_blank" rel="noopener noreferrer">Babylon</a></li>
15   - <li><a href="https://primefaces.org/ultima-vue/" target="_blank" rel="noopener noreferrer">Ultima</a></li>
16   - <li><a href="https://primefaces.org/diamond-vue/" target="_blank" rel="noopener noreferrer">Diamond</a></li>
17   - </ul>
18   - <ul>
19   - <li><a href="https://primefaces.org/freya-vue/" target="_blank" rel="noopener noreferrer">Freya</a></li>
20   - <li><a href="https://primefaces.org/apollo-vue/" target="_blank" rel="noopener noreferrer">Apollo</a></li>
21   - <li><a href="https://primefaces.org/serenity-vue/" target="_blank" rel="noopener noreferrer">Serenity</a></li>
22   - <li><a href="https://primefaces.org/avalon-vue/" target="_blank" rel="noopener noreferrer">Avalon</a></li>
23   - <li><a href="https://primefaces.org/sapphire-vue/" target="_blank" rel="noopener noreferrer">Sapphire</a></li>
24   - </ul>
25   - </div>
26   - </div>
27   - <div class="col-12 md:col-6 lg:col-3">
28   - <span>DEMOS</span>
29   - <div class="grid">
30   - <ul class="links">
31   - <li><a href="https://primefaces.org/primevue/" target="_blank" rel="noopener noreferrer">PrimeVue</a></li>
32   - <li><a href="https://primefaces.org/primeng/" target="_blank" rel="noopener noreferrer">PrimeNG</a></li>
33   - <li><a href="https://primefaces.org/primereact/" target="_blank" rel="noopener noreferrer">PrimeReact</a></li>
34   - </ul>
35   - </div>
  4 + <div class="col-12 md:col-12 lg:col-12">
  5 + <span class="logo flex align-items-center justify-content-center">(주)대유씨엔에이</span>
  6 + <p class="flex align-items-center justify-content-center">서울특별시 성동구 성수일로 99 서울숲AK밸리 303호</p>
36 7 </div>
37 8 </div>
38 9 </div>
... ...
prestige-vue-4.0.0/src/layout/AppTopbar.vue
... ... @@ -24,24 +24,6 @@
24 24 <div class="layout-quickmenu-tooltip-text">{{ sampleTitle }}</div>
25 25 </div>
26 26 </li>
27   - <li>
28   - <a href="#" class="layout-topbar-icon">
29   - <i class="topbar-icon pi pi-chart-bar"></i>
30   - </a>
31   - <div class="layout-quickmenu-tooltip">
32   - <div class="layout-quickmenu-tooltip-arrow"></div>
33   - <div class="layout-quickmenu-tooltip-text">Statistics</div>
34   - </div>
35   - </li>
36   - <li>
37   - <router-link to="/logout">
38   - <i class="topbar-icon pi pi-sign-out"></i>
39   - </router-link>
40   - <div class="layout-quickmenu-tooltip">
41   - <div class="layout-quickmenu-tooltip-arrow"></div>
42   - <div class="layout-quickmenu-tooltip-text">Sign Out</div>
43   - </div>
44   - </li>
45 27 </ul>
46 28 </transition>
47 29 </li>
... ... @@ -72,24 +54,23 @@
72 54 <li :class="[{ 'active-topmenuitem': activeTopbarItem === 'profile' }]" class="user-profile" @click="$emit('topbar-item-click', { originalEvent: $event, item: 'profile' })">
73 55 <a href="#">
74 56 <div class="user-profile-info profile-link">
75   - <span class="user-profile-name">Ava Gregoraci</span>
76   - <span class="user-profile-role">Design Ops</span>
  57 + <span class="user-profile-name">{{ store.getters.getLoginId }}</span>
  58 + <span class="user-profile-role">{{ store.getters.getCompanyName }}</span>
77 59 </div>
78   - <img class="logo" src="/layout/images/avatar/avatar-ava.jpg" alt="prestige-layout" />
  60 + <i class="pi pi-android" style="font-size: 3.5rem"></i>
79 61 </a>
80 62 <transition name="layout-submenu-container">
81 63 <ul class="fadeInDown" v-show="activeTopbarItem === 'profile'">
82   - <li class="profile-detail">
83   - <div class="user-profile-info">
84   - <img class="logo" src="/layout/images/avatar/avatar-ava.jpg" alt="prestige-layout" />
85   - <div class="profile-info">
86   - <span class="user-profile-name">Ava Gregoraci</span>
87   - <span class="user-profile-role">Design Ops</span>
88   - </div>
  64 + <li>
  65 + <router-link to="/logout">
89 66 <a href="#" class="profile-detail-icon">
90 67 <i class="pi pi-sign-out"></i>
  68 + <div class="menu-text">
  69 + <span class="menu-title">Logout</span>
  70 + <span class="menu-subtitle">Logout from current User</span>
  71 + </div>
91 72 </a>
92   - </div>
  73 + </router-link>
93 74 </li>
94 75 <li>
95 76 <a href="#">
... ... @@ -112,30 +93,6 @@
112 93 <i class="right-icon pi pi-angle-right"></i>
113 94 </a>
114 95 </li>
115   - <li>
116   - <a href="#">
117   - <i class="pi pi-inbox"></i>
118   - <div class="menu-text">
119   - <span class="menu-title">Messages</span>
120   - <span class="menu-subtitle"
121   - >You have a
122   - <div class="blue">3 new</div>
123   - messages</span
124   - >
125   - </div>
126   - <i class="right-icon pi pi-angle-right"></i>
127   - </a>
128   - </li>
129   - <li>
130   - <a href="#">
131   - <i class="pi pi-globe"></i>
132   - <div class="menu-text">
133   - <span class="menu-title">Notification</span>
134   - <span class="menu-subtitle">No new notification</span>
135   - </div>
136   - <i class="right-icon pi pi-angle-right"></i>
137   - </a>
138   - </li>
139 96 </ul>
140 97 </transition>
141 98 </li>
... ...
prestige-vue-4.0.0/src/main.js
... ... @@ -213,7 +213,8 @@ app.component(&#39;BlockViewer&#39;, BlockViewer);
213 213  
214 214 //ag-grid
215 215 import "ag-grid-community/styles//ag-grid.css";
216   -import "ag-grid-community/styles//ag-theme-quartz.css";
  216 +// import "ag-grid-community/styles//ag-theme-quartz.css";
  217 +import "ag-grid-community/styles//ag-theme-balham.css";
217 218 import { AgGridVue } from "ag-grid-vue3";
218 219 app.component('AgGridVue', AgGridVue);
219 220  
... ...
prestige-vue-4.0.0/src/router/index.js
... ... @@ -19,47 +19,6 @@ const routes = [
19 19 },
20 20 },
21 21 {
22   - path: '/basic1',
23   - name: 'basic1',
24   - component: () => import('@/views/basic/Basic1.vue'),
25   - meta: {
26   - breadcrumb: [{ parent: 'Basic', label: 'Basic1' }],
27   - },
28   - },
29   - {
30   - path: '/basic2',
31   - name: 'basic2',
32   - component: () => import('@/views/basic/Basic2.vue'),
33   - meta: {
34   - breadcrumb: [{ parent: 'Basic', label: 'Basic2' }],
35   - },
36   - },
37   - {
38   - path: '/basic3',
39   - name: 'basic3',
40   - component: () => import('@/views/basic/Basic3.vue'),
41   - meta: {
42   - breadcrumb: [{ parent: 'Basic', label: 'Basic3' }],
43   - },
44   - },
45   - {
46   - path: '/basic4',
47   - name: 'basic4',
48   - component: () => import('@/views/basic/Basic4.vue'),
49   - meta: {
50   - breadcrumb: [{ parent: 'Basic', label: 'Basic4' }],
51   - },
52   - },
53   - {
54   - path: '/basic5',
55   - name: 'basic5',
56   - component: () => import('@/views/basic/Basic5.vue'),
57   - meta: {
58   - breadcrumb: [{ parent: 'Basic', label: 'Basic5' }],
59   - },
60   - },
61   -
62   - {
63 22 path: '/systemCode',
64 23 name: 'systemCode',
65 24 component: () => import('@/views/system/SystemCode.vue'),
... ... @@ -76,19 +35,11 @@ const routes = [
76 35 },
77 36 },
78 37 {
79   - path: '/authority',
80   - name: 'authority',
81   - component: () => import('@/views/system/Authority.vue'),
82   - meta: {
83   - breadcrumb: [{ parent: 'System', label: 'Authority' }],
84   - },
85   - },
86   - {
87   - path: '/messages',
88   - name: 'messages',
89   - component: () => import('@/views/system/Messages.vue'),
  38 + path: '/userAuthority',
  39 + name: 'userAuthority',
  40 + component: () => import('@/views/system/UserAuthority.vue'),
90 41 meta: {
91   - breadcrumb: [{ parent: 'System', label: 'Messages' }],
  42 + breadcrumb: [{ parent: 'System', label: 'User Authority' }],
92 43 },
93 44 },
94 45 ],
... ...
prestige-vue-4.0.0/src/service/AgGridService.js 0 → 100644
  1 +const agGridService = {
  2 + /**
  3 + * 그리드의 데이타를 전체/변경된 것을 가져온다
  4 + * @param {*} pGridApi
  5 + * @param {*} pOnlyUpdated
  6 + */
  7 + agGridGetData: (pGridApi, pOnlyUpdated) => {
  8 + console.log("agGridGetData");
  9 + let updatedData = [];
  10 + let sRowStatus = "N,U,D";
  11 + pGridApi.value.forEachNode(rec => {
  12 + if (pOnlyUpdated) {
  13 + if (sRowStatus.indexOf(rec.data.rowStatus) != -1) {
  14 + updatedData.push(rec.data);
  15 + }
  16 + } else {
  17 + updatedData.push(rec.data);
  18 + }
  19 + });
  20 + return updatedData;
  21 + },
  22 +
  23 + /**
  24 + * 새로운행울 추가하고 해당 결과에 대한 정보를 배열로 돌려준다
  25 + * @param {*} pGridApi
  26 + * @returns
  27 + */
  28 + agGridAddRow: (pGridApi, pRowCnt, pIdx) => {
  29 + console.log("agGridAddRow");
  30 + let newRows = [];
  31 + for (let i=0; i<pRowCnt; i++) {
  32 + let newData = {
  33 + rowStatus: "N"
  34 + };
  35 + newRows.push(newData);
  36 + }
  37 + const res = pGridApi.value.applyTransaction({
  38 + addIndex: pIdx,
  39 + add: newRows
  40 + });
  41 + return res;
  42 + },
  43 +
  44 + /**
  45 + * 레코드를 삭제처리하고 결과를 돌려준다
  46 + * @param {*} pGridApi
  47 + * @returns
  48 + */
  49 + agGridDelRow: (pGridApi, pSelectedNodes) => {
  50 + console.log("agGridDelRow");
  51 +
  52 + let removeNodes = [];
  53 + let updateNodes = [];
  54 + pSelectedNodes.map(
  55 + curNode => {
  56 + if (curNode.data.rowStatus === "N") {
  57 + removeNodes.push(curNode.data);
  58 + } else {
  59 + curNode.data.rowStatus = "D";
  60 + updateNodes.push(curNode.data);
  61 + }
  62 + }
  63 + )
  64 +
  65 + const res = pGridApi.value.applyTransaction({
  66 + remove: removeNodes,
  67 + update: updateNodes
  68 + });
  69 + return res;
  70 + },
  71 +
  72 + /**
  73 + * 레코드의 변경상태를 초기화 한다(신규레코드는 제외)
  74 + * @param {*} pGridApi
  75 + * @returns
  76 + */
  77 + agGridEraseStatusRow: (pGridApi) => {
  78 + console.log("agGridEraseStatusRow");
  79 + const selectedRows = pGridApi.value.getSelectedRows();
  80 +
  81 + if ("U,D".indexOf(selectedRows[0].rowStatus) > -1) {
  82 + selectedRows.map(curRec => curRec.rowStatus = "");
  83 + const res = gridApi.value.applyTransaction({
  84 + update: selectedRows
  85 + });
  86 + return res;
  87 + }
  88 +
  89 + return res;
  90 + },
  91 +
  92 + /**
  93 + * 셀변경시 상태 처리
  94 + * @param {*} pGridApi
  95 + * @returns
  96 + */
  97 + agGridChangeStatusRow: (pGridApi, pEvent) => {
  98 + console.log("onCellValueChanged");
  99 + if ('N,D'.indexOf(pEvent.data.rowStatus) == -1) pEvent.data.rowStatus = "U";
  100 + const res = pGridApi.value.applyTransaction({
  101 + update: [pEvent.data]
  102 + });
  103 +
  104 + return res;
  105 + }
  106 +}
  107 +export default agGridService;
0 108 \ No newline at end of file
... ...
prestige-vue-4.0.0/src/service/MenuDataService.js
... ... @@ -7,11 +7,6 @@ export let menu =
7 7 icon: 'pi pi-fw pi-wrench',
8 8 ord: 2,
9 9 items: [
10   - { label: 'Basic1', icon: 'pi pi-fw pi-id-card', to: '/basic1', authrity: 'CURD', ord: 1},
11   - { label: 'Basic2', icon: 'pi pi-fw pi-check-square', to: '/basic2', authrity: 'CURD', ord: 2 },
12   - { label: 'Basic3', icon: 'pi pi-fw pi-bookmark', to: '/basic3', authrity: 'CURD', ord: 3 },
13   - { label: 'Basic4', icon: 'pi pi-fw pi-exclamation-circle', to: '/basic4', authrity: 'CURD', ord: 4 },
14   - { label: 'Basic5', icon: 'pi pi-fw pi-mobile', to: '/basic5', class: 'rotated-icon', authrity: 'CURD', ord: 5 },
15 10 ],
16 11 },
17 12 {
... ... @@ -22,8 +17,7 @@ export let menu =
22 17 items: [
23 18 { label: 'System Code', icon: 'pi pi-fw pi-list', to: '/systemCode', authrity: 'CURD', ord: 1 },
24 19 { label: 'User', icon: 'pi pi-fw pi-users', to: '/user', authrity: 'CURD', ord: 1 },
25   - { label: 'Authority', icon: 'pi pi-fw pi-id-card', to: '/authority', authrity: 'CURD', ord: 1 },
26   - { label: 'Messages', icon: 'pi pi-fw pi-bars', to: '/messages', authrity: 'CURD', ord: 1 },
  20 + { label: 'Authority', icon: 'pi pi-fw pi-id-card', to: '/userAuthority', authrity: 'CURD', ord: 1 },
27 21 ],
28 22 },
29 23 ];
... ...
prestige-vue-4.0.0/src/service/axios.js
... ... @@ -27,7 +27,7 @@ axios.interceptors.response.use(function (response) {
27 27 // Do something with response error
28 28 console.log('에러일 경우', error.config);
29 29 const errorAPI = error.config;
30   - if((error.code != null || error.response.data.status===401) && errorAPI.retry===undefined){
  30 + if((error.response.status===401 || error.response.status===405) && errorAPI.retry===undefined){
31 31 errorAPI.retry = true;
32 32 console.log('토큰이 이상한 오류일 경우');
33 33 await refreshToken();
... ...
prestige-vue-4.0.0/src/service/login.js
... ... @@ -21,6 +21,8 @@ export async function loginForm(loginInfo, store){
21 21 if (response.status == '200') {
22 22 console.log('store = ' + store);
23 23 store.commit("setLogined", true);
  24 + store.commit("setCompanyName", "(주)대유씨엔에이");
  25 + store.commit("setLoginId", loginInfo.username);
24 26 }
25 27 return response.status;
26 28 }catch(err){
... ... @@ -47,6 +49,8 @@ export async function logoutForm(store){
47 49 console.log("refresh_token=" + VueCookies.get('refresh_token'));
48 50  
49 51 store.commit("setLogined", false);
  52 + store.commit("setCompanyName", null);
  53 + store.commit("setLoginId", null);
50 54  
51 55 console.log("Logout Completed");
52 56 }
... ...
prestige-vue-4.0.0/src/store/index.js
... ... @@ -3,10 +3,18 @@ import createPersistedState from &#39;vuex-persistedstate&#39;
3 3  
4 4 export default createStore({
5 5 state: {
  6 + companyName : null,
  7 + loginId : null,
6 8 logined : false,
7 9 samplePages : false,
8 10 },
9 11 getters: {
  12 + getCompanyName(state){
  13 + return state.companyName;
  14 + },
  15 + getLoginId(state){
  16 + return state.loginId;
  17 + },
10 18 getLogined(state){
11 19 return state.logined;
12 20 },
... ... @@ -15,6 +23,12 @@ export default createStore({
15 23 }
16 24 },
17 25 mutations: {
  26 + setCompanyName(state, companyName){
  27 + state.companyName = companyName;
  28 + },
  29 + setLoginId(state, loginId){
  30 + state.loginId = loginId;
  31 + },
18 32 setLogined(state, logined){
19 33 state.logined = logined;
20 34 },
... ...
prestige-vue-4.0.0/src/views/basic/Basic1.vue deleted
1   -<script setup>
2   -import { onMounted, ref } from 'vue';
3   -
4   -class CustomTextEditor {
5   - constructor(props) {
6   - const el = document.createElement('input');
7   - const { maxLength } = props.columnInfo.editor.options;
8   -
9   - el.type = 'text';
10   - el.maxLength = maxLength;
11   - el.value = String(props.value);
12   -
13   - this.el = el;
14   - }
15   -
16   - getElement() {
17   - return this.el;
18   - }
19   -
20   - getValue() {
21   - return this.el.value;
22   - }
23   -
24   - mounted() {
25   - this.el.select();
26   - }
27   -}
28   -
29   -const data = ref([
30   - {
31   - id: '10012',
32   - city: 'Seoul',
33   - country: 'South Korea',
34   - },
35   - {
36   - id: '10013',
37   - city: 'Tokyo',
38   - country: 'Japan',
39   - },
40   - {
41   - id: '10014',
42   - city: 'London',
43   - country: 'England',
44   - },
45   - {
46   - id: '10015',
47   - city: 'Ljubljana',
48   - country: 'Slovenia',
49   - },
50   - {
51   - id: '10016',
52   - city: 'Reykjavik',
53   - country: 'Iceland',
54   - },
55   -]);
56   -
57   -const columns = ref([
58   - {
59   - header: 'ID',
60   - name: 'id',
61   - editor: {
62   - type: CustomTextEditor,
63   - options: {
64   - maxLength: 10,
65   - },
66   - },
67   - },
68   - {
69   - header: 'CITY',
70   - name: 'city',
71   - editor: 'text',
72   - },
73   - {
74   - header: 'COUNTRY',
75   - name: 'country',
76   - formatter: 'listItemText',
77   - editor: {
78   - type: 'select',
79   - options: {
80   - listItems: [
81   - { text: 'South Korea', value: 'South Korea' },
82   - { text: 'England', value: 'England' },
83   - { text: 'Japan', value: 'Japan' },
84   - { text: 'Slovenia', value: 'Slovenia' },
85   - ],
86   - },
87   - },
88   - },
89   -]);
90   -
91   -const GridTable = ref();
92   -
93   -onMounted(() => {
94   - const grid = GridTable.value;
95   - const optPreset = {
96   - selection: {
97   - background: '#4daaf9',
98   - border: '#004082',
99   - },
100   - scrollbar: {
101   - background: '#f5f5f5',
102   - thumb: '#d9d9d9',
103   - active: '#c1c1c1',
104   - },
105   - row: {
106   - even: {
107   - background: '#f3ffe3',
108   - },
109   - hover: {
110   - background: '#ccc',
111   - },
112   - },
113   - cell: {
114   - normal: {
115   - background: '#fbfbfb',
116   - border: '#e0e0e0',
117   - showVerticalBorder: true,
118   - },
119   - header: {
120   - background: '#eee',
121   - border: '#ccc',
122   - showVerticalBorder: true,
123   - },
124   - rowHeader: {
125   - border: '#ccc',
126   - showVerticalBorder: true,
127   - },
128   - editable: {
129   - background: '#fbfbfb',
130   - },
131   - selectedHeader: {
132   - background: '#d8d8d8',
133   - },
134   - focused: {
135   - border: '#418ed4',
136   - },
137   - disabled: {
138   - text: '#b0b0b0',
139   - },
140   - },
141   - };
142   - grid?.applyTheme('striped', optPreset);
143   - grid?.setLanguage('ko');
144   - // const instance = grid?.gridInstance;
145   - // instance?.setWidth(500);
146   -
147   - //data Load
148   - // const loginInfo = {};
149   -
150   - // const response = getData();
151   -});
152   -</script>
153   -
154   -<template>
155   - <div class="card">
156   - <Accordion :activeIndex="0">
157   - <AccordionTab header="Header I" class="w-full">
158   - <tui-grid ref="GridTable" :data="data" :columns="columns"> </tui-grid>
159   - </AccordionTab>
160   - <AccordionTab header="Header II">
161   - <p class="m-0">
162   - Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
163   - ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
164   - </p>
165   - </AccordionTab>
166   - <AccordionTab header="Header III">
167   - <p class="m-0">
168   - At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui
169   - officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
170   - </p>
171   - </AccordionTab>
172   - </Accordion>
173   - </div>
174   -</template>
prestige-vue-4.0.0/src/views/basic/Basic2.vue deleted
1   -<template>
2   - <div class="grid p-fluid">
3   - <div class="col-12 lg:col-6">
4   - <div class="card">
5   - <h5>Linear Chart</h5>
6   - <Chart type="line" :data="lineData"></Chart>
7   - </div>
8   - <div class="card flex flex-column align-items-center">
9   - <h5 class="align-self-start">Pie Chart</h5>
10   - <Chart type="pie" :data="pieData" style="position: relative; width: 50%"></Chart>
11   - </div>
12   - <div class="card flex flex-column align-items-center">
13   - <h5 class="align-self-start">Polar Area Chart</h5>
14   - <Chart type="polarArea" :data="polarData" style="position: relative; width: 50%"></Chart>
15   - </div>
16   - </div>
17   - <div class="col-12 lg:col-6">
18   - <div class="card">
19   - <h5>Bar Chart</h5>
20   - <Chart type="bar" :data="barData"></Chart>
21   - </div>
22   - <div class="card flex flex-column align-items-center">
23   - <h5 class="align-self-start">Doughnut Chart</h5>
24   - <Chart type="doughnut" :data="pieData" style="position: relative; width: 50%"></Chart>
25   - </div>
26   - <div class="card flex flex-column align-items-center">
27   - <h5 class="align-self-start">Radar Chart</h5>
28   - <Chart type="radar" :data="radarData" style="position: relative; width: 50%"></Chart>
29   - </div>
30   - </div>
31   - </div>
32   -</template>
33   -
34   -<script>
35   -export default {
36   - data() {
37   - return {
38   - lineData: {
39   - labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
40   - datasets: [
41   - {
42   - label: 'First Dataset',
43   - data: [65, 59, 80, 81, 56, 55, 40],
44   - fill: false,
45   - borderColor: '#03A9F4',
46   - tension: 0.4,
47   - },
48   - {
49   - label: 'Second Dataset',
50   - data: [28, 48, 40, 19, 86, 27, 90],
51   - fill: false,
52   - borderColor: '#FFC107',
53   - tension: 0.4,
54   - },
55   - ],
56   - },
57   - pieData: {
58   - labels: ['A', 'B', 'C'],
59   - datasets: [
60   - {
61   - data: [540, 325, 702, 421],
62   - backgroundColor: ['rgb(54, 162, 235)', 'rgb(255, 99, 132)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)'],
63   - },
64   - ],
65   - },
66   - polarData: {
67   - datasets: [
68   - {
69   - data: [11, 16, 7, 3],
70   - backgroundColor: ['rgb(54, 162, 235)', 'rgb(255, 99, 132)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)'],
71   - label: 'My dataset',
72   - },
73   - ],
74   - labels: ['Blue', 'Purple', 'Orange', 'Green'],
75   - },
76   - barData: {
77   - labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
78   - datasets: [
79   - {
80   - label: 'My First dataset',
81   - backgroundColor: 'rgb(255, 99, 132)',
82   - borderColor: 'rgb(255, 99, 132)',
83   - data: [65, 59, 80, 81, 56, 55, 40],
84   - },
85   - {
86   - label: 'My Second dataset',
87   - backgroundColor: 'rgb(54, 162, 235)',
88   - borderColor: 'rgb(54, 162, 235)',
89   - data: [28, 48, 40, 19, 86, 27, 90],
90   - },
91   - ],
92   - },
93   - doughnutData: {
94   - labels: ['A', 'B', 'C'],
95   - datasets: [
96   - {
97   - data: [300, 50, 100],
98   - backgroundColor: ['#FFC107', '#03A9F4', '#4CAF50'],
99   - hoverBackgroundColor: ['#FFE082', '#81D4FA', '#A5D6A7'],
100   - },
101   - ],
102   - },
103   - radarData: {
104   - labels: ['Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'],
105   - datasets: [
106   - {
107   - label: 'My First dataset',
108   - backgroundColor: 'rgba(179,181,198,0.2)',
109   - borderColor: 'rgba(179,181,198,1)',
110   - pointBackgroundColor: 'rgba(179,181,198,1)',
111   - pointBorderColor: '#fff',
112   - pointHoverBackgroundColor: '#fff',
113   - pointHoverBorderColor: 'rgba(179,181,198,1)',
114   - data: [65, 59, 90, 81, 56, 55, 40],
115   - },
116   - {
117   - label: 'My Second dataset',
118   - backgroundColor: 'rgba(255,99,132,0.2)',
119   - borderColor: 'rgba(255,99,132,1)',
120   - pointBackgroundColor: 'rgba(255,99,132,1)',
121   - pointBorderColor: '#fff',
122   - pointHoverBackgroundColor: '#fff',
123   - pointHoverBorderColor: 'rgba(255,99,132,1)',
124   - data: [28, 48, 40, 19, 96, 27, 100],
125   - },
126   - ],
127   - },
128   - };
129   - },
130   -};
131   -</script>
132   -
133   -<style scoped></style>
prestige-vue-4.0.0/src/views/basic/Basic3.vue deleted
1   -<template>
2   - <div class="grid">
3   - <div class="col-12">
4   - <div class="card">
5   - <h5>Advanced</h5>
6   - <FileUpload name="demo[]" @uploader="onUpload" :multiple="true" accept="image/*" :maxFileSize="1000000" customUpload />
7   -
8   - <h5>Basic</h5>
9   - <FileUpload mode="basic" name="demo[]" accept="image/*" :maxFileSize="1000000" @uploader="onUpload" customUpload />
10   - </div>
11   - </div>
12   - <Toast />
13   - </div>
14   -</template>
15   -
16   -<script>
17   -export default {
18   - methods: {
19   - onUpload() {
20   - this.$toast.add({ severity: 'info', summary: 'Success', detail: 'File Uploaded', life: 3000 });
21   - },
22   - },
23   -};
24   -</script>
25   -
26   -<style scoped></style>
prestige-vue-4.0.0/src/views/basic/Basic4.vue deleted
1   -<template>
2   - <div class="floatlabel-demo">
3   - <div class="card">
4   - <h5>Float Label</h5>
5   - <p>All input text components support floating labels by adding (<mark>.p-float-label</mark>) to wrapper class.</p>
6   - <div class="grid p-fluid">
7   - <div class="col-12 md:col-6">
8   - <div class="field">
9   - <span class="p-float-label">
10   - <InputText type="text" id="inputtext" v-model="value1" />
11   - <label for="inputtext">InputText</label>
12   - </span>
13   - </div>
14   - <div class="field">
15   - <span class="p-float-label p-input-icon-left">
16   - <i class="pi pi-search" />
17   - <InputText type="text" id="lefticon" v-model="value3" />
18   - <label for="lefticon">Left Icon</label>
19   - </span>
20   - </div>
21   - <div class="field">
22   - <span class="p-float-label p-input-icon-right">
23   - <i class="pi pi-spin pi-spinner" />
24   - <InputText type="text" id="righticon" v-model="value5" />
25   - <label for="righticon">Right Icon</label>
26   - </span>
27   - </div>
28   - <div class="field">
29   - <span class="p-float-label">
30   - <InputMask id="inputmask" mask="99/99/9999" v-model="value7"></InputMask>
31   - <label for="inputmask">InputMask</label>
32   - </span>
33   - </div>
34   - <div class="field">
35   - <span class="p-float-label">
36   - <InputNumber id="inputnumber" v-model="value9"></InputNumber>
37   - <label for="inputnumber">InputNumber</label>
38   - </span>
39   - </div>
40   - <div class="field">
41   - <span class="p-float-label">
42   - <Chips inputId="chips" v-model="value11"></Chips>
43   - <label for="chips">Chips</label>
44   - </span>
45   - </div>
46   - </div>
47   -
48   - <div class="col-12 md:col-6">
49   - <div class="field">
50   - <div class="p-inputgroup">
51   - <span class="p-inputgroup-addon">
52   - <i class="pi pi-user"></i>
53   - </span>
54   - <span class="p-float-label">
55   - <InputText type="text" id="inputgroup" v-model="value2" />
56   - <label for="inputgroup">InputGroup</label>
57   - </span>
58   - </div>
59   - </div>
60   - <div class="field">
61   - <span class="p-float-label">
62   - <AutoComplete id="autocomplete" v-model="value4" :suggestions="filteredCountries" @complete="searchCountry($event)" field="name"></AutoComplete>
63   - <label for="autocomplete">AutoComplete</label>
64   - </span>
65   - </div>
66   - <div class="field">
67   - <span class="p-float-label">
68   - <Calendar inputId="calendar" v-model="value6"></Calendar>
69   - <label for="calendar">Calendar</label>
70   - </span>
71   - </div>
72   - <div class="field">
73   - <span class="p-float-label">
74   - <Dropdown id="dropdown" :options="cities" v-model="value8" optionLabel="name"></Dropdown>
75   - <label for="dropdown">Dropdown</label>
76   - </span>
77   - </div>
78   - <div class="field">
79   - <span class="p-float-label">
80   - <MultiSelect id="multiselect" :options="cities" v-model="value10" optionLabel="name" :filter="false"></MultiSelect>
81   - <label for="multiselect">MultiSelect</label>
82   - </span>
83   - </div>
84   - <div class="field">
85   - <span class="p-float-label">
86   - <Textarea inputId="textarea" rows="3" cols="30" v-model="value12"></Textarea>
87   - <label for="textarea">Textarea</label>
88   - </span>
89   - </div>
90   - </div>
91   - </div>
92   - </div>
93   - </div>
94   -</template>
95   -
96   -<script>
97   -import CountryService from '@/service/CountryService';
98   -export default {
99   - data() {
100   - return {
101   - countries: [],
102   - filteredCountries: null,
103   - cities: [
104   - { name: 'New York', code: 'NY' },
105   - { name: 'Rome', code: 'RM' },
106   - { name: 'London', code: 'LDN' },
107   - { name: 'Istanbul', code: 'IST' },
108   - { name: 'Paris', code: 'PRS' },
109   - ],
110   - value1: null,
111   - value2: null,
112   - value3: null,
113   - value4: null,
114   - value5: null,
115   - value6: null,
116   - value7: null,
117   - value8: null,
118   - value9: null,
119   - value10: null,
120   - value11: null,
121   - value12: null,
122   - };
123   - },
124   - created() {
125   - this.countryService = new CountryService();
126   - },
127   - mounted() {
128   - this.countryService.getCountries().then((countries) => {
129   - this.countries = countries;
130   - });
131   - },
132   - methods: {
133   - searchCountry(event) {
134   - // in a real application, make a request to a remote url with the query and
135   - // return filtered results, for demo we filter at client side
136   - const filtered = [];
137   - const query = event.query;
138   - for (let i = 0; i < this.countries.length; i++) {
139   - const country = this.countries[i];
140   - if (country.name.toLowerCase().indexOf(query.toLowerCase()) == 0) {
141   - filtered.push(country);
142   - }
143   - }
144   - this.filteredCountries = filtered;
145   - },
146   - },
147   -};
148   -</script>
149   -
150   -<style lang="scss" scoped>
151   -.floatlabel-demo {
152   - .field {
153   - margin-top: 2rem;
154   - }
155   -}
156   -</style>
prestige-vue-4.0.0/src/views/basic/Basic5.vue deleted
1   -<template>
2   - <div class="grid">
3   - <div class="col-12 md:col-6">
4   - <div class="card p-fluid">
5   - <h5>Vertical</h5>
6   - <div class="field">
7   - <label for="name1">Name</label>
8   - <InputText id="name1" type="text" />
9   - </div>
10   - <div class="field">
11   - <label for="email1">Email</label>
12   - <InputText id="email1" type="text" />
13   - </div>
14   - <div class="field">
15   - <label for="age1">Age</label>
16   - <InputText id="age1" type="text" />
17   - </div>
18   - </div>
19   -
20   - <div class="card p-fluid">
21   - <h5>Vertical Grid</h5>
22   - <div class="formgrid grid">
23   - <div class="field col">
24   - <label for="name2">Name</label>
25   - <InputText id="name2" type="text" />
26   - </div>
27   - <div class="field col">
28   - <label for="email2">Email</label>
29   - <InputText id="email2" type="text" />
30   - </div>
31   - </div>
32   - </div>
33   - </div>
34   -
35   - <div class="col-12 md:col-6">
36   - <div class="card p-fluid">
37   - <h5>Horizontal</h5>
38   - <div class="field grid">
39   - <label for="name3" class="col-12 mb-2 md:col-2 md:mb-0">Name</label>
40   - <div class="col-12 md:col-10">
41   - <InputText id="name3" type="text" />
42   - </div>
43   - </div>
44   - <div class="field grid">
45   - <label for="email3" class="col-12 mb-2 md:col-2 md:mb-0">Email</label>
46   - <div class="col-12 md:col-10">
47   - <InputText id="email3" type="text" />
48   - </div>
49   - </div>
50   - </div>
51   -
52   - <div class="card">
53   - <h5>Inline</h5>
54   - <div class="formgroup-inline">
55   - <div class="field">
56   - <label for="firstname1" class="p-sr-only">Firstname</label>
57   - <InputText id="firstname1" type="text" placeholder="Firstname" />
58   - </div>
59   - <div class="field">
60   - <label for="lastname1" class="p-sr-only">Lastname</label>
61   - <InputText id="lastname1" type="text" placeholder="Lastname" />
62   - </div>
63   - <Button label="Submit"></Button>
64   - </div>
65   - </div>
66   -
67   - <div class="card">
68   - <h5>Help Text</h5>
69   - <div class="field p-fluid">
70   - <label for="username">Username</label>
71   - <InputText id="username" type="text" />
72   - <small>Enter your username to reset your password.</small>
73   - </div>
74   - </div>
75   - </div>
76   -
77   - <div class="col-12">
78   - <div class="card">
79   - <h5>Advanced</h5>
80   - <div class="p-fluid formgrid grid">
81   - <div class="field col-12 md:col-6">
82   - <label for="firstname2">Firstname</label>
83   - <InputText id="firstname2" type="text" />
84   - </div>
85   - <div class="field col-12 md:col-6">
86   - <label for="lastname2">Lastname</label>
87   - <InputText id="lastname2" type="text" />
88   - </div>
89   - <div class="field col-12">
90   - <label for="address">Address</label>
91   - <Textarea id="address" rows="4" />
92   - </div>
93   - <div class="field col-12 md:col-6">
94   - <label for="city">City</label>
95   - <InputText id="city" type="text" />
96   - </div>
97   - <div class="field col-12 md:col-3">
98   - <label for="state">State</label>
99   - <Dropdown id="state" v-model="dropdownItem" :options="dropdownItems" optionLabel="name" placeholder="Select One"></Dropdown>
100   - </div>
101   - <div class="field col-12 md:col-3">
102   - <label for="zip">Zip</label>
103   - <InputText id="zip" type="text" />
104   - </div>
105   - </div>
106   - </div>
107   - </div>
108   - </div>
109   -</template>
110   -<script>
111   -export default {
112   - data() {
113   - return {
114   - dropdownItems: [
115   - { name: 'Option 1', code: 'Option 1' },
116   - { name: 'Option 2', code: 'Option 2' },
117   - { name: 'Option 3', code: 'Option 3' },
118   - ],
119   - dropdownItem: null,
120   - };
121   - },
122   -};
123   -</script>
prestige-vue-4.0.0/src/views/system/Authority.vue deleted
1   -<template>
2   - <div class="grid">
3   - <div class="col-12">
4   - <div class="card">
5   - <h5>Calendar</h5>
6   - <FullCalendar :events="events" :options="options" />
7   -
8   - <Dialog v-model:visible="eventDialog" :style="{ width: '450px' }" header="Event Details" :modal="true" :closable="true">
9   - <div class="p-fluid">
10   - <div class="field">
11   - <label for="title">Title</label>
12   - <InputText id="title" v-if="clickedEvent" v-model="changedEvent.title" required="true" autofocus />
13   - </div>
14   - <div class="field">
15   - <label for="start">From</label>
16   - <Calendar id="start" v-if="clickedEvent" v-model="changedEvent.start" :showTime="true" appendTo="body" />
17   - </div>
18   - <div class="field">
19   - <label for="end">To</label>
20   - <Calendar id="end" v-if="clickedEvent" v-model="changedEvent.end" :showTime="true" appendTo="body" />
21   - </div>
22   - <div class="field-checkbox">
23   - <Checkbox id="allday" name="allday" value="All Day" v-model="changedEvent.allDay" />
24   - <label for="allday">All Day</label>
25   - </div>
26   - </div>
27   - <template #footer>
28   - <Button label="Save" icon="pi pi-check" class="p-button-text" @click="save" />
29   - <Button label="Reset" icon="pi pi-refresh" class="p-button-text" @click="reset" />
30   - </template>
31   - </Dialog>
32   - </div>
33   - </div>
34   - </div>
35   -</template>
36   -
37   -<script>
38   -import '@fullcalendar/core/vdom';
39   -import EventService from '@/service/EventService';
40   -import dayGridPlugin from '@fullcalendar/daygrid';
41   -import timeGridPlugin from '@fullcalendar/timegrid';
42   -import interactionPlugin from '@fullcalendar/interaction';
43   -import FullCalendar from 'primevue/fullcalendar';
44   -export default {
45   - components: {
46   - FullCalendar,
47   - },
48   - data() {
49   - return {
50   - eventDialog: false,
51   - clickedEvent: null,
52   - changedEvent: { title: '', start: null, end: '', allDay: null },
53   - options: {
54   - plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
55   - initialDate: '2023-01-01',
56   - headerToolbar: {
57   - left: 'prev,next',
58   - center: 'title',
59   - right: 'dayGridMonth,timeGridWeek,timeGridDay',
60   - },
61   - editable: true,
62   - selectable: true,
63   - selectMirror: true,
64   - dayMaxEvents: true,
65   - eventClick: (e) => {
66   - this.eventDialog = true;
67   - this.clickedEvent = e.event;
68   - this.changedEvent.title = this.clickedEvent.title;
69   - this.changedEvent.start = this.clickedEvent.start;
70   - this.changedEvent.end = this.clickedEvent.end;
71   - },
72   - },
73   - events: null,
74   - };
75   - },
76   - eventService: null,
77   - created() {
78   - this.eventService = new EventService();
79   - },
80   - mounted() {
81   - this.eventService.getEvents().then((data) => (this.events = data));
82   - },
83   - methods: {
84   - findIndexById(id) {
85   - let index = -1;
86   - for (let i = 0; i < this.events.length; i++) {
87   - if (this.events[i].id === id) {
88   - index = i;
89   - break;
90   - }
91   - }
92   - return index;
93   - },
94   - save() {
95   - this.eventDialog = false;
96   - this.clickedEvent.setProp('title', this.changedEvent.title);
97   - this.clickedEvent.setStart(this.changedEvent.start);
98   - this.clickedEvent.setEnd(this.changedEvent.end);
99   - this.clickedEvent.setAllDay(this.changedEvent.allDay);
100   - this.changedEvent = { title: '', start: null, end: '', allDay: null };
101   - },
102   - reset() {
103   - this.changedEvent.title = this.clickedEvent.title;
104   - this.changedEvent.start = this.clickedEvent.start;
105   - this.changedEvent.end = this.clickedEvent.end;
106   - },
107   - },
108   -};
109   -</script>
110   -
111   -<style scoped>
112   -::v-deep(.fc .fc-col-header-cell-cushion),
113   -::v-deep(.fc-daygrid-dot-event .fc-event-time),
114   -::v-deep(.fc-daygrid-dot-event .fc-event-title),
115   -::v-deep(.fc .fc-daygrid-day-number),
116   -::v-deep(.fc .fc-daygrid-more-link) {
117   - color: var(--text-color);
118   -}
119   -
120   -@media screen and (max-width: 960px) {
121   - ::v-deep(.fc-header-toolbar) {
122   - display: flex;
123   - flex-wrap: wrap;
124   - }
125   -}
126   -</style>
prestige-vue-4.0.0/src/views/system/SystemCode.vue
1 1 <template>
2 2 <div class="card">
3 3 <Toast />
4   - <div class="card formgrid grid">
5   - <div class="field col grid">
6   - <div class="field col-12 md:col-6">
  4 + <div class="card formgrid grid" style="margin-bottom: 0px;">
  5 + <div class="field col grid" style="margin-bottom: 0px;">
  6 + <div class="field col-12 md:col-6" style="margin-bottom: 0px;">
7 7 <label for="codeType">코드유형</label>
8 8 <AutoComplete v-model="codeType" dropdown :suggestions="filteredItems" @complete="searchItems" class="w-full" />
9 9 </div>
10   - <div class="field col-12 md:col-6">
  10 + <div class="field col-12 md:col-6" style="margin-bottom: 0px;">
11 11 <label for="useAt">사용여부</label>
12 12 <SelectButton v-model="useAt" :options="options" aria-labelledby="basic" class="w-full" @click="setData(data)"/>
13 13 </div>
14 14 </div>
15 15 <SplitButton label="Search" icon="pi pi-plus" @click="search" :model="buttonItems" class="bg-primary" />
16 16 </div>
17   -
  17 + <Toolbar style="background: #ffffff; border: 0px;">
  18 + <template #end>
  19 + <Button icon="pi pi-refresh" aria-label="Filter" @click="refreshRow()"/>
  20 + <span style="width: 5px;"></span>
  21 + <Button icon="pi pi-plus" aria-label="Filter" @click="addRow()"/>
  22 + <span style="width: 5px;"></span>
  23 + <Button icon="pi pi-minus" aria-label="Filter" @click="delRow()"/>
  24 + </template>
  25 + </Toolbar>
18 26 <div class="grid">
19 27 <div class="col-12 md:col-4" style="padding: 0; padding-right: 10px;">
20 28 <ag-grid-vue
21 29 style="width: 100%; height: 350px;"
22   - class="ag-theme-quartz"
  30 + class="ag-theme-balham"
23 31 :columnDefs="columnsType"
24 32 :rowData="codeTypeItems"
25 33 @grid-ready="onGridReadyType"
... ... @@ -32,7 +40,7 @@
32 40 <div class="col-12 md:col-8" style="padding: 0">
33 41 <ag-grid-vue
34 42 style="width: 100%; height: 350px;"
35   - class="ag-theme-quartz"
  43 + class="ag-theme-balham"
36 44 :columnDefs="columns"
37 45 :rowData="codeItems"
38 46 :rowSelection="rowSelection"
... ... @@ -56,6 +64,7 @@ import axios from &#39;../../service/axios&#39;;
56 64 import { onBeforeMount, ref } from 'vue';
57 65 import { useI18n } from 'vue-i18n'
58 66 import RendererRowStatus from "../common/RendererRowStatus.vue";
  67 +import ags from '../../service/AgGridService';
59 68  
60 69 const toast = useToast();
61 70  
... ... @@ -103,6 +112,12 @@ const columns = [
103 112 cellRenderer: RendererRowStatus
104 113 },
105 114 {
  115 + headerName: i18n.t('System.SystemCode.grid.CodeType'),
  116 + field: "codeTy",
  117 + editable: true,
  118 + pinned: 'left',
  119 + },
  120 + {
106 121 headerName: i18n.t('System.SystemCode.grid.Code'),
107 122 field: "cmmnCode",
108 123 editable: true,
... ... @@ -181,6 +196,7 @@ const columns = [
181 196 const rowSelection = ref(null);
182 197 const gridApiType = ref();
183 198 const gridApi = ref();
  199 +let selectCodeTy = "";
184 200  
185 201 onBeforeMount(() => {
186 202 rowSelection.value = 'single';
... ... @@ -198,16 +214,14 @@ const onSelectionChanged = () =&gt; {
198 214 }
199 215 );
200 216 }
  217 + selectCodeTy = selectedRows[0].cmmnCode;
201 218 };
202 219  
203 220 const onCellValueChanged = (event) => {
204   - console.log("onCellValueChanged");
205   - event.data.rowStatus = "U";
206   - const res = gridApi.value.applyTransaction({
207   - update: [event.data]
208   - });
  221 + let res = ags.agGridChangeStatusRow(gridApi, event);
209 222 console.log(res);
210 223 };
  224 +
211 225 const onGridReadyType = (params) => {
212 226 gridApiType.value = params.api;
213 227  
... ... @@ -269,6 +283,7 @@ const setData = (responseData) =&gt; {
269 283 defaultMinWidth: 50
270 284 });
271 285 codeItems.value = [];
  286 + selectCodeTy = "";
272 287 }
273 288  
274 289 const buttonItems = [
... ... @@ -323,6 +338,24 @@ const saveData = async () =&gt; {
323 338  
324 339 };
325 340  
  341 +const addRow = () => {
  342 + const res = ags.agGridAddRow(gridApi, 1, false);
  343 + console.log(res);
  344 +}
  345 +
  346 +const delRow = () => {
  347 + const selectedNodes = gridApi.value.getSelectedNodes(); //[]
  348 + const res = ags.agGridDelRow(gridApi, selectedNodes);
  349 + console.log(res);
  350 +}
  351 +
  352 +const refreshRow = () => {
  353 + const selectedRows = gridApi.value.getSelectedRows();
  354 + ags.agGridEraseStatusRow(gridApi, selectedRows);
  355 + console.log(res);
  356 +}
  357 +
  358 +
326 359 //--------------------------------------------------------------------------------------------
327 360  
328 361 </script>
... ...
prestige-vue-4.0.0/src/views/system/User.vue
1 1 <template>
2   - <div class="grid crud-demo">
3   - <div class="col-12">
4   - <div class="card">
5   - <Toast />
6   - <Toolbar class="mb-4">
7   - <template v-slot:start>
8   - <div class="my-2">
9   - <Button label="New" icon="pi pi-plus" class="p-button-success mr-2" @click="openNew" />
10   - <Button label="Delete" icon="pi pi-trash" class="p-button-danger" @click="confirmDeleteSelected" :disabled="!selectedProducts || !selectedProducts.length" />
11   - </div>
12   - </template>
13   -
14   - <template v-slot:end>
15   - <FileUpload mode="basic" accept="image/*" :maxFileSize="1000000" label="Import" chooseLabel="Import" class="mr-2 inline-block" />
16   - <Button label="Export" icon="pi pi-upload" class="p-button-help" @click="exportCSV($event)" />
17   - </template>
18   - </Toolbar>
19   -
20   - <DataTable
21   - ref="dt"
22   - :value="products"
23   - v-model:selection="selectedProducts"
24   - dataKey="id"
25   - :paginator="true"
26   - :rows="10"
27   - :filters="filters"
28   - paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
29   - :rowsPerPageOptions="[5, 10, 25]"
30   - currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products"
31   - responsiveLayout="scroll"
  2 + <div class="card">
  3 + <Toast />
  4 + <div class="card formgrid grid" style="margin-bottom: 0px;">
  5 + <div class="field col grid" style="margin-bottom: 0px;">
  6 + <div class="field col-12 md:col-6" style="margin-bottom: 0px;">
  7 + <label for="userId">사용자Id</label>
  8 + <AutoComplete v-model="userId" dropdown :suggestions="filteredItems" @complete="searchItems" class="w-full" />
  9 + </div>
  10 + <div class="field col-12 md:col-6" style="margin-bottom: 0px;">
  11 + <label for="activated">사용여부</label>
  12 + <SelectButton v-model="activated" :options="options" aria-labelledby="basic" class="w-full" @click="setData(data)"/>
  13 + </div>
  14 + </div>
  15 + <SplitButton label="Search" icon="pi pi-plus" @click="search" :model="buttonItems" class="bg-primary" />
  16 + </div>
  17 + <Toolbar style="background: #ffffff; border: 0px;">
  18 + <template #end>
  19 + <Button icon="pi pi-refresh" aria-label="Filter" @click="refreshRow()"/>
  20 + <span style="width: 5px;"></span>
  21 + <Button icon="pi pi-plus" aria-label="Filter" @click="addRow()"/>
  22 + <span style="width: 5px;"></span>
  23 + <Button icon="pi pi-minus" aria-label="Filter" @click="delRow()"/>
  24 + </template>
  25 + </Toolbar>
  26 + <div class="grid">
  27 + <div class="col-12 md:col-12" style="padding: 0; padding-right: 10px;">
  28 + <ag-grid-vue
  29 + style="width: 100%; height: 350px;"
  30 + class="ag-theme-balham"
  31 + :columnDefs="columns"
  32 + :rowData="userItems"
  33 + @grid-ready="onGridReady"
  34 + :rowSelection="rowSelection"
  35 + @cell-value-changed ="onCellValueChanged"
  36 + :defaultColDef="defaultColDef"
32 37 >
33   - <template #header>
34   - <div class="flex flex-column md:flex-row md:justify-content-between md:align-items-center">
35   - <h5 class="m-0">Manage Products</h5>
36   - <span class="block mt-2 md:mt-0 p-input-icon-left">
37   - <i class="pi pi-search" />
38   - <InputText v-model="filters['global'].value" placeholder="Search..." />
39   - </span>
40   - </div>
41   - </template>
42   -
43   - <Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
44   - <Column field="code" header="Code" :sortable="true" headerStyle="width:14%; min-width:10rem;">
45   - <template #body="slotProps">
46   - <span class="p-column-title">Code</span>
47   - {{ slotProps.data.code }}
48   - </template>
49   - </Column>
50   - <Column field="name" header="Name" :sortable="true" headerStyle="width:14%; min-width:10rem;">
51   - <template #body="slotProps">
52   - <span class="p-column-title">Name</span>
53   - {{ slotProps.data.name }}
54   - </template>
55   - </Column>
56   - <Column header="Image" headerStyle="width:14%; min-width:10rem;">
57   - <template #body="slotProps">
58   - <span class="p-column-title">Image</span>
59   - <img :src="'/demo/images/product/' + slotProps.data.image" :alt="slotProps.data.image" class="shadow-2" width="100" />
60   - </template>
61   - </Column>
62   - <Column field="price" header="Price" :sortable="true" headerStyle="width:14%; min-width:8rem;">
63   - <template #body="slotProps">
64   - <span class="p-column-title">Price</span>
65   - {{ formatCurrency(slotProps.data.price) }}
66   - </template>
67   - </Column>
68   - <Column field="category" header="Category" :sortable="true" headerStyle="width:14%; min-width:10rem;">
69   - <template #body="slotProps">
70   - <span class="p-column-title">Category</span>
71   - {{ formatCurrency(slotProps.data.category) }}
72   - </template>
73   - </Column>
74   - <Column field="rating" header="Reviews" :sortable="true" headerStyle="width:14%; min-width:10rem;">
75   - <template #body="slotProps">
76   - <span class="p-column-title">Rating</span>
77   - <Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
78   - </template>
79   - </Column>
80   - <Column field="inventoryStatus" header="Status" :sortable="true" headerStyle="width:14%; min-width:10rem;">
81   - <template #body="slotProps">
82   - <span class="p-column-title">Status</span>
83   - <span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{ slotProps.data.inventoryStatus }}</span>
84   - </template>
85   - </Column>
86   - <Column headerStyle="width:14%; min-width:10rem;">
87   - <template #body="slotProps">
88   - <Button icon="pi pi-pencil" class="p-button-rounded p-button-success mr-2" @click="editProduct(slotProps.data)" />
89   - <Button icon="pi pi-trash" class="p-button-rounded p-button-warning" @click="confirmDeleteProduct(slotProps.data)" />
90   - </template>
91   - </Column>
92   - </DataTable>
93   -
94   - <Dialog v-model:visible="productDialog" :style="{ width: '450px' }" header="Product Details" :modal="true" class="p-fluid">
95   - <img :src="'/demo/images/product/' + product.image" :alt="product.image" v-if="product.image" width="150" class="mt-0 mx-auto mb-5 block shadow-2" />
96   - <div class="field">
97   - <label for="name">Name</label>
98   - <InputText id="name" v-model.trim="product.name" required="true" autofocus :class="{ 'p-invalid': submitted && !product.name }" />
99   - <small class="p-invalid" v-if="submitted && !product.name">Name is required.</small>
100   - </div>
101   - <div class="field">
102   - <label for="description">Description</label>
103   - <Textarea id="description" v-model="product.description" required="true" rows="3" cols="20" />
104   - </div>
105   -
106   - <div class="field">
107   - <label for="inventoryStatus" class="mb-3">Inventory Status</label>
108   - <Dropdown id="inventoryStatus" v-model="product.inventoryStatus" :options="statuses" optionLabel="label" placeholder="Select a Status">
109   - <template #value="slotProps">
110   - <div v-if="slotProps.value && slotProps.value.value">
111   - <span :class="'product-badge status-' + slotProps.value.value">{{ slotProps.value.label }}</span>
112   - </div>
113   - <div v-else-if="slotProps.value && !slotProps.value.value">
114   - <span :class="'product-badge status-' + slotProps.value.toLowerCase()">{{ slotProps.value }}</span>
115   - </div>
116   - <span v-else>
117   - {{ slotProps.placeholder }}
118   - </span>
119   - </template>
120   - </Dropdown>
121   - </div>
122   -
123   - <div class="field">
124   - <label class="mb-3">Category</label>
125   - <div class="formgrid grid">
126   - <div class="field-radiobutton col-6">
127   - <RadioButton id="category1" name="category" value="Accessories" v-model="product.category" />
128   - <label for="category1">Accessories</label>
129   - </div>
130   - <div class="field-radiobutton col-6">
131   - <RadioButton id="category2" name="category" value="Clothing" v-model="product.category" />
132   - <label for="category2">Clothing</label>
133   - </div>
134   - <div class="field-radiobutton col-6">
135   - <RadioButton id="category3" name="category" value="Electronics" v-model="product.category" />
136   - <label for="category3">Electronics</label>
137   - </div>
138   - <div class="field-radiobutton col-6">
139   - <RadioButton id="category4" name="category" value="Fitness" v-model="product.category" />
140   - <label for="category4">Fitness</label>
141   - </div>
142   - </div>
143   - </div>
144   -
145   - <div class="formgrid grid">
146   - <div class="field col">
147   - <label for="price">Price</label>
148   - <InputNumber id="price" v-model="product.price" mode="currency" currency="USD" locale="en-US" />
149   - </div>
150   - <div class="field col">
151   - <label for="quantity">Quantity</label>
152   - <InputNumber id="quantity" v-model="product.quantity" integeronly />
153   - </div>
154   - </div>
155   - <template #footer>
156   - <Button label="Cancel" icon="pi pi-times" class="p-button-text" @click="hideDialog" />
157   - <Button label="Save" icon="pi pi-check" class="p-button-text" @click="saveProduct" />
158   - </template>
159   - </Dialog>
160   -
161   - <Dialog v-model:visible="deleteProductDialog" :style="{ width: '450px' }" header="Confirm" :modal="true">
162   - <div class="flex align-items-center justify-content-center">
163   - <i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem" />
164   - <span v-if="product"
165   - >Are you sure you want to delete <b>{{ product.name }}</b
166   - >?</span
167   - >
168   - </div>
169   - <template #footer>
170   - <Button label="No" icon="pi pi-times" class="p-button-text" @click="deleteProductDialog = false" />
171   - <Button label="Yes" icon="pi pi-check" class="p-button-text" @click="deleteProduct" />
172   - </template>
173   - </Dialog>
174   -
175   - <Dialog v-model:visible="deleteProductsDialog" :style="{ width: '450px' }" header="Confirm" :modal="true">
176   - <div class="flex align-items-center justify-content-center">
177   - <i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem" />
178   - <span v-if="product">Are you sure you want to delete the selected products?</span>
179   - </div>
180   - <template #footer>
181   - <Button label="No" icon="pi pi-times" class="p-button-text" @click="deleteProductsDialog = false" />
182   - <Button label="Yes" icon="pi pi-check" class="p-button-text" @click="deleteSelectedProducts" />
183   - </template>
184   - </Dialog>
  38 + </ag-grid-vue>
185 39 </div>
  40 +
186 41 </div>
187 42 </div>
188 43 </template>
189 44  
190   -<script>
191   -import { FilterMatchMode } from 'primevue/api';
192   -import ProductService from '@/service/ProductService';
193   -
194   -export default {
195   - data() {
196   - return {
197   - products: null,
198   - productDialog: false,
199   - deleteProductDialog: false,
200   - deleteProductsDialog: false,
201   - product: {},
202   - selectedProducts: null,
203   - filters: {},
204   - submitted: false,
205   - statuses: [
206   - { label: 'INSTOCK', value: 'instock' },
207   - { label: 'LOWSTOCK', value: 'lowstock' },
208   - { label: 'OUTOFSTOCK', value: 'outofstock' },
209   - ],
210   - };
  45 +<script setup>
  46 +//--------------------------------------------------------------------------------------------
  47 +// imprort
  48 +//--------------------------------------------------------------------------------------------
  49 +import { useToast } from "primevue/usetoast";
  50 +import axios from '../../service/axios';
  51 +import { onBeforeMount, ref } from 'vue';
  52 +import { useI18n } from 'vue-i18n'
  53 +import RendererRowStatus from "../common/RendererRowStatus.vue";
  54 +import ags from '../../service/AgGridService';
  55 +
  56 +const toast = useToast();
  57 +
  58 +//--------------------------------------------------------------------------------------------
  59 +// 변수선언
  60 +//--------------------------------------------------------------------------------------------
  61 +const userItems = ref("");
  62 +const filteredItems = ref();
  63 +const userId = ref("");
  64 +const activated = ref("전체");
  65 +const options = ref(['전체', '사용', '미사용']);
  66 +
  67 +let data = [];
  68 +
  69 +const i18n = useI18n()
  70 +//--------------------------------------------------------------------------------------------
  71 +
  72 +//--------------------------------------------------------------------------------------------
  73 +// ag-grid Header
  74 +//--------------------------------------------------------------------------------------------
  75 +
  76 +const defaultColDef = {
  77 + filter: true,
  78 + enableCellChangeFlash: true,
  79 +};
  80 +
  81 +const columns = [
  82 + {
  83 + headerName: "",
  84 + field: "rowStatus",
  85 + editable: false,
  86 + pinned: 'left',
  87 + maxWidth: 45,
  88 + cellRenderer: RendererRowStatus
  89 + },
  90 + {
  91 + headerName: "사용자ID",
  92 + field: "userId",
  93 + editable: false,
211 94 },
212   - productService: null,
213   - created() {
214   - this.productService = new ProductService();
215   - this.initFilters();
  95 + {
  96 + headerName: "사용여부",
  97 + field: "activated",
  98 + maxWidth: 100,
  99 + editable: true,
216 100 },
217   - mounted() {
218   - this.productService.getProducts().then((data) => (this.products = data));
  101 + {
  102 + headerName: "사용자명",
  103 + field: "username",
  104 + editable: true,
219 105 },
220   - methods: {
221   - formatCurrency(value) {
222   - if (value) return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
223   - return;
224   - },
225   - openNew() {
226   - this.product = {};
227   - this.submitted = false;
228   - this.productDialog = true;
229   - },
230   - hideDialog() {
231   - this.productDialog = false;
232   - this.submitted = false;
233   - },
234   - saveProduct() {
235   - this.submitted = true;
236   - if (this.product.name.trim()) {
237   - if (this.product.id) {
238   - this.product.inventoryStatus = this.product.inventoryStatus.value ? this.product.inventoryStatus.value : this.product.inventoryStatus;
239   - this.products[this.findIndexById(this.product.id)] = this.product;
240   - this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Updated', life: 3000 });
241   - } else {
242   - this.product.id = this.createId();
243   - this.product.code = this.createId();
244   - this.product.image = 'product-placeholder.svg';
245   - this.product.inventoryStatus = this.product.inventoryStatus ? this.product.inventoryStatus.value : 'INSTOCK';
246   - this.products.push(this.product);
247   - this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Created', life: 3000 });
248   - }
249   - this.productDialog = false;
250   - this.product = {};
251   - }
252   - },
253   - editProduct(product) {
254   - this.product = { ...product };
255   - this.productDialog = true;
256   - },
257   - confirmDeleteProduct(product) {
258   - this.product = product;
259   - this.deleteProductDialog = true;
260   - },
261   - deleteProduct() {
262   - this.products = this.products.filter((val) => val.id !== this.product.id);
263   - this.deleteProductDialog = false;
264   - this.product = {};
265   - this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Deleted', life: 3000 });
266   - },
267   - findIndexById(id) {
268   - let index = -1;
269   - for (let i = 0; i < this.products.length; i++) {
270   - if (this.products[i].id === id) {
271   - index = i;
272   - break;
273   - }
274   - }
275   - return index;
276   - },
277   - createId() {
278   - let id = '';
279   - var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
280   - for (var i = 0; i < 5; i++) {
281   - id += chars.charAt(Math.floor(Math.random() * chars.length));
282   - }
283   - return id;
284   - },
285   - exportCSV() {
286   - this.$refs.dt.exportCSV();
287   - },
288   - confirmDeleteSelected() {
289   - this.deleteProductsDialog = true;
290   - },
291   - deleteSelectedProducts() {
292   - this.products = this.products.filter((val) => !this.selectedProducts.includes(val));
293   - this.deleteProductsDialog = false;
294   - this.selectedProducts = null;
295   - this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Products Deleted', life: 3000 });
296   - },
297   - initFilters() {
298   - this.filters = {
299   - global: { value: null, matchMode: FilterMatchMode.CONTAINS },
300   - };
301   - },
  106 + {
  107 + headerName: "패스워드",
  108 + field: "password",
  109 + editable: true,
302 110 },
  111 + {
  112 + headerName: "별명",
  113 + field: "nickname",
  114 + editable: true,
  115 + }
  116 +];
  117 +//--------------------------------------------------------------------------------------------
  118 +
  119 +
  120 +
  121 +//--------------------------------------------------------------------------------------------
  122 +//ag-grid function
  123 +//--------------------------------------------------------------------------------------------
  124 +const rowSelection = ref(null);
  125 +const gridApi = ref();
  126 +
  127 +onBeforeMount(() => {
  128 + rowSelection.value = 'single';
  129 +});
  130 +
  131 +const onCellValueChanged = (event) => {
  132 + let res = ags.agGridChangeStatusRow(gridApi, event);
  133 + console.log(res);
303 134 };
304   -</script>
305 135  
306   -<style scoped lang="scss">
307   -@import '@/assets/demo/styles/badges.scss';
308   -</style>
  136 +const onGridReady = (params) => {
  137 + gridApi.value = params.api;
  138 +
  139 + getData();
  140 +};
  141 +
  142 +const searchItems = (event) => {
  143 + let query = event.query;
  144 + let _filteredItems = [];
  145 +
  146 + for (let i = 0; i < userItems.value.length; i++) {
  147 + let item = userItems.value[i];
  148 +
  149 + if (item.username.toLowerCase().indexOf(query.toLowerCase()) >= 0) {
  150 + _filteredItems.push(item.userId + " : " + item.username );
  151 + }
  152 + }
  153 +
  154 + filteredItems.value = _filteredItems;
  155 +};
  156 +//--------------------------------------------------------------------------------------------
  157 +
  158 +//--------------------------------------------------------------------------------------------
  159 +// 일반 Function
  160 +//--------------------------------------------------------------------------------------------
  161 +const getData = async () => {
  162 +
  163 + try{
  164 + const response = await axios.post('/api/user/users', {});
  165 + console.log('response => ');
  166 + console.log(response);
  167 +
  168 + console.log('response.status = ' + response.status);
  169 + if (response.status == 200) {
  170 + console.log('Search Datas: ' + JSON.stringify(response.data));
  171 +
  172 + setData(response.data);
  173 +
  174 + toast.add({ severity: 'success', summary: 'Success', detail: 'Search successfully', life: 3000 });
  175 + }
  176 + return response.status;
  177 + }catch(err){
  178 + toast.add({ severity: 'error', summary: 'Error', detail: err.message, life: 3000 });
  179 + return err.message;
  180 + }
  181 +
  182 +};
  183 +
  184 +const setData = (responseData) => {
  185 + data = responseData; //조회데이타
  186 + //코드타입 데이타만 업데이트
  187 + let sActivated = activated.value==="전체"?"true,false":activated.value==="사용"?"true":"false";
  188 + userItems.value = data.filter(rec => sActivated.indexOf(rec.activated) > -1).sort((a, b) => a.userId - b.userId) ;
  189 + gridApi.value.sizeColumnsToFit({
  190 + defaultMinWidth: 50
  191 + });
  192 +}
  193 +
  194 +const buttonItems = [
  195 +{
  196 + label: 'Save',
  197 + icon: 'pi pi-save',
  198 + command: () => {
  199 + saveData();
  200 + }
  201 +},
  202 +{
  203 + label: 'Download',
  204 + icon: 'pi pi-file-excel',
  205 + command: () => {
  206 + window.location.href = 'https://vuejs.org/';
  207 + }
  208 +}
  209 +];
  210 +
  211 +const search = () => {
  212 + getData();
  213 +};
  214 +
  215 +const saveData = async () => {
  216 +
  217 + try{
  218 + //rowStatus가 N,U,D인 것만 필터링
  219 + let updatedData = ags.agGridGetData(gridApi, true);
  220 + const saveParams = {
  221 + //여기에 업데이트된 데이타 보내기
  222 + searchCond: {},
  223 + saveData: updatedData
  224 + };
  225 + const response = await axios.post('/api/user/saveUsers', saveParams);
  226 + console.log('response => ');
  227 + console.log(response);
  228 +
  229 + console.log('response.status = ' + response.status);
  230 + if (response.status == 200) {
  231 + console.log('Search Datas: ' + JSON.stringify(response.data));
  232 +
  233 + setData(response.data);
  234 +
  235 + toast.add({ severity: 'success', summary: 'Success', detail: 'Save successfully', life: 3000 });
  236 + }
  237 + return response.status;
  238 + }catch(err){
  239 + toast.add({ severity: 'error', summary: 'Error', detail: err.message, life: 3000 });
  240 + return err.message;
  241 + }
  242 +
  243 +};
  244 +
  245 +const addRow = () => {
  246 + const res = ags.agGridAddRow(gridApi, 1, false);
  247 + console.log(res);
  248 +}
  249 +
  250 +const delRow = () => {
  251 + const selectedNodes = gridApi.value.getSelectedNodes(); //[]
  252 + const res = ags.agGridDelRow(gridApi, selectedNodes);
  253 + console.log(res);
  254 +}
  255 +
  256 +const refreshRow = () => {
  257 + const selectedRows = gridApi.value.getSelectedRows();
  258 + ags.agGridEraseStatusRow(gridApi, selectedRows);
  259 + console.log(res);
  260 +}
  261 +
  262 +
  263 +//--------------------------------------------------------------------------------------------
  264 +
  265 +</script>
... ...
prestige-vue-4.0.0/src/views/system/UserAuthority.vue 0 → 100644
  1 +<template>
  2 + <div class="card">
  3 + <Toast />
  4 + <div class="card formgrid grid" style="margin-bottom: 0px;">
  5 + <div class="field col grid" style="margin-bottom: 0px;">
  6 + <div class="field col-12 md:col-6" style="margin-bottom: 0px;">
  7 + <label for="username">사용자명</label>
  8 + <AutoComplete v-model="username" dropdown :suggestions="filteredItems" @complete="searchItems" class="w-full" />
  9 + </div>
  10 + </div>
  11 + <SplitButton label="Search" icon="pi pi-plus" @click="search" :model="buttonItems" class="bg-primary" />
  12 + </div>
  13 + <Toolbar style="background: #ffffff; border: 0px;">
  14 + <template #end>
  15 + <Button icon="pi pi-refresh" aria-label="Filter" @click="refreshRow()"/>
  16 + <span style="width: 5px;"></span>
  17 + <Button icon="pi pi-plus" aria-label="Filter" @click="addRow()"/>
  18 + <span style="width: 5px;"></span>
  19 + <Button icon="pi pi-minus" aria-label="Filter" @click="delRow()"/>
  20 + </template>
  21 + </Toolbar>
  22 + <div class="grid">
  23 + <div class="col-12 md:col-12" style="padding: 0; padding-right: 10px;">
  24 + <ag-grid-vue
  25 + style="width: 100%; height: 350px;"
  26 + class="ag-theme-balham"
  27 + :columnDefs="columns"
  28 + :rowData="userAuthorityItems"
  29 + @grid-ready="onGridReady"
  30 + :rowSelection="rowSelection"
  31 + @cell-value-changed ="onCellValueChanged"
  32 + :defaultColDef="defaultColDef"
  33 + >
  34 + </ag-grid-vue>
  35 + </div>
  36 +
  37 + </div>
  38 + </div>
  39 +</template>
  40 +
  41 +<script setup>
  42 +//--------------------------------------------------------------------------------------------
  43 +// imprort
  44 +//--------------------------------------------------------------------------------------------
  45 +import { useToast } from "primevue/usetoast";
  46 +import axios from '../../service/axios';
  47 +import { onBeforeMount, ref } from 'vue';
  48 +import { useI18n } from 'vue-i18n'
  49 +import RendererRowStatus from "../common/RendererRowStatus.vue";
  50 +import ags from '../../service/AgGridService';
  51 +
  52 +const toast = useToast();
  53 +
  54 +//--------------------------------------------------------------------------------------------
  55 +// 변수선언
  56 +//--------------------------------------------------------------------------------------------
  57 +const userAuthorityItems = ref("");
  58 +const filteredItems = ref();
  59 +const username = ref("");
  60 +
  61 +let data = [];
  62 +
  63 +const i18n = useI18n()
  64 +//--------------------------------------------------------------------------------------------
  65 +
  66 +//--------------------------------------------------------------------------------------------
  67 +// ag-grid Header
  68 +//--------------------------------------------------------------------------------------------
  69 +
  70 +const defaultColDef = {
  71 + filter: true,
  72 + enableCellChangeFlash: true,
  73 +};
  74 +
  75 +const userNames = ref([]);
  76 +const authorities = ref([]);
  77 +
  78 +const columns = [
  79 + {
  80 + headerName: "",
  81 + field: "rowStatus",
  82 + editable: false,
  83 + pinned: 'left',
  84 + maxWidth: 45,
  85 + cellRenderer: RendererRowStatus
  86 + },
  87 + {
  88 + headerName: "사용자ID",
  89 + field: "userId",
  90 + editable: false,
  91 + maxWidth: 150,
  92 + },
  93 + {
  94 + headerName: "사용자명",
  95 + field: "username",
  96 + editable: true,
  97 + cellEditor: "agSelectCellEditor",
  98 + cellEditorParams: { values: userNames.value },
  99 + },
  100 + {
  101 + headerName: "권한명",
  102 + field: "authorityName",
  103 + editable: true,
  104 + cellEditor: "agSelectCellEditor",
  105 + cellEditorParams: { values: authorities.value },
  106 + }
  107 +];
  108 +//--------------------------------------------------------------------------------------------
  109 +
  110 +
  111 +
  112 +//--------------------------------------------------------------------------------------------
  113 +//ag-grid function
  114 +//--------------------------------------------------------------------------------------------
  115 +const rowSelection = ref(null);
  116 +const gridApi = ref();
  117 +
  118 +onBeforeMount(() => {
  119 + rowSelection.value = 'single';
  120 +});
  121 +
  122 +const onCellValueChanged = (event) => {
  123 + let res = ags.agGridChangeStatusRow(gridApi, event);
  124 + console.log(res);
  125 +};
  126 +
  127 +const onGridReady = (params) => {
  128 + gridApi.value = params.api;
  129 +
  130 + getData();
  131 +};
  132 +
  133 +const searchItems = (event) => {
  134 + let query = event.query;
  135 + let _filteredItems = [];
  136 +
  137 + for (let i = 0; i < userAuthorityItems.value.length; i++) {
  138 + let item = userAuthorityItems.value[i];
  139 +
  140 + if (item.username.toLowerCase().indexOf(query.toLowerCase()) >= 0) {
  141 + _filteredItems.push(item.username);
  142 + }
  143 + }
  144 +
  145 + filteredItems.value = _filteredItems;
  146 +};
  147 +//--------------------------------------------------------------------------------------------
  148 +
  149 +//--------------------------------------------------------------------------------------------
  150 +// 일반 Function
  151 +//--------------------------------------------------------------------------------------------
  152 +const getData = async () => {
  153 +
  154 + try{
  155 + const response = await axios.post('/api/user/usersAuthority', {
  156 + username: username.value
  157 + });
  158 + console.log('response => ');
  159 + console.log(response);
  160 +
  161 + console.log('response.status = ' + response.status);
  162 + if (response.status == 200) {
  163 + console.log('Search Datas: ' + JSON.stringify(response.data));
  164 +
  165 + setData(response.data);
  166 +
  167 + toast.add({ severity: 'success', summary: 'Success', detail: 'Search successfully', life: 3000 });
  168 + }
  169 + return response.status;
  170 + }catch(err){
  171 + toast.add({ severity: 'error', summary: 'Error', detail: err.message, life: 3000 });
  172 + return err.message;
  173 + }
  174 +
  175 +};
  176 +
  177 +const setData = (responseData) => {
  178 + data = responseData; //조회데이타(userAuthority, userList, authorityList)
  179 +
  180 + //리스트에 새로운 배열을 셋팅해서 넣으면 컬럼의 값과 연결이 되지 않기 때문에 기존의 배열을 조작해서 넣어야 연결이 된다.
  181 + userNames.value.splice(0);
  182 + data.userList.map(rec => userNames.value.push(rec.username));
  183 + authorities.value.splice(0);
  184 + data.authorityList.map(rec => authorities.value.push(rec.authority_name));
  185 +
  186 + //데이타 셋팅
  187 + userAuthorityItems.value = data.userAuthority.sort((a, b) => a.userId - b.userId) ;
  188 +
  189 + gridApi.value.sizeColumnsToFit({
  190 + defaultMinWidth: 50
  191 + });
  192 +
  193 +
  194 +}
  195 +
  196 +const buttonItems = [
  197 +{
  198 + label: 'Save',
  199 + icon: 'pi pi-save',
  200 + command: () => {
  201 + saveData();
  202 + }
  203 +},
  204 +{
  205 + label: 'Download',
  206 + icon: 'pi pi-file-excel',
  207 + command: () => {
  208 + window.location.href = 'https://vuejs.org/';
  209 + }
  210 +}
  211 +];
  212 +
  213 +const search = () => {
  214 + getData();
  215 +};
  216 +
  217 +const saveData = async () => {
  218 +
  219 + try{
  220 + //rowStatus가 N,U,D인 것만 필터링
  221 + let updatedData = ags.agGridGetData(gridApi, true);
  222 + const saveParams = {
  223 + //여기에 업데이트된 데이타 보내기
  224 + searchCond: {"username": username},
  225 + saveData: updatedData
  226 + };
  227 + const response = await axios.post('/api/user/saveUsersAuthority', saveParams);
  228 + console.log('response => ');
  229 + console.log(response);
  230 +
  231 + console.log('response.status = ' + response.status);
  232 + if (response.status == 200) {
  233 + console.log('Search Datas: ' + JSON.stringify(response.data));
  234 +
  235 + setData(response.data);
  236 +
  237 + toast.add({ severity: 'success', summary: 'Success', detail: 'Save successfully', life: 3000 });
  238 + }
  239 + return response.status;
  240 + }catch(err){
  241 + toast.add({ severity: 'error', summary: 'Error', detail: err.message, life: 3000 });
  242 + return err.message;
  243 + }
  244 +
  245 +};
  246 +
  247 +const addRow = () => {
  248 + const res = ags.agGridAddRow(gridApi, 1, false);
  249 + console.log(res);
  250 +}
  251 +
  252 +const delRow = () => {
  253 + const selectedNodes = gridApi.value.getSelectedNodes(); //[]
  254 + const res = ags.agGridDelRow(gridApi, selectedNodes);
  255 + console.log(res);
  256 +}
  257 +
  258 +const refreshRow = () => {
  259 + const selectedRows = gridApi.value.getSelectedRows();
  260 + ags.agGridEraseStatusRow(gridApi, selectedRows);
  261 + console.log(res);
  262 +}
  263 +
  264 +
  265 +//--------------------------------------------------------------------------------------------
  266 +
  267 +</script>
... ...
src/main/java/daeucna/config/security/JwtSecurityConfig.java
... ... @@ -12,7 +12,7 @@ import lombok.RequiredArgsConstructor;
12 12 @RequiredArgsConstructor
13 13 public class JwtSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
14 14 private final JwtTokenProvider tokenProvider;
15   -
  15 +
16 16 @Override
17 17 public void configure(HttpSecurity http) {
18 18  
... ...
src/main/java/daeucna/config/security/SecurityConfig.java
... ... @@ -10,8 +10,11 @@ import org.springframework.security.config.http.SessionCreationPolicy;
10 10 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
11 11 import org.springframework.security.crypto.password.PasswordEncoder;
12 12 import org.springframework.security.web.SecurityFilterChain;
  13 +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
13 14  
  15 +import daeucna.config.security.jwt.JwtAccessDeniedHandler;
14 16 import daeucna.config.security.jwt.JwtAuthenticationEntryPoint;
  17 +import daeucna.config.security.jwt.JwtFilter;
15 18 import daeucna.config.security.jwt.JwtTokenProvider;
16 19 import lombok.RequiredArgsConstructor;
17 20  
... ... @@ -22,6 +25,7 @@ public class SecurityConfig {
22 25  
23 26 private final JwtTokenProvider tokenProvider;
24 27 private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
  28 + private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
25 29  
26 30 // PasswordEncoder는 BCryptPasswordEncoder를 사용
27 31 @Bean
... ... @@ -45,6 +49,11 @@ public class SecurityConfig {
45 49 // .anyRequest().permitAll()
46 50 .anyRequest().authenticated() // 그 외 인증 없이 접근X
47 51 )
  52 + .exceptionHandling(exceptionHandling -> exceptionHandling
  53 + .authenticationEntryPoint(jwtAuthenticationEntryPoint)
  54 + .accessDeniedPage("/api/exceptionDenied")
  55 + .accessDeniedHandler(jwtAccessDeniedHandler)
  56 + )
48 57 .formLogin(Customizer.withDefaults())
49 58 .headers((headers) ->
50 59 headers
... ... @@ -52,16 +61,13 @@ public class SecurityConfig {
52 61 .sameOrigin()
53 62 )
54 63 )
55   - .exceptionHandling(exceptionHandling -> exceptionHandling
56   - .authenticationEntryPoint(jwtAuthenticationEntryPoint)
57   - .accessDeniedPage("/api/exceptionDenied")
58   - )
59 64 // 세션을 사용하지 않기 때문에 STATELESS로 설정
60 65 .sessionManagement((sessionManagement) ->
61 66 sessionManagement
62 67 .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
63 68 )
64   - .apply(new JwtSecurityConfig(tokenProvider)); // JwtFilter를 addFilterBefore로 등록했던 JwtSecurityConfig class 적용
  69 + .addFilterBefore(new JwtFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class);
  70 +// .apply(new JwtSecurityConfig(tokenProvider)); // JwtFilter를 addFilterBefore로 등록했던 JwtSecurityConfig class 적용
65 71  
66 72 return httpSecurity.build();
67 73 }
... ...
src/main/java/daeucna/config/security/controller/ExceptionController.java
... ... @@ -16,7 +16,7 @@ public class ExceptionController {
16 16 @Operation(summary = "인가 거부", description = "인가에 따른 예외가 발생했습니다.")
17 17 @RequestMapping(value = "/exceptionDenied", method = {RequestMethod.GET, RequestMethod.POST})
18 18 public void AccessDeniedException() {
19   - throw new AccessDeniedException("");
  19 + throw new AccessDeniedException("인가거부");
20 20 }
21 21  
22 22 }
... ...
src/main/java/daeucna/config/security/controller/UserController.java
... ... @@ -18,7 +18,7 @@ import jakarta.servlet.http.HttpServletResponse;
18 18 import jakarta.validation.Valid;
19 19 import lombok.RequiredArgsConstructor;
20 20  
21   -@RestController
  21 +@RestController(value = "SecurityUserController")
22 22 @RequiredArgsConstructor
23 23 @RequestMapping("/api")
24 24 public class UserController {
... ...
src/main/java/daeucna/config/security/jwt/JwtAccessDeniedHandler.java 0 → 100644
  1 +package daeucna.config.security.jwt;
  2 +
  3 +import java.io.IOException;
  4 +
  5 +import org.springframework.security.access.AccessDeniedException;
  6 +import org.springframework.security.web.access.AccessDeniedHandler;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import jakarta.servlet.http.HttpServletRequest;
  10 +import jakarta.servlet.http.HttpServletResponse;
  11 +
  12 +@Component
  13 +public class JwtAccessDeniedHandler implements AccessDeniedHandler {
  14 +
  15 + @Override
  16 + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
  17 + //필요한 권한이 없이 접근하려 할때 403
  18 + response.sendError(HttpServletResponse.SC_FORBIDDEN);
  19 + }
  20 +}
... ...
src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java
... ... @@ -89,11 +89,16 @@ public class JwtTokenProvider implements InitializingBean {
89 89 .parseSignedClaims(token)
90 90 .getPayload();
91 91  
92   - Collection<? extends GrantedAuthority> authorities =
93   - Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
94   - .map(SimpleGrantedAuthority::new)
95   - .collect(Collectors.toList());
  92 +// Collection<? extends GrantedAuthority> authorities =
  93 +// Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
  94 +// .map(SimpleGrantedAuthority::new)
  95 +// .collect(Collectors.toList());
96 96  
  97 + Collection<? extends GrantedAuthority> authorities =
  98 + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
  99 + .map(role -> new SimpleGrantedAuthority(role))
  100 + .collect(Collectors.toList());
  101 +
97 102 User principal = new User(claims.getSubject(), "", authorities);
98 103  
99 104 return new UsernamePasswordAuthenticationToken(principal, token, authorities);
... ...
src/main/java/daeucna/mapper/primary/system/UserMapper.java 0 → 100644
  1 +package daeucna.mapper.primary.system;
  2 +
  3 +import java.util.List;
  4 +import java.util.Map;
  5 +
  6 +import org.apache.ibatis.annotations.Mapper;
  7 +
  8 +import daeucna.system.user.UserAuthorityDto;
  9 +import daeucna.system.user.UserDto;
  10 +
  11 +@Mapper
  12 +public interface UserMapper {
  13 + List<UserDto> getUsers(UserDto param);
  14 + int saveUser(UserDto param);
  15 + void deleteUser(UserDto param);
  16 +
  17 + List<UserAuthorityDto> getUsersAuthority(UserAuthorityDto param);
  18 + int saveUserAuthority(UserAuthorityDto param);
  19 + void deleteUserAuthority(UserAuthorityDto param);
  20 +
  21 + List<Map> getUserList(Map param);
  22 + List<Map> getAuthorityList(Map param);
  23 +
  24 +}
0 25 \ No newline at end of file
... ...
src/main/java/daeucna/system/code/CodeServiceImpl.java
... ... @@ -42,7 +42,7 @@ public class CodeServiceImpl implements CodeService {
42 42 //삭제처리먼저
43 43 for (CodeDto curRec : params.getSaveData()) {
44 44 String sRowStatus = curRec.getRowStatus();
45   - if ("D".indexOf(sRowStatus) > 0) {
  45 + if ("D".indexOf(sRowStatus) > -1) {
46 46 //코드
47 47 codeMapper.deleteCmmnCode(curRec);
48 48 //코드Nls
... ... @@ -52,7 +52,7 @@ public class CodeServiceImpl implements CodeService {
52 52 //신규및 업데이트 처리
53 53 for (CodeDto curRec : params.getSaveData()) {
54 54 String sRowStatus = curRec.getRowStatus();
55   - if ("N,U".indexOf(sRowStatus) > 0) {
  55 + if ("N,U".indexOf(sRowStatus) > -1) {
56 56 //코드
57 57 codeMapper.saveCmmnCode(curRec);
58 58 //코드Nls
... ...
src/main/java/daeucna/system/user/UserAuthorityDto.java 0 → 100644
  1 +package daeucna.system.user;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class UserAuthorityDto {
  7 + private String rowStatus;
  8 +
  9 + private Long userId;
  10 + private String username;
  11 + private String authorityName;
  12 +}
... ...
src/main/java/daeucna/system/user/UserAuthoritySaveDto.java 0 → 100644
  1 +package daeucna.system.user;
  2 +
  3 +import java.util.List;
  4 +
  5 +import lombok.Data;
  6 +
  7 +@Data
  8 +public class UserAuthoritySaveDto {
  9 + private UserAuthorityDto searchCond;
  10 + private List<UserAuthorityDto> saveData;
  11 +}
... ...
src/main/java/daeucna/system/user/UserController.java 0 → 100644
  1 +package daeucna.system.user;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.HashMap;
  5 +import java.util.List;
  6 +import java.util.Map;
  7 +
  8 +import org.springframework.beans.factory.annotation.Autowired;
  9 +import org.springframework.http.ResponseEntity;
  10 +import org.springframework.web.bind.annotation.PostMapping;
  11 +import org.springframework.web.bind.annotation.RequestBody;
  12 +import org.springframework.web.bind.annotation.RequestMapping;
  13 +import org.springframework.web.bind.annotation.RestController;
  14 +
  15 +import lombok.RequiredArgsConstructor;
  16 +
  17 +@RestController
  18 +@RequiredArgsConstructor
  19 +@RequestMapping("/api/user")
  20 +public class UserController {
  21 + @Autowired
  22 + private final UserService userService;
  23 +
  24 + @PostMapping("/users")
  25 + public ResponseEntity<List<UserDto>> getUsers(@RequestBody UserDto param) {
  26 + List<UserDto> rtnVal = new ArrayList<UserDto>();
  27 +
  28 + rtnVal = userService.getUsers(param);
  29 +
  30 + return ResponseEntity.ok(rtnVal);
  31 + }
  32 +
  33 + @PostMapping("/saveUsers")
  34 + public ResponseEntity<List<UserDto>> saveUsers(@RequestBody UserSaveDto params) {
  35 +
  36 + List<UserDto> rtnVal = new ArrayList<UserDto>();
  37 +
  38 + rtnVal = userService.saveUsers(params);
  39 +
  40 + return ResponseEntity.ok(rtnVal);
  41 + }
  42 +
  43 +
  44 +
  45 + @PostMapping("/usersAuthority")
  46 + public ResponseEntity<Map<String, Object>> usersAuthority(@RequestBody UserAuthorityDto param) {
  47 + Map<String, Object> rtnVal = new HashMap<String, Object>();
  48 +
  49 + rtnVal = userService.getUsersAuthority(param);
  50 +
  51 + return ResponseEntity.ok(rtnVal);
  52 + }
  53 +
  54 + @PostMapping("/saveUsersAuthority")
  55 + public ResponseEntity<Map<String, Object>> saveUsersAuthority(@RequestBody UserAuthoritySaveDto params) {
  56 +
  57 + Map<String, Object> rtnVal = new HashMap<String, Object>();
  58 +
  59 + rtnVal = userService.saveUsersAuthority(params);
  60 +
  61 + return ResponseEntity.ok(rtnVal);
  62 + }
  63 +
  64 +}
0 65 \ No newline at end of file
... ...
src/main/java/daeucna/system/user/UserDto.java 0 → 100644
  1 +package daeucna.system.user;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class UserDto {
  7 + private String rowStatus;
  8 +
  9 + private Long userId;
  10 + private String username;
  11 + private boolean activated;
  12 + private String nickname;
  13 + private String password;
  14 +}
... ...
src/main/java/daeucna/system/user/UserSaveDto.java 0 → 100644
  1 +package daeucna.system.user;
  2 +
  3 +import java.util.List;
  4 +
  5 +import lombok.Data;
  6 +
  7 +@Data
  8 +public class UserSaveDto {
  9 + private UserDto searchCond;
  10 + private List<UserDto> saveData;
  11 +}
... ...
src/main/java/daeucna/system/user/UserService.java 0 → 100644
  1 +package daeucna.system.user;
  2 +
  3 +import java.util.List;
  4 +import java.util.Map;
  5 +
  6 +public interface UserService {
  7 +
  8 + @SuppressWarnings("rawtypes")
  9 + public List<UserDto> getUsers(UserDto param);
  10 +
  11 + @SuppressWarnings("rawtypes")
  12 + public List<UserDto> saveUsers(UserSaveDto params);
  13 +
  14 +
  15 + @SuppressWarnings("rawtypes")
  16 + public Map<String, Object> getUsersAuthority(UserAuthorityDto param);
  17 +
  18 + @SuppressWarnings("rawtypes")
  19 + public Map<String, Object> saveUsersAuthority(UserAuthoritySaveDto params);
  20 +
  21 +}
0 22 \ No newline at end of file
... ...
src/main/java/daeucna/system/user/UserServiceImpl.java 0 → 100644
  1 +package daeucna.system.user;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.HashMap;
  5 +import java.util.List;
  6 +import java.util.Map;
  7 +
  8 +import org.springframework.beans.factory.annotation.Autowired;
  9 +import org.springframework.security.crypto.password.PasswordEncoder;
  10 +import org.springframework.stereotype.Repository;
  11 +import org.springframework.stereotype.Service;
  12 +import org.springframework.transaction.annotation.Propagation;
  13 +import org.springframework.transaction.annotation.Transactional;
  14 +
  15 +import daeucna.mapper.primary.system.UserMapper;
  16 +import daeucna.utils.StringUtil;
  17 +import lombok.RequiredArgsConstructor;
  18 +import lombok.extern.slf4j.Slf4j;
  19 +
  20 +@Service
  21 +@RequiredArgsConstructor
  22 +@Slf4j
  23 +@Repository
  24 +@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
  25 +public class UserServiceImpl implements UserService {
  26 + @Autowired
  27 + private UserMapper userMapper;
  28 + private final PasswordEncoder passwordEncoder;
  29 +
  30 + @Override
  31 + public List<UserDto> getUsers(UserDto param) {
  32 + List<UserDto> lUserDto = new ArrayList<UserDto>();
  33 +
  34 + lUserDto = userMapper.getUsers(param);
  35 +
  36 + log.info("getUsers");
  37 + return lUserDto;
  38 + }
  39 +
  40 + @SuppressWarnings("unchecked")
  41 + @Override
  42 + public List<UserDto> saveUsers(UserSaveDto params) {
  43 +
  44 + // 삭제처리먼저
  45 + for (UserDto curRec : params.getSaveData()) {
  46 + String sRowStatus = curRec.getRowStatus();
  47 + if ("D".indexOf(sRowStatus) > -1) {
  48 + // 사용자
  49 + userMapper.deleteUser(curRec);
  50 + }
  51 + }
  52 + // 신규및 업데이트 처리
  53 + for (UserDto curRec : params.getSaveData()) {
  54 + String sRowStatus = curRec.getRowStatus();
  55 + if ("N,U".indexOf(sRowStatus) > -1) {
  56 + // 사용자
  57 + // 패스워드를 암호화
  58 + String sEncodedPassword = null;
  59 + String sOrgPassword = StringUtil.defaultIfEmpty(curRec.getPassword(), null);
  60 + if (sOrgPassword != null) sEncodedPassword = passwordEncoder.encode(sOrgPassword);
  61 + curRec.setPassword(sEncodedPassword);
  62 + userMapper.saveUser(curRec);
  63 + }
  64 + }
  65 +
  66 + List<UserDto> lUserDto = userMapper.getUsers(params.getSearchCond());
  67 +
  68 + log.info("saveUsers");
  69 + return lUserDto;
  70 + }
  71 +
  72 + @Override
  73 + public Map<String, Object> getUsersAuthority(UserAuthorityDto param) {
  74 + Map<String, Object> rtnVal = new HashMap<String, Object>();
  75 +
  76 + List<UserAuthorityDto> lUserAuthority = userMapper.getUsersAuthority(param);
  77 + rtnVal.put("userAuthority", lUserAuthority);
  78 +
  79 + List<Map> lmUserList = userMapper.getUserList(new HashMap<String, String>());
  80 + rtnVal.put("userList", lmUserList);
  81 +
  82 + List<Map> lmAuthorityList = userMapper.getAuthorityList(new HashMap<String, String>());
  83 + rtnVal.put("authorityList", lmAuthorityList);
  84 +
  85 + log.info("getUsersAuthority");
  86 + return rtnVal;
  87 + }
  88 +
  89 + @Override
  90 + public Map<String, Object> saveUsersAuthority(UserAuthoritySaveDto params) {
  91 +
  92 + // 삭제처리먼저
  93 + for (UserAuthorityDto curRec : params.getSaveData()) {
  94 + String sRowStatus = curRec.getRowStatus();
  95 + if ("D".indexOf(sRowStatus) > -1) {
  96 + // 사용자
  97 + userMapper.deleteUserAuthority(curRec);
  98 + }
  99 + }
  100 + // 신규및 업데이트 처리
  101 + for (UserAuthorityDto curRec : params.getSaveData()) {
  102 + String sRowStatus = curRec.getRowStatus();
  103 + if ("N,U".indexOf(sRowStatus) > -1) {
  104 + // 사용자
  105 + userMapper.saveUserAuthority(curRec);
  106 + }
  107 + }
  108 +
  109 + Map<String, Object> rtnVal = getUsersAuthority(params.getSearchCond());
  110 +
  111 + log.info("saveUsersAuthority");
  112 + return rtnVal;
  113 + }
  114 +
  115 +}
0 116 \ No newline at end of file
... ...
src/main/java/daeucna/utils/ConvertUtil.java 0 → 100644
  1 +package daeucna.utils;
  2 +
  3 +import java.sql.Timestamp;
  4 +import java.text.SimpleDateFormat;
  5 +import java.util.Locale;
  6 +
  7 +public class ConvertUtil {
  8 +
  9 + /**
  10 + *
  11 + * Timestamp 형식의 날짜를 입력한 Format 과 Locale 에 따라 Formatting 한다.
  12 + *
  13 + * <pre>
  14 + *
  15 + * [사용 예제]
  16 + *
  17 + * formatTimestamp("2004-02-25 15:45:31.156","yyyy년MM월dd일",Locale) ===> 2004년02월25일
  18 + *
  19 + * </pre>
  20 + *
  21 + * @param timestamp Timestamp 형식의 날짜
  22 + * @param format SimpleDateFormat 에 적용할 format
  23 + * @param locale 국가별 LOCALE
  24 + * @return java.lang.String
  25 + */
  26 + public static String formatTimestamp(Timestamp timestamp, String format, Locale locale) {
  27 +
  28 + SimpleDateFormat formatter = new SimpleDateFormat(format, locale);
  29 + return formatter.format(timestamp);
  30 +
  31 + }
  32 +
  33 +}
0 34 \ No newline at end of file
... ...
src/main/java/daeucna/utils/DateUtil.java 0 → 100644
  1 +package daeucna.utils;
  2 +
  3 +import java.sql.Timestamp;
  4 +import java.text.ParseException;
  5 +import java.util.Calendar;
  6 +import java.util.GregorianCalendar;
  7 +import java.util.Locale;
  8 +
  9 +public class DateUtil {
  10 +
  11 + public static java.util.Date formatValidDate(String date, String format, Locale lcal) throws Exception {
  12 +
  13 + if (date == null || format == null)
  14 + return null;
  15 + if (lcal == null)
  16 + lcal = java.util.Locale.KOREA; // 디폴트는 Korea
  17 +
  18 + java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(format, lcal);
  19 + java.util.Date formattedDate = null;
  20 +
  21 + formattedDate = formatter.parse(date);
  22 +
  23 + return formattedDate;
  24 + }
  25 +
  26 + /**
  27 + *
  28 + * yyyyMMdd Format으로 입력된 날짜에 addDay 만큼 더한 날짜(yyyyMMdd)를 Return한다.
  29 + *
  30 + * <pre>
  31 + *
  32 + * [사용 예제]
  33 + *
  34 + * addDays("20040225", 1) ===> 20040226
  35 + *
  36 + * </pre>
  37 + *
  38 + * @param date
  39 + * @param addDay
  40 + * @return String
  41 + * @throws ChainedException
  42 + */
  43 + public static String addDays(String date, int addDay) throws Exception {
  44 + return addDays(date, "yyyyMMdd", addDay, null);
  45 + }
  46 +
  47 + /**
  48 + *
  49 + * 입력한 날짜를 입력한 Format으로 해석하여 addDay 만큼 더한 날짜를 Return한다.
  50 + *
  51 + * @param date
  52 + * @param addDay 더할 일수
  53 + * @param format
  54 + * @return String
  55 + * @throws ChainedException
  56 + */
  57 + public static String addDays(String date, String format, int addDay, Locale lcal) throws Exception {
  58 + if (lcal == null)
  59 + lcal = java.util.Locale.KOREA; // 디폴트는 Korea
  60 +
  61 + java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(format, lcal);
  62 + java.util.Date formattedDate = formatValidDate(date, format, lcal);
  63 + formattedDate.setTime(formattedDate.getTime() + ((long) addDay * 1000 * 60 * 60 * 24));
  64 + return formatter.format(formattedDate);
  65 + }
  66 +
  67 + /**
  68 + *
  69 + * yyyyMMdd Format으로 입력된 날짜에 addMonth 만큼 더한 날짜를 Return한다.
  70 + *
  71 + * @param date
  72 + * @param addMonth 더할 월수
  73 + * @return String
  74 + * @throws ChainedException
  75 + */
  76 + public static String addMonths(String date, int addMonth) throws Exception {
  77 + return addMonths(date, "yyyyMMdd", addMonth, null);
  78 + }
  79 +
  80 + /**
  81 + *
  82 + * 입력한 날짜를 입력한 Format으로 해석하여 addMonth 만큼 더한 날짜를 Return한다.
  83 + *
  84 + * @param date
  85 + * @param addMonth 더할 월수
  86 + * @param format
  87 + * @return String
  88 + * @throws ChainedException
  89 + */
  90 + public static String addMonths(String date, String format, int addMonth, Locale lcal) throws Exception {
  91 + if (lcal == null)
  92 + lcal = java.util.Locale.KOREA; // 디폴트는 Korea
  93 + java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(format, lcal);
  94 + java.util.Date formattedDate = formatValidDate(date, format, lcal);
  95 +
  96 + java.text.SimpleDateFormat yearFormat = new java.text.SimpleDateFormat("yyyy", lcal);
  97 + java.text.SimpleDateFormat monthFormat = new java.text.SimpleDateFormat("MM", lcal);
  98 + java.text.SimpleDateFormat dayFormat = new java.text.SimpleDateFormat("dd", lcal);
  99 +
  100 + int year = Integer.parseInt(yearFormat.format(formattedDate));
  101 + int month = Integer.parseInt(monthFormat.format(formattedDate));
  102 + int day = Integer.parseInt(dayFormat.format(formattedDate));
  103 + month += addMonth;
  104 + if (addMonth > 0) {
  105 + while (month > 12) {
  106 + month -= 12;
  107 + year += 1;
  108 + }
  109 + } else {
  110 + while (month <= 0) {
  111 + month += 12;
  112 + year -= 1;
  113 + }
  114 + }
  115 + java.text.DecimalFormat fourDf = new java.text.DecimalFormat("0000");
  116 + java.text.DecimalFormat twoDf = new java.text.DecimalFormat("00");
  117 + String tempDate = String.valueOf(fourDf.format(year)) + String.valueOf(twoDf.format(month))
  118 + + String.valueOf(twoDf.format(day));
  119 + java.util.Date targetDate = null;
  120 + try {
  121 + targetDate = formatValidDate(tempDate, "yyyyMMdd", lcal);
  122 + } catch (Exception e) {
  123 + day = getLastDay(year, month);
  124 + tempDate = String.valueOf(fourDf.format(year)) + String.valueOf(twoDf.format(month))
  125 + + String.valueOf(twoDf.format(day));
  126 + targetDate = formatValidDate(tempDate, "yyyyMMdd", lcal);
  127 + }
  128 + return formatter.format(targetDate);
  129 + }
  130 +
  131 + /**
  132 + *
  133 + * yyyyMMdd Format으로 입력된 날짜에 addYear 만큼 더한 날짜를 Return한다.
  134 + *
  135 + * @param date
  136 + * @param addYear 더할 년수
  137 + * @return String
  138 + * @throws ChainedException
  139 + */
  140 + public static String addYears(String date, int addYear) throws Exception {
  141 + return addYears(date, addYear, "yyyyMMdd", null);
  142 + }
  143 +
  144 + /**
  145 + *
  146 + * 입력한 날짜를 입력한 Format으로 해석하여 addYear 만큼 더한 날짜를 Return한다.
  147 + *
  148 + * @param date
  149 + * @param addYear 더할 년수
  150 + * @param format
  151 + * @return String
  152 + * @throws ChainedException
  153 + */
  154 + public static String addYears(String date, int addYear, String format, Locale lcal) throws Exception {
  155 + if (lcal == null)
  156 + lcal = java.util.Locale.KOREA; // 디폴트는 Korea
  157 +
  158 + java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(format, lcal);
  159 + java.util.Date formattedDate = formatValidDate(date, format, lcal);
  160 +
  161 + Calendar calendar = new GregorianCalendar();
  162 + calendar.setTime(formattedDate);
  163 + calendar.add(Calendar.YEAR, addYear);
  164 + formattedDate = calendar.getTime();
  165 +
  166 + return formatter.format(formattedDate);
  167 +
  168 + }
  169 +
  170 + /**
  171 + *
  172 + * 현재 시각을 HHmmss Format 의 String 으로 Return한다.
  173 + *
  174 + * @return java.lang.String
  175 + */
  176 + public static String getCurrentTimeString() {
  177 + return getCurrentDateString("HHmmss", null);
  178 + }
  179 +
  180 + /**
  181 + *
  182 + * 현재 날짜와 시각을 yyyy-MM-dd hh:mm:ss.fffffffff Format의 Timestamp 로 Return한다.
  183 + *
  184 + * @return Timestamp
  185 + */
  186 + public static Timestamp getCurrentTimeStamp() {
  187 + return new Timestamp(new GregorianCalendar().getTime().getTime());
  188 + }
  189 +
  190 + /**
  191 + *
  192 + * 현재 날짜를 yyyyMMdd Format 의 String 으로 Return한다.
  193 + *
  194 + * @return java.lang.String
  195 + */
  196 + public static String getCurrentDateString() {
  197 + return getCurrentDateString("yyyyMMdd", null);
  198 + }
  199 +
  200 + /**
  201 + *
  202 + * 현재 날짜를 주어진 Format 의 String 으로 Return한다.
  203 + *
  204 + * <pre>
  205 + *
  206 + * [사용 예제]
  207 + *
  208 + * CDateUtil.getCurrentDateString("yyyy/MM/dd") ===> 2004/02/24
  209 + * CDateUtil.getCurrentDateString("HH:mm:ss")); ===> 13:40:05
  210 + * CDateUtil.getCurrentDateString("hh:mm:ss")); ===> 01:40:05
  211 + *
  212 + * format : h hour in am/pm (1~12)
  213 + * format : H hour in day (0~23)
  214 + *
  215 + * </pre>
  216 + *
  217 + * @param format
  218 + * @return java.lang.String
  219 + */
  220 + public static String getCurrentDateString(String format, Locale lcal) {
  221 + if (lcal == null) lcal = java.util.Locale.KOREA;
  222 + return ConvertUtil.formatTimestamp(getCurrentTimeStamp(), format, lcal);
  223 + }
  224 +
  225 + /**
  226 + *
  227 + * yyyyMMdd Format으로 입력된 날짜가 유효한 날짜인지 확인한다.
  228 + *
  229 + * <pre>
  230 + *
  231 + * [사용 예제]
  232 + *
  233 + * CDateUtil.isValidDate("20050225") ===> true
  234 + *
  235 + * </pre>
  236 + *
  237 + * @param date
  238 + * @return boolean
  239 + * @throws ChainedException
  240 + */
  241 + public static boolean isValidDate(String date) throws Exception {
  242 + return DateUtil.isValidDate(date, "yyyyMMdd", null);
  243 + }
  244 +
  245 + /**
  246 + *
  247 + * 입력된 날짜와 입력된 Format 으로 해석하여 입력된 날짜가 유효한 날짜인지 확인한다.
  248 + *
  249 + * <pre>
  250 + *
  251 + * [사용 예제]
  252 + *
  253 + * CDateUtil.isValidDate("2004-02-99","yyyy-MM-dd") ===> false
  254 + *
  255 + * </pre>
  256 + *
  257 + * @param date
  258 + * @return boolean
  259 + * @throws ChainedException
  260 + */
  261 + public static boolean isValidDate(String date, String format, Locale lcal) throws Exception {
  262 + if (lcal == null)
  263 + lcal = java.util.Locale.KOREA;
  264 + try {
  265 + java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(format, lcal);
  266 + java.util.Date formattedDate = null;
  267 +
  268 + try {
  269 +
  270 + formattedDate = formatter.parse(date);
  271 +
  272 + } catch (java.text.ParseException e) {
  273 + return false;
  274 + }
  275 +
  276 + if (!formatter.format(formattedDate).equals(date))
  277 + return false;
  278 +
  279 + return true;
  280 + } catch (Exception e) {
  281 + return false;
  282 + }
  283 + }
  284 +
  285 + /**
  286 + *
  287 + * yyyyMMdd Format으로 입력된 from 날짜와 to 날짜 사이의 일수를 Return한다.
  288 + *
  289 + * <pre>
  290 + *
  291 + * [사용 예제]
  292 + *
  293 + * daysBetween("20040225", "20040301") ===> 5
  294 + *
  295 + * </pre>
  296 + *
  297 + * @param from
  298 + * @param to
  299 + * @return int
  300 + * @throws ChainedException
  301 + */
  302 + public static int getDaysBetween(String from, String to) throws Exception {
  303 + return getDaysBetween(from, to, "yyyyMMdd", null);
  304 + }
  305 +
  306 + /**
  307 + *
  308 + * 입력된 from 날짜와 to 날짜를 입력된 Format으로 해석하여 날짜 사이의 일수를 Return한다.
  309 + *
  310 + * <pre>
  311 + *
  312 + * [사용 예제]
  313 + *
  314 + * daysBetween("2004-02-25", "2004-03-01", "yyyy-MM-dd") ===> 5
  315 + *
  316 + * </pre>
  317 + *
  318 + * @param from
  319 + * @param to
  320 + * @param format
  321 + * @return int
  322 + * @throws ChainedException
  323 + */
  324 + public static int getDaysBetween(String from, String to, String format, Locale lcal) throws Exception {
  325 + if (lcal == null)
  326 + lcal = java.util.Locale.KOREA;
  327 + java.util.Date d1 = formatValidDate(from, format, lcal);
  328 + java.util.Date d2 = formatValidDate(to, format, lcal);
  329 + long duration = d2.getTime() - d1.getTime();
  330 + return (int) (duration / (1000 * 60 * 60 * 24));
  331 + }
  332 +
  333 + /**
  334 + *
  335 + * yyyyMMdd Format으로 입력된 from 날짜와 to 날짜 사이의 월수를 Return한다.
  336 + *
  337 + * <pre>
  338 + *
  339 + * [사용 예제]
  340 + *
  341 + * monthsBetween("20040225", "20041001") ===> 8
  342 + *
  343 + * </pre>
  344 + *
  345 + * @param from
  346 + * @param to
  347 + * @return int
  348 + * @throws ChainedException
  349 + */
  350 + public static int getMonthsBetween(String from, String to) throws Exception {
  351 + return getMonthsBetween(from, to, "yyyyMMdd", null);
  352 + }
  353 +
  354 + /**
  355 + *
  356 + * 입력된 from 날짜와 to 날짜를 입력된 Format으로 해석하여 날짜 사이의 월수를 Return한다.
  357 + *
  358 + * <pre>
  359 + *
  360 + * [사용 예제]
  361 + *
  362 + * monthsBetween("2004-02-25", "2004-10-01", "yyyy-MM-dd") ===> 8
  363 + *
  364 + * </pre>
  365 + *
  366 + * @param from
  367 + * @param to
  368 + * @param format
  369 + * @return int
  370 + * @throws ChainedException
  371 + */
  372 + public static int getMonthsBetween(String from, String to, String format, Locale lcal) throws Exception {
  373 + if (lcal == null)
  374 + lcal = java.util.Locale.KOREA;
  375 + java.util.Date fromDate = formatValidDate(from, format, lcal);
  376 + java.util.Date toDate = formatValidDate(to, format, lcal);
  377 + // if two date are same, return 0.
  378 + if (fromDate.compareTo(toDate) == 0)
  379 + return 0;
  380 + java.text.SimpleDateFormat yearFormat = new java.text.SimpleDateFormat("yyyy", lcal);
  381 + java.text.SimpleDateFormat monthFormat = new java.text.SimpleDateFormat("MM", lcal);
  382 + java.text.SimpleDateFormat dayFormat = new java.text.SimpleDateFormat("dd", lcal);
  383 + int fromYear = Integer.parseInt(yearFormat.format(fromDate));
  384 + int toYear = Integer.parseInt(yearFormat.format(toDate));
  385 + int fromMonth = Integer.parseInt(monthFormat.format(fromDate));
  386 + int toMonth = Integer.parseInt(monthFormat.format(toDate));
  387 + int fromDay = Integer.parseInt(dayFormat.format(fromDate));
  388 + int toDay = Integer.parseInt(dayFormat.format(toDate));
  389 + int result = 0;
  390 + result += ((toYear - fromYear) * 12);
  391 + result += (toMonth - fromMonth);
  392 + // if (((toDay - fromDay) < 0) ) result += fromDate.compareTo(toDate);
  393 + // ceil과 floor의 효과
  394 + if (((toDay - fromDay) > 0))
  395 + result += toDate.compareTo(fromDate);
  396 + return result;
  397 + }
  398 +
  399 + /**
  400 + *
  401 + * yyyyMMdd Format으로 입력된 from 날짜와 to 날짜 사이의 년수를 Return한다.
  402 + *
  403 + * <pre>
  404 + *
  405 + * [사용 예제]
  406 + * yearsBetween("20040225", "20071001") ===> 3
  407 + *
  408 + * </pre>
  409 + *
  410 + * @param from
  411 + * @param to
  412 + * @return int
  413 + * @throws ChainedException
  414 + */
  415 + public static int getYearsBetween(String from, String to) throws Exception {
  416 + return getYearsBetween(from, to, "yyyyMMdd", null);
  417 + }
  418 +
  419 + /**
  420 + *
  421 + * 입력된 from 날짜와 to 날짜를 입력된 Format으로 해석하여 날짜 사이의 년수를 Return한다.
  422 + *
  423 + * <pre>
  424 + *
  425 + * [사용 예제]
  426 + *
  427 + * yearsBetween("2004-02-25", "2007-10-01", "yyyy-MM-dd") ===> 3
  428 + *
  429 + * </pre>
  430 + *
  431 + * @param from
  432 + * @param to
  433 + * @param format
  434 + * @return int
  435 + * @throws ChainedException
  436 + */
  437 + public static int getYearsBetween(String from, String to, String format, Locale lcal) throws Exception {
  438 + if (lcal == null)
  439 + lcal = java.util.Locale.KOREA;
  440 + return (int) (getDaysBetween(from, to, format, lcal) / 365);
  441 + }
  442 +
  443 + /**
  444 + *
  445 + * yyyyMMdd Format으로 입력된 날짜에서 해당 년월의 마지막 날짜를 Return한다.
  446 + *
  447 + * <pre>
  448 + *
  449 + * [사용 예제]
  450 + *
  451 + * lastDayOfMonth("20040202") ===> 20040229
  452 + *
  453 + * </pre>
  454 + *
  455 + * @param date
  456 + * @return String
  457 + * @throws ChainedException
  458 + */
  459 + public static String getLastDayOfMonth(String date) throws Exception {
  460 + return getLastDayOfMonth(date, "yyyyMMdd", null);
  461 + }
  462 +
  463 + /**
  464 + *
  465 + * 입력된 날짜을 입력된 Format 으로 해석하여 그 날짜에서 해당 년월의 마지막 날짜를 Return한다.
  466 + *
  467 + * <pre>
  468 + *
  469 + * [사용 예제]
  470 + *
  471 + * lastDayOfMonth("20040202", "yyyyMMdd") ===> 20040429
  472 + *
  473 + * </pre>
  474 + *
  475 + * @param date
  476 + * @param format
  477 + * @return String
  478 + * @throws ChainedException
  479 + */
  480 + public static String getLastDayOfMonth(String date, String format, Locale lcal) throws Exception {
  481 + if (lcal == null)
  482 + lcal = java.util.Locale.KOREA;
  483 + java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(format, lcal);
  484 + java.util.Date formattedDate = formatValidDate(date, format, lcal);
  485 + java.text.SimpleDateFormat yearFormat = new java.text.SimpleDateFormat("yyyy", lcal);
  486 + java.text.SimpleDateFormat monthFormat = new java.text.SimpleDateFormat("MM", lcal);
  487 + int year = Integer.parseInt(yearFormat.format(formattedDate));
  488 + int month = Integer.parseInt(monthFormat.format(formattedDate));
  489 + int day = getLastDay(year, month);
  490 + java.text.DecimalFormat fourDf = new java.text.DecimalFormat("0000");
  491 + java.text.DecimalFormat twoDf = new java.text.DecimalFormat("00");
  492 + String tempDate = String.valueOf(fourDf.format(year)) + String.valueOf(twoDf.format(month))
  493 + + String.valueOf(twoDf.format(day));
  494 + java.util.Date targetDate = formatValidDate(tempDate, "yyyyMMdd", lcal);
  495 + return formatter.format(targetDate);
  496 + }
  497 +
  498 + /**
  499 + *
  500 + * 입력된 년도와 입력된 월의 마지막 일를 Return한다.
  501 + *
  502 + * <pre>
  503 + *
  504 + * [사용 예제]
  505 + *
  506 + * lastDay(2004,02) ===> 29
  507 + *
  508 + * </pre>
  509 + *
  510 + * @param year
  511 + * @param month
  512 + * @return int
  513 + * @throws ParseException
  514 + */
  515 + public static int getLastDay(int year, int month) throws java.text.ParseException {
  516 + int day = 0;
  517 + switch (month) {
  518 + case 1:
  519 + case 3:
  520 + case 5:
  521 + case 7:
  522 + case 8:
  523 + case 10:
  524 + case 12:
  525 + day = 31;
  526 + break;
  527 + case 2:
  528 + if ((year % 4) == 0) {
  529 + if ((year % 100) == 0 && (year % 400) != 0) {
  530 + day = 28;
  531 + } else {
  532 + day = 29;
  533 + }
  534 + } else {
  535 + day = 28;
  536 + }
  537 + break;
  538 + default:
  539 + day = 30;
  540 + }
  541 + return day;
  542 + }
  543 +
  544 + /**
  545 + *
  546 + * 현재 시간을 Long Type 으로 Return한다. (워크플로우 작업이력저장 용도)
  547 + *
  548 + * <pre>
  549 + *
  550 + * [사용 예제]
  551 + *
  552 + * DateUtil.getCurrentTime()
  553 + *
  554 + * </pre>
  555 + *
  556 + * @return Long
  557 + * @throws Exception
  558 + */
  559 + public static Long getCurrentTime() throws Exception {
  560 + java.util.Date date = new java.util.Date();
  561 +
  562 + long ltime1 = date.getTime(); // 현재시간
  563 +
  564 + Calendar cal = Calendar.getInstance();
  565 + cal.set(1970, 0, 1, 9, 0, 0);// 파일넷 기준시간
  566 +
  567 + long ltime2 = cal.getTimeInMillis();
  568 +
  569 + long curTime = ltime1 - ltime2;
  570 +
  571 + return new Long(curTime / 1000);
  572 + }
  573 +
  574 +}
0 575 \ No newline at end of file
... ...
src/main/java/daeucna/utils/JsonUtil.java 0 → 100644
  1 +package daeucna.utils;
  2 +
  3 +import daeucna.config.security.utils.CommonJson;
  4 +
  5 +public class JsonUtil {
  6 +
  7 + public static String objectToString(Object object) {
  8 + return CommonJson.objectToString(object);
  9 + }
  10 +
  11 + public static Object stringToObject(String sJson, Class<?> objClass) {
  12 + return CommonJson.stringToObject(sJson, objClass);
  13 + }
  14 +
  15 + public static Object objectToObject(Object object, Class<?> objClass) {
  16 + return CommonJson.objectToObject(object, objClass);
  17 + }
  18 +
  19 +}
0 20 \ No newline at end of file
... ...
src/main/java/daeucna/utils/StringUtil.java 0 → 100644
  1 +package daeucna.utils;
  2 +
  3 +import java.io.UnsupportedEncodingException;
  4 +import java.net.URLDecoder;
  5 +import java.net.URLEncoder;
  6 +import java.util.HashMap;
  7 +import java.util.Iterator;
  8 +import java.util.List;
  9 +import java.util.Map;
  10 +import java.util.StringTokenizer;
  11 +import java.util.Vector;
  12 +
  13 +import org.apache.commons.lang3.StringUtils;
  14 +
  15 +/**
  16 + * <p>
  17 + * <code>StringUtil</code> 은 String의 handling과 관련된 class이다.
  18 + * <p>
  19 + */
  20 +
  21 +public class StringUtil {
  22 + /**
  23 + * lPad(inStr, iSize, sPadStr)
  24 + *
  25 + * @param inStr
  26 + * @param iSize
  27 + * @param sPadStr
  28 + * @return
  29 + */
  30 + public static String leftPad(String inStr, int iSize, String sPadStr) {
  31 + return StringUtils.leftPad(inStr, iSize, sPadStr);
  32 + }
  33 +
  34 + /**
  35 + * rPad(inStr, iSize, sPadStr)
  36 + *
  37 + * @param inStr
  38 + * @param iSize
  39 + * @param sPadStr
  40 + * @return
  41 + */
  42 + public static String rightPad(String inStr, int iSize, String sPadStr) {
  43 + return StringUtils.rightPad(inStr, iSize, sPadStr);
  44 + }
  45 +
  46 + /**
  47 + * inStr이 null/""/"공백문자" 이면 default
  48 + *
  49 + * @param inStr
  50 + * @param sDefault
  51 + * @return
  52 + */
  53 + public static String defaultIfBlank(String inStr, String sDefault) {
  54 + return StringUtils.defaultIfBlank(inStr, sDefault);
  55 + }
  56 +
  57 + /**
  58 + * inStr이 null/"" 이면 default
  59 + *
  60 + * @param inStr
  61 + * @param sDefault
  62 + * @return
  63 + */
  64 + public static String defaultIfEmpty(String inStr, String sDefault) {
  65 + return StringUtils.defaultIfEmpty(inStr, sDefault);
  66 + }
  67 +
  68 + /**
  69 + * Strip 결과가 Null이나 ""이면 ""
  70 + *
  71 + * @param inStr
  72 + * @param sDefault
  73 + * @return
  74 + */
  75 + public static String stripToEmpty(String inStr) {
  76 + return StringUtils.stripToEmpty(inStr);
  77 + }
  78 +
  79 + /**
  80 + * Strip 결과가 "" 이면 NULL
  81 + *
  82 + * @param inStr
  83 + * @param sDefault
  84 + * @return
  85 + */
  86 + public static String stripToNull(String inStr) {
  87 + return StringUtils.stripToNull(inStr);
  88 + }
  89 +
  90 + public static String remove(String inStr, String sRemoveStr) {
  91 + return StringUtils.remove(inStr, sRemoveStr);
  92 + }
  93 +
  94 + public static String replace(String inStr, String sTargetStr, String sReplaceStr) {
  95 + return StringUtils.replace(sTargetStr, inStr, sReplaceStr);
  96 + }
  97 +
  98 + public static String trimToEmpty(String inStr) {
  99 + return StringUtils.trimToEmpty(inStr);
  100 + }
  101 +
  102 + public static String trimToNull(String inStr) {
  103 + return StringUtils.trimToNull(inStr);
  104 + }
  105 +
  106 +}
0 107 \ No newline at end of file
... ...
src/main/resources/application.properties
... ... @@ -17,9 +17,9 @@ spring.jpa.defer-datasource-initialization=true
17 17 ## Datasource
18 18 # primary
19 19 spring.datasource.hikari.primary.driver-class-name=org.postgresql.Driver
20   -spring.datasource.hikari.primary.jdbc-url=jdbc:postgresql://daeuserver.iptime.org:20430/account
21   -spring.datasource.hikari.primary.username=account
22   -spring.datasource.hikari.primary.password=daeucna10!
  20 +spring.datasource.hikari.primary.jdbc-url=jdbc:postgresql://localhost:5432/sangkiham
  21 +spring.datasource.hikari.primary.username=sangkiham
  22 +spring.datasource.hikari.primary.password=sangkiham
23 23  
24 24 # secondary
25 25 #spring.datasource.hikari.secondary.driver-class-name=oracle.jdbc.driver.OracleDriver
... ...
src/main/resources/data.sql
... ... @@ -21,21 +21,25 @@ WHEN NOT MATCHED THEN
21 21 MERGE INTO users m
22 22 USING (
23 23 SELECT
24   - 1 as user_id,
25 24 true as activated,
26 25 'sangkiham' as nickname,
27 26 '$2a$10$nyHQj.Nj2tID4UzIkd1/SuMeYwlKaaHT8Gi3Wgg2x/h9K9qLQciLO' as password,
28 27 'sangkiham' as username
29 28 ) s
30 29 ON
31   - m.user_id = s.user_id
  30 + m.username = s.username
  31 +WHEN MATCHED THEN
  32 + UPDATE SET
  33 + nickname = s.nickname
  34 + , activated = s.activated
  35 + , password = s.password
32 36 WHEN NOT MATCHED THEN
33   - INSERT (user_id, activated, nickname, password, username) VALUES (s.user_id, s.activated, s.nickname, s.password, s.username);
  37 + INSERT (activated, nickname, password, username) VALUES (s.activated, s.nickname, s.password, s.username);
34 38  
35 39 MERGE INTO user_authority m
36 40 USING (
37 41 SELECT
38   - 1 as user_id,
  42 + (SELECT user_id FROM users WHERE username = 'sangkiham') as user_id,
39 43 'ROLE_ADMIN' as authority_name
40 44 ) s
41 45 ON
... ...
src/main/resources/mybatis/mybatis-config.xml
... ... @@ -22,6 +22,8 @@
22 22 <!-- 별칭 -->
23 23 <typeAliases>
24 24 <typeAlias type="daeucna.system.code.CodeDto" alias="CodeDto"/>
  25 + <typeAlias type="daeucna.system.user.UserDto" alias="UserDto"/>
  26 + <typeAlias type="daeucna.system.user.UserAuthorityDto" alias="UserAuthorityDto"/>
25 27 </typeAliases>
26 28  
27 29 </configuration>
28 30 \ No newline at end of file
... ...
src/main/resources/mybatis/primary/system/UserMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="daeucna.mapper.primary.system.UserMapper">
  4 +
  5 + <select id="getUsers" parameterType="UserDto" resultType="UserDto">
  6 + SELECT
  7 + m.user_id
  8 + , m.activated
  9 + , m.nickname
  10 + , null as password
  11 + , m.username
  12 + FROM public.users m
  13 + ORDER BY
  14 + m.username
  15 + </select>
  16 +
  17 + <update id="saveUser" parameterType="UserDto">
  18 + MERGE INTO public.users m
  19 + USING (
  20 + SELECT
  21 + #{activated} as activated
  22 + , #{nickname} as nickname
  23 + , #{username} as username
  24 + <if test='password != null and !password.equals("")'>
  25 + , #{password} as password
  26 + </if>
  27 + ) s
  28 + ON (
  29 + m.username = s.username
  30 + )
  31 + WHEN MATCHED THEN
  32 + UPDATE SET
  33 + activated = s.activated
  34 + , nickname = s.nickname
  35 + , username = s.username
  36 + <if test='password != null and !password.equals("")'>
  37 + , password = s.password
  38 + </if>
  39 + WHEN NOT MATCHED THEN
  40 + INSERT (
  41 + activated
  42 + , nickname
  43 + , username
  44 + <if test='password != null and !password.equals("")'>
  45 + , password
  46 + </if>
  47 + ) VALUES (
  48 + s.activated
  49 + , s.nickname
  50 + , s.username
  51 + <if test='password != null and !password.equals("")'>
  52 + , s.password
  53 + </if>
  54 + )
  55 + </update>
  56 +
  57 + <delete id="deleteUser" parameterType="UserDto">
  58 + DELETE FROM public.users m
  59 + WHERE
  60 + user_id = #{userId}
  61 + </delete>
  62 +
  63 +
  64 + <select id="getUsersAuthority" parameterType="UserAuthorityDto" resultType="UserAuthorityDto">
  65 + SELECT
  66 + m.user_id
  67 + , s1.username
  68 + , s2.authority_name
  69 + FROM public.user_authority m
  70 + inner join public.users s1
  71 + on s1.user_id = m.user_id
  72 + inner join public.authority s2
  73 + on s2.authority_name = m.authority_name
  74 + WHERE 1=1
  75 + <if test='username != null and !username.equals("")'>
  76 + and s1.username like ('%' || #{username} || '%')
  77 + </if>
  78 + ORDER BY m.user_id ASC
  79 + </select>
  80 +
  81 + <update id="saveUserAuthority" parameterType="UserAuthorityDto">
  82 + MERGE INTO public.user_authority m
  83 + USING (
  84 + SELECT
  85 + (SELECT user_id FROM public.users WHERE username=#{username}) as user_id
  86 + , #{authorityName} as authority_name
  87 + ) s
  88 + ON (
  89 + m.user_id = s.user_id
  90 + )
  91 + WHEN MATCHED THEN
  92 + UPDATE SET
  93 + authority_name = s.authority_name
  94 + WHEN NOT MATCHED THEN
  95 + INSERT (
  96 + user_id
  97 + , authority_name
  98 + ) VALUES (
  99 + s.user_id
  100 + , s.authority_name
  101 + )
  102 + </update>
  103 +
  104 + <delete id="deleteUserAuthority" parameterType="UserAuthorityDto">
  105 + DELETE FROM public.user_authority m
  106 + WHERE
  107 + user_id = #{userId}
  108 + </delete>
  109 +
  110 + <select id="getUserList" parameterType="Map" resultType="Map">
  111 + SELECT
  112 + user_id
  113 + , username
  114 + FROM public.users
  115 + WHERE
  116 + activated = true
  117 + ORDER BY username ASC
  118 + </select>
  119 +
  120 + <select id="getAuthorityList" parameterType="Map" resultType="Map">
  121 + SELECT
  122 + authority_name
  123 + FROM public.authority
  124 + ORDER BY authority_name ASC
  125 + </select>
  126 +
  127 +</mapper>
0 128 \ No newline at end of file
... ...
src/main/resources/schema.sql
... ... @@ -223,7 +223,6 @@ CREATE TABLE IF NOT EXISTS batch_user_job_status
223 223 exit_code character varying(10) COLLATE pg_catalog."default",
224 224 exit_message character varying(2000) COLLATE pg_catalog."default",
225 225 CONSTRAINT batch_user_job_status_pkey PRIMARY KEY (user_job_id)
226   - USING INDEX TABLESPACE account
227 226 );
228 227  
229 228 COMMENT ON TABLE batch_user_job_status
... ... @@ -267,12 +266,12 @@ CREATE TABLE IF NOT EXISTS user_authority
267 266 CONSTRAINT user_authority_pkey PRIMARY KEY (user_id, authority_name),
268 267 CONSTRAINT fk6ktglpl5mjosa283rvken2py5 FOREIGN KEY (authority_name)
269 268 REFERENCES authority (authority_name) MATCH SIMPLE
270   - ON UPDATE NO ACTION
271   - ON DELETE NO ACTION,
  269 + ON UPDATE CASCADE
  270 + ON DELETE CASCADE,
272 271 CONSTRAINT fkhi46vu7680y1hwvmnnuh4cybx FOREIGN KEY (user_id)
273 272 REFERENCES users (user_id) MATCH SIMPLE
274   - ON UPDATE NO ACTION
275   - ON DELETE NO ACTION
  273 + ON UPDATE CASCADE
  274 + ON DELETE CASCADE
276 275 );
277 276  
278 277 -- Table: sy_cmmn_code_mng
... ...