项目功能开发
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
This commit is contained in:
186
src/pages/Management/Project/edit.tsx
Normal file
186
src/pages/Management/Project/edit.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { message, Form } from 'antd';
|
||||
import { ModalForm, ProFormText, ProFormTextArea, ProFormSelect, ProFormTreeSelect } from '@ant-design/pro-components';
|
||||
import { getProjectDetail, addProject, updateProject } from '@/services/cms/project';
|
||||
import { getDictValueEnum } from '@/services/system/dict';
|
||||
import { getCmsIndustryTreeList } from '@/services/classify/industry';
|
||||
|
||||
interface EditProjectFormProps {
|
||||
open: boolean;
|
||||
values?: API.Project.ProjectItem;
|
||||
mode?: 'edit' | 'view';
|
||||
onCancel: () => void;
|
||||
onSuccess?: () => void;
|
||||
}
|
||||
|
||||
const EditProjectForm: React.FC<EditProjectFormProps> = ({ open, values, mode, onCancel, onSuccess }) => {
|
||||
const [form] = Form.useForm();
|
||||
const isView = mode === 'view';
|
||||
const isEdit = !!values?.projectId && !isView;
|
||||
const [regionOptions, setRegionOptions] = useState<{ label: string; value: string }[]>([]);
|
||||
|
||||
const title = isView ? '项目详情' : isEdit ? '编辑项目' : '新建项目';
|
||||
|
||||
// 加载字典数据
|
||||
useEffect(() => {
|
||||
// 地区字典(与发布岗位工作区县同一个字典)
|
||||
getDictValueEnum('area', true, true).then((data) => {
|
||||
const opts = Object.entries(data || {}).map(([k, v]: [string, any]) => ({ label: v.text, value: v.text }));
|
||||
setRegionOptions(opts);
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (open && values?.projectId) {
|
||||
getProjectDetail(values.projectId).then((res) => {
|
||||
if (res.code === 200 && res.data) {
|
||||
form?.setFieldsValue?.(res.data);
|
||||
}
|
||||
});
|
||||
} else if (open && !values?.projectId) {
|
||||
form?.resetFields?.();
|
||||
}
|
||||
}, [open, values]);
|
||||
|
||||
const handleSubmit = async (formValues: API.Project.ProjectItem) => {
|
||||
try {
|
||||
let res;
|
||||
if (isEdit) {
|
||||
res = await updateProject({ ...formValues, projectId: values?.projectId });
|
||||
} else {
|
||||
res = await addProject(formValues);
|
||||
}
|
||||
if (res.code === 200) {
|
||||
message.success(isEdit ? '修改成功' : '新增成功');
|
||||
onSuccess?.();
|
||||
return true;
|
||||
} else {
|
||||
message.error(res.msg || '操作失败');
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
message.error('操作失败,请重试');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalForm
|
||||
title={title}
|
||||
open={open}
|
||||
form={form}
|
||||
width={650}
|
||||
modalProps={{
|
||||
onCancel,
|
||||
destroyOnClose: true,
|
||||
maskClosable: !isView,
|
||||
}}
|
||||
readonly={isView}
|
||||
submitTimeout={2000}
|
||||
onFinish={handleSubmit}
|
||||
submitter={
|
||||
isView
|
||||
? false
|
||||
: {
|
||||
searchConfig: {
|
||||
submitText: isEdit ? '保存修改' : '创建项目',
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<ProFormText
|
||||
name="title"
|
||||
label="项目名称"
|
||||
placeholder="请输入项目名称"
|
||||
rules={[{ required: true, message: '请输入项目名称' }]}
|
||||
readonly={isView}
|
||||
/>
|
||||
<ProFormTextArea
|
||||
name="description"
|
||||
label="项目描述"
|
||||
placeholder="请输入项目描述(背景、目标、内容、特点等)"
|
||||
fieldProps={{ rows: 4 }}
|
||||
readonly={isView}
|
||||
/>
|
||||
<ProFormTextArea
|
||||
name="requiredPersonnel"
|
||||
label="项目需求人员"
|
||||
placeholder="请输入项目所需的人员类型、专业技能、工作经验等"
|
||||
fieldProps={{ rows: 3 }}
|
||||
readonly={isView}
|
||||
/>
|
||||
<ProFormSelect
|
||||
name="cooperationMode"
|
||||
label="合作方式"
|
||||
placeholder="请选择合作方式"
|
||||
readonly={isView}
|
||||
options={[
|
||||
{ label: '合作开发', value: '合作开发' },
|
||||
{ label: '技术转让', value: '技术转让' },
|
||||
{ label: '技术咨询', value: '技术咨询' },
|
||||
{ label: '技术服务', value: '技术服务' },
|
||||
{ label: '联合研究', value: '联合研究' },
|
||||
{ label: '委托开发', value: '委托开发' },
|
||||
]}
|
||||
/>
|
||||
<ProFormTreeSelect
|
||||
name="industry"
|
||||
label="行业"
|
||||
placeholder="请选择行业"
|
||||
readonly={isView}
|
||||
allowClear
|
||||
request={async () => getCmsIndustryTreeList().then((res) => res.data)}
|
||||
fieldProps={{
|
||||
suffixIcon: null,
|
||||
filterTreeNode: true,
|
||||
showSearch: true,
|
||||
popupMatchSelectWidth: false,
|
||||
labelInValue: false,
|
||||
autoClearSearchValue: true,
|
||||
multiple: false,
|
||||
treeNodeFilterProp: 'label',
|
||||
fieldNames: { label: 'label', value: 'label', children: 'children' },
|
||||
}}
|
||||
/>
|
||||
<ProFormSelect
|
||||
name="region"
|
||||
label="地区"
|
||||
placeholder="请选择地区"
|
||||
readonly={isView}
|
||||
options={regionOptions}
|
||||
fieldProps={{ showSearch: true }}
|
||||
/>
|
||||
<ProFormText
|
||||
name="contactName"
|
||||
label="联系人"
|
||||
placeholder="请输入联系人姓名"
|
||||
readonly={isView}
|
||||
/>
|
||||
<ProFormText
|
||||
name="contactPhone"
|
||||
label="联系电话"
|
||||
placeholder="请输入联系电话"
|
||||
readonly={isView}
|
||||
/>
|
||||
<ProFormText
|
||||
name="contactEmail"
|
||||
label="联系邮箱"
|
||||
placeholder="请输入联系邮箱"
|
||||
readonly={isView}
|
||||
/>
|
||||
<ProFormSelect
|
||||
name="status"
|
||||
label="状态"
|
||||
placeholder="请选择状态"
|
||||
readonly={isView}
|
||||
options={[
|
||||
{ label: '草稿', value: '0' },
|
||||
{ label: '发布', value: '1' },
|
||||
]}
|
||||
initialValue="0"
|
||||
/>
|
||||
</ModalForm>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditProjectForm;
|
||||
373
src/pages/Management/Project/index.tsx
Normal file
373
src/pages/Management/Project/index.tsx
Normal file
@@ -0,0 +1,373 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useAccess } from '@umijs/max';
|
||||
import { Button, message, Modal, Switch, Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||
import { PlusOutlined, DeleteOutlined, FormOutlined, MessageOutlined } from '@ant-design/icons';
|
||||
import { getProjectList, deleteProject, updateProject, getProjectComments, replyComment } from '@/services/cms/project';
|
||||
import { getDictValueEnum } from '@/services/system/dict';
|
||||
import { getCmsIndustryTreeList } from '@/services/classify/industry';
|
||||
import EditProjectForm from './edit';
|
||||
|
||||
const statusMap: Record<string, { text: string; color: string }> = {
|
||||
'0': { text: '草稿', color: 'default' },
|
||||
'1': { text: '已发布', color: 'green' },
|
||||
};
|
||||
|
||||
const ProjectMgmt: React.FC = () => {
|
||||
const access = useAccess();
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [editModalOpen, setEditModalOpen] = useState(false);
|
||||
const [editValues, setEditValues] = useState<API.Project.ProjectItem | undefined>();
|
||||
const [viewModalOpen, setViewModalOpen] = useState(false);
|
||||
const [viewValues, setViewValues] = useState<API.Project.ProjectItem | undefined>();
|
||||
const [dictEnumMap, setDictEnumMap] = useState<Record<string, Record<string, { text: string }>>>({});
|
||||
const [commentModalOpen, setCommentModalOpen] = useState(false);
|
||||
const [commentProjectId, setCommentProjectId] = useState<number | undefined>();
|
||||
const [comments, setComments] = useState<any[]>([]);
|
||||
const [replyTexts, setReplyTexts] = useState<Record<number, string>>({});
|
||||
const [industryLabelMap, setIndustryLabelMap] = useState<Record<string, string>>({});
|
||||
|
||||
// 加载字典数据
|
||||
useEffect(() => {
|
||||
getDictValueEnum('area', true, true).then((data) => {
|
||||
const textMap: Record<string, { text: string }> = {};
|
||||
Object.values(data || {}).forEach((v: any) => { textMap[v.text] = { text: v.text }; });
|
||||
setDictEnumMap((prev) => ({ ...prev, region: textMap }));
|
||||
}).catch(() => {});
|
||||
// 加载行业树,构建 id->label 映射
|
||||
getCmsIndustryTreeList().then((res) => {
|
||||
const map: Record<string, string> = {};
|
||||
const walk = (nodes: any[]) => {
|
||||
nodes.forEach((n: any) => {
|
||||
if (n.id && n.label) map[String(n.id)] = n.label;
|
||||
if (n.children) walk(n.children);
|
||||
});
|
||||
};
|
||||
walk(res?.data || []);
|
||||
setIndustryLabelMap(map);
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
const handleRemove = async (ids: string) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除选中的项目吗?',
|
||||
onOk: async () => {
|
||||
const hide = message.loading('正在删除');
|
||||
try {
|
||||
const res = await deleteProject(ids);
|
||||
hide();
|
||||
if (res.code === 200) {
|
||||
message.success('删除成功');
|
||||
actionRef.current?.reload();
|
||||
} else {
|
||||
message.error(res.msg || '删除失败');
|
||||
}
|
||||
} catch {
|
||||
hide();
|
||||
message.error('删除失败,请重试');
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const loadComments = async (projectId: number) => {
|
||||
setCommentProjectId(projectId);
|
||||
try {
|
||||
const res = await getProjectComments(projectId);
|
||||
if (res.code === 200) {
|
||||
setComments(res.data || []);
|
||||
}
|
||||
} catch { message.error('加载评论失败'); }
|
||||
setCommentModalOpen(true);
|
||||
};
|
||||
|
||||
const handleReply = async (commentId: number) => {
|
||||
const reply = replyTexts[commentId]?.trim();
|
||||
if (!reply) { message.warning('请输入回复内容'); return; }
|
||||
try {
|
||||
const res = await replyComment({ commentId, reply });
|
||||
if (res.code === 200) {
|
||||
message.success('回复成功');
|
||||
setReplyTexts((prev) => ({ ...prev, [commentId]: '' }));
|
||||
if (commentProjectId) loadComments(commentProjectId);
|
||||
} else { message.error(res.msg || '回复失败'); }
|
||||
} catch { message.error('回复失败'); }
|
||||
};
|
||||
|
||||
const handleStatusChange = async (record: API.Project.ProjectItem, checked: boolean) => {
|
||||
const newStatus = checked ? '1' : '0';
|
||||
try {
|
||||
const res = await updateProject({ ...record, status: newStatus });
|
||||
if (res.code === 200) {
|
||||
message.success(checked ? '已发布' : '已下架');
|
||||
actionRef.current?.reload();
|
||||
} else {
|
||||
message.error(res.msg || '状态更新失败');
|
||||
}
|
||||
} catch {
|
||||
message.error('状态更新失败');
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ProColumns<API.Project.ProjectItem>[] = [
|
||||
{
|
||||
title: '项目名称',
|
||||
dataIndex: 'title',
|
||||
valueType: 'text',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '行业',
|
||||
dataIndex: 'industry',
|
||||
valueType: 'treeSelect',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
render: (_, record) => record.industry || '-',
|
||||
fieldProps: {
|
||||
showSearch: true,
|
||||
filterTreeNode: true,
|
||||
treeNodeFilterProp: 'label',
|
||||
fieldNames: { label: 'label', value: 'label', children: 'children' },
|
||||
},
|
||||
request: async () => {
|
||||
const res = await getCmsIndustryTreeList();
|
||||
return res?.data || [];
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '地区',
|
||||
dataIndex: 'region',
|
||||
valueType: 'select',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (_, record) => {
|
||||
const val = dictEnumMap.region?.[record.region || ''];
|
||||
return val?.text || record.region || '-';
|
||||
},
|
||||
valueEnum: dictEnumMap.region,
|
||||
},
|
||||
{
|
||||
title: '合作方式',
|
||||
dataIndex: 'cooperationMode',
|
||||
valueType: 'text',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
render: (_, record) => record.cooperationMode || '-',
|
||||
},
|
||||
{
|
||||
title: '联系人',
|
||||
dataIndex: 'contactName',
|
||||
valueType: 'text',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => record.contactName || '-',
|
||||
},
|
||||
{
|
||||
title: '联系电话',
|
||||
dataIndex: 'contactPhone',
|
||||
valueType: 'text',
|
||||
align: 'center',
|
||||
width: 130,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => record.contactPhone || '-',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
valueType: 'select',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
valueEnum: { '0': '草稿', '1': '已发布' },
|
||||
render: (_, record) => {
|
||||
const st = statusMap[record.status || '0'];
|
||||
return (
|
||||
<Switch
|
||||
checked={record.status === '1'}
|
||||
onChange={(checked) => handleStatusChange(record, checked)}
|
||||
checkedChildren="发布"
|
||||
unCheckedChildren="草稿"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
valueType: 'text',
|
||||
align: 'center',
|
||||
width: 160,
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 180,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => (
|
||||
<>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<MessageOutlined />}
|
||||
onClick={() => loadComments(record.projectId!)}
|
||||
>
|
||||
评论
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setViewValues(record);
|
||||
setViewModalOpen(true);
|
||||
}}
|
||||
>
|
||||
详情
|
||||
</Button>
|
||||
{access.hasPerms('cms:project:edit') && (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<FormOutlined />}
|
||||
onClick={() => {
|
||||
setEditValues(record);
|
||||
setEditModalOpen(true);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
{access.hasPerms('cms:project:remove') && (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleRemove(String(record.projectId))}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProTable<API.Project.ProjectItem>
|
||||
actionRef={actionRef}
|
||||
rowKey="projectId"
|
||||
columns={columns}
|
||||
headerTitle="项目管理"
|
||||
request={async (params) => {
|
||||
const { current, pageSize, ...searchParams } = params;
|
||||
const response = await getProjectList({
|
||||
...searchParams,
|
||||
pageNum: current,
|
||||
pageSize,
|
||||
});
|
||||
return {
|
||||
data: response.rows || [],
|
||||
total: response.total || 0,
|
||||
success: true,
|
||||
};
|
||||
}}
|
||||
search={{
|
||||
labelWidth: 'auto',
|
||||
}}
|
||||
pagination={{
|
||||
defaultPageSize: 10,
|
||||
showSizeChanger: true,
|
||||
}}
|
||||
toolBarRender={() => [
|
||||
access.hasPerms('cms:project:add') && (
|
||||
<Button
|
||||
key="add"
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => {
|
||||
setEditValues(undefined);
|
||||
setEditModalOpen(true);
|
||||
}}
|
||||
>
|
||||
新建项目
|
||||
</Button>
|
||||
),
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* 编辑/新建弹窗 */}
|
||||
<EditProjectForm
|
||||
open={editModalOpen}
|
||||
values={editValues}
|
||||
onCancel={() => {
|
||||
setEditModalOpen(false);
|
||||
setEditValues(undefined);
|
||||
}}
|
||||
onSuccess={() => {
|
||||
setEditModalOpen(false);
|
||||
setEditValues(undefined);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 查看详情弹窗 */}
|
||||
<EditProjectForm
|
||||
open={viewModalOpen}
|
||||
values={viewValues}
|
||||
mode="view"
|
||||
onCancel={() => {
|
||||
setViewModalOpen(false);
|
||||
setViewValues(undefined);
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 评论管理弹窗 */}
|
||||
<Modal
|
||||
title="评论管理"
|
||||
open={commentModalOpen}
|
||||
onCancel={() => { setCommentModalOpen(false); setComments([]); setReplyTexts({}); }}
|
||||
footer={null}
|
||||
width={700}
|
||||
>
|
||||
{comments.length === 0 ? (
|
||||
<div style={{ textAlign: 'center', color: '#999', padding: 40 }}>暂无评论</div>
|
||||
) : (
|
||||
<div style={{ maxHeight: 400, overflowY: 'auto' }}>
|
||||
{comments.map((c: any) => (
|
||||
<div key={c.commentId} style={{ borderBottom: '1px solid #f0f0f0', padding: '16px 0' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
|
||||
<span style={{ fontWeight: 500, color: '#1a62ce' }}>{c.userName || '匿名用户'}</span>
|
||||
<span style={{ color: '#999', fontSize: 12 }}>{c.createTime}</span>
|
||||
</div>
|
||||
<div style={{ color: '#333', marginBottom: 8 }}>{c.content}</div>
|
||||
{c.reply ? (
|
||||
<div style={{ background: '#f6ffed', padding: '8px 12px', borderRadius: 6, marginTop: 4 }}>
|
||||
<span style={{ color: '#52c41a', fontSize: 12 }}>已回复 ({c.replyTime}):</span>
|
||||
<div style={{ color: '#333' }}>{c.reply}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||
<input
|
||||
style={{ flex: 1, padding: '6px 12px', border: '1px solid #d9d9d9', borderRadius: 6 }}
|
||||
placeholder="输入回复..."
|
||||
value={replyTexts[c.commentId] || ''}
|
||||
onChange={(e) => setReplyTexts((prev) => ({ ...prev, [c.commentId]: e.target.value }))}
|
||||
/>
|
||||
<Button size="small" type="primary" onClick={() => handleReply(c.commentId)}>回复</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectMgmt;
|
||||
54
src/services/cms/project.ts
Normal file
54
src/services/cms/project.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { request } from '@umijs/max';
|
||||
|
||||
// 查询项目列表
|
||||
export async function getProjectList(params?: API.Project.ListParams) {
|
||||
return request<API.Project.ProjectResult>('/api/cms/project/list', {
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
// 获取项目详情
|
||||
export async function getProjectDetail(id: number | string) {
|
||||
return request<API.Project.ProjectDetailResult>(`/api/cms/project/${id}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
// 新增项目
|
||||
export async function addProject(data: Partial<API.Project.ProjectItem>) {
|
||||
return request<API.Result>('/api/cms/project', {
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 修改项目
|
||||
export async function updateProject(data: Partial<API.Project.ProjectItem>) {
|
||||
return request<API.Result>('/api/cms/project', {
|
||||
method: 'PUT',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 删除项目
|
||||
export async function deleteProject(ids: string) {
|
||||
return request<API.Result>(`/api/cms/project/${ids}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
// 获取项目评论列表
|
||||
export async function getProjectComments(projectId: number | string) {
|
||||
return request<API.Result>(`/api/cms/project/comments/${projectId}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
// 回复评论
|
||||
export async function replyComment(data: { commentId: number; reply: string }) {
|
||||
return request<API.Result>('/api/cms/project/comment/reply', {
|
||||
method: 'PUT',
|
||||
data,
|
||||
});
|
||||
}
|
||||
44
src/types/cms/project.d.ts
vendored
Normal file
44
src/types/cms/project.d.ts
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
declare namespace API.Project {
|
||||
export interface ProjectResult {
|
||||
total: number;
|
||||
rows: ProjectItem[];
|
||||
code: number;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
export interface ProjectDetailResult {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: ProjectItem;
|
||||
}
|
||||
|
||||
export interface ProjectItem {
|
||||
projectId?: number;
|
||||
title: string;
|
||||
description?: string;
|
||||
requiredPersonnel?: string;
|
||||
cooperationMode?: string;
|
||||
industry?: string;
|
||||
region?: string;
|
||||
contactName?: string;
|
||||
contactPhone?: string;
|
||||
contactEmail?: string;
|
||||
status?: string;
|
||||
createBy?: string;
|
||||
createTime?: string;
|
||||
updateBy?: string;
|
||||
updateTime?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface ListParams {
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
searchValue?: string;
|
||||
title?: string;
|
||||
industry?: string;
|
||||
region?: string;
|
||||
cooperationMode?: string;
|
||||
status?: string;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user