Skip to content

Commit 963062a

Browse files
authored
🎊 feat: create project form (#43)
1 parent e4c247f commit 963062a

File tree

11 files changed

+742
-10
lines changed

11 files changed

+742
-10
lines changed

.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ module.exports = {
8383
'vue/no-v-html': 'off',
8484
'vue/multi-word-component-names': 0,
8585
'vue/singleline-html-element-content-newline': 'off',
86+
'vue/multiline-html-element-content-newline': ['warn', {
87+
'allowEmptyLines': true
88+
}],
8689
'vue/require-default-prop': 'off',
8790
'vue/html-closing-bracket-spacing': 'error',
8891
'vue/no-unused-components': 1,

components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ declare module 'vue' {
5050
NSpace: typeof import('naive-ui')['NSpace']
5151
NSpin: typeof import('naive-ui')['NSpin']
5252
NSwitch: typeof import('naive-ui')['NSwitch']
53+
NText: typeof import('naive-ui')['NText']
5354
NThing: typeof import('naive-ui')['NThing']
5455
NTooltip: typeof import('naive-ui')['NTooltip']
5556
Octocat: typeof import('./src/components/Octocat.vue')['default']
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
<template>
2+
<n-form
3+
ref="refForm"
4+
:model="projectFormModel"
5+
label-placement="top"
6+
label-width="auto"
7+
>
8+
<n-list>
9+
<template #header>
10+
<div class="flex items-center">
11+
<n-icon
12+
class="mr-10px"
13+
size="18"
14+
:component="IconBookInformation24Regular"
15+
/>
16+
<span class="text-16px font-700">基本信息</span>
17+
</div>
18+
</template>
19+
<n-list-item>
20+
<n-form-item
21+
path="projectName"
22+
label="项目名称"
23+
:rule="getRequiredRules({
24+
trigger: 'change',
25+
message: '请输入项目名称'
26+
})"
27+
>
28+
<n-input
29+
v-model:value="projectFormModel.projectName"
30+
maxlength="100"
31+
show-count
32+
placeholder="请输入项目名称"
33+
/>
34+
</n-form-item>
35+
36+
<n-grid
37+
:x-gap="20"
38+
cols="2"
39+
item-responsive
40+
responsive="screen"
41+
>
42+
<n-form-item-gi
43+
v-for="(infoItem, index) in projectBasicMap"
44+
:key="index"
45+
:path="infoItem.path"
46+
:label="infoItem.label"
47+
:span="infoItem.span || `xs:2 s:2 m:1`"
48+
:rule="getRequiredRules({
49+
trigger: 'change',
50+
...infoItem.rule
51+
})"
52+
>
53+
<component
54+
:is="infoItem.render"
55+
v-if="infoItem.render"
56+
v-model:value="projectFormModel[infoItem.path]"
57+
class="flex-1"
58+
/>
59+
60+
<n-input
61+
v-else
62+
v-model:value="projectFormModel[infoItem.path]"
63+
/>
64+
</n-form-item-gi>
65+
</n-grid>
66+
</n-list-item>
67+
</n-list>
68+
69+
70+
<n-list>
71+
<template #header>
72+
<div class="flex items-center">
73+
<n-icon
74+
class="mr-10px"
75+
size="18"
76+
:component="IconTeamOutlined"
77+
/>
78+
<span class="text-16px font-700">成员分配</span>
79+
</div>
80+
</template>
81+
<n-list-item>
82+
<n-button @click="handleSelectMembers()">选择成员</n-button>
83+
<!-- <n-form-item
84+
path="memberList"
85+
>
86+
<n-input
87+
v-model:value="projectFormModel.memberList"
88+
/>
89+
</n-form-item> -->
90+
</n-list-item>
91+
</n-list>
92+
</n-form>
93+
<pre>{{ JSON.stringify(projectFormModel, null, 2) }}</pre>
94+
95+
</template>
96+
97+
98+
<script lang="ts" setup>
99+
import {
100+
NSelect,
101+
NInput,
102+
NDatePicker
103+
} from 'naive-ui'
104+
import {
105+
BookInformation24Regular as IconBookInformation24Regular
106+
} from '@vicons/fluent'
107+
import {
108+
TeamOutlined as IconTeamOutlined
109+
} from '@vicons/antd'
110+
111+
import type { TypesHomeFront } from '@/modules/HomeFront/types'
112+
import {
113+
DepartmentBranchMap,
114+
ProjectLevelMap
115+
} from '@/modules/HomeFront/data'
116+
117+
import MemberAssignCard from '@/modules/MemberTeam/components/MemberAssignCard.vue'
118+
119+
defineOptions({
120+
name: 'CreateProjectForm'
121+
})
122+
123+
124+
125+
const projectFormModel = ref<TypesHomeFront.TypeCreateProjectInfo>({
126+
projectName: '',
127+
projectBranch: null,
128+
projectLevel: null,
129+
projectDesc: '',
130+
startDate: null,
131+
endDate: null,
132+
memberList: ''
133+
})
134+
135+
136+
const projectBasicMap = shallowRef([
137+
{
138+
path: 'projectBranch',
139+
label: '项目分部',
140+
rule: {
141+
message: '请选择'
142+
},
143+
render: () => h(
144+
NSelect,
145+
{
146+
placeholder: '请选择所属分部',
147+
options: DepartmentBranchMap,
148+
value: projectFormModel.value.projectBranch,
149+
onUpdateValue (v) {
150+
projectFormModel.value.projectBranch = v
151+
}
152+
}
153+
)
154+
},
155+
{
156+
path: 'projectLevel',
157+
label: '项目等级',
158+
rule: {
159+
message: '请选择'
160+
},
161+
render: () => h(
162+
NSelect,
163+
{
164+
placeholder: '请选择项目等级',
165+
options: ProjectLevelMap,
166+
value: projectFormModel.value.projectLevel,
167+
onUpdateValue (v) {
168+
projectFormModel.value.projectLevel = v
169+
}
170+
}
171+
)
172+
},
173+
{
174+
path: 'startDate',
175+
label: '开始日期',
176+
rule: {
177+
message: '请选择'
178+
},
179+
render: () => h(
180+
NDatePicker,
181+
{
182+
placeholder: '请选择项目开始日期',
183+
valueFormat: 'yyyy.MM.dd',
184+
type: 'date',
185+
formattedValue: projectFormModel.value.startDate,
186+
onUpdateFormattedValue (v) {
187+
projectFormModel.value.startDate = v
188+
}
189+
}
190+
)
191+
},
192+
{
193+
path: 'endDate',
194+
label: '结束日期',
195+
rule: {
196+
message: '请选择'
197+
},
198+
render: () => h(
199+
NDatePicker,
200+
{
201+
placeholder: '请选择项目结束日期',
202+
valueFormat: 'yyyy.MM.dd',
203+
type: 'date',
204+
formattedValue: projectFormModel.value.endDate,
205+
isDateDisabled(ts: number) {
206+
if (!projectFormModel.value.startDate) {
207+
return false
208+
}
209+
return ts < Date.parse(projectFormModel.value.startDate)
210+
},
211+
onUpdateFormattedValue (v) {
212+
projectFormModel.value.endDate = v
213+
}
214+
}
215+
)
216+
},
217+
{
218+
path: 'projectDesc',
219+
label: '项目概括',
220+
span: 'xs:2 s:2 m:2',
221+
render: () => h(
222+
NInput,
223+
{
224+
placeholder: '请简要描述一下项目基本情况',
225+
type: 'textarea',
226+
autosize: {
227+
minRows: 2,
228+
maxRows: 4
229+
},
230+
maxlength: '200',
231+
showCount: true,
232+
value: projectFormModel.value.projectDesc,
233+
onUpdateValue (v) {
234+
projectFormModel.value.projectDesc = v
235+
}
236+
}
237+
)
238+
}
239+
])
240+
241+
const handleSelectMembers = () => {
242+
const dd = window.$ModalDialog.create({
243+
title: '选择成员',
244+
style: {
245+
maxWidth: '650px',
246+
width: '70%'
247+
},
248+
maskClosable: false,
249+
closeOnEsc: false,
250+
content: () => h(
251+
MemberAssignCard
252+
),
253+
positiveText: '确定',
254+
async onPositiveClick() {
255+
// const isValid = await instanceRef.value.validateRules()
256+
// if (!isValid) {
257+
// return Promise.reject()
258+
// }
259+
260+
// dd.loading = true
261+
// dd.positiveText = '提交中..'
262+
// await sleep(1000)
263+
264+
// dd.positiveText = _positiveText
265+
// dd.loading = false
266+
return Promise.reject()
267+
}
268+
})
269+
}
270+
271+
const refForm = ref<FormInst>()
272+
const validateRules = async () => {
273+
return new Promise((resolve) => {
274+
refForm.value!.validate(errors => {
275+
if (errors) {
276+
resolve(false)
277+
} else {
278+
resolve(true)
279+
}
280+
})
281+
})
282+
}
283+
284+
defineExpose({
285+
validateRules
286+
})
287+
288+
</script>
289+
290+
<style lang="scss" scoped>
291+
292+
</style>

