Skip to content

Commit bbb1aaa

Browse files
committed
Merge branch 'main' into fix/default_passive
2 parents 5ca0e84 + 0d9b508 commit bbb1aaa

6 files changed

Lines changed: 286 additions & 7 deletions

File tree

.github/workflows/main.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
name: Deploy via SSH
22

33
on:
4-
push:
5-
branches:
6-
- main # 或者改为你的主分支名称
4+
# push:
5+
# branches:
6+
# - main # 或者改为你的主分支名称
77
workflow_dispatch: # 允许手动触发
88

99
jobs:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ dist-ssr
2222
*.njsproj
2323
*.sln
2424
*.sw?
25+
CLAUDE.md
26+
dist.zip

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# 联创团队SSO系统-前端
2-
2+
hr2024.hustunique.com
33
## 🚀技术栈
44

55
```
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
<template>
2+
<a-modal
3+
v-model:visible="visible"
4+
:title="$t('common.operation.updateRecruitment')"
5+
:on-before-ok="sendForm"
6+
draggable
7+
>
8+
<a-space direction="vertical" size="mini">
9+
<a-form ref="recruitmentForm" :model="formData" layout="vertical">
10+
<a-form-item field="select_recruitment" label="选择招新">
11+
<a-select
12+
v-model="selectedRid"
13+
placeholder="请选择要修改的招新"
14+
@change="onRecruitmentChange"
15+
>
16+
<a-option
17+
v-for="rec in recruitmentStore.data"
18+
:key="rec.uid"
19+
:value="rec.uid"
20+
:label="rec.name"
21+
>
22+
{{ rec.name }}
23+
</a-option>
24+
</a-select>
25+
</a-form-item>
26+
27+
<a-form-item field="rec_name" :label="$t('common.createRec.recName')">
28+
<a-input
29+
v-model="formData.name"
30+
:placeholder="$t('common.createRec.inputRecName')"
31+
/>
32+
</a-form-item>
33+
34+
<a-form-item
35+
field="rec_time_range"
36+
:label="$t('common.createRec.recTimeRange')"
37+
>
38+
<a-range-picker
39+
v-model="timeRange1"
40+
show-time
41+
:time-picker-props="{ defaultValue: ['00:00:00', '00:00:00'] }"
42+
format="YYYY-MM-DD HH:mm"
43+
@ok="onOk1"
44+
/>
45+
</a-form-item>
46+
47+
<a-form-item field="deadline" label="报名结束时间">
48+
<a-date-picker
49+
v-model="deadline"
50+
show-time
51+
:time-picker-props="{ defaultValue: '00:00:00' }"
52+
format="YYYY-MM-DD HH:mm"
53+
@ok="onDeadlineChange"
54+
/>
55+
</a-form-item>
56+
</a-form>
57+
</a-space>
58+
</a-modal>
59+
</template>
60+
61+
<script setup lang="ts">
62+
import { ref, watch } from 'vue';
63+
import { Message } from '@arco-design/web-vue';
64+
import { useI18n } from 'vue-i18n';
65+
import useRecruitmentStore from '@/store/modules/recruitment';
66+
import type { UpdateParams } from '@/store/modules/recruitment/types';
67+
68+
const { t } = useI18n();
69+
const recruitmentStore = useRecruitmentStore();
70+
71+
const visible = defineModel<boolean>('visible', {
72+
type: Boolean,
73+
default: false,
74+
required: true,
75+
});
76+
77+
const selectedRid = ref<string>('');
78+
79+
const formData = ref<{
80+
name?: string;
81+
beginning?: string;
82+
deadline?: string;
83+
end?: string;
84+
}>({
85+
name: '',
86+
beginning: '',
87+
deadline: '',
88+
end: '',
89+
});
90+
91+
const emit = defineEmits<{
92+
(e: 'recruitmentUpdated'): void;
93+
}>();
94+
95+
const timeRange1 = ref<string[]>([]);
96+
const deadline = ref<string>('');
97+
98+
// 当选择招新时,填充表单数据
99+
const onRecruitmentChange = (rid: string) => {
100+
const recruitment = recruitmentStore.data.find((rec) => rec.uid === rid);
101+
if (recruitment) {
102+
formData.value = {
103+
name: recruitment.name || '',
104+
beginning: recruitment.beginning || '',
105+
deadline: recruitment.deadline || '',
106+
end: recruitment.end || '',
107+
};
108+
109+
// 填充时间选择器(转换为本地时间)
110+
if (recruitment.beginning && recruitment.end) {
111+
timeRange1.value = [
112+
new Date(recruitment.beginning).toLocaleString().replace(' ', ' '),
113+
new Date(recruitment.end).toLocaleString().replace(' ', ' '),
114+
];
115+
} else {
116+
timeRange1.value = [];
117+
}
118+
119+
// 填充报名结束时间(转换为本地时间)
120+
if (recruitment.deadline) {
121+
deadline.value = new Date(recruitment.deadline)
122+
.toLocaleString()
123+
.replace(' ', ' ');
124+
} else {
125+
deadline.value = '';
126+
}
127+
128+
console.log('timeRange1.value:', timeRange1.value);
129+
console.log('deadline.value:', deadline.value);
130+
}
131+
};
132+
133+
// 当 modal 打开时,清空表单
134+
watch(
135+
() => visible.value,
136+
(newValue) => {
137+
if (!newValue) {
138+
// modal 关闭时,清空表单
139+
selectedRid.value = '';
140+
formData.value = {
141+
name: '',
142+
beginning: '',
143+
deadline: '',
144+
end: '',
145+
};
146+
timeRange1.value = [];
147+
deadline.value = '';
148+
}
149+
},
150+
);
151+
152+
const formatName = (name: string) => {
153+
let normalizedName = name.trim();
154+
if (normalizedName.includes('')) {
155+
normalizedName = normalizedName.replace(/.*/, 'S');
156+
} else if (normalizedName.includes('')) {
157+
normalizedName = normalizedName.replace(/.*/, 'C');
158+
} else if (normalizedName.includes('')) {
159+
normalizedName = normalizedName.replace(/.*/, 'A');
160+
}
161+
return normalizedName;
162+
};
163+
164+
const formValidate = () => {
165+
const errors: { [key: string]: string } = {};
166+
const originalName = formData.value.name;
167+
168+
// 名称验证(如果提供了名称)
169+
if (originalName) {
170+
const formattedName = formatName(originalName);
171+
const nameRegex = /^\d{4}[SAC]$/;
172+
if (!nameRegex.test(formattedName)) {
173+
errors.name = t('common.createRec.nameFormat');
174+
} else {
175+
formData.value.name = formattedName;
176+
}
177+
}
178+
179+
// 时间范围验证
180+
if (formData.value.beginning && formData.value.end) {
181+
const beginningTime = new Date(formData.value.beginning).getTime();
182+
const endTime = new Date(formData.value.end).getTime();
183+
184+
if (beginningTime >= endTime) {
185+
errors.rec_time_range = '招新开始时间必须早于结束时间';
186+
}
187+
}
188+
189+
if (formData.value.deadline && formData.value.end) {
190+
const endTime = new Date(formData.value.end).getTime();
191+
const deadlineTime = new Date(formData.value.deadline).getTime();
192+
193+
if (deadlineTime >= endTime) {
194+
errors.signup_time_range = t(
195+
'common.createRec.signupEndTimeBeforeRecEndTime',
196+
);
197+
}
198+
}
199+
200+
if (Object.keys(errors).length > 0) {
201+
Message.error(Object.values(errors).join('; '));
202+
return false;
203+
}
204+
205+
return true;
206+
};
207+
208+
const sendForm = async () => {
209+
try {
210+
// 检查是否选择了招新
211+
if (!selectedRid.value) {
212+
Message.error('请先选择要修改的招新');
213+
return false;
214+
}
215+
216+
const isValid = formValidate();
217+
if (!isValid) {
218+
return false;
219+
}
220+
221+
// 只发送有值的字段
222+
const updateData: UpdateParams = {};
223+
if (formData.value.name) {
224+
updateData.name = formData.value.name;
225+
}
226+
if (formData.value.beginning) {
227+
updateData.beginning = formData.value.beginning;
228+
}
229+
if (formData.value.deadline) {
230+
updateData.deadline = formData.value.deadline;
231+
}
232+
if (formData.value.end) {
233+
updateData.end = formData.value.end;
234+
}
235+
236+
// 如果没有任何更新,提示用户
237+
if (Object.keys(updateData).length === 0) {
238+
Message.warning('没有任何修改');
239+
return false;
240+
}
241+
242+
await recruitmentStore.updateRecruitment(selectedRid.value, updateData);
243+
Message.success('招新更新成功');
244+
emit('recruitmentUpdated');
245+
return true;
246+
} catch (error) {
247+
Message.error((error as any).message || '更新失败');
248+
return false;
249+
}
250+
};
251+
252+
const onOk1 = (dateString: string[], _date: any) => {
253+
formData.value.beginning = new Date(dateString[0]).toISOString();
254+
formData.value.end = new Date(dateString[1]).toISOString();
255+
};
256+
257+
const onDeadlineChange = (dateString: string, _date: any) => {
258+
formData.value.deadline = new Date(dateString).toISOString();
259+
};
260+
</script>

src/components/navbar/index.vue

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,24 @@
2929
<a-button
3030
type="text"
3131
class="w-32 text-base font-normal"
32-
@click="visible = true"
32+
@click="showCreateModel = true"
3333
>
3434
<IconPlus class="mr-2" />{{
3535
$t(`common.operation.createRecruitment`)
3636
}}
3737
</a-button>
3838
</div>
39+
<div class="py-1 text-center">
40+
<a-button
41+
type="text"
42+
class="w-32 text-base font-normal"
43+
@click="showUpdateModel = true"
44+
>
45+
<IconSettings class="mr-2" />{{
46+
$t(`common.operation.updateRecruitment`)
47+
}}
48+
</a-button>
49+
</div>
3950
</template>
4051
</a-select>
4152
</li>
@@ -123,14 +134,18 @@
123134

124135
<!--发起招新的模态框-->
125136
<create-newrec-modal
126-
v-model:visible="visible"
137+
v-model:visible="showCreateModel"
127138
@recruitment-created="handleRecruitmentCreated"
128139
/>
140+
141+
<!--更新招新的模态框-->
142+
<update-rec-modal v-model:visible="showUpdateModel" />
129143
</div>
130144
</template>
131145

132146
<script setup lang="ts">
133147
import CreateNewrecModal from '@/components/navbar/components/create-newrec-modal.vue';
148+
import UpdateRecModal from '@/components/navbar/components/update-rec-modal.vue';
134149
import LogoSVG from '@/assets/svg/logo.svg';
135150
import useRecruitmentStore from '@/store/modules/recruitment';
136151
import useUserStore from '@/store/modules/user';
@@ -175,7 +190,8 @@ const changeDayNight = () => {
175190
}
176191
};
177192
178-
const visible = ref(false);
193+
const showCreateModel = ref(false);
194+
const showUpdateModel = ref(false);
179195
const isMenuVisible = ref(false);
180196
181197
const handleVisibleChange = (menuVisible: boolean) => {

src/locale/zh-CN/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export default {
3434
'common.operation.allocateTime': '分配时间',
3535
'common.operation.candidateSeletedTime': '选手已选',
3636
'common.operation.createRecruitment': '发起招新',
37+
'common.operation.updateRecruitment': '更新招新',
3738
'common.operation.noRecruitments': '没有招新记录',
3839
'common.operation.selectRecruitment': '选择招新',
3940
'common.operation.userSetting': '用户设置',

0 commit comments

Comments
 (0)