Merge branch 'main' of http://113.45.157.195:3003/insiinc/leader-mail
This commit is contained in:
commit
9abc34c031
|
@ -26,7 +26,6 @@ export class PostService extends BaseService<Prisma.PostDelegate> {
|
|||
}
|
||||
onModuleInit() {
|
||||
EventBus.on('updatePostState', ({ id }) => {
|
||||
console.log('updatePostState');
|
||||
updatePostState(id);
|
||||
});
|
||||
}
|
||||
|
@ -34,7 +33,6 @@ export class PostService extends BaseService<Prisma.PostDelegate> {
|
|||
args: Prisma.PostCreateArgs,
|
||||
params: { staff?: UserProfile; tx?: Prisma.PostDelegate },
|
||||
) {
|
||||
console.log('params?.staff?.id', params?.staff?.id);
|
||||
args.data.authorId = params?.staff?.id;
|
||||
args.data.updatedAt = new Date();
|
||||
// args.data.resources
|
||||
|
|
|
@ -10,7 +10,6 @@ export class VisitService extends BaseService<Prisma.VisitDelegate> {
|
|||
async create(args: Prisma.VisitCreateArgs, staff?: UserProfile) {
|
||||
const { postId, messageId } = args.data;
|
||||
const clientIp = (args.data.meta as any)?.ip;
|
||||
console.log('visit create');
|
||||
const visitorId = args.data.visitorId || staff?.id;
|
||||
let result;
|
||||
const existingVisit = await db.visit.findFirst({
|
||||
|
|
|
@ -15,13 +15,11 @@ export class PostQueueService implements OnModuleInit {
|
|||
constructor(@InjectQueue('general') private generalQueue: Queue) {}
|
||||
onModuleInit() {
|
||||
EventBus.on('updateVisitCount', ({ id, objectType, visitType }) => {
|
||||
console.log('updateVisitCount');
|
||||
if (objectType === ObjectType.POST) {
|
||||
this.addUpdateVisitCountJob({ id, type: visitType });
|
||||
}
|
||||
});
|
||||
EventBus.on('updatePostState', ({ id }) => {
|
||||
console.log('updatePostState');
|
||||
this.addUpdatePostState({ id });
|
||||
});
|
||||
}
|
||||
|
|
|
@ -88,7 +88,6 @@ export class TusService implements OnModuleInit {
|
|||
upload: Upload,
|
||||
) {
|
||||
try {
|
||||
console.log('upload.id', upload.id);
|
||||
const resource = await this.resourceService.update({
|
||||
where: { fileId: this.getFileId(upload.id) },
|
||||
data: { status: ResourceStatus.UPLOADED },
|
||||
|
|
|
@ -43,6 +43,11 @@ export const RegisterForm = ({ onSubmit, isLoading }: RegisterFormProps) => {
|
|||
<AvatarUploader
|
||||
className="rounded-lg"
|
||||
placeholder="点击上传头像"
|
||||
onChange={(url) => {
|
||||
if (url) {
|
||||
console.log(url);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
width: `100%`,
|
||||
height: 210,
|
||||
|
@ -123,7 +128,7 @@ export const RegisterForm = ({ onSubmit, isLoading }: RegisterFormProps) => {
|
|||
</Form.Item>
|
||||
<Form.Item noStyle name={"office"}>
|
||||
<Input
|
||||
placeholder="请输入办公室地点"
|
||||
placeholder="请输入办公地点"
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
allowClear
|
||||
|
@ -151,10 +156,10 @@ export const RegisterForm = ({ onSubmit, isLoading }: RegisterFormProps) => {
|
|||
noStyle
|
||||
rules={[
|
||||
{ message: "请输入证件号" },
|
||||
{
|
||||
pattern: /^\d{5,12}$/,
|
||||
message: "请输入有效的证件号(5-12位数字)",
|
||||
},
|
||||
// {
|
||||
// pattern: /^\d{5,12}$/,
|
||||
// message: "请输入有效的证件号(5-12位数字)",
|
||||
// },
|
||||
]}>
|
||||
<Input placeholder="证件号" />
|
||||
</Form.Item>
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import PostDetail from "@web/src/components/models/post/detail/PostDetail";
|
||||
import { useEffect } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
export default function LetterDetailPage() {
|
||||
const { id } = useParams();
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return <div className="shadow-elegant border-2 border-white rounded-xl bg-slate-200">
|
||||
|
||||
<PostDetail id={id}></PostDetail>
|
||||
</div>;
|
||||
return (
|
||||
<div className="shadow-elegant border-2 border-white rounded-xl bg-slate-200">
|
||||
<PostDetail id={id}></PostDetail>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,3 +10,16 @@ export const defaultModules = {
|
|||
["clean"],
|
||||
],
|
||||
};
|
||||
|
||||
// 如果需要自定义 tooltip
|
||||
const customTooltip = {
|
||||
header: {
|
||||
1: "标题 1",
|
||||
2: "标题 2",
|
||||
3: "标题 3",
|
||||
4: "标题 4",
|
||||
5: "标题 5",
|
||||
6: "标题 6",
|
||||
false: "正文",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -36,6 +36,8 @@ const AvatarUploader: React.FC<AvatarUploaderProps> = ({
|
|||
const [file, setFile] = useState<UploadingFile | null>(null);
|
||||
const avatarRef = useRef<HTMLImageElement>(null);
|
||||
const [previewUrl, setPreviewUrl] = useState<string>(value || "");
|
||||
|
||||
const [compressedUrl, setCompressedUrl] = useState<string>(value || "");
|
||||
const [url, setUrl] = useState<string>(value || "");
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
@ -46,7 +48,9 @@ const AvatarUploader: React.FC<AvatarUploaderProps> = ({
|
|||
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const selectedFile = event.target.files?.[0];
|
||||
if (!selectedFile) return;
|
||||
|
||||
// Create an object URL for the selected file
|
||||
const objectUrl = URL.createObjectURL(selectedFile);
|
||||
setPreviewUrl(objectUrl);
|
||||
setFile({
|
||||
name: selectedFile.name,
|
||||
progress: 0,
|
||||
|
@ -70,7 +74,7 @@ const AvatarUploader: React.FC<AvatarUploaderProps> = ({
|
|||
}));
|
||||
|
||||
setUrl(result.url);
|
||||
setPreviewUrl(result.compressedUrl);
|
||||
setCompressedUrl(result.compressedUrl);
|
||||
// 直接使用 result 中的最新值
|
||||
resolve(compressed ? result.compressedUrl : result.url);
|
||||
},
|
||||
|
@ -80,6 +84,9 @@ const AvatarUploader: React.FC<AvatarUploaderProps> = ({
|
|||
file?.fileKey
|
||||
);
|
||||
});
|
||||
// await new Promise((resolve) => setTimeout(resolve,4999)); // 方法1:使用 await 暂停执行
|
||||
// 使用 resolved 的最新值调用 onChange
|
||||
// 强制刷新 Avatar 组件
|
||||
setAvatarKey((prev) => prev + 1); // 修改 key 强制重新挂载
|
||||
onChange?.(uploadedUrl);
|
||||
console.log(uploadedUrl)
|
||||
|
|
|
@ -47,7 +47,6 @@ export default function StaffForm() {
|
|||
rank,
|
||||
office,
|
||||
} = values;
|
||||
console.log("photoUrl", photoUrl);
|
||||
setFormLoading(true);
|
||||
try {
|
||||
if (data && user?.id) {
|
||||
|
@ -185,13 +184,13 @@ export default function StaffForm() {
|
|||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
rules={[
|
||||
{
|
||||
required: false,
|
||||
pattern: /^\d{5,18}$/,
|
||||
message: "请输入正确的证件号(数字)",
|
||||
},
|
||||
]}
|
||||
// rules={[
|
||||
// {
|
||||
// required: false,
|
||||
// pattern: /^\d{5,18}$/,
|
||||
// message: "请输入正确的证件号(数字)",
|
||||
// },
|
||||
// ]}
|
||||
noStyle
|
||||
name={"officerId"}>
|
||||
<Input
|
||||
|
@ -229,7 +228,7 @@ export default function StaffForm() {
|
|||
</Form.Item>
|
||||
<Form.Item noStyle name={"office"}>
|
||||
<Input
|
||||
placeholder="请输入办公室地点(可选)"
|
||||
placeholder="请输入办公地点(可选)"
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
allowClear
|
||||
|
|
|
@ -48,6 +48,7 @@ export default function PostCommentEditor() {
|
|||
toast.success("发布成功!");
|
||||
setContent("");
|
||||
setFileIds([]); // 重置上传组件状态
|
||||
setSignature("");
|
||||
setUploaderKey(uploaderKey + 1);
|
||||
} catch (error) {
|
||||
toast.error("发布失败,请稍后重试");
|
||||
|
@ -91,7 +92,6 @@ export default function PostCommentEditor() {
|
|||
key={uploaderKey}
|
||||
value={fileIds}
|
||||
onChange={(value) => {
|
||||
console.log("ids", value);
|
||||
setFileIds(value);
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -45,6 +45,7 @@ export function LetterFormProvider({
|
|||
|
||||
const onSubmit = async (data: LetterFormData) => {
|
||||
try {
|
||||
console.log(data);
|
||||
const receivers = data?.receivers;
|
||||
const terms = data?.terms;
|
||||
delete data.receivers;
|
||||
|
@ -78,14 +79,14 @@ export function LetterFormProvider({
|
|||
: undefined,
|
||||
},
|
||||
});
|
||||
const formattedDateTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
||||
const formattedDateTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
// 创建包含信件编号和提交时间的文本
|
||||
const fileContent = `信件编号: ${result.id}\n投递时间: ${formattedDateTime}`;
|
||||
// 创建包含信件编号和提交时间的Blob对象
|
||||
const blob = new Blob([fileContent], { type: 'text/plain' });
|
||||
const blob = new Blob([fileContent], { type: "text/plain" });
|
||||
// 创建下载链接
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
link.download = `信件编号-${result.id}.txt`; // 设置下载文件名
|
||||
document.body.appendChild(link);
|
||||
|
@ -93,10 +94,16 @@ export function LetterFormProvider({
|
|||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
|
||||
toast.success(`信件投递成功!信件编号已保存到本地,请妥善保管用于进度查询`, {
|
||||
duration: 5000 // 10秒
|
||||
});
|
||||
navigate(`/${result.id}/detail`, { replace: true });
|
||||
toast.success(
|
||||
`信件投递成功!信件编号已保存到本地,请妥善保管用于进度查询`,
|
||||
{
|
||||
duration: 5000, // 10秒
|
||||
}
|
||||
);
|
||||
// navigate(`/${result.id}/detail`, {
|
||||
// replace: true,
|
||||
// state: { scrollToTop: true },
|
||||
// });
|
||||
form.resetFields();
|
||||
} catch (error) {
|
||||
console.error("Error submitting form:", error);
|
||||
|
|
|
@ -6,12 +6,39 @@ import { TusUploader } from "@web/src/components/common/uploader/TusUploader";
|
|||
import StaffSelect from "../../../staff/staff-select";
|
||||
import TermSelect from "../../../term/term-select";
|
||||
import TabPane from "antd/es/tabs/TabPane";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
export function LetterBasicForm() {
|
||||
const { onSubmit, receiverId, termId, form } = useLetterEditor();
|
||||
const handleFinish = async (values: any) => {
|
||||
await onSubmit(values);
|
||||
};
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await form.validateFields();
|
||||
form.submit();
|
||||
// toast.success("提交成功!");
|
||||
} catch (error) {
|
||||
// 提取所有错误信息
|
||||
const errorMessages = (error as any).errorFields
|
||||
.map((field) => field.errors[0])
|
||||
.filter(Boolean);
|
||||
|
||||
// 显示 toast 错误提示
|
||||
toast.error(
|
||||
<div className="flex flex-col gap-1">
|
||||
<b>表单校验失败:</b>
|
||||
{errorMessages.map((msg, i) => (
|
||||
<span key={i}>· {msg}</span>
|
||||
))}
|
||||
</div>,
|
||||
{
|
||||
duration: 5000, // 显示 5 秒
|
||||
position: "top-center",
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className=" p-6 ">
|
||||
<Form
|
||||
|
@ -63,13 +90,15 @@ export function LetterBasicForm() {
|
|||
<TabPane tab="正文" key="1">
|
||||
<Form.Item
|
||||
name="content"
|
||||
rules={[{ required: true, message: "请输入内容" }]}
|
||||
rules={[
|
||||
{ required: true, message: "请输入正文内容" },
|
||||
]}
|
||||
required={false}>
|
||||
<div className="rounded-xl border border-white hover:ring-1 ring-white transition-all duration-300 ease-in-out bg-slate-100">
|
||||
<QuillEditor
|
||||
maxLength={10000}
|
||||
placeholder="请输入内容"
|
||||
minRows={16}
|
||||
minRows={6}
|
||||
onChange={(content) =>
|
||||
form.setFieldValue("content", content)
|
||||
}
|
||||
|
@ -78,22 +107,30 @@ export function LetterBasicForm() {
|
|||
</Form.Item>
|
||||
</TabPane>
|
||||
<TabPane tab="附件" key="2">
|
||||
<Form.Item name="resources" required={false}>
|
||||
<div className="rounded-xl border border-white hover:ring-1 ring-white transition-all duration-300 ease-in-out bg-slate-100">
|
||||
<div className="rounded-xl border border-white hover:ring-1 ring-white transition-all duration-300 ease-in-out bg-slate-100">
|
||||
<Form.Item name="resources" required={false}>
|
||||
<TusUploader
|
||||
onChange={async (resources) => {
|
||||
// console.log(resources);
|
||||
form.setFieldValue(
|
||||
"resources",
|
||||
resources
|
||||
);
|
||||
// console.log(
|
||||
// form.getFieldValue("resources")
|
||||
// );
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
{/* <Button
|
||||
onClick={() => {
|
||||
console.log(form.getFieldValue("resources"));
|
||||
}}></Button> */}
|
||||
{/* Footer Actions */}
|
||||
<div className="flex flex-col-reverse sm:flex-row items-center justify-between gap-4 ">
|
||||
<div className="flex flex-col-reverse sm:flex-row items-center justify-between gap-4 mt-2 ">
|
||||
<Form.Item name="isPublic" valuePropName="checked">
|
||||
<Checkbox className="text-gray-600 hover:text-gray-900 transition-colors text-sm">
|
||||
是否公开
|
||||
|
@ -112,7 +149,7 @@ export function LetterBasicForm() {
|
|||
</Form.Item>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => form.submit()}
|
||||
onClick={handleSubmit}
|
||||
size="large"
|
||||
icon={<SendOutlined />}
|
||||
className="w-full sm:w-40">
|
||||
|
|
|
@ -204,13 +204,15 @@ export default function StaffForm() {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
noStyle
|
||||
rules={[
|
||||
{
|
||||
required: false,
|
||||
pattern: /^\d{5,18}$/,
|
||||
message: "请输入正确的证件号(数字)",
|
||||
},
|
||||
]}
|
||||
rules={
|
||||
[
|
||||
// {
|
||||
// required: false,
|
||||
// pattern: /^\d{5,18}$/,
|
||||
// message: "请输入正确的证件号(数字)",
|
||||
// },
|
||||
]
|
||||
}
|
||||
name={"officerId"}
|
||||
label="证件号">
|
||||
<Input
|
||||
|
@ -248,7 +250,7 @@ export default function StaffForm() {
|
|||
</Form.Item>
|
||||
<Form.Item noStyle name={"office"}>
|
||||
<Input
|
||||
placeholder="请输入办公室地点(可选)"
|
||||
placeholder="请输入办公地点(可选)"
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
allowClear
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
border: none;
|
||||
@apply text-base
|
||||
@apply text-base;
|
||||
}
|
||||
|
||||
.ag-custom-dragging-class {
|
||||
|
@ -41,8 +41,6 @@
|
|||
/* 垂直居中 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 滚动条轨道 */
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 10px;
|
||||
|
@ -69,7 +67,9 @@
|
|||
}
|
||||
|
||||
/* 覆盖 Ant Design 的默认样式 raido button左侧的按钮*/
|
||||
.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)::before {
|
||||
.ant-radio-button-wrapper-checked:not(
|
||||
.ant-radio-button-wrapper-disabled
|
||||
)::before {
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,38 @@
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
.no-wrap-header .ant-table-thead>tr>th {
|
||||
.no-wrap-header .ant-table-thead > tr > th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||
content: "标题 1";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||
content: "标题 2";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||
content: "标题 3";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||
content: "标题 4";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||
content: "标题 5";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||
content: "标题 6";
|
||||
}
|
||||
/* 针对下拉菜单中的选项 */
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item:not([data-value])::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label:not([data-value])::before {
|
||||
content: "正文" !important;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ server {
|
|||
|
||||
# 文件上传处理位置
|
||||
location /uploads/ {
|
||||
|
||||
|
||||
# 文件实际存储路径
|
||||
alias /data/uploads/;
|
||||
# 文件传输性能优化
|
||||
|
|
Loading…
Reference in New Issue