diff --git a/apps/web/src/common/components/buttons/ActionMenuButton.vue b/apps/web/src/common/components/buttons/ActionMenuButton.vue
new file mode 100644
index 0000000000..5342cc512e
--- /dev/null
+++ b/apps/web/src/common/components/buttons/ActionMenuButton.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/schema/opsflow/task-category/api-verbs/update.ts b/apps/web/src/schema/opsflow/task-category/api-verbs/update.ts
index 0f4c0b2ced..3416088623 100644
--- a/apps/web/src/schema/opsflow/task-category/api-verbs/update.ts
+++ b/apps/web/src/schema/opsflow/task-category/api-verbs/update.ts
@@ -6,7 +6,7 @@ export interface TaskCategoryUpdateParameters {
category_id: string;
name?: string;
description?: string;
- status_options: TaskStatusOptions;
+ status_options?: TaskStatusOptions;
fields?: TaskField[];
force?: boolean;
tags?: Tags;
diff --git a/apps/web/src/schema/opsflow/task-type/api-verbs/create.ts b/apps/web/src/schema/opsflow/task-type/api-verbs/create.ts
index 0643987823..964b11a175 100644
--- a/apps/web/src/schema/opsflow/task-type/api-verbs/create.ts
+++ b/apps/web/src/schema/opsflow/task-type/api-verbs/create.ts
@@ -5,6 +5,7 @@ export interface TaskTypeCreateParameters {
name: string;
description?: string;
fields?: TaskField[];
+ assignee_pool?: string[];
tags?: Tags;
category_id: string;
}
diff --git a/apps/web/src/schema/opsflow/task-type/api-verbs/update.ts b/apps/web/src/schema/opsflow/task-type/api-verbs/update.ts
index 222322242b..73a4a8e376 100644
--- a/apps/web/src/schema/opsflow/task-type/api-verbs/update.ts
+++ b/apps/web/src/schema/opsflow/task-type/api-verbs/update.ts
@@ -6,6 +6,7 @@ export interface TaskTypeUpdateParameters {
name?: string;
description?: string;
fields?: TaskField[];
+ assignee_pool?: string[];
tags?: Tags;
category_id?: string;
}
diff --git a/apps/web/src/schema/opsflow/task-type/model.ts b/apps/web/src/schema/opsflow/task-type/model.ts
index 5bd439638a..537215f1ce 100644
--- a/apps/web/src/schema/opsflow/task-type/model.ts
+++ b/apps/web/src/schema/opsflow/task-type/model.ts
@@ -6,7 +6,7 @@ export interface TaskTypeModel {
name: string;
description: string;
fields: TaskField[];
- assignee?: string;
+ assignee_pool?: string[];
tags: Tags;
category_id: string;
domain_id: string;
diff --git a/apps/web/src/services/ops-flow/components/CategoryForm.vue b/apps/web/src/services/ops-flow/components/CategoryForm.vue
index c25ac98108..f0e71f5beb 100644
--- a/apps/web/src/services/ops-flow/components/CategoryForm.vue
+++ b/apps/web/src/services/ops-flow/components/CategoryForm.vue
@@ -47,14 +47,14 @@ const handleConfirm = async () => {
try {
loading.value = true;
if (taskManagementPageState.editTargetCategoryId) {
- await taskCategoryStore.updateCategory({
+ await taskCategoryStore.update({
category_id: taskManagementPageState.editTargetCategoryId,
name: name.value,
description: description.value,
});
} else {
if (!taskManagementPageGetters.defaultPackage) throw Error('Default package is not found');
- await taskCategoryStore.createCategory({
+ await taskCategoryStore.create({
name: name.value,
description: description.value,
package_id: taskManagementPageGetters.defaultPackage.package_id,
diff --git a/apps/web/src/services/ops-flow/components/PackageForm.vue b/apps/web/src/services/ops-flow/components/PackageForm.vue
index 5efde013e0..029bd6805d 100644
--- a/apps/web/src/services/ops-flow/components/PackageForm.vue
+++ b/apps/web/src/services/ops-flow/components/PackageForm.vue
@@ -1,6 +1,6 @@
@@ -59,7 +55,7 @@ onBeforeMount(() => {
계약에 따라 고객이 이용할 수 있는 기능의 묶음입니다. 전체 서비스의 범위를 나타내며, 하위 카테고를 생성할 수 있습니다.
diff --git a/apps/web/src/services/ops-flow/components/TaskCategoryPanel.vue b/apps/web/src/services/ops-flow/components/TaskCategoryPanel.vue
index cfbf5e1b2c..e8277e87f4 100644
--- a/apps/web/src/services/ops-flow/components/TaskCategoryPanel.vue
+++ b/apps/web/src/services/ops-flow/components/TaskCategoryPanel.vue
@@ -1,11 +1,14 @@
@@ -76,6 +76,15 @@ onBeforeMount(() => {
:items="taskCategoryStore.getters.taskCategories"
:fields="state.categoryFields"
>
+
+
+
+import { ref } from 'vue';
+
+import DeleteModal from '@/common/components/modals/DeleteModal.vue';
+
+import { useTaskCategoryPageStore } from '@/services/ops-flow/stores/admin/task-category-page-store';
+
+const taskCategoryPageStore = useTaskCategoryPageStore();
+const loading = ref(false);
+const handleConfirm = async () => {
+ loading.value = true;
+ // await taskCategoryPageStore.deleteStatus();
+ taskCategoryPageStore.closeDeleteStatusModal();
+ loading.value = false;
+};
+const handleCloseOrCancel = () => {
+ taskCategoryPageStore.closeDeleteStatusModal();
+};
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/components/TaskStatusDraggableItem.vue b/apps/web/src/services/ops-flow/components/TaskStatusDraggableItem.vue
new file mode 100644
index 0000000000..e999b926f8
--- /dev/null
+++ b/apps/web/src/services/ops-flow/components/TaskStatusDraggableItem.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/components/TaskStatusForm.vue b/apps/web/src/services/ops-flow/components/TaskStatusForm.vue
new file mode 100644
index 0000000000..e3c6726d78
--- /dev/null
+++ b/apps/web/src/services/ops-flow/components/TaskStatusForm.vue
@@ -0,0 +1,231 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Confirm
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/components/TaskStatusList.vue b/apps/web/src/services/ops-flow/components/TaskStatusList.vue
new file mode 100644
index 0000000000..fa7da4b3df
--- /dev/null
+++ b/apps/web/src/services/ops-flow/components/TaskStatusList.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+ {{ props.header }}
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/components/TaskStatusListFoldButton.vue b/apps/web/src/services/ops-flow/components/TaskStatusListFoldButton.vue
new file mode 100644
index 0000000000..c9a41c2818
--- /dev/null
+++ b/apps/web/src/services/ops-flow/components/TaskStatusListFoldButton.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/components/TaskStatusTree.vue b/apps/web/src/services/ops-flow/components/TaskStatusTree.vue
new file mode 100644
index 0000000000..7f17438002
--- /dev/null
+++ b/apps/web/src/services/ops-flow/components/TaskStatusTree.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/components/TaskTypeForm.vue b/apps/web/src/services/ops-flow/components/TaskTypeForm.vue
new file mode 100644
index 0000000000..0192bd18dc
--- /dev/null
+++ b/apps/web/src/services/ops-flow/components/TaskTypeForm.vue
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Confirm
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/composables/use-category-field.ts b/apps/web/src/services/ops-flow/composables/use-category-field.ts
index 4722235ba5..f2da10791c 100644
--- a/apps/web/src/services/ops-flow/composables/use-category-field.ts
+++ b/apps/web/src/services/ops-flow/composables/use-category-field.ts
@@ -63,7 +63,7 @@ export const useCategoryField = ({
const addPackageToCategories = async (packageId: string, categoryIds: string[]) => {
try {
await Promise.allSettled([
- ...categoryIds.map((categoryId) => taskCategoryStore.updateCategory({
+ ...categoryIds.map((categoryId) => taskCategoryStore.update({
package_id: packageId,
category_id: categoryId,
})),
@@ -77,7 +77,7 @@ export const useCategoryField = ({
if (!defaultPackage.value) throw new Error('Default package not found');
const defaultPackageId = defaultPackage.value.package_id;
await Promise.allSettled([
- ...categoryIds.map((categoryId) => taskCategoryStore.updateCategory({
+ ...categoryIds.map((categoryId) => taskCategoryStore.update({
package_id: defaultPackageId,
category_id: categoryId,
})),
diff --git a/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPage.vue b/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPage.vue
index fab086bd99..bc72a30161 100644
--- a/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPage.vue
+++ b/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPage.vue
@@ -1,7 +1,130 @@
+
+
- detail
+
+
+
+
+ {{ headerTitle }}
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageStatusTab.vue b/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageStatusTab.vue
new file mode 100644
index 0000000000..89f9ea562e
--- /dev/null
+++ b/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageStatusTab.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+ Status
+
+
+
+
+ Add Status
+
+
+
+
+ 티켓 상태를 보고 사용자 지정 티켓 상태를 만들어 워크플로우 배치를 향상시키고 고객과의 커뮤니케이션을 개선하세요.
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageTaskTypeTab.vue b/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageTaskTypeTab.vue
new file mode 100644
index 0000000000..148fe1aa23
--- /dev/null
+++ b/apps/web/src/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageTaskTypeTab.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+ Ticket Topic
+
+
+
+
+
+ Add Ticket Topic
+
+
+
+
+ 티켓 양식으로 티켓에 포함된 필드와 데이터를 결정합니다. 여러 티켓 양식을 만들 수 있습니다.
+ 예를 들어 서비스별로 서로 다른 양식을 만들 수 있습니다. 그런 경우에는 최종 사용자가 적절한 양식을 선택하여 요청을 제출합니다.
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/services/ops-flow/pages/admin/AdminTaskManagementPage.vue b/apps/web/src/services/ops-flow/pages/admin/AdminTaskManagementPage.vue
index 3f136ff5d5..67ee420b92 100644
--- a/apps/web/src/services/ops-flow/pages/admin/AdminTaskManagementPage.vue
+++ b/apps/web/src/services/ops-flow/pages/admin/AdminTaskManagementPage.vue
@@ -7,10 +7,6 @@ import PackageForm from '@/services/ops-flow/components/PackageForm.vue';
import SupportPackagePanel from '@/services/ops-flow/components/SupportPackagePanel.vue';
import TaskCategoryPanel from '@/services/ops-flow/components/TaskCategoryPanel.vue';
import TaskManagementTemplatePanel from '@/services/ops-flow/components/TaskManagementTemplatePanel.vue';
-import { useTaskManagementPageStore } from '@/services/ops-flow/stores/admin/task-management-page-store';
-
-const taskManagementPageStore = useTaskManagementPageStore();
-const taskManagementPageState = taskManagementPageStore.state;
@@ -24,8 +20,8 @@ const taskManagementPageState = taskManagementPageStore.state;
-
-
+
+
diff --git a/apps/web/src/services/ops-flow/routes/admin/routes.ts b/apps/web/src/services/ops-flow/routes/admin/routes.ts
index 6847c0c6b5..4d4393b38c 100644
--- a/apps/web/src/services/ops-flow/routes/admin/routes.ts
+++ b/apps/web/src/services/ops-flow/routes/admin/routes.ts
@@ -11,6 +11,8 @@ const OpsFlowContainer = () => import('@/services/ops-flow/OpsFlowContainer.vue'
const AdminTaskManagementPage = () => import('@/services/ops-flow/pages/admin/AdminTaskManagementPage.vue');
const AdminTaskCategoryDetailPage = () => import('@/services/ops-flow/pages/admin/AdminTaskCategoryDetailPage.vue');
+const AdminTaskCategoryDetailPageStatusTab = () => import('@/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageStatusTab.vue');
+const AdminTaskCategoryDetailPageTaskTypeTab = () => import('@/services/ops-flow/pages/admin/AdminTaskCategoryDetailPageTaskTypeTab.vue');
const AdminWorkflowPage = () => import('@/services/ops-flow/pages/admin/AdminWorkflowPage.vue');
const adminOpsFlowRoutes: RouteConfig = {
@@ -39,7 +41,23 @@ const adminOpsFlowRoutes: RouteConfig = {
{
path: 'task-category/:taskCategoryId',
name: makeAdminRouteName(OPS_FLOW_ROUTE.TASK_MANAGEMENT.TASK_CATEGORY.DETAIL._NAME),
+ props: true,
+ redirect: { name: makeAdminRouteName(OPS_FLOW_ROUTE.TASK_MANAGEMENT.TASK_CATEGORY.DETAIL.STATUS._NAME) },
component: AdminTaskCategoryDetailPage as any,
+ children: [
+ {
+ path: 'status',
+ name: makeAdminRouteName(OPS_FLOW_ROUTE.TASK_MANAGEMENT.TASK_CATEGORY.DETAIL.STATUS._NAME),
+ props: true,
+ component: AdminTaskCategoryDetailPageStatusTab as any,
+ },
+ {
+ path: 'task-type',
+ name: makeAdminRouteName(OPS_FLOW_ROUTE.TASK_MANAGEMENT.TASK_CATEGORY.DETAIL.TASK_TYPE._NAME),
+ props: true,
+ component: AdminTaskCategoryDetailPageTaskTypeTab as any,
+ },
+ ],
},
],
},
diff --git a/apps/web/src/services/ops-flow/routes/route-constant.ts b/apps/web/src/services/ops-flow/routes/route-constant.ts
index c509582360..85ef4550a0 100644
--- a/apps/web/src/services/ops-flow/routes/route-constant.ts
+++ b/apps/web/src/services/ops-flow/routes/route-constant.ts
@@ -15,7 +15,11 @@ export const OPS_FLOW_ROUTE = Object.freeze({
TASK_MANAGEMENT: {
_NAME: `${MENU_ID.OPS_FLOW}.${MENU_ID.TASK_MANAGEMENT}`,
TASK_CATEGORY: {
- DETAIL: { _NAME: `${MENU_ID.OPS_FLOW}.${MENU_ID.TASK_MANAGEMENT}.task_category.detail` },
+ DETAIL: {
+ _NAME: `${MENU_ID.OPS_FLOW}.${MENU_ID.TASK_MANAGEMENT}.task_category.detail`,
+ STATUS: { _NAME: `${MENU_ID.OPS_FLOW}.${MENU_ID.TASK_MANAGEMENT}.task_category.detail.status` },
+ TASK_TYPE: { _NAME: `${MENU_ID.OPS_FLOW}.${MENU_ID.TASK_MANAGEMENT}.task_category.detail.task_type` },
+ },
CREATE: { _NAME: `${MENU_ID.OPS_FLOW}.${MENU_ID.TASK_MANAGEMENT}.task_category.create` },
},
},
diff --git a/apps/web/src/services/ops-flow/stores/admin/package-store.ts b/apps/web/src/services/ops-flow/stores/admin/package-store.ts
index ee64ec2ecb..d288b03bb4 100644
--- a/apps/web/src/services/ops-flow/stores/admin/package-store.ts
+++ b/apps/web/src/services/ops-flow/stores/admin/package-store.ts
@@ -1,3 +1,5 @@
+import { asyncComputed } from '@vueuse/core';
+import type { Ref, UnwrapRef } from 'vue';
import { reactive } from 'vue';
import { defineStore } from 'pinia';
@@ -9,15 +11,28 @@ import type { PackageModel } from '@/schema/identity/package/model';
interface UsePackageStoreState {
loading: boolean;
- packages?: PackageModel[];
+ items?: PackageModel[];
+}
+interface UsePackageStoreGetters {
+ packages: Ref>
}
export const usePackageStore = defineStore('package', () => {
const state = reactive({
loading: false,
- packages: undefined,
+ items: undefined,
});
+
+ const getters = reactive({
+ packages: asyncComputed(async () => {
+ if (state.items === undefined) {
+ await actions.list();
+ }
+ return state.items ?? [];
+ }, [], { lazy: true }),
+ }) as UnwrapRef;
+
const actions = {
- async fetchPackages() {
+ async list() {
return new Promise((resolve) => {
state.loading = true;
setTimeout(() => {
@@ -56,17 +71,17 @@ export const usePackageStore = defineStore('package', () => {
updated_at: '2021-09-01T00:00:00',
},
];
- state.packages = packages;
+ state.items = packages;
state.loading = false;
resolve(packages);
}, 1000);
});
},
- async createPackage(param: PackageCreateParameters) {
+ async create(param: PackageCreateParameters) {
return new Promise((resolve) => {
setTimeout(() => {
const result: PackageModel = {
- package_id: `package_${(state.packages?.length ?? 0) + 1}`,
+ package_id: `package_${getters.packages.length + 1}`,
name: param.name,
description: param.description ?? '',
order: 4,
@@ -76,15 +91,16 @@ export const usePackageStore = defineStore('package', () => {
created_at: '2021-09-01T00:00:00',
updated_at: '2021-09-01T00:00:00',
};
- state.packages?.push(result);
+ if (state.items) state.items.push(result);
+ else state.items = [result];
resolve(result);
}, 1000);
});
},
- async updatePackage(param: PackageUpdateParameters) {
+ async update(param: PackageUpdateParameters) {
return new Promise((resolve, reject) => {
setTimeout(() => {
- const targetPackage = state.packages?.find((p) => p.package_id === param.package_id);
+ const targetPackage = getters.packages.find((p) => p.package_id === param.package_id);
if (targetPackage) {
targetPackage.name = param.name ?? targetPackage.name;
targetPackage.description = param.description ?? targetPackage.description;
@@ -100,7 +116,7 @@ export const usePackageStore = defineStore('package', () => {
async setDefaultPackage(packageId: string) {
return new Promise((resolve, reject) => {
setTimeout(() => {
- const targetPackage = state.packages?.find((p) => p.package_id === packageId);
+ const targetPackage = getters.packages.find((p) => p.package_id === packageId);
if (targetPackage) {
targetPackage.is_default = true;
resolve(targetPackage);
@@ -113,6 +129,7 @@ export const usePackageStore = defineStore('package', () => {
};
return {
state,
+ getters,
...actions,
};
});
diff --git a/apps/web/src/services/ops-flow/stores/admin/task-category-page-store.ts b/apps/web/src/services/ops-flow/stores/admin/task-category-page-store.ts
new file mode 100644
index 0000000000..f5cf4c33ad
--- /dev/null
+++ b/apps/web/src/services/ops-flow/stores/admin/task-category-page-store.ts
@@ -0,0 +1,154 @@
+import type { ComputedRef, UnwrapRef } from 'vue';
+import { reactive, computed } from 'vue';
+
+import { defineStore } from 'pinia';
+
+import type { TaskCategoryModel } from '@/schema/opsflow/task-category/model';
+import type { TaskTypeModel } from '@/schema/opsflow/task-type/model';
+import type { TaskStatusOption, TaskStatusOptions, TaskStatusType } from '@/schema/opsflow/task/type';
+
+import { useTaskCategoryStore } from '@/services/ops-flow/stores/admin/task-category-store';
+import { useTaskTypeStore } from '@/services/ops-flow/stores/admin/task-type-store';
+
+interface UseTaskCategoryPageStoreState {
+ currentCategoryId?: string;
+ // status
+ visibleStatusForm: boolean;
+ targetStatus: {
+ type: TaskStatusType;
+ index: number;
+ }|undefined;
+ visibleStatusDeleteModal: boolean;
+ // task type
+ visibleTaskTypeForm: boolean;
+ targetTaskTypeId?: string;
+ visibleTaskTypeDeleteModal: boolean;
+}
+
+interface UseTaskCategoryPageStoreGetters {
+ currentCategory: ComputedRef;
+ // status
+ statusOptions: ComputedRef;
+ targetStatusOption: ComputedRef<{
+ type: TaskStatusType;
+ data: TaskStatusOption;
+ }|undefined>;
+ // task type
+ taskTypes: ComputedRef;
+ targetTaskType: ComputedRef;
+}
+
+export const useTaskCategoryPageStore = defineStore('task-management-category-page', () => {
+ const taskCategoryStore = useTaskCategoryStore();
+ const taskTypeStore = useTaskTypeStore();
+ const state = reactive({
+ currentCategoryId: undefined,
+ // status
+ visibleStatusForm: false,
+ targetStatus: undefined,
+ visibleStatusDeleteModal: false,
+ // task type
+ visibleTaskTypeForm: false,
+ targetTaskTypeId: undefined,
+ visibleTaskTypeDeleteModal: false,
+ });
+
+ const getters = reactive({
+ currentCategory: computed(() => taskCategoryStore.getters.taskCategories.find((c) => c.category_id === state.currentCategoryId)),
+ // status
+ statusOptions: computed(() => {
+ const category = getters.currentCategory;
+ if (!category) {
+ return {
+ TODO: [],
+ IN_PROGRESS: [],
+ COMPLETED: [],
+ };
+ }
+ return category.status_options;
+ }),
+ targetStatusOption: computed<{
+ type: TaskStatusType;
+ data: TaskStatusOption;
+ }|undefined>(() => {
+ if (!state.targetStatus) return undefined;
+ const { index, type } = state.targetStatus;
+ const statusOptions = getters.statusOptions;
+ if (!statusOptions) return undefined;
+ return {
+ type,
+ data: statusOptions[type][index],
+ };
+ }),
+ // task type
+ taskTypes: computed(() => {
+ if (!state.currentCategoryId) return undefined;
+ const allTaskTypes = taskTypeStore.getters.taskTypes;
+ return allTaskTypes.filter((taskType) => taskType.category_id === state.currentCategoryId);
+ }),
+ targetTaskType: computed(() => {
+ if (!state.targetTaskTypeId) return undefined;
+ return taskTypeStore.getters.taskTypes.find((taskType) => taskType.task_type_id === state.targetTaskTypeId);
+ }),
+ }) as UnwrapRef;
+
+ const actions = {
+ setCurrentCategoryId(categoryId: string) {
+ state.currentCategoryId = categoryId;
+ },
+ // status
+ openAddStatusForm() {
+ state.targetStatus = undefined;
+ state.visibleStatusForm = true;
+ },
+ openEditStatusForm(index: number, statusType: TaskStatusType) {
+ state.targetStatus = {
+ index,
+ type: statusType,
+ };
+ state.visibleStatusForm = true;
+ },
+ closeStatusForm() {
+ state.visibleStatusForm = false;
+ state.targetStatus = undefined;
+ },
+ openDeleteStatusModal(index: number, statusType: TaskStatusType) {
+ state.targetStatus = {
+ index,
+ type: statusType,
+ };
+ state.visibleStatusDeleteModal = true;
+ },
+ closeDeleteStatusModal() {
+ state.visibleStatusDeleteModal = false;
+ state.targetStatus = undefined;
+ },
+ // task type
+ openAddTaskTypeForm() {
+ state.targetTaskTypeId = undefined;
+ state.visibleTaskTypeForm = true;
+ },
+ openEditTaskTypeForm(taskTypeId: string) {
+ state.targetTaskTypeId = taskTypeId;
+ state.visibleTaskTypeForm = true;
+ },
+ closeTaskTypeForm() {
+ state.visibleTaskTypeForm = false;
+ state.targetTaskTypeId = undefined;
+ },
+ openDeleteTaskTypeModal(taskTypeId: string) {
+ state.targetTaskTypeId = taskTypeId;
+ state.visibleTaskTypeDeleteModal = true;
+ },
+ closeDeleteTaskTypeModal() {
+ state.visibleTaskTypeDeleteModal = false;
+ state.targetTaskTypeId = undefined;
+ },
+ };
+ return {
+ state,
+ getters,
+ ...actions,
+ taskCategoryStore,
+ };
+});
diff --git a/apps/web/src/services/ops-flow/stores/admin/task-category-store.ts b/apps/web/src/services/ops-flow/stores/admin/task-category-store.ts
index 10f4ea14e0..c78eb8a174 100644
--- a/apps/web/src/services/ops-flow/stores/admin/task-category-store.ts
+++ b/apps/web/src/services/ops-flow/stores/admin/task-category-store.ts
@@ -1,5 +1,5 @@
import { asyncComputed } from '@vueuse/core';
-import type { Ref, DeepReadonly } from 'vue';
+import type { Ref } from 'vue';
import { reactive } from 'vue';
import { defineStore } from 'pinia';
@@ -14,7 +14,7 @@ interface UseTaskCategoryStoreState {
items?: TaskCategoryModel[];
}
interface UseTaskCategoryStoreGetters {
- taskCategories: Ref>
+ taskCategories: Ref>
}
export const useTaskCategoryStore = defineStore('task-category', () => {
@@ -26,14 +26,14 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
const getters = reactive({
taskCategories: asyncComputed(async () => {
if (state.items === undefined) {
- await actions.fetchCategories();
+ await actions.list();
}
return state.items ?? [];
}, [], { lazy: true }),
});
const actions = {
- async fetchCategories() {
+ async list() {
return new Promise((resolve) => {
state.loading = true;
setTimeout(() => {
@@ -48,7 +48,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'todo_1',
name: '요청',
- color: 'gray',
+ color: 'gray200',
is_default: true,
},
],
@@ -56,7 +56,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'in_progress_1',
name: '진행중',
- color: 'blue',
+ color: 'blue200',
is_default: true,
},
],
@@ -64,19 +64,19 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'complete_1',
name: '완료',
- color: 'green',
+ color: 'green200',
is_default: true,
},
{
status_id: 'complete_2',
name: '보류',
- color: 'yellow',
+ color: 'yellow200',
is_default: false,
},
{
status_id: 'complete_3',
name: '취소',
- color: 'red',
+ color: 'red100',
is_default: false,
},
],
@@ -97,7 +97,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'todo_1',
name: '요청',
- color: 'gray',
+ color: 'gray200',
is_default: true,
},
],
@@ -105,13 +105,13 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'in_progress_1',
name: '확인중',
- color: 'yellow',
+ color: 'yellow200',
is_default: true,
},
{
status_id: 'in_progress_2',
name: '진행중',
- color: 'blue',
+ color: 'blue200',
is_default: false,
},
],
@@ -119,7 +119,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'complete_1',
name: '완료',
- color: 'green',
+ color: 'green200',
is_default: true,
},
],
@@ -139,7 +139,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'todo_1',
name: '요청',
- color: 'gray',
+ color: 'gray200',
is_default: true,
},
],
@@ -147,7 +147,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'in_progress_1',
name: '진행중',
- color: 'blue',
+ color: 'blue200',
is_default: false,
},
],
@@ -155,7 +155,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'complete_1',
name: '완료',
- color: 'green',
+ color: 'green200',
is_default: true,
},
],
@@ -172,7 +172,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
}, 1000);
});
},
- async createCategory(param: Omit) {
+ async create(param: Omit) {
return new Promise((resolve) => {
const result: TaskCategoryModel = {
category_id: `category_${(getters.taskCategories.length) + 1}`,
@@ -184,7 +184,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'todo_1',
name: '요청',
- color: 'gray',
+ color: 'gray200',
is_default: true,
},
],
@@ -192,7 +192,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'in_progress_1',
name: '진행중',
- color: 'blue',
+ color: 'blue200',
is_default: true,
},
],
@@ -200,7 +200,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
{
status_id: 'complete_1',
name: '완료',
- color: 'green',
+ color: 'green200',
is_default: true,
},
],
@@ -215,7 +215,7 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
resolve(result);
});
},
- async updateCategory(param: Omit) {
+ async update(param: TaskCategoryUpdateParameters) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const targetCategory = state.items?.find((category) => category.category_id === param.category_id);
@@ -224,6 +224,19 @@ export const useTaskCategoryStore = defineStore('task-category', () => {
if (param.description) targetCategory.description = param.description ?? '';
if (param.tags) targetCategory.tags = param.tags ?? {};
if (param.package_id) targetCategory.package_id = param.package_id;
+ if (param.status_options) targetCategory.status_options = param.status_options;
+ resolve(targetCategory);
+ } else {
+ reject(new Error('Category not found'));
+ }
+ }, 1000);
+ });
+ },
+ async get(categoryId: string) {
+ return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ const targetCategory = state.items?.find((category) => category.category_id === categoryId);
+ if (targetCategory) {
resolve(targetCategory);
} else {
reject(new Error('Category not found'));
diff --git a/apps/web/src/services/ops-flow/stores/admin/task-management-page-store.ts b/apps/web/src/services/ops-flow/stores/admin/task-management-page-store.ts
index ab8f862f1d..ea66b4069b 100644
--- a/apps/web/src/services/ops-flow/stores/admin/task-management-page-store.ts
+++ b/apps/web/src/services/ops-flow/stores/admin/task-management-page-store.ts
@@ -40,9 +40,9 @@ export const useTaskManagementPageStore = defineStore('task-management-page', ()
editTargetCategoryId: undefined,
});
const getters = reactive({
- editTargetPackage: computed(() => packageStore.state.packages?.find((p) => p.package_id === state.editTargetPackageId)),
+ editTargetPackage: computed(() => packageStore.getters.packages.find((p) => p.package_id === state.editTargetPackageId)),
editTargetCategory: computed|undefined>(() => taskCategoryStore.getters.taskCategories.find((c) => c.category_id === state.editTargetCategoryId)),
- defaultPackage: computed(() => packageStore.state.packages?.find((p) => p.is_default)),
+ defaultPackage: computed(() => packageStore.getters.packages.find((p) => p.is_default)),
});
const actions = {
setCurrentTemplateId(templateId: string) {
diff --git a/apps/web/src/services/ops-flow/stores/admin/task-type-store.ts b/apps/web/src/services/ops-flow/stores/admin/task-type-store.ts
index fe4bcaeaae..e961e337bc 100644
--- a/apps/web/src/services/ops-flow/stores/admin/task-type-store.ts
+++ b/apps/web/src/services/ops-flow/stores/admin/task-type-store.ts
@@ -1,3 +1,5 @@
+import { asyncComputed } from '@vueuse/core';
+import type { Ref, UnwrapRef } from 'vue';
import { reactive } from 'vue';
import { defineStore } from 'pinia';
@@ -7,116 +9,140 @@ import type { TaskTypeModel } from '@/schema/opsflow/task-type/model';
import getRandomId from '@/lib/random-id-generator';
interface UseTaskTypeStoreState {
- taskTypes?: TaskTypeModel[];
+ items?: TaskTypeModel[];
+}
+
+interface UseTaskTypeStoreGetters {
+ taskTypes: Ref>
}
export const useTaskTypeStore = defineStore('task-type', () => {
const state = reactive({
- taskTypes: [
- {
- task_type_id: 'task_type_1',
- name: 'Account',
- description: '계정과 관련된 문의사항',
- assignee: 'wanjin@mz.co.kr',
- fields: [
- {
- field_id: getRandomId(),
- name: '제목',
- field_type: 'TEXT',
- is_required: true,
- is_primary: true,
- },
- {
- field_id: getRandomId(),
- name: '설명',
- field_type: 'PARAGRAPH',
- is_required: false,
- is_primary: true,
- },
- ],
- category_id: 'category_1',
- tags: {},
- domain_id: '1',
- created_at: '2021-09-01T00:00:00',
- updated_at: '2021-09-01T00:00:00',
- },
- {
- task_type_id: 'task_type_2',
- name: 'Invoice',
- description: '청구서와 관련된 문의사항',
- assignee: 'bokjang@mz.co.kr',
- fields: [
- {
- field_id: getRandomId(),
- name: '제목',
- field_type: 'TEXT',
- is_required: true,
- is_primary: true,
- },
- {
- field_id: getRandomId(),
- name: '설명',
- field_type: 'PARAGRAPH',
- is_required: true,
- is_primary: true,
- },
- {
- field_id: getRandomId(),
- name: '서비스',
- field_type: 'DROPDOWN',
- options: ['서비스1', '서비스2', '서비스3'],
- is_required: false,
- },
- {
- field_id: getRandomId(),
- name: '연결된 자산',
- field_type: 'ASSET',
- is_required: false,
- },
- {
- field_id: getRandomId(),
- name: '담당자',
- field_type: 'USER',
- is_required: false,
- },
- ],
- category_id: 'category_1',
- tags: {},
- domain_id: '1',
- created_at: '2021-09-01T00:00:00',
- updated_at: '2021-09-01T00:00:00',
- },
- {
- task_type_id: 'task_type_3',
- name: 'Billing',
- description: '빌링과 관련된 문의사항',
- fields: [
- {
- field_id: getRandomId(),
- name: '제목',
- field_type: 'TEXT',
- is_required: true,
- is_primary: true,
- },
- {
- field_id: getRandomId(),
- name: '설명',
- field_type: 'PARAGRAPH',
- is_required: false,
- is_primary: false,
- },
- ],
- category_id: 'category_2',
- tags: {},
- domain_id: '1',
- created_at: '2021-09-01T00:00:00',
- updated_at: '2021-09-01T00:00:00',
- },
- ],
+ items: undefined,
}) as UseTaskTypeStoreState;
- const actions = {};
+
+ const getters = reactive({
+ taskTypes: asyncComputed(async () => {
+ if (!state.items) {
+ await actions.list();
+ }
+ return state.items ?? [];
+ }, [], { lazy: true }),
+ }) as UnwrapRef;
+
+ const actions = {
+ async list() {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ state.items = [
+ {
+ task_type_id: 'task_type_1',
+ name: 'Account',
+ description: '계정과 관련된 문의사항',
+ assignee_pool: ['wanjin@mz.co.kr'],
+ fields: [
+ {
+ field_id: getRandomId(),
+ name: '제목',
+ field_type: 'TEXT',
+ is_required: true,
+ is_primary: true,
+ },
+ {
+ field_id: getRandomId(),
+ name: '설명',
+ field_type: 'PARAGRAPH',
+ is_required: false,
+ is_primary: true,
+ },
+ ],
+ category_id: 'category_1',
+ tags: {},
+ domain_id: '1',
+ created_at: '2021-09-01T00:00:00',
+ updated_at: '2021-09-01T00:00:00',
+ },
+ {
+ task_type_id: 'task_type_2',
+ name: 'Invoice',
+ description: '청구서와 관련된 문의사항',
+ assignee_pool: ['bokjang@mz.co.kr'],
+ fields: [
+ {
+ field_id: getRandomId(),
+ name: '제목',
+ field_type: 'TEXT',
+ is_required: true,
+ is_primary: true,
+ },
+ {
+ field_id: getRandomId(),
+ name: '설명',
+ field_type: 'PARAGRAPH',
+ is_required: true,
+ is_primary: true,
+ },
+ {
+ field_id: getRandomId(),
+ name: '서비스',
+ field_type: 'DROPDOWN',
+ options: ['서비스1', '서비스2', '서비스3'],
+ is_required: false,
+ },
+ {
+ field_id: getRandomId(),
+ name: '연결된 자산',
+ field_type: 'ASSET',
+ is_required: false,
+ },
+ {
+ field_id: getRandomId(),
+ name: '담당자',
+ field_type: 'USER',
+ is_required: false,
+ },
+ ],
+ category_id: 'category_1',
+ tags: {},
+ domain_id: '1',
+ created_at: '2021-09-01T00:00:00',
+ updated_at: '2021-09-01T00:00:00',
+ },
+ {
+ task_type_id: 'task_type_3',
+ name: 'Billing',
+ description: '빌링과 관련된 문의사항',
+ fields: [
+ {
+ field_id: getRandomId(),
+ name: '제목',
+ field_type: 'TEXT',
+ is_required: true,
+ is_primary: true,
+ },
+ {
+ field_id: getRandomId(),
+ name: '설명',
+ field_type: 'PARAGRAPH',
+ is_required: false,
+ is_primary: false,
+ },
+ ],
+ category_id: 'category_2',
+ tags: {},
+ domain_id: '1',
+ created_at: '2021-09-01T00:00:00',
+ updated_at: '2021-09-01T00:00:00',
+ },
+ ];
+ resolve(state.items);
+ }, 1000);
+ });
+ },
+ };
return {
state,
+ getters,
...actions,
};
});