-
-
-
-
-
-
+
{{ tname }}
@{{ user.username }}
-
@@ -44,6 +42,7 @@
v-show="item"
:model-value="displayUser[key]"
dense
+ readonly
filled
class="w100"
:label = "$t('user_card__' + key)"
@@ -60,21 +59,19 @@
diff --git a/src/pages/main/UsersPage.vue b/src/pages/main/UsersPage.vue
index 536172d..15cc982 100644
--- a/src/pages/main/UsersPage.vue
+++ b/src/pages/main/UsersPage.vue
@@ -27,26 +27,26 @@
@click="goUserInfo(item.id)"
>
-
-
-
-
-
-
-
- {{item.section1}}
-
-
- {{item.section3}}
-
-
-
-
-
{{item.section2_1}}
-
{{'@' + item.section2_2}}
-
-
-
+
+
+
+
+ {{item.section1}}
+
+
+ {{item.section3}}
+
+
+
+
+
{{item.section2_1}}
+
{{'@' + item.section2_2}}
+
+
+
diff --git a/src/router/index.ts b/src/router/index.ts
index a346060..770fa93 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -24,26 +24,42 @@ export default defineRouter(function (/* { store, ssrContext } */) {
})
Router.beforeEach(async (to) => {
- console.log(to)
- if (to.name === 'settings') return;
- const projectsStore = useProjectsStore()
+
+ if (to.name === 'settings') return
+ if (to.name === '404') return
+ const projectsStore = useProjectsStore()
+ console.log('router mount', projectsStore.startRouteInfo)
+
+ if (projectsStore.startRouteInfo && to.path === '/') {
+ const { id, taskId, meetingId } = projectsStore.startRouteInfo
+ projectsStore.setStartRouteInfo(null)
+
+ if (!projectsStore.isInit) await projectsStore.init()
+ const project = projectsStore.projectById(id)
+
+ if (!project) return { name: '404' }
+
+ return taskId
+ ? { name: 'task_info', params: { id, taskId } }
+ : meetingId
+ ? { name: 'meeting_info', params: { id, meetingId } }
+ : { name: 'files', params: { id } }
+ }
+
if (to.params.id) {
const projectId = Number(to.params.id)
-
if (!projectsStore.isInit) await projectsStore.init()
const project = projectsStore.projectById(projectId)
- if (!project) return { name: 'page404' }
-
+ if (!project) return { name: '404' }
+
if (projectsStore.currentProjectId !== projectId) {
projectsStore.setCurrentProjectId(projectId)
}
} else {
- if (!projectsStore.startProjectId) return { name: 'page404' }
- projectsStore.setCurrentProjectId(projectsStore.startProjectId)
- return { name: 'files', params: { id: projectsStore.startProjectId }}
+ return { name: '404' }
}
})
@@ -61,7 +77,7 @@ export default defineRouter(function (/* { store, ssrContext } */) {
}
Router.afterEach((to) => {
- const BackButton = window.Telegram?.WebApp?.BackButton;
+ const BackButton = window.Telegram?.WebApp?.BackButton
if (BackButton) {
// Управление видимостью
if (to.meta.hideBackButton) {
diff --git a/src/router/routes.ts b/src/router/routes.ts
index 39d66c8..a94d273 100644
--- a/src/router/routes.ts
+++ b/src/router/routes.ts
@@ -48,6 +48,11 @@ const routes: RouteRecordRaw[] = [
path: '/project/:id(\\d+)/task/add',
component: () => import('pages/TaskAddPage.vue')
},
+ {
+ name: 'task_edit',
+ path: '/project/:id(\\d+)/task/:taskId(\\d+)/edit',
+ component: () => import('pages/TaskEditPage.vue'),
+ },
{
name: 'task_info',
path: '/project/:id(\\d+)/task/:taskId(\\d+)',
@@ -60,7 +65,7 @@ const routes: RouteRecordRaw[] = [
},
{
name: 'meeting_edit',
- path: '/project/:id(\\d+)/meeting/:meetingId(\\d+)',
+ path: '/project/:id(\\d+)/meeting/:meetingId(\\d+)/edit',
component: () => import('pages/MeetingEditPage.vue'),
},
{
@@ -81,6 +86,7 @@ const routes: RouteRecordRaw[] = [
]
},
{
+ name: '404',
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'),
}
diff --git a/src/stores/auth.ts b/src/stores/auth.ts
new file mode 100644
index 0000000..78ab3fd
--- /dev/null
+++ b/src/stores/auth.ts
@@ -0,0 +1,21 @@
+import { defineStore } from 'pinia'
+import { ref } from 'vue'
+import { api } from 'boot/axios'
+import type { WebApp } from '@twa-dev/types'
+
+export const useAuthStore = defineStore('auth', () => {
+ const isInit = ref(false)
+ const telegramUserData = ref()
+
+ async function init (tg: WebApp) {
+ await api.post('/auth?' + tg?.initData)
+ telegramUserData.value = tg?.initDataUnsafe.user
+ isInit.value = true
+ }
+
+ return {
+ isInit,
+ telegramUserData,
+ init
+ }
+})
diff --git a/src/stores/chats.ts b/src/stores/chats.ts
index a4ef668..0d135b7 100644
--- a/src/stores/chats.ts
+++ b/src/stores/chats.ts
@@ -13,8 +13,8 @@ export const useChatsStore = defineStore('chats', () => {
const currentProjectId = computed(() => projectsStore.currentProjectId)
async function init () {
- const response = await api.get('/project/' + currentProjectId.value + '/chat')
- const chatsAPI = response.data.data
+ const { data } = await api.get('/project/' + currentProjectId.value + '/chat')
+ const chatsAPI = data.data
chats.value.push(...chatsAPI)
isInit.value = true
}
@@ -24,6 +24,8 @@ export const useChatsStore = defineStore('chats', () => {
isInit.value = false
}
+ const getChats = computed(() => chats.value)
+
function chatById (id: number) {
return chats.value.find(el =>el.id === id)
}
@@ -33,6 +35,7 @@ export const useChatsStore = defineStore('chats', () => {
isInit,
init,
reset,
+ getChats,
chatById
}
})
diff --git a/src/stores/files.ts b/src/stores/files.ts
index 9eacac1..9f3b735 100644
--- a/src/stores/files.ts
+++ b/src/stores/files.ts
@@ -2,19 +2,19 @@ import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { api } from 'boot/axios'
import { useProjectsStore } from 'stores/projects'
-import type { File } from 'types/File'
+import type { FileLink } from 'types/FileLink'
export const useFilesStore = defineStore('files', () => {
- const files = ref
([])
+ const files = ref([])
const isInit = ref(false)
const projectsStore = useProjectsStore()
const currentProjectId = computed(() => projectsStore.currentProjectId)
async function init () {
- const response = await api.get('/project/' + currentProjectId.value + '/file')
- const filesAPI = response.data.data
+ const { data } = await api.get('/project/' + currentProjectId.value + '/file')
+ const filesAPI = data.data
files.value.push(...filesAPI)
isInit.value = true
}
@@ -34,6 +34,7 @@ export const useFilesStore = defineStore('files', () => {
return (await response).data.data
}
+ const getFiles = computed(() => files.value)
function fileById (id: number) {
return files.value.find(el =>el.id === id)
@@ -46,6 +47,7 @@ export const useFilesStore = defineStore('files', () => {
reset,
fileUrl,
remove,
+ getFiles,
fileById
}
})
diff --git a/src/stores/meetings.ts b/src/stores/meetings.ts
index 9a280e9..7c20051 100644
--- a/src/stores/meetings.ts
+++ b/src/stores/meetings.ts
@@ -13,8 +13,8 @@ export const useMeetingsStore = defineStore('meetings', () => {
const currentProjectId = computed(() => projectsStore.currentProjectId)
async function init () {
- const response = await api.get('/project/' + currentProjectId.value + '/meeting')
- const meetingsAPI = response.data.data
+ const { data } = await api.get('/project/' + currentProjectId.value + '/meeting')
+ const meetingsAPI = data.data
meetings.value.push(...meetingsAPI)
isInit.value = true
}
@@ -24,44 +24,57 @@ export const useMeetingsStore = defineStore('meetings', () => {
isInit.value = false
}
- async function add (meetingData: MeetingParams) {
- const response = await api.post('/project/' + currentProjectId.value + '/meeting', meetingData)
- const newMeetingAPI = response.data.data
+ async function add (meetingData: MeetingParams, newFiles: File[]) {
+ const { data } = await api.post('/project/' + currentProjectId.value + '/meeting', meetingData)
+ const newMeetingAPI = data.data
meetings.value.push(newMeetingAPI)
- return newMeetingAPI
+ const id = newMeetingAPI.id
+ await updateParticipants(id, meetingData.participants)
+ if (newFiles.length !== 0) await attachFiles(id, newFiles)
+ return newMeetingAPI //not include files and participants!!
}
async function update (meetingId: number, meetingData: MeetingParams) {
- const response = await api.put('/project/' + currentProjectId.value + '/meeting/' + meetingId, meetingData)
- const meetingAPI = response.data.data
+ const { data } = await api.put('/project/' + currentProjectId.value + '/meeting/' + meetingId, meetingData)
+ const meetingAPI = data.data
const idx = meetings.value.findIndex(item => item.id === meetingAPI.id)
if (meetings.value[idx]) Object.assign(meetings.value[idx], meetingAPI)
}
async function updateParticipants (meetingId: number, participants: number[]) {
- const response = await api.put('/project/' + currentProjectId.value + '/meeting/' + meetingId + '/participant', participants)
- const participantsAPI = response.data.data
+ const { data } = await api.put('/project/' + currentProjectId.value + '/meeting/' + meetingId + '/participant', participants)
+ const participantsAPI = data.data
const idx = meetings.value.findIndex(item => item.id === meetingId)
if (meetings.value[idx]) meetings.value[idx].participants = participantsAPI
}
- async function attachFiles (meetingId: number, files: number[]) {
- const response = await api.put('/project/' + currentProjectId.value + '/meeting/' + meetingId + '/attach', files)
- const filesAPI = response.data.data
+ async function attachFiles (meetingId: number, files: File[]) {
+ const formData = new FormData()
+ files.forEach(file => formData.append('files[]', file))
+ const { data } = await api.post(
+ '/project/' + currentProjectId.value + '/meeting/' + meetingId + '/attach',
+ formData,
+ {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ }
+ )
+ const filesAPI = data.data
const idx = meetings.value.findIndex(item => item.id === meetingId)
if (meetings.value[idx]) meetings.value[idx].files = filesAPI
}
async function setCancelStatus (meetingId: number, status: boolean) {
- const response = await api.put('/project/' + currentProjectId.value + '/meeting/' + meetingId, { is_cancel: status })
- const meetingAPI = response.data.data
+ const { data } = await api.put('/project/' + currentProjectId.value + '/meeting/' + meetingId, { is_cancel: status })
+ const meetingAPI = data.data
const idx = meetings.value.findIndex(item => item.id === meetingAPI.id)
if (meetings.value[idx]) Object.assign(meetings.value[idx], meetingAPI)
}
async function remove (meetingId: number) {
- const response = await api.delete('/project/' + currentProjectId.value + '/meeting/' + meetingId)
- const meetingAPIid = response.data.data.id
+ const { data } = await api.delete('/project/' + currentProjectId.value + '/meeting/' + meetingId)
+ const meetingAPIid = data.data.id
const idx = meetings.value.findIndex(item => item.id === meetingAPIid)
meetings.value.splice(idx, 1)
}
@@ -70,6 +83,9 @@ export const useMeetingsStore = defineStore('meetings', () => {
return meetings.value.find(el => el.id === id)
}
+ // getters
+ const getMeetings = computed(() => meetings.value)
+
return {
meetings,
isInit,
@@ -81,6 +97,7 @@ export const useMeetingsStore = defineStore('meetings', () => {
attachFiles,
setCancelStatus,
remove,
+ getMeetings,
meetingById
}
})
diff --git a/src/stores/projects.ts b/src/stores/projects.ts
index 6af0459..5ec6881 100644
--- a/src/stores/projects.ts
+++ b/src/stores/projects.ts
@@ -1,7 +1,9 @@
-import { ref, watch } from 'vue'
+import { ref, watch, computed } from 'vue'
import { defineStore } from 'pinia'
import { api } from 'boot/axios'
+import { useAuthStore } from 'stores/auth'
+
import { useFilesStore } from 'stores/files'
import { useTasksStore } from 'stores/tasks'
import { useMeetingsStore } from 'stores/meetings'
@@ -13,7 +15,6 @@ import type { Project } from 'types/Project'
export const useProjectsStore = defineStore('projects', () => {
const projects = ref([])
const currentProjectId = ref(null)
- const startProjectId = ref(null)
const isInit = ref(false)
const filesStore = useFilesStore()
@@ -23,8 +24,8 @@ export const useProjectsStore = defineStore('projects', () => {
const chatsStore = useChatsStore()
async function init () {
- const response = await api.get('/project')
- const projectsAPI = response.data.data
+ const { data } = await api.get('/project')
+ const projectsAPI = data.data
projects.value.push(...projectsAPI)
isInit.value = true
}
@@ -43,18 +44,21 @@ export const useProjectsStore = defineStore('projects', () => {
currentProjectId.value = id
}
- function setStartProjectId (id: number | null) {
- startProjectId.value = id
- }
+ const authStore = useAuthStore()
+
async function initStores () {
resetStores()
- if (!filesStore.isInit) await filesStore.init()
- if (!tasksStore.isInit) await tasksStore.init()
- if (!meetingsStore.isInit) await meetingsStore.init()
- if (!usersStore.isInit) await usersStore.init()
- if (!chatsStore.isInit) await chatsStore.init()
-
+
+ await Promise.all([
+ filesStore.init(),
+ tasksStore.init(),
+ meetingsStore.init(),
+ usersStore.init(),
+ chatsStore.init()
+ ])
+
+ usersStore.setMyId(authStore.telegramUserData.id)
}
function resetStores () {
@@ -65,6 +69,14 @@ export const useProjectsStore = defineStore('projects', () => {
chatsStore.reset()
}
+ const getProjects = computed(() => projects.value)
+
+ const startRouteInfo = ref<{ id: number; taskId?: number; meetingId?: number } | null>(null)
+
+ function setStartRouteInfo (info: { id: number; taskId?: number; meetingId?: number } | null) {
+ startRouteInfo.value = info
+ }
+
watch (currentProjectId, async (newId) => {
if (newId) await initStores(); else resetStores()
}, { flush: 'sync' })
@@ -75,11 +87,12 @@ export const useProjectsStore = defineStore('projects', () => {
isInit,
projects,
currentProjectId,
- startProjectId,
projectById,
setCurrentProjectId,
- setStartProjectId,
initStores,
- resetStores
+ resetStores,
+ getProjects,
+ startRouteInfo,
+ setStartRouteInfo
}
})
diff --git a/src/stores/settings.ts b/src/stores/settings.ts
index 9453984..5619c08 100644
--- a/src/stores/settings.ts
+++ b/src/stores/settings.ts
@@ -54,8 +54,6 @@ export const useSettingsStore = defineStore('settings', () => {
console.error('Quasar Error load locale:', quasarLang, e)
}
}
-
-
const detectLocale = (): string => {
const localeMap = {
@@ -113,10 +111,10 @@ export const useSettingsStore = defineStore('settings', () => {
const init = async () => {
try {
- const response = await api.get('/settings')
+ const { data } = await api.get('/settings')
settings.value = {
- fontSize: response.data.data.settings.fontSize || defaultSettings.fontSize,
- locale: response.data.data.settings.locale || detectLocale()
+ fontSize: data.data.settings.fontSize || defaultSettings.fontSize,
+ locale: data.data.settings.locale || detectLocale()
}
} catch {
settings.value.locale = detectLocale()
diff --git a/src/stores/tasks.ts b/src/stores/tasks.ts
index ba0efb6..0ac89b5 100644
--- a/src/stores/tasks.ts
+++ b/src/stores/tasks.ts
@@ -45,13 +45,37 @@ export const useTasksStore = defineStore('tasks', () => {
if (tasks.value[idx]) tasks.value[idx].participants = observersAPI
}
- async function attachFiles (taskId: number, files: number[]) {
- const response = await api.put('/project/' + currentProjectId.value + '/task/' + taskId + '/attach', files)
+ async function attachFiles (taskId: number, files: File[]) {
+ const formData = new FormData()
+ files.forEach(file => formData.append('files[]', file))
+ const response = await api.post(
+ '/project/' + currentProjectId.value + '/task/' + taskId + '/attach',
+ formData,
+ {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ }
+ )
const filesAPI = response.data.data
const idx = tasks.value.findIndex(item => item.id === taskId)
if (tasks.value[idx]) tasks.value[idx].files = filesAPI
}
+ async function setCancelStatus (taskId: number) {
+ const response = await api.put('/project/' + currentProjectId.value + '/task/' + taskId, { status: 6 })
+ const taskAPI = response.data.data
+ const idx = tasks.value.findIndex(item => item.id === taskAPI.id)
+ if (tasks.value[idx]) Object.assign(tasks.value[idx], taskAPI)
+ }
+
+ async function setRestoreStatus (taskId: number) {
+ const response = await api.put('/project/' + currentProjectId.value + '/task/' + taskId, { status: 0 })
+ const taskAPI = response.data.data
+ const idx = tasks.value.findIndex(item => item.id === taskAPI.id)
+ if (tasks.value[idx]) Object.assign(tasks.value[idx], taskAPI)
+ }
+
async function remove (taskId: number) {
const response = await api.delete('/project/' + currentProjectId.value + '/task/' + taskId)
const taskAPIid = response.data.data.id
@@ -59,6 +83,8 @@ export const useTasksStore = defineStore('tasks', () => {
tasks.value.splice(idx, 1)
}
+ const getTasks = computed(() => tasks.value)
+
function taskById (id :number) {
return tasks.value.find(el => el.id === id)
}
@@ -72,7 +98,10 @@ export const useTasksStore = defineStore('tasks', () => {
update,
updateObservers,
attachFiles,
+ setCancelStatus,
+ setRestoreStatus,
remove,
+ getTasks,
taskById
}
})
diff --git a/src/stores/users.ts b/src/stores/users.ts
index 8529bcb..f112cb4 100644
--- a/src/stores/users.ts
+++ b/src/stores/users.ts
@@ -6,15 +6,21 @@ import type { User } from 'types/User'
export const useUsersStore = defineStore('users', () => {
+ interface myId {
+ telegram_id: number
+ id: number
+ }
+
const users = ref([])
const isInit = ref(false)
+ const myId = ref({ telegram_id: -1, id: -1 })
const projectsStore = useProjectsStore()
const currentProjectId = computed(() => projectsStore.currentProjectId)
async function init () {
- const response = await api.get('/project/' + currentProjectId.value + '/user')
- const usersAPI = response.data.data
+ const { data } = await api.get('/project/' + currentProjectId.value + '/user')
+ const usersAPI = data.data
users.value.push(...usersAPI)
isInit.value = true
}
@@ -34,6 +40,8 @@ export const useUsersStore = defineStore('users', () => {
return users.value.find(el =>el.id === id)
}
+ const getUsers = computed(() => users.value)
+
function userNameById (id: number) {
const user = userById(id)
return user?.fullname
@@ -42,13 +50,22 @@ export const useUsersStore = defineStore('users', () => {
|| '---'
}
+ function setMyId (telegram_id: number | undefined) {
+ if (!telegram_id) return
+ const me = users.value.find(el => el.telegram_id === telegram_id)
+ if (me) myId.value = { telegram_id: telegram_id, id: me.id }
+ }
+
return {
users,
isInit,
+ myId,
init,
reset,
reload,
userById,
- userNameById
+ getUsers,
+ userNameById,
+ setMyId
}
})
diff --git a/src/types/File.ts b/src/types/FileLink.ts
similarity index 86%
rename from src/types/File.ts
rename to src/types/FileLink.ts
index 7dcf80e..5495ea4 100644
--- a/src/types/File.ts
+++ b/src/types/FileLink.ts
@@ -1,10 +1,11 @@
-interface File {
+interface FileLink {
id: number
project_id: number
origin_chat_id: number
origin_message_id: number
chat_id: number
message_id: number
+ telegram_chat_id: number
file_id: number
filename: string
mime: string
@@ -19,5 +20,5 @@ interface File {
}
export type {
- File
+ FileLink
}
diff --git a/src/types/Meeting.ts b/src/types/Meeting.ts
index 7f1f8f8..e9ece19 100644
--- a/src/types/Meeting.ts
+++ b/src/types/Meeting.ts
@@ -3,16 +3,18 @@ interface MeetingParams {
description: string
place: string
meet_date: number
- chat_attach: number | null
+ chat_id: number | null
participants: number[]
files: number[]
is_cancel: boolean
+ [key: string]: unknown
}
interface Meeting extends MeetingParams {
id: number
project_id: number
created_by: number
+ is_editable: boolean
[key: string]: unknown
}
diff --git a/src/types/Task.ts b/src/types/Task.ts
index 72a52ae..1c9df80 100644
--- a/src/types/Task.ts
+++ b/src/types/Task.ts
@@ -1,12 +1,16 @@
interface TaskParams {
name: string
description: string
- assigned_to: number
+ assigned_to: number | null
priority: 0 | 1 | 2 | 3
- status: 1 | 5
+ status: 1 | 5 | 6
time_spent?: number
- create_date: number
plan_date: number
+ observers: number[]
+ files: number[]
+ chat_id: number | null
+ close_files: number[]
+ close_comment: string
}
interface Task extends TaskParams {
@@ -14,8 +18,7 @@ interface Task extends TaskParams {
project_id: number
created_by: number
closed_by: number | null
- observers: number[]
- files: number[]
+ create_date: number
close_date: number
[key: string]: unknown
}