add include Role

This commit is contained in:
KarolChang 2022-04-16 13:37:36 +08:00
parent 3a335f578a
commit 0d24a3b730
26 changed files with 179 additions and 158 deletions

View File

@ -21,7 +21,6 @@ git commit -m 'deploy'
# if you are deploying to https://<USERNAME>.Github.io/<REPO>
# git push -f https://github.com/<USERNAME>/<REPO>.git master:gh-pages
git push origin master
git push -f https://github.com/KarolChang/jm-expense-vue-ts.git master:gh-pages
cd -

11
package-lock.json generated
View File

@ -661,6 +661,11 @@
"fastq": "^1.6.0"
}
},
"@popperjs/core": {
"version": "2.11.5",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz",
"integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw=="
},
"@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
@ -2687,9 +2692,9 @@
"dev": true
},
"sweetalert2": {
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.3.0.tgz",
"integrity": "sha512-C0TFp0VLxgx+PmhJ0mL8qzx+iYjnCLdDbvQHKY6KAGI+xwawMvLkStPgw2LmJl6itaDhR/qLQStPFIbr1VK9Ow=="
"version": "11.4.8",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.4.8.tgz",
"integrity": "sha512-BDS/+E8RwaekGSxCPUbPnsRAyQ439gtXkTF/s98vY2l9DaVEOMjGj1FaQSorfGREKsbbxGSP7UXboibL5vgTMA=="
},
"table": {
"version": "5.4.6",

View File

@ -9,6 +9,7 @@
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src"
},
"dependencies": {
"@popperjs/core": "^2.11.5",
"@vueform/multiselect": "^2.3.1",
"axios": "^0.24.0",
"bootstrap": "^5.1.3",
@ -21,7 +22,7 @@
"firebase": "^9.6.3",
"luxon": "^1.0.0",
"pinia": "^2.0.6",
"sweetalert2": "^11.3.0",
"sweetalert2": "^11.4.8",
"vue": "^3.2.29",
"vue-class-component": "^8.0.0-0",
"vue-router": "^4.0.0-0",

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import expenseAPI from '@/apis/expense'
import { CategoryInput } from '@/models'

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import expenseAPI from '@/apis/expense'
import { Category, CategoryInput } from '@/models'

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject, computed, Ref } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import expenseAPI from '@/apis/expense'
import { ExpenseInput, Category } from '@/models'
import { useStore } from '@/store/index'
@ -75,19 +74,28 @@ const btnClick = async () => {
if (!item || !amount || !date) {
Swal.showValidationMessage('除了[備註],所有資料都是必填!')
}
return {
input: {
UserId: store.currentUser?.id,
CategoryId: Number(categoryId),
item,
amount,
note,
date
} as ExpenseInput
console.log('store.currentUser', store.currentUser)
console.log('store.currentUser?.id', store.currentUser?.id)
if (store.currentUser) {
return {
input: {
UserId: store.currentUser.id,
CategoryId: Number(categoryId),
item,
amount,
note,
date
} as ExpenseInput
}
} else {
Toast.fire({
icon: 'error',
title: '無法取得使用者ID'
})
}
}
})
if (formValues) {
if (formValues?.input) {
createExpense(formValues)
}
} catch (error) {

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { computed, inject, Ref } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import expenseAPI from '@/apis/expense'
import { Expense, ExpenseInput, Category } from '@/models'
import { useStore } from '@/store/index'
@ -88,19 +87,27 @@ const btnClick = async () => {
if (!item || !amount || !date) {
Swal.showValidationMessage('除了[備註],所有資料都是必填!')
}
return {
input: {
UserId: store.currentUser?.id,
CategoryId: Number(categoryId),
item,
amount,
note,
date
} as ExpenseInput
if (store.currentUser) {
return {
input: {
UserId: store.currentUser.id,
CategoryId: Number(categoryId),
item,
amount,
note,
date
} as ExpenseInput
}
} else {
Toast.fire({
icon: 'error',
title: '無法取得使用者ID'
})
}
}
})
if (formValues) {
console.log('formValues', formValues)
if (formValues?.input) {
editExpense(formValues)
}
} catch (error) {

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject, computed } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import userAPI from '@/apis/user'
import { PermissionInput, ActionTypePermission } from '@/models'
const actions: ActionTypePermission[] = ['查看', '新增', '編輯', '刪除', '停用', '操作']

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject, computed } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import userAPI from '@/apis/user'
import { Permission, PermissionInput, ActionTypePermission } from '@/models'
const actions: ActionTypePermission[] = ['查看', '新增', '編輯', '刪除', '停用', '操作']

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import recordAPI from '@/apis/record'
import { pushMsgToBoth } from '@/utils/lineBotMsg'
import { RecordInput } from '@/models'
@ -66,18 +65,25 @@ const btnClick = async () => {
if (!item || !merchant || !amount || !date) {
Swal.showValidationMessage('所有資料都是必填!若紀錄者為空,請登入~')
}
return {
input: {
item,
merchant,
amount,
date,
UserId: store.currentUser?.id
} as RecordInput
if (store.currentUser) {
return {
input: {
item,
merchant,
amount,
date,
UserId: store.currentUser?.id
} as RecordInput
}
} else {
Toast.fire({
icon: 'error',
title: '無法取得使用者ID'
})
}
}
})
if (formValues) {
if (formValues?.input) {
createRecord(formValues)
}
} catch (error) {

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import recordAPI from '@/apis/record'
import { pushMsgToBoth } from '@/utils/lineBotMsg'
import { Record, RecordInput } from '@/models'
@ -65,19 +64,26 @@ const btnClick = async () => {
if (!item || !merchant || !amount || !date) {
Swal.showValidationMessage('所有資料都是必填!若編輯者為空,請登入~')
}
return {
id: record.id as number,
input: {
item,
merchant,
amount,
date,
UserId: store.currentUser?.id
} as RecordInput
if (store.currentUser) {
return {
id: record.id as number,
input: {
item,
merchant,
amount,
date,
UserId: store.currentUser.id
} as RecordInput
}
} else {
Toast.fire({
icon: 'error',
title: '無法取得使用者ID'
})
}
}
})
if (formValues) {
if (formValues?.input) {
editRecord(formValues)
}
} catch (error) {

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import userAPI from '@/apis/user'
import { RoleInput } from '@/models'

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { inject } from 'vue'
import Swal from 'sweetalert2'
import { Toast, ConfirmBox } from '@/utils/swal'
import { Swal, Toast, ConfirmBox } from '@/utils/swal'
import userAPI from '@/apis/user'
import { Role, RoleInput } from '@/models'

View File

@ -114,6 +114,7 @@ const openUserRP = () => {
</ul>
</div>
</div>
<!-- <transition name="slide-right">
<UserRP v-show="userRPOpen" />
</transition> -->

View File

@ -1,6 +1,6 @@
// import Vue from 'vue'
import { createApp } from 'vue'
import App from '@/App.vue'
import App from '@/views/App.vue'
function capitalizeFirstLetter(string: string) {
return string.charAt(0).toUpperCase() + string.slice(1)

View File

@ -20,7 +20,7 @@ export const getFirebaseUser = () => {
console.log(`[firebase] onAuthStateChanged`)
if (user) {
console.log('[auth] Get Firebase User', user)
store.login(user)
await store.login(user)
} else {
store.logout()
}

View File

@ -1,6 +1,6 @@
import { initializeApp } from 'firebase/app'
import { initializeApp, FirebaseOptions } from 'firebase/app'
const firebaseConfig = {
const firebaseConfig: FirebaseOptions = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTO_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
@ -8,7 +8,7 @@ const firebaseConfig = {
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID
}
} as FirebaseOptions
export const initFirebase = () => {
initializeApp(firebaseConfig)

View File

@ -1,5 +1,5 @@
import { createApp } from 'vue'
import App from './App.vue'
import App from './views/App.vue'
import router from './router'
import { createPinia } from 'pinia'
import { getFirebaseUser } from '@/firebase/auth'
@ -8,6 +8,7 @@ import { initFirebase } from '@/firebase/config'
import Datepicker from 'vue3-date-time-picker'
import 'vue3-date-time-picker/dist/main.css'
import '@popperjs/core'
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootswatch/dist/minty/bootstrap.min.css'

View File

@ -4,7 +4,7 @@ export class Category {
id!: number
name!: string
icon!: string
// photoUrl?: string
photoUrl!: string | null
type!: CategoryType
deletedAt!: Date | null
createdAt!: Date

View File

@ -1,7 +1,7 @@
import { Toast } from '@/utils/swal'
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import { useStore } from '../store/index'
import Default from '@/views/Default.vue'
import AppLayout from '@/views/App.vue'
const root = '/jm-expense-vue-ts'
@ -73,15 +73,15 @@ export const routes: RouteRecordRaw[] = [
show: true
}
},
{
path: `${root}/tools`,
name: 'Tools',
component: () => import('../views/Tools.vue'),
meta: {
pageTitle: '小工具',
show: true
}
},
// {
// path: `${root}/tools`,
// name: 'Tools',
// component: () => import('../views/Tools.vue'),
// meta: {
// pageTitle: '小工具',
// show: true
// }
// },
{
path: `${root}/game`,
name: 'Game',
@ -92,74 +92,63 @@ export const routes: RouteRecordRaw[] = [
// auth: ['root', 'admin', 'member']
}
},
{
path: `${root}/admin`,
name: 'Admin',
redirect: { name: 'Admin-Role' },
component: Default,
meta: {
pageTitle: '管理面板',
show: true
}
// children: [
// {
// path: 'role',
// name: 'Admin-Role',
// component: () => import('../views/Role.vue'),
// meta: {
// pageTitle: '角色管理',
// show: true
// }
// },
// {
// path: 'permission',
// name: 'Admin-Permission',
// component: () => import('../views/Permission.vue'),
// meta: {
// pageTitle: '權限管理',
// show: true
// }
// }
// ]
},
{
path: '/admin/role',
name: 'Admin-Role',
component: () => import('@/views/Role.vue'),
meta: {
pageTitle: '角色管理',
show: true
}
// children: [
// {
// path: ':id/access',
// name: 'Admin-Role-Access',
// component: () => import('@/views/Access.vue'),
// meta: {
// pageTitle: '角色管理 / 設置權限[角色名稱]',
// show: false
// }
// }
// ]
},
{
path: '/admin/role/:id/access',
name: 'Admin-Role-Access',
component: () => import('@/views/Access.vue'),
meta: {
pageTitle: '角色管理 / 設置權限[角色名稱]',
show: false
}
},
{
path: '/admin/permission',
name: 'Admin-Permission',
component: () => import('../views/Permission.vue'),
meta: {
pageTitle: '權限管理',
show: true
}
},
// {
// path: `${root}/admin`,
// name: 'Admin',
// redirect: { name: 'Admin-Role' },
// component: AppLayout,
// meta: {
// pageTitle: '管理面板',
// show: true
// },
// children: [
// {
// path: 'role',
// name: 'Admin-Role',
// component: () => import('../views/Role.vue'),
// meta: {
// pageTitle: '角色管理',
// show: true
// }
// },
// {
// path: 'permission',
// name: 'Admin-Permission',
// component: () => import('../views/Permission.vue'),
// meta: {
// pageTitle: '權限管理',
// show: true
// }
// }
// ]
// },
// {
// path: `${root}/admin/role`,
// name: 'Admin-Role',
// component: () => import('@/views/Role.vue'),
// meta: {
// pageTitle: '角色管理',
// show: true
// }
// },
// {
// path: '/admin/role/:id/access',
// name: 'Admin-Role-Access',
// component: () => import('@/views/Access.vue'),
// meta: {
// pageTitle: '角色管理 / 設置權限[角色名稱]',
// show: false
// }
// },
// {
// path: '/admin/permission',
// name: 'Admin-Permission',
// component: () => import('../views/Permission.vue'),
// meta: {
// pageTitle: '權限管理',
// show: true
// }
// },
{
path: '/:pathMatch(.*)*',
name: 'NotFound',

View File

@ -43,9 +43,9 @@ export const useStore = defineStore('index', {
console.error('error')
}
},
login(user: FirebaseUser) {
async login(user: FirebaseUser) {
this.firebaseUser = user
this.getCurrentUser(user.email!)
await this.getCurrentUser(user.email!)
},
logout() {
this.firebaseUser = null

View File

@ -1,4 +1,5 @@
import Swal from 'sweetalert2'
import Swal from 'sweetalert2/dist/sweetalert2.js'
import 'sweetalert2/dist/sweetalert2.css'
export const Toast = Swal.mixin({
toast: true,
@ -11,3 +12,5 @@ export const ConfirmBox = Swal.mixin({
showConfirmButton: true,
showCancelButton: true
})
export { Swal }

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import Navbar from '@/components/Navbar.vue'
import { onLoad } from './cocos/config'
import { onLoad } from '../cocos/config'
import { useRoute } from 'vue-router'
const route = useRoute()
@ -11,7 +11,6 @@ if (import.meta.env.NODE_ENV === 'production') {
</script>
<template>
<!-- <div> -->
<Navbar>
<template #main>
<router-view v-slot="{ Component }">
@ -21,7 +20,6 @@ if (import.meta.env.NODE_ENV === 'production') {
</router-view>
</template>
</Navbar>
<!-- </div> -->
</template>
<style>
@import url('https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic:wght@400;700&display=swap');

View File

@ -127,7 +127,7 @@ provide('categoriesByType', categoriesByType)
</div>
<!-- filter -->
<div class="d-flex mb-4" style="width: 100%">
<div class="mt-4" style="width: 50px">
<div class="mt-4" style="width: 100px">
<label for="type" style="float: left; font-size: 0.7em">TYPE</label>
<select class="form-select" id="type" aria-label="Default select example" v-model="selectedType">
<option selected>ALL</option>

View File

@ -49,13 +49,13 @@ provide('refetchRoles', fetchRoles)
<td>{{ role.name }}</td>
<td>{{ role.name_en }}</td>
<td>{{ role.deletedAt === null ? 'V' : 'X' }}</td>
<td>
<!-- <td>
<router-link :to="{ name: 'Admin-Role-Access', params: { id: role.id } }">
<i class="fa-solid fa-circle-question"></i
></router-link>
<EditRoleModalButton :role="role" class="ms-2" />
<DeleteRoleModalButton :role="role" class="ms-2" />
</td>
</td> -->
</tr>
</tbody>
</table>

View File

@ -11,5 +11,8 @@ export default defineConfig({
alias: {
'@': path.resolve(__dirname, './src')
}
},
server: {
port: 8080
}
})