src/modules/HomeFront/data/index.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,80 @@ export const mockHomeProjectList = Array.from({ length: 50 }).map((item, index)
1515
return {
1616
id: '' + id,
1717
project_code: 'ACBD' + id,
18-
project_name: '项目' + id,
18+
projectName: '项目' + id,
1919
status: '进行中',
2020
create_time: '2023-06-14 12:00',
2121
create_by: '李华'
2222
}
2323
})
24+
25+
26+
/**
27+
* 项目所属分部
28+
*/
29+
export const DepartmentBranchMap = [
30+
{
31+
value: '北京总部',
32+
label: '北京总部'
33+
},
34+
{
35+
value: '上海分部',
36+
label: '上海分部'
37+
},
38+
{
39+
value: '广州分部',
40+
label: '广州分部'
41+
},
42+
{
43+
value: '深圳分部',
44+
label: '深圳分部'
45+
},
46+
{
47+
value: '成都分部',
48+
label: '成都分部'
49+
},
50+
{
51+
value: '西安分部',
52+
label: '西安分部'
53+
},
54+
{
55+
value: '天津分部',
56+
label: '天津分部'
57+
},
58+
{
59+
value: '青岛分部',
60+
label: '青岛分部'
61+
},
62+
{
63+
value: '杭州分部',
64+
label: '杭州分部'
65+
},
66+
{
67+
value: '重庆分部',
68+
label: '重庆分部'
69+
}
70+
]
71+
72+
73+
74+
/**
75+
* 项目所属等级
76+
*/
77+
export const ProjectLevelMap = [
78+
{
79+
value: 'A',
80+
label: 'A'
81+
},
82+
{
83+
value: 'B',
84+
label: 'B'
85+
},
86+
{
87+
value: 'C',
88+
label: 'C'
89+
},
90+
{
91+
value: 'D',
92+
label: 'D'
93+
}
94+
]

0 commit comments

Comments
 (0)