提交 970e033d authored 作者: 王鹏飞's avatar 王鹏飞

refactor: 重构项目管理

上级 370f329c
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
"name": "center-zws", "name": "center-zws",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@vueuse/core": "^9.6.0",
"axios": "^1.2.1", "axios": "^1.2.1",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"element-plus": "^2.2.26", "element-plus": "^2.2.26",
...@@ -1022,13 +1023,13 @@ ...@@ -1022,13 +1023,13 @@
} }
}, },
"node_modules/@vueuse/core": { "node_modules/@vueuse/core": {
"version": "9.4.0", "version": "9.6.0",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.6.0.tgz",
"integrity": "sha512-JzgenGj1ZF2BHOen5rsFiAyyI9sXAv7aKhNLlm9b7SwYQeKTcxTWdhudonURCSP3Egl9NQaRBzes2lv/1JUt/Q==", "integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
"dependencies": { "dependencies": {
"@types/web-bluetooth": "^0.0.16", "@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.4.0", "@vueuse/metadata": "9.6.0",
"@vueuse/shared": "9.4.0", "@vueuse/shared": "9.6.0",
"vue-demi": "*" "vue-demi": "*"
} }
}, },
...@@ -1055,14 +1056,14 @@ ...@@ -1055,14 +1056,14 @@
} }
}, },
"node_modules/@vueuse/metadata": { "node_modules/@vueuse/metadata": {
"version": "9.4.0", "version": "9.6.0",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.6.0.tgz",
"integrity": "sha512-7GKMdGAsJyQJl35MYOz/RDpP0FxuiZBRDSN79QIPbdqYx4Sd0sVTnIC68KJ6Oln0t0SouvSUMvRHuno216Ud2Q==" "integrity": "sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w=="
}, },
"node_modules/@vueuse/shared": { "node_modules/@vueuse/shared": {
"version": "9.4.0", "version": "9.6.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.6.0.tgz",
"integrity": "sha512-fTuem51KwMCnqUKkI8B57qAIMcFovtGgsCtAeqxIzH3i6nE9VYge+gVfneNHAAy7lj8twbkNfqQSygOPJTm4tQ==", "integrity": "sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==",
"dependencies": { "dependencies": {
"vue-demi": "*" "vue-demi": "*"
} }
...@@ -5093,13 +5094,13 @@ ...@@ -5093,13 +5094,13 @@
"requires": {} "requires": {}
}, },
"@vueuse/core": { "@vueuse/core": {
"version": "9.4.0", "version": "9.6.0",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.6.0.tgz",
"integrity": "sha512-JzgenGj1ZF2BHOen5rsFiAyyI9sXAv7aKhNLlm9b7SwYQeKTcxTWdhudonURCSP3Egl9NQaRBzes2lv/1JUt/Q==", "integrity": "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==",
"requires": { "requires": {
"@types/web-bluetooth": "^0.0.16", "@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.4.0", "@vueuse/metadata": "9.6.0",
"@vueuse/shared": "9.4.0", "@vueuse/shared": "9.6.0",
"vue-demi": "*" "vue-demi": "*"
}, },
"dependencies": { "dependencies": {
...@@ -5112,14 +5113,14 @@ ...@@ -5112,14 +5113,14 @@
} }
}, },
"@vueuse/metadata": { "@vueuse/metadata": {
"version": "9.4.0", "version": "9.6.0",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.6.0.tgz",
"integrity": "sha512-7GKMdGAsJyQJl35MYOz/RDpP0FxuiZBRDSN79QIPbdqYx4Sd0sVTnIC68KJ6Oln0t0SouvSUMvRHuno216Ud2Q==" "integrity": "sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w=="
}, },
"@vueuse/shared": { "@vueuse/shared": {
"version": "9.4.0", "version": "9.6.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.6.0.tgz",
"integrity": "sha512-fTuem51KwMCnqUKkI8B57qAIMcFovtGgsCtAeqxIzH3i6nE9VYge+gVfneNHAAy7lj8twbkNfqQSygOPJTm4tQ==", "integrity": "sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==",
"requires": { "requires": {
"vue-demi": "*" "vue-demi": "*"
}, },
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
"cert": "node ./cert.js" "cert": "node ./cert.js"
}, },
"dependencies": { "dependencies": {
"@vueuse/core": "^9.6.0",
"axios": "^1.2.1", "axios": "^1.2.1",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"element-plus": "^2.2.26", "element-plus": "^2.2.26",
......
...@@ -16,7 +16,9 @@ withDefaults(defineProps<{ hasBreadcrumb?: boolean }>(), { ...@@ -16,7 +16,9 @@ withDefaults(defineProps<{ hasBreadcrumb?: boolean }>(), {
<AppBreadcrumb v-if="hasBreadcrumb"></AppBreadcrumb> <AppBreadcrumb v-if="hasBreadcrumb"></AppBreadcrumb>
</div> </div>
<div class="app-main-container"> <div class="app-main-container">
<RouterView></RouterView> <Suspense>
<RouterView></RouterView>
</Suspense>
</div> </div>
</div> </div>
</section> </section>
......
import httpRequest from '@/utils/axios' import httpRequest from '@/utils/axios'
import type { ProjectRequestParams } from './types'
// 获取列表 // 获取列表
export function getProjectList(params?: { export function getProjectList(params?: {
...@@ -23,38 +24,22 @@ export function getProjectRoles() { ...@@ -23,38 +24,22 @@ export function getProjectRoles() {
} }
// 创建项目 // 创建项目
export function createProject(data?: { export function createProject(data: ProjectRequestParams) {
title?: string
alias?: string
project_type: string
project_status: string
project_uri?: string
landing_page_uri?: string
members: string
}) {
return httpRequest.post('/api/zws/v1/backend/project/create', data) return httpRequest.post('/api/zws/v1/backend/project/create', data)
} }
// 详情 // 详情
export function getProjectDetail(params?: { id?: string | string[] }) { export function getProjectDetail(params: { id: string }) {
return httpRequest.get('/api/zws/v1/backend/project/view', { params }) return httpRequest.get('/api/zws/v1/backend/project/view', { params })
} }
// 获取成员列表 // 获取成员列表
export function getProjectUserList(params?: { id?: string | string[] }) { export function getProjectUserList(params: { id: string; 'per-page'?: number; page?: number }) {
return httpRequest.get('/api/zws/v1/backend/project/member', { params }) return httpRequest.get('/api/zws/v1/backend/project/member', { params })
} }
// 更新项目 // 更新项目
export function updateProject(data?: { export function updateProject(data: { id: string } & ProjectRequestParams) {
id: string | string[]
title?: string
alias?: string
project_type: string
project_status: string
project_uri?: string
landing_page_uri?: string
}) {
return httpRequest.post('/api/zws/v1/backend/project/update', data) return httpRequest.post('/api/zws/v1/backend/project/update', data)
} }
......
...@@ -9,7 +9,7 @@ interface FormData { ...@@ -9,7 +9,7 @@ interface FormData {
} }
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', modelValue: boolean): void (e: 'update:modelValue', modelValue: boolean): void
(e: 'changeUser', data: FormData): void (e: 'submit', data: FormData): void
}>() }>()
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
...@@ -43,8 +43,7 @@ onMounted(() => { ...@@ -43,8 +43,7 @@ onMounted(() => {
// 选择完成 // 选择完成
function submit() { function submit() {
formRef?.validate(() => { formRef?.validate(() => {
emit('changeUser', form as FormData) emit('submit', form as FormData)
emit('update:modelValue', false)
}) })
} }
</script> </script>
......
<script setup lang="ts"> <script setup lang="ts">
import type { FormRules } from 'element-plus' import type { ProjectFormData } from '../types'
import { getProjectDetail } from '../api'
import { useMap } from '../composables/useMap' import { useMap } from '../composables/useMap'
import { provideForm } from '../util'
const route = useRoute() const { types, status, projectId, checkAuth, prefix } = await useMap()
const { types, status, projectId, checkAuth, prefix } = useMap()
prefix.value = 'U:zws_config_projects:' prefix.value = 'U:zws_config_projects:'
const ruleFormRef = ref() const form = inject(provideForm) as ProjectFormData
watchEffect(() => {
interface Props { if (form.project_id) {
isAdd?: boolean projectId.value = form.project_id
isUpdate?: boolean
isView?: boolean
}
const prop = defineProps<Props>()
interface ProjectInfoBase {
title: string
alias: string
project_type: string
project_status: string
project_uri: string
landing_page_uri: string
project_id: string
}
let form = reactive<ProjectInfoBase>({
title: '',
alias: '',
project_type: '',
project_status: '',
project_uri: '',
landing_page_uri: '',
project_id: ''
})
onMounted(() => {
if (prop?.isView || prop?.isUpdate) {
getProjectDetail({ id: route.params.id }).then((res: { data: ProjectInfoBase }) => {
form = Object.assign(form, res.data)
projectId.value = res.data.project_id
window.localStorage.projectId = res.data.project_id
})
} }
}) })
const rules = reactive<FormRules>({
project_type: [{ required: true, message: '请选择类型' }],
project_status: [{ required: true, message: '请选择状态' }]
})
const submit = () => {
return ruleFormRef.value.validate()
}
defineExpose({
form,
submit
})
</script> </script>
<template> <template>
<el-card shadow="never" header="基本信息"> <el-card shadow="never" header="基本信息">
<el-form ref="ruleFormRef" :disabled="prop?.isView" :model="form" :rules="rules" label-width="140px"> <el-form-item label="项目编号" prop="project_id" v-if="$route.params.id">
<el-form-item label="项目名称" v-if="!checkAuth('title')"> <el-input v-model="form.project_id" disabled />
<el-input v-model="form.title" :disabled="!checkAuth('title')" /> </el-form-item>
</el-form-item> <el-form-item
<el-form-item label="项目别名"> label="项目名称"
<el-input v-model="form.alias" :disabled="!checkAuth('alias')" /> prop="title"
</el-form-item> :rules="[{ required: true, message: '请输入项目名称', trigger: 'blur' }]">
<el-form-item label="项目类型" prop="project_type"> <el-input v-model="form.title" :disabled="!checkAuth('title')" />
<el-select v-model="form.project_type" placeholder="请选择" :disabled="!checkAuth('project_type')"> </el-form-item>
<el-option v-for="item in types" :key="item.id" :label="item.name" :value="item.id" /> <el-form-item label="项目别名" prop="alias">
</el-select> <el-input v-model="form.alias" :disabled="!checkAuth('alias')" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="project_status"> <el-form-item label="项目类型" prop="project_type" :rules="[{ required: true, message: '请选择项目类型' }]">
<el-select v-model="form.project_status" placeholder="请选择" :disabled="!checkAuth('project_status')"> <el-select v-model="form.project_type" placeholder="请选择" :disabled="!checkAuth('project_type')">
<el-option v-for="item in status" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in types" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="项目站首页(原项目页)"> <el-form-item label="状态" prop="project_status" :rules="[{ required: true, message: '请选择项目状态' }]">
<el-input v-model="form.project_uri" :disabled="!checkAuth('project_uri')" /> <el-select v-model="form.project_status" placeholder="请选择" :disabled="!checkAuth('project_status')">
</el-form-item> <el-option v-for="item in status" :key="item.id" :label="item.name" :value="item.id" />
<el-form-item label="移动端落地页(原着陆页地址)"> </el-select>
<el-input v-model="form.landing_page_uri" :disabled="!checkAuth('landing_page_uri')" /> </el-form-item>
</el-form-item> <el-form-item label="项目站首页">
</el-form> <el-input v-model="form.project_uri" :disabled="!checkAuth('project_uri')" />
</el-form-item>
<el-form-item label="移动端落地页">
<el-input v-model="form.landing_page_uri" :disabled="!checkAuth('landing_page_uri')" />
</el-form-item>
</el-card> </el-card>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { ProjectFormData, ProjectMember, User, Role } from '../types'
import AppList from '@/components/base/AppList.vue' import AppList from '@/components/base/AppList.vue'
import { getProjectUserList, deleteMember } from '../api' import { getProjectUserList, addMember, deleteMember } from '../api'
import { useMap } from '../composables/useMap' import { useMap } from '../composables/useMap'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
const { checkAuth, hasAuth, projectId } = useMap() import { provideForm } from '../util'
import { useNow, useDateFormat } from '@vueuse/core'
const { hasAuth, projectId } = await useMap()
const AddMember = defineAsyncComponent(() => import('../components/AddMember.vue')) const AddMember = defineAsyncComponent(() => import('../components/AddMember.vue'))
const route = useRoute() const route = useRoute()
const isAdd = $computed(() => !route.params.id)
interface Props { const form = inject(provideForm) as ProjectFormData
isAdd?: boolean watchEffect(() => {
isUpdate?: boolean if (form.project_id) {
isView?: boolean projectId.value = form.project_id
} }
})
const prop = defineProps<Props>()
interface User {
nickname: string
mobile: string
email: string
role: string[]
}
let userList = $ref<User[]>([]) const appList = $ref<InstanceType<typeof AppList> | null>(null)
const listOptions = $computed(() => { const listOptions = $computed(() => {
return { return {
remote: !isAdd ? { httpRequest: getProjectUserList, params: { id: route.params.id } } : {},
columns: [ columns: [
{ { label: '姓名', prop: 'name' },
label: '姓名',
prop: 'nickname',
computed(row: any) {
let name = ''
if (row.row?.name) {
name = row.row.name
} else {
name = row.row.nickname
}
return name
}
},
{ label: '手机号', prop: 'mobile' }, { label: '手机号', prop: 'mobile' },
{ label: '邮箱', prop: 'email' }, { label: '邮箱', prop: 'email' },
{ { label: '角色', prop: 'role_name' },
label: '角色',
prop: 'role',
computed(row: any) {
if (row.row?.role_name) {
return row.row?.role_name
} else {
return row.row.role.reduce((a: any, b: any) => a.push(b.name) && a, []).toString()
}
}
},
{ label: '加入日期', prop: 'updated_time' }, { label: '加入日期', prop: 'updated_time' },
{ label: '操作', prop: 'name', slots: 'table-x', width: 100 } { label: '操作', prop: 'name', slots: 'table-x', width: 100 }
], ],
data: userList data: form.members
} }
}) })
const labelVisible = $ref(false)
// 选择人员 let memberVisible = $ref(false)
const changeUser = function (e: any) { // 添加人员
const info = Object.assign(e.userInfo, { role: e.role }) const handleSubmitMember = function (data: { user: User; role: Role[] }) {
userList.push(info) if (isAdd) {
const formatted = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss')
const temp = {
user_id: data.user.id,
name: data.user.realname || data.user.nickname,
mobile: data.user.mobile,
email: data.user.email,
role_name: data.role.map(item => item.name).join('、'),
role_id: data.role.map(item => item.id).join(','),
updated_time: formatted.value
}
form.members.unshift(temp)
memberVisible = false
} else {
const params = {
user_id: data.user.id,
projects_id: form.project_id,
roles: data.role.map(item => item.id).join(',')
}
addMember(params).then(() => {
memberVisible = false
ElMessage({ message: '添加成功', type: 'success' })
appList?.refetch()
})
}
} }
// 删除人员 // 删除人员
const deleteProjectMember = function (row: any) { function handleDelete(row: ProjectMember, index: number) {
if (!prop?.isAdd) { if (isAdd) {
form.members.splice(index, 1)
} else {
deleteMember({ user_id: row.user_id, role_id: row.role_id, project_id: window.localStorage.projectId }).then(() => { deleteMember({ user_id: row.user_id, role_id: row.role_id, project_id: window.localStorage.projectId }).then(() => {
ElMessage({ ElMessage({ message: '删除成功', type: 'success' })
message: '删除成功', appList?.refetch()
type: 'success'
})
getProjectUser()
}) })
} else {
const index = userList.findIndex((item: any) => item.id === row.id)
userList.splice(index, 1)
}
}
// 新建时重构接口需要的数据
const data = function () {
if (!prop?.isUpdate) {
return JSON.stringify(
userList.reduce((a: any, b: any) => {
a.push({
user_id: b.id,
roles: b.role.reduce((roleA: any, roleB: any) => roleA.push(roleB.id) && roleA, []).toString()
})
return a
}, [])
)
} }
} }
// 详情
onMounted(() => {
if (prop?.isView || prop?.isUpdate) {
getProjectUser()
}
})
const getProjectUser = function () {
getProjectUserList({ id: route.params.id }).then((res: { data: { list: User[] } }) => {
userList = res.data.list
projectId.value = window.localStorage.projectId
})
}
defineExpose({
data
})
</script> </script>
<template> <template>
<el-card shadow="never" header="成员信息"> <el-card shadow="never" header="成员信息">
<AppList v-bind="listOptions" ref="appList"> <AppList v-bind="listOptions" ref="appList">
<template #header-buttons> <template #header-buttons>
<el-button v-if="prop?.isAdd" type="primary" @click="labelVisible = true">添加成员</el-button> <el-button type="primary" @click="memberVisible = true" v-if="hasAuth('project-member-create')">
添加成员
</el-button>
</template> </template>
<template #table-x="{ row }"> <template #table-x="{ row, $index }">
<el-button text type="primary" @click="deleteProjectMember(row)">删除</el-button> <el-button text type="primary" @click="handleDelete(row, $index)" v-if="hasAuth('project-member-delete')">
删除
</el-button>
</template> </template>
</AppList> </AppList>
</el-card> </el-card>
<AddMember v-model="labelVisible" @changeUser="changeUser"></AddMember> <AddMember v-model="memberVisible" @submit="handleSubmitMember" v-if="memberVisible"></AddMember>
</template> </template>
...@@ -16,11 +16,11 @@ const status = ref<State[]>([]) ...@@ -16,11 +16,11 @@ const status = ref<State[]>([])
const authProjectList = ref<Project[]>([]) const authProjectList = ref<Project[]>([])
const tags = ref<Record<string, string>>({}) const tags = ref<Record<string, string>>({})
export function useMap() { export async function useMap() {
const projectId = ref('') const projectId = ref('')
const prefix = ref('') const prefix = ref('')
function fetchInfo() { async function fetchInfo() {
getProjectMap().then((res: any) => { await getProjectMap().then((res: any) => {
const data = res.data const data = res.data
types.value = types.value =
data.project_type_map?.map((item: { id: number; name: string }) => ({ ...item, id: item.id.toString() })) || [] data.project_type_map?.map((item: { id: number; name: string }) => ({ ...item, id: item.id.toString() })) || []
...@@ -31,7 +31,7 @@ export function useMap() { ...@@ -31,7 +31,7 @@ export function useMap() {
tags.value = data.tags || {} tags.value = data.tags || {}
}) })
} }
if (!authProjectList.value.length) fetchInfo() if (!authProjectList.value.length) await fetchInfo()
// 当前项目 // 当前项目
const project = computed(() => { const project = computed(() => {
......
...@@ -7,14 +7,24 @@ export const routes: Array<RouteRecordRaw> = [ ...@@ -7,14 +7,24 @@ export const routes: Array<RouteRecordRaw> = [
component: AppLayout, component: AppLayout,
children: [ children: [
{ name: 'projectIndex', path: '', component: () => import('./views/Index.vue') }, { name: 'projectIndex', path: '', component: () => import('./views/Index.vue') },
{ name: 'projectCreate', path: 'create', component: () => import('./views/Update.vue'), props: { isAdd: true } }, {
name: 'projectCreate',
path: 'create',
component: () => import('./views/Update.vue'),
props: { action: 'add' }
},
{ {
name: 'projectUpdate', name: 'projectUpdate',
path: 'update/:id', path: 'update/:id',
component: () => import('./views/Update.vue'), component: () => import('./views/Update.vue'),
props: { isUpdate: true } props: route => ({ action: 'update', id: route.params.id })
}, },
{ name: 'projectView', path: 'view/:id', component: () => import('./views/Update.vue'), props: { isView: true } } {
name: 'projectView',
path: 'view/:id',
component: () => import('./views/Update.vue'),
props: route => ({ action: 'view', id: route.params.id })
}
] ]
} }
] ]
...@@ -26,6 +26,17 @@ export interface ProjectItem { ...@@ -26,6 +26,17 @@ export interface ProjectItem {
project_status_name: string project_status_name: string
} }
// 项目成员
export interface ProjectMember {
user_id: string
role_id: string
updated_time: string
name: string
mobile: string
email: string
role_name: string
}
// 用户信息 // 用户信息
export interface User { export interface User {
id: string id: string
...@@ -51,3 +62,16 @@ export interface RoleLevel { ...@@ -51,3 +62,16 @@ export interface RoleLevel {
level_tag: string level_tag: string
level_group_tag: string level_group_tag: string
} }
export interface ProjectRequestParams {
title: string
alias: string
project_type: string
project_status: string
project_uri: string
landing_page_uri: string
project_id: string
members?: string
}
export type ProjectFormData = Omit<ProjectRequestParams, 'members'> & { members: ProjectMember[] }
import type { InjectionKey } from 'vue'
import type { ProjectFormData } from './types'
export const provideForm = Symbol() as InjectionKey<ProjectFormData>
...@@ -4,11 +4,10 @@ import AppList from '@/components/base/AppList.vue' ...@@ -4,11 +4,10 @@ import AppList from '@/components/base/AppList.vue'
import { getProjectList, addMember, deleteProject } from '../api' import { getProjectList, addMember, deleteProject } from '../api'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { useMap } from '../composables/useMap' import { useMap } from '../composables/useMap'
const { types, status } = await useMap()
const AddMember = defineAsyncComponent(() => import('../components/AddMember.vue')) const AddMember = defineAsyncComponent(() => import('../components/AddMember.vue'))
const { types, status } = useMap()
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
const listOptions = $computed(() => { const listOptions = $computed(() => {
...@@ -79,7 +78,7 @@ let currentUser = $ref<{ user: User; role: Role[] }>() ...@@ -79,7 +78,7 @@ let currentUser = $ref<{ user: User; role: Role[] }>()
let memberRoleVisible = $ref(false) let memberRoleVisible = $ref(false)
let memberParams = $ref<{ user_id: string; projects_id: string; roles: string; type?: string }>() let memberParams = $ref<{ user_id: string; projects_id: string; roles: string; type?: string }>()
const changeMember = function (data: { user: User; role: Role[] }) { const handleSubmitMember = function (data: { user: User; role: Role[] }) {
currentUser = data currentUser = data
memberParams = { memberParams = {
user_id: data.user.id, user_id: data.user.id,
...@@ -92,6 +91,7 @@ const changeMember = function (data: { user: User; role: Role[] }) { ...@@ -92,6 +91,7 @@ const changeMember = function (data: { user: User; role: Role[] }) {
const addMemberRequest = function (type?: string) { const addMemberRequest = function (type?: string) {
const params = Object.assign({}, memberParams, { type }) const params = Object.assign({}, memberParams, { type })
addMember(params).then((res: any) => { addMember(params).then((res: any) => {
memberVisible = false
if (res.code === 0) { if (res.code === 0) {
ElMessage({ message: '添加成功', type: 'success' }) ElMessage({ message: '添加成功', type: 'success' })
} }
...@@ -131,16 +131,20 @@ const handleDelete = function (row: any) { ...@@ -131,16 +131,20 @@ const handleDelete = function (row: any) {
</template> </template>
<template #table-x="{ row }"> <template #table-x="{ row }">
<el-button text> <el-button text>
<router-link :to="{ name: 'projectView', params: { id: row.id } }">查看</router-link> <router-link :to="{ name: 'projectView', params: { id: row.id }, query: { project_id: row.project_id } }"
>查看</router-link
>
</el-button> </el-button>
<el-button text style="--el-button-text-color: #3276fc"> <el-button text style="--el-button-text-color: #3276fc">
<router-link :to="{ name: 'projectUpdate', params: { id: row.id } }">编辑</router-link> <router-link :to="{ name: 'projectUpdate', params: { id: row.id }, query: { project_id: row.project_id } }"
>编辑</router-link
>
</el-button> </el-button>
<el-button text style="--el-button-text-color: #00bfbf" @click="handleAddMember(row)">添加成员</el-button> <el-button text style="--el-button-text-color: #00bfbf" @click="handleAddMember(row)">添加成员</el-button>
<el-button text style="--el-button-text-color: #d9001b" @click="handleDelete(row)">删除</el-button> <el-button text style="--el-button-text-color: #d9001b" @click="handleDelete(row)">删除</el-button>
</template> </template>
</AppList> </AppList>
<AddMember @changeUser="changeMember" v-model="memberVisible"></AddMember> <AddMember v-model="memberVisible" @submit="handleSubmitMember" v-if="memberVisible"></AddMember>
</AppCard> </AppCard>
<el-dialog v-model="memberRoleVisible" title="提示" width="500px"> <el-dialog v-model="memberRoleVisible" title="提示" width="500px">
<el-form label-suffix=":"> <el-form label-suffix=":">
......
<script setup lang="ts"> <script setup lang="ts">
import type { ProjectRequestParams, ProjectFormData } from '../types'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import InfoBase from '../components/InfoBase.vue' import InfoBase from '../components/InfoBase.vue'
import InfoUsers from '../components/InfoUsers.vue' import InfoUsers from '../components/InfoUsers.vue'
import { createProject, updateProject } from '../api' import { createProject, updateProject, getProjectDetail } from '../api'
import { ElMessage } from 'element-plus' import { provideForm } from '../util'
import { useMap } from '../composables/useMap'
const router = useRouter() const { projectId, hasAuth } = await useMap()
const route = useRoute()
interface Props { interface Props {
isAdd?: boolean id?: string
isUpdate?: boolean action: string
isView?: boolean
} }
const props = defineProps<Props>() const props = withDefaults(defineProps<Props>(), { action: 'add', id: '' })
const router = useRouter()
const route = useRoute()
const title = $computed(() => { const title = $computed(() => {
return (props.isAdd && '创建项目') || (props.isUpdate && '编辑项目') || (props.isView && '查看项目') || '' if (props.action === 'update') return '编辑项目'
if (props.action === 'view') return '查看项目'
return '创建项目'
}) })
interface InfoBaseFrom { const formRef = $ref<FormInstance>()
form: { const form: ProjectFormData = reactive({
title: string title: '',
alias: string alias: '',
project_type: string project_type: '',
project_status: string project_status: '',
project_uri: string project_uri: '',
landing_page_uri: string landing_page_uri: '',
project_id: (route.query.project_id as string) || '',
site_uri: 'https://www.ezijing.com/',
members: []
})
provide(provideForm, form)
watchEffect(() => {
if (form.project_id) {
projectId.value = form.project_id
} }
submit: any })
// 获取基本信息
function fetchInfo() {
if (!props.id) return
getProjectDetail({ id: props.id }).then(res => {
Object.assign(form, res.data)
})
}
onMounted(() => {
if (props.action !== 'add') fetchInfo()
})
// 取消
function handleCancel() {
router.push('/base/project')
}
// 提交
function handleSubmit() {
formRef?.validate().then(() => {
const members = form.members.map(item => {
return { user_id: item.user_id, roles: item.role_id }
})
const params = { ...form, members: JSON.stringify(members) }
if (props.action === 'add') handleAdd(params)
if (props.action === 'update') handleUpdate(params)
})
}
// 添加
function handleAdd(params: ProjectRequestParams) {
createProject(params).then(() => {
ElMessage({ message: '创建成功', type: 'success' })
router.push('/base/project')
})
} }
const infoBase = $ref<InfoBaseFrom>() // 修改
const infoUsers = $ref<{ data: any }>() function handleUpdate(params: ProjectRequestParams) {
const onSubmit = function () { updateProject({ id: props.id, ...params }).then(() => {
infoBase.submit().then(() => { ElMessage({ message: '更新成功', type: 'success' })
const params = Object.assign(infoBase.form, { members: infoUsers.data() }) router.push('/base/project')
if (props.isAdd) {
createProject(params).then((res: any) => {
ElMessage({
message: '创建成功',
type: 'success'
})
router.go(-1)
})
} else {
updateProject(Object.assign(params, { id: route.params.id })).then((res: any) => {
ElMessage({
message: '更新成功',
type: 'success'
})
router.go(-1)
})
}
}) })
} }
</script> </script>
<template> <template>
<AppCard :title="title"> <AppCard :title="title">
<InfoBase v-bind="props" ref="infoBase" style="margin: 20px 0"></InfoBase> <el-form :model="form" label-width="100px" :disabled="action === 'view'" ref="formRef">
<InfoUsers v-bind="props" ref="infoUsers"></InfoUsers> <InfoBase style="margin: 20px 0"></InfoBase>
<el-button v-if="!props?.isView" @click="onSubmit" style="margin: 20px auto; display: block" type="primary" </el-form>
>提交</el-button <InfoUsers v-if="action !== 'update' && hasAuth('project-member')"></InfoUsers>
> <el-row justify="center" style="margin-top: 40px">
<template v-if="action === 'view'">
<el-button auto-insert-space @click="handleCancel">关闭</el-button>
</template>
<template v-else>
<el-button auto-insert-space @click="handleCancel">取消</el-button>
<el-button type="primary" auto-insert-space @click="handleSubmit">提交</el-button>
</template>
</el-row>
</AppCard> </AppCard>
</template> </template>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论