完善审计报告生成页面
This commit is contained in:
@@ -114,7 +114,7 @@ export async function updateAiHistoryBatch(data: { list: AiHistory[] }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除AI审计历史记录表
|
* 批量删除 AI审计历史记录表
|
||||||
*/
|
*/
|
||||||
export async function removeAiHistoryBatch(ids: number[]) {
|
export async function removeAiHistoryBatch(ids: number[]) {
|
||||||
const res = await request.delete<ApiResult<unknown>>(
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
@@ -127,3 +127,20 @@ export async function removeAiHistoryBatch(ids: number[]) {
|
|||||||
return Promise.reject(new Error(res.data.message));
|
return Promise.reject(new Error(res.data.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据接口名称和项目 ID 查询最新的历史记录
|
||||||
|
*/
|
||||||
|
export async function getLatestHistoryByInterface(params: {
|
||||||
|
interfaceName: string;
|
||||||
|
projectId: number;
|
||||||
|
}) {
|
||||||
|
const res = await request.get<ApiResult<AiHistory>>(
|
||||||
|
`${MODULES_API_URL}/ai/history/latest`,
|
||||||
|
{ params }
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return null; // 如果没有数据,返回 null
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,4 +183,117 @@ export async function generateAuditReportWithEvidences(projectId: number, eviden
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error('文件下载失败'));
|
return Promise.reject(new Error('文件下载失败'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据项目 ID、选中的取证单和章节内容生成审计报告并下载
|
||||||
|
* @param projectId 项目 ID
|
||||||
|
* @param evidenceIds 勾选的取证单 ID 列表
|
||||||
|
* @param chapters 章节内容数组(包含 formCommit 和 reportContent)
|
||||||
|
* @param evaluate 总体评价
|
||||||
|
* @param suggestion 审计建议
|
||||||
|
*/
|
||||||
|
export async function generateAuditReportWithContent(
|
||||||
|
projectId: number,
|
||||||
|
evidenceIds: number[],
|
||||||
|
chapters: Array<{
|
||||||
|
formCommit: number;
|
||||||
|
reportContent: string;
|
||||||
|
}>,
|
||||||
|
evaluate?: string,
|
||||||
|
suggestion?: string
|
||||||
|
) {
|
||||||
|
const res = await request.post(
|
||||||
|
MODULES_API_URL + '/ai/auditReport/generateWithContent',
|
||||||
|
{
|
||||||
|
evidenceIds,
|
||||||
|
chapters,
|
||||||
|
evaluate,
|
||||||
|
suggestion
|
||||||
|
},
|
||||||
|
{
|
||||||
|
params: { projectId },
|
||||||
|
responseType: 'blob' // 处理二进制流响应
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error('文件下载失败'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI 生成默认话术
|
||||||
|
*/
|
||||||
|
export async function generateDefaultText(params: {
|
||||||
|
projectId?: number;
|
||||||
|
formCommit: number;
|
||||||
|
chapterTitle?: string;
|
||||||
|
evidenceIds?: number[]; // 新增:选中的取证单 ID 列表
|
||||||
|
}) {
|
||||||
|
const res = await request.post<ApiResult<string>>(
|
||||||
|
MODULES_API_URL + '/ai/auditReport/generateDefaultText',
|
||||||
|
{
|
||||||
|
projectId: params.projectId,
|
||||||
|
formCommit: params.formCommit,
|
||||||
|
chapterTitle: params.chapterTitle,
|
||||||
|
evidenceIds: params.evidenceIds
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
// 后端返回的数据在 message 字段中
|
||||||
|
return res.data.message || res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI 分析用户自定义输入
|
||||||
|
*/
|
||||||
|
export async function analyzeUserInput(params: {
|
||||||
|
formCommit: number;
|
||||||
|
userQuestion: string;
|
||||||
|
chapterContent?: string;
|
||||||
|
}) {
|
||||||
|
const res = await request.post<ApiResult<string>>(
|
||||||
|
MODULES_API_URL + '/ai/auditReport/analyzeUserInput',
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据取证单生成审计建议
|
||||||
|
*/
|
||||||
|
export async function generateAuditSuggestion(params: {
|
||||||
|
projectId: number;
|
||||||
|
evidenceIds: number[];
|
||||||
|
}) {
|
||||||
|
const res = await request.post<ApiResult<string>>(
|
||||||
|
MODULES_API_URL + '/ai/auditReport/generateAuditSuggestion',
|
||||||
|
{ evidenceIds: params.evidenceIds },
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
projectId: params.projectId
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
// 后端返回的数据在 message 字段中
|
||||||
|
return res.data.message || res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
title="编辑行数据"
|
title="编辑行数据"
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
:confirm-loading="loading"
|
:confirm-loading="loading"
|
||||||
width="600px"
|
width="600px"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="modal-title">
|
<div class="modal-title">
|
||||||
@@ -17,23 +17,23 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<a-alert
|
<a-alert
|
||||||
v-if="displayRecords.length > 1"
|
v-if="displayRecords.length > 1"
|
||||||
type="info"
|
type="info"
|
||||||
show-icon
|
show-icon
|
||||||
style="margin-bottom: 12px"
|
style="margin-bottom: 12px"
|
||||||
:message="`已选择 ${displayRecords.length} 条记录,将把当前修改同步到这些记录`"
|
:message="`已选择 ${displayRecords.length} 条记录,将把当前修改同步到这些记录`"
|
||||||
/>
|
/>
|
||||||
<a-list
|
<a-list
|
||||||
v-if="displayRecords.length > 1"
|
v-if="displayRecords.length > 1"
|
||||||
size="small"
|
size="small"
|
||||||
bordered
|
bordered
|
||||||
:data-source="displayRecords"
|
:data-source="displayRecords"
|
||||||
style="margin-bottom: 12px; max-height: 160px; overflow-y: auto"
|
style="margin-bottom: 12px; max-height: 160px; overflow-y: auto"
|
||||||
>
|
>
|
||||||
<template #renderItem="{ item, index }">
|
<template #renderItem="{ item, index }">
|
||||||
<a-list-item
|
<a-list-item
|
||||||
:class="['record-item', { active: index === selectedRecordIndex }]"
|
:class="['record-item', { active: index === selectedRecordIndex }]"
|
||||||
@click="selectRecord(index)"
|
@click="selectRecord(index)"
|
||||||
>
|
>
|
||||||
<span class="record-label">#{{ index + 1 }}</span>
|
<span class="record-label">#{{ index + 1 }}</span>
|
||||||
</a-list-item>
|
</a-list-item>
|
||||||
@@ -45,22 +45,23 @@
|
|||||||
<a-form-item :label="field.title" v-if="!field.children">
|
<a-form-item :label="field.title" v-if="!field.children">
|
||||||
<template v-if="field.type === 'textarea'">
|
<template v-if="field.type === 'textarea'">
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="activeFormData[field.dataIndex]"
|
v-model:value="activeFormData[field.dataIndex]"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
:placeholder="`请输入${field.title}`"
|
:placeholder="`请输入${field.title}`"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="field.dataIndex === 'workPaperIndex'">
|
<template v-else-if="field.dataIndex === 'workPaperIndex'">
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="activeFormData[field.dataIndex]"
|
v-model:value="activeFormData[field.dataIndex]"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
:placeholder="'每行一个文件,格式为:file_id||文件名||url'"
|
:placeholder="'每行一个文件,格式为:file_id||文件名||url'"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-input
|
<a-textarea
|
||||||
v-model:value="activeFormData[field.dataIndex]"
|
:rows="4"
|
||||||
:placeholder="`请输入${field.title}`"
|
v-model:value="activeFormData[field.dataIndex]"
|
||||||
|
:placeholder="`请输入${field.title}`"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -71,14 +72,14 @@
|
|||||||
<div class="field-group-title">{{ field.title }}</div>
|
<div class="field-group-title">{{ field.title }}</div>
|
||||||
<div class="field-group-content">
|
<div class="field-group-content">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
v-for="childField in field.children"
|
v-for="childField in field.children"
|
||||||
:key="childField.key"
|
:key="childField.key"
|
||||||
:label="childField.title"
|
:label="childField.title"
|
||||||
class="nested-field-item"
|
class="nested-field-item"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="activeFormData[childField.dataIndex]"
|
v-model:value="activeFormData[childField.dataIndex]"
|
||||||
:placeholder="`请输入${childField.title}`"
|
:placeholder="`请输入${childField.title}`"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</div>
|
</div>
|
||||||
@@ -90,207 +91,219 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch, computed } from 'vue';
|
import { ref, watch, computed } from 'vue';
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
record: any;
|
record: any;
|
||||||
fields: any[];
|
fields: any[];
|
||||||
records?: any[];
|
records?: any[];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'save']);
|
const emit = defineEmits(['update:visible', 'save']);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const formDataList = ref<any[]>([]);
|
const formDataList = ref<any[]>([]);
|
||||||
const selectedRecordIndex = ref(0);
|
const selectedRecordIndex = ref(0);
|
||||||
|
|
||||||
const displayRecords = computed(() => {
|
const displayRecords = computed(() => {
|
||||||
if (props.records && Array.isArray(props.records) && props.records.length) {
|
if (props.records && Array.isArray(props.records) && props.records.length) {
|
||||||
return props.records;
|
return props.records;
|
||||||
}
|
}
|
||||||
if (props.record) return [props.record];
|
if (props.record) return [props.record];
|
||||||
return [];
|
return [];
|
||||||
});
|
|
||||||
|
|
||||||
const transformRecordToFormData = (record: any) => {
|
|
||||||
if (!record) return {};
|
|
||||||
const recordCopy = JSON.parse(JSON.stringify(record));
|
|
||||||
|
|
||||||
if (
|
|
||||||
hasWorkPaperIndexField.value &&
|
|
||||||
recordCopy.workPaperIndex &&
|
|
||||||
Array.isArray(recordCopy.workPaperIndex)
|
|
||||||
) {
|
|
||||||
recordCopy.workPaperIndex = recordCopy.workPaperIndex
|
|
||||||
.map((item: any) => {
|
|
||||||
if (typeof item === 'object') {
|
|
||||||
return `${item.fileId || ''}||${item.fileName || ''}||${item.fileUrl || ''}`;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
})
|
|
||||||
.join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
return recordCopy;
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasWorkPaperIndexField = computed(() => {
|
|
||||||
return (props.fields || []).some((field) => {
|
|
||||||
return field?.dataIndex === 'workPaperIndex' || field?.key === 'workPaperIndex';
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// 处理字段,将嵌套结构展平
|
const transformRecordToFormData = (record: any) => {
|
||||||
const processedFields = computed(() => {
|
if (!record) return {};
|
||||||
const processed: any[] = [];
|
const recordCopy = JSON.parse(JSON.stringify(record));
|
||||||
|
|
||||||
(props.fields || []).forEach(field => {
|
if (
|
||||||
if (field.children && Array.isArray(field.children)) {
|
hasWorkPaperIndexField.value &&
|
||||||
// 处理有子字段的情况(如职务)
|
recordCopy.workPaperIndex &&
|
||||||
processed.push({
|
Array.isArray(recordCopy.workPaperIndex)
|
||||||
...field,
|
) {
|
||||||
children: field.children.flatMap(child =>
|
recordCopy.workPaperIndex = recordCopy.workPaperIndex
|
||||||
child.children && Array.isArray(child.children)
|
.map((item: any) => {
|
||||||
|
if (typeof item === 'object') {
|
||||||
|
return `${item.fileId || ''}||${item.fileName || ''}||${
|
||||||
|
item.fileUrl || ''
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordCopy;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasWorkPaperIndexField = computed(() => {
|
||||||
|
return (props.fields || []).some((field) => {
|
||||||
|
return (
|
||||||
|
field?.dataIndex === 'workPaperIndex' || field?.key === 'workPaperIndex'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理字段,将嵌套结构展平
|
||||||
|
const processedFields = computed(() => {
|
||||||
|
const processed: any[] = [];
|
||||||
|
|
||||||
|
(props.fields || []).forEach((field) => {
|
||||||
|
if (field.children && Array.isArray(field.children)) {
|
||||||
|
// 处理有子字段的情况(如职务)
|
||||||
|
processed.push({
|
||||||
|
...field,
|
||||||
|
children: field.children.flatMap(
|
||||||
|
(child) =>
|
||||||
|
child.children && Array.isArray(child.children)
|
||||||
? child.children // 如果是多层嵌套,直接取孙子字段
|
? child.children // 如果是多层嵌套,直接取孙子字段
|
||||||
: child // 否则就是子字段
|
: child // 否则就是子字段
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
processed.push(field);
|
processed.push(field);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return processed;
|
||||||
});
|
});
|
||||||
|
|
||||||
return processed;
|
watch(
|
||||||
});
|
() => props.visible,
|
||||||
|
(visible) => {
|
||||||
|
if (visible) {
|
||||||
|
selectedRecordIndex.value = 0;
|
||||||
|
formDataList.value = displayRecords.value.map((rec) =>
|
||||||
|
transformRecordToFormData(rec)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
watch(
|
const handleOk = () => {
|
||||||
() => props.visible,
|
if (!formDataList.value || formDataList.value.length === 0) {
|
||||||
(visible) => {
|
message.warning('没有数据可保存');
|
||||||
if (visible) {
|
return;
|
||||||
selectedRecordIndex.value = 0;
|
}
|
||||||
formDataList.value = displayRecords.value.map((rec) =>
|
|
||||||
transformRecordToFormData(rec)
|
// 处理workPaperIndex:将字符串转换回对象数组
|
||||||
|
const dataToSave = formDataList.value.map((item) => {
|
||||||
|
const cloned = JSON.parse(JSON.stringify(item || {}));
|
||||||
|
if (
|
||||||
|
hasWorkPaperIndexField.value &&
|
||||||
|
cloned.workPaperIndex &&
|
||||||
|
typeof cloned.workPaperIndex === 'string'
|
||||||
|
) {
|
||||||
|
const lines = cloned.workPaperIndex
|
||||||
|
.split('\n')
|
||||||
|
.filter((line: string) => line.trim() !== '');
|
||||||
|
cloned.workPaperIndex = lines.map((line: string) => {
|
||||||
|
const parts = line.split('||');
|
||||||
|
if (parts.length >= 3) {
|
||||||
|
return {
|
||||||
|
fileId: parts[0] || '',
|
||||||
|
fileName: parts[1] || '',
|
||||||
|
fileUrl: parts[2] || ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return cloned;
|
||||||
|
});
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
emit('save', dataToSave);
|
||||||
|
loading.value = false;
|
||||||
|
emit('update:visible', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('update:visible', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectRecord = (index: number) => {
|
||||||
|
if (index < 0 || index >= displayRecords.value.length) return;
|
||||||
|
selectedRecordIndex.value = index;
|
||||||
|
if (!formDataList.value[index]) {
|
||||||
|
formDataList.value[index] = transformRecordToFormData(
|
||||||
|
displayRecords.value[index]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleOk = () => {
|
const activeFormData = computed({
|
||||||
if (!formDataList.value || formDataList.value.length === 0) {
|
get() {
|
||||||
message.warning('没有数据可保存');
|
if (!displayRecords.value.length) return {};
|
||||||
return;
|
if (!formDataList.value[selectedRecordIndex.value]) {
|
||||||
}
|
formDataList.value[selectedRecordIndex.value] =
|
||||||
|
transformRecordToFormData(
|
||||||
// 处理workPaperIndex:将字符串转换回对象数组
|
displayRecords.value[selectedRecordIndex.value]
|
||||||
const dataToSave = formDataList.value.map((item) => {
|
);
|
||||||
const cloned = JSON.parse(JSON.stringify(item || {}));
|
}
|
||||||
if (hasWorkPaperIndexField.value && cloned.workPaperIndex && typeof cloned.workPaperIndex === 'string') {
|
return formDataList.value[selectedRecordIndex.value] || {};
|
||||||
const lines = cloned.workPaperIndex.split('\n').filter((line: string) => line.trim() !== '');
|
},
|
||||||
cloned.workPaperIndex = lines.map((line: string) => {
|
set(val) {
|
||||||
const parts = line.split('||');
|
if (!displayRecords.value.length) return;
|
||||||
if (parts.length >= 3) {
|
formDataList.value[selectedRecordIndex.value] = val || {};
|
||||||
return {
|
|
||||||
fileId: parts[0] || '',
|
|
||||||
fileName: parts[1] || '',
|
|
||||||
fileUrl: parts[2] || ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return line;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return cloned;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
loading.value = true;
|
|
||||||
emit('save', dataToSave);
|
|
||||||
loading.value = false;
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectRecord = (index: number) => {
|
|
||||||
if (index < 0 || index >= displayRecords.value.length) return;
|
|
||||||
selectedRecordIndex.value = index;
|
|
||||||
if (!formDataList.value[index]) {
|
|
||||||
formDataList.value[index] = transformRecordToFormData(
|
|
||||||
displayRecords.value[index]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const activeFormData = computed({
|
|
||||||
get() {
|
|
||||||
if (!displayRecords.value.length) return {};
|
|
||||||
if (!formDataList.value[selectedRecordIndex.value]) {
|
|
||||||
formDataList.value[selectedRecordIndex.value] = transformRecordToFormData(
|
|
||||||
displayRecords.value[selectedRecordIndex.value]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return formDataList.value[selectedRecordIndex.value] || {};
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
if (!displayRecords.value.length) return;
|
|
||||||
formDataList.value[selectedRecordIndex.value] = val || {};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.nested-fields {
|
.nested-fields {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field-group-title {
|
.field-group-title {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field-group-content {
|
.field-group-content {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nested-field-item {
|
.nested-field-item {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-label {
|
.record-label {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 36px;
|
width: 36px;
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-text {
|
.record-text {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-item {
|
.record-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-item:hover {
|
.record-item:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.record-item.active {
|
.record-item.active {
|
||||||
background-color: #e6f7ff;
|
background-color: #e6f7ff;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -72,11 +72,22 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>审计(调查)事项</th>
|
<th>审计(调查)事项</th>
|
||||||
<td>
|
<td>
|
||||||
<textarea
|
<a-select style="min-width: 600px"
|
||||||
v-model="form.auditMatter"
|
v-model:value="form.auditMatter"
|
||||||
class="cell-input single"
|
placeholder="请选择审计(调查)事项"
|
||||||
placeholder="填写审计(调查)事项"
|
>
|
||||||
></textarea>
|
<a-select-option
|
||||||
|
v-for="(item, index) in auditMatterOptions"
|
||||||
|
:key="index"
|
||||||
|
:value="item"
|
||||||
|
>{{ item }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
<!-- <textarea-->
|
||||||
|
<!-- v-model="form.auditMatter"-->
|
||||||
|
<!-- class="cell-input single"-->
|
||||||
|
<!-- placeholder="填写审计(调查)事项"-->
|
||||||
|
<!-- ></textarea>-->
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@@ -257,7 +268,10 @@
|
|||||||
import { PropType, reactive, ref, watch } from 'vue';
|
import { PropType, reactive, ref, watch } from 'vue';
|
||||||
import { message, Modal } from 'ant-design-vue';
|
import { message, Modal } from 'ant-design-vue';
|
||||||
import { PwlProject } from '@/api/pwl/pwlProject/model';
|
import { PwlProject } from '@/api/pwl/pwlProject/model';
|
||||||
import { downloadAuditEvidence, saveAuditEvidence } from '@/api/ai/auditContent';
|
import {
|
||||||
|
downloadAuditEvidence,
|
||||||
|
saveAuditEvidence
|
||||||
|
} from '@/api/ai/auditContent';
|
||||||
|
|
||||||
type BaseInfo = {
|
type BaseInfo = {
|
||||||
caseIndex?: string;
|
caseIndex?: string;
|
||||||
@@ -286,6 +300,17 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const auditMatterOptions = [
|
||||||
|
'贯彻执行党和国家经济方针政策、决策部署情况',
|
||||||
|
'企业发展战略规划的制定、执行和效果情况',
|
||||||
|
'重大经济事项的决策、执行和效果情况',
|
||||||
|
'企业法人治理结构的建立、健全和运行情况,内部控制制度的制定和执行情况',
|
||||||
|
'企业财务的真实合法效益情况,风险管控情况,境外资产管理情况,生态环境保护情况',
|
||||||
|
'在经济活动中落实有关党风廉政建设责任和遵守廉洁从业规定情况',
|
||||||
|
'以往审计发现问题的整改情况',
|
||||||
|
'其他需要审计的内容'
|
||||||
|
];
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:visible', value: boolean): void;
|
(e: 'update:visible', value: boolean): void;
|
||||||
}>();
|
}>();
|
||||||
@@ -342,21 +367,30 @@
|
|||||||
console.log('===== applyBaseInfo 开始执行 =====');
|
console.log('===== applyBaseInfo 开始执行 =====');
|
||||||
console.log('1. selectedRows:', props.selectedRows);
|
console.log('1. selectedRows:', props.selectedRows);
|
||||||
console.log('2. baseInfo:', props.baseInfo);
|
console.log('2. baseInfo:', props.baseInfo);
|
||||||
console.log('3. baseInfo.auditMatterType:', props.baseInfo?.auditMatterType);
|
console.log(
|
||||||
|
'3. baseInfo.auditMatterType:',
|
||||||
|
props.baseInfo?.auditMatterType
|
||||||
|
);
|
||||||
|
|
||||||
// 重置表单为默认值
|
// 重置表单为默认值
|
||||||
Object.assign(form, defaultForm(), props.baseInfo || {});
|
Object.assign(form, defaultForm(), props.baseInfo || {});
|
||||||
|
|
||||||
console.log('4. Object.assign 后的 form.auditMatterType:', form.auditMatterType);
|
console.log(
|
||||||
|
'4. Object.assign 后的 form.auditMatterType:',
|
||||||
|
form.auditMatterType
|
||||||
|
);
|
||||||
|
|
||||||
// 特殊处理:确保 auditMatterType 被正确复制(Object.assign 可能会覆盖)
|
// 特殊处理:确保 auditMatterType 被正确复制(Object.assign 可能会覆盖)
|
||||||
if (props.baseInfo?.auditMatterType) {
|
if (props.baseInfo?.auditMatterType) {
|
||||||
form.auditMatterType = props.baseInfo.auditMatterType;
|
form.auditMatterType = props.baseInfo.auditMatterType;
|
||||||
console.log('✓ 5. 显式设置后的 form.auditMatterType:', form.auditMatterType);
|
console.log(
|
||||||
|
'✓ 5. 显式设置后的 form.auditMatterType:',
|
||||||
|
form.auditMatterType
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.warn('✗ 5. auditMatterType 为空或未设置,无法复制');
|
console.warn('✗ 5. auditMatterType 为空或未设置,无法复制');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('===== applyBaseInfo 执行完毕 =====');
|
console.log('===== applyBaseInfo 执行完毕 =====');
|
||||||
|
|
||||||
// 如果有传入的selectedRows,直接使用第一个对象的数据(生成取证单时通常只有一个)
|
// 如果有传入的selectedRows,直接使用第一个对象的数据(生成取证单时通常只有一个)
|
||||||
@@ -366,8 +400,15 @@
|
|||||||
|
|
||||||
// 直接将后端返回的数据映射到表单字段
|
// 直接将后端返回的数据映射到表单字段
|
||||||
form.caseIndex =
|
form.caseIndex =
|
||||||
props.baseInfo?.caseIndex || props.project?.caseIndex || form.caseIndex || '';
|
props.baseInfo?.caseIndex ||
|
||||||
form.projectName = props.project?.code || evidenceData.projectName || form.projectName || '';
|
props.project?.caseIndex ||
|
||||||
|
form.caseIndex ||
|
||||||
|
'';
|
||||||
|
form.projectName =
|
||||||
|
props.project?.code ||
|
||||||
|
evidenceData.projectName ||
|
||||||
|
form.projectName ||
|
||||||
|
'';
|
||||||
form.auditedTarget =
|
form.auditedTarget =
|
||||||
evidenceData.auditedTarget || form.auditedTarget || '';
|
evidenceData.auditedTarget || form.auditedTarget || '';
|
||||||
form.auditMatter = evidenceData.auditMatter || form.auditMatter || '';
|
form.auditMatter = evidenceData.auditMatter || form.auditMatter || '';
|
||||||
@@ -439,7 +480,10 @@
|
|||||||
watch(
|
watch(
|
||||||
() => props.baseInfo,
|
() => props.baseInfo,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
console.log('watch baseInfo triggered, newVal.auditMatterType:', newVal?.auditMatterType);
|
console.log(
|
||||||
|
'watch baseInfo triggered, newVal.auditMatterType:',
|
||||||
|
newVal?.auditMatterType
|
||||||
|
);
|
||||||
if (props.visible) {
|
if (props.visible) {
|
||||||
applyBaseInfo();
|
applyBaseInfo();
|
||||||
}
|
}
|
||||||
@@ -514,7 +558,7 @@
|
|||||||
feedbackDeadline: form.feedbackDeadline,
|
feedbackDeadline: form.feedbackDeadline,
|
||||||
history: '' // 历史内容,如果需要的话
|
history: '' // 历史内容,如果需要的话
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('=== 保存取证单 ===');
|
console.log('=== 保存取证单 ===');
|
||||||
console.log('form:', form);
|
console.log('form:', form);
|
||||||
console.log('form.auditMatterType:', form.auditMatterType);
|
console.log('form.auditMatterType:', form.auditMatterType);
|
||||||
@@ -582,7 +626,9 @@
|
|||||||
link.href = url;
|
link.href = url;
|
||||||
|
|
||||||
// 设置文件名
|
// 设置文件名
|
||||||
const fileName = `审计取证单_${form.projectName || '取证单'}_${form.caseIndex || ''}.docx`;
|
const fileName = `审计取证单_${form.projectName || '取证单'}_${
|
||||||
|
form.caseIndex || ''
|
||||||
|
}.docx`;
|
||||||
link.setAttribute('download', fileName);
|
link.setAttribute('download', fileName);
|
||||||
|
|
||||||
// 触发下载
|
// 触发下载
|
||||||
|
|||||||
@@ -80,11 +80,12 @@ const props = defineProps<{
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
interfaceName?: string;
|
interfaceName?: string;
|
||||||
projectId?: number;
|
projectId?: number;
|
||||||
|
chapter?: any; // 当前章节对象
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:visible', visible: boolean): void;
|
(e: 'update:visible', visible: boolean): void;
|
||||||
(e: 'select', record: any): void;
|
(e: 'select', record: any, chapter?: any): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||||
@@ -99,7 +100,11 @@ const datasource: DatasourceFunction = async ({ page, limit, orders }) => {
|
|||||||
if (orders) {
|
if (orders) {
|
||||||
Object.assign(params, orders);
|
Object.assign(params, orders);
|
||||||
}
|
}
|
||||||
console.log(props,'props');
|
|
||||||
|
console.log('===== HistoryModal Props =====', props);
|
||||||
|
console.log('interfaceName:', props.interfaceName);
|
||||||
|
console.log('projectId:', props.projectId);
|
||||||
|
|
||||||
// 使用传入的接口名称进行过滤
|
// 使用传入的接口名称进行过滤
|
||||||
if (props.interfaceName) {
|
if (props.interfaceName) {
|
||||||
params.interfaceName = props.interfaceName;
|
params.interfaceName = props.interfaceName;
|
||||||
@@ -107,6 +112,8 @@ const datasource: DatasourceFunction = async ({ page, limit, orders }) => {
|
|||||||
if (props.projectId) {
|
if (props.projectId) {
|
||||||
params.projectId = props.projectId;
|
params.projectId = props.projectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('查询参数 params:', params);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await pageAiHistory(params);
|
const result = await pageAiHistory(params);
|
||||||
@@ -116,14 +123,23 @@ const datasource: DatasourceFunction = async ({ page, limit, orders }) => {
|
|||||||
let processingTime = '';
|
let processingTime = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// responseData 直接就是 AI 生成的文本内容,不是 JSON 对象
|
||||||
|
// 这里只是为了统计展示信息,不影响主要内容显示
|
||||||
if (record.responseData) {
|
if (record.responseData) {
|
||||||
const responseData = JSON.parse(record.responseData);
|
// 尝试解析是否为 JSON 格式(兼容旧数据)
|
||||||
if (responseData.data && Array.isArray(responseData.data)) {
|
try {
|
||||||
dataCount = responseData.data.length;
|
const parsed = JSON.parse(record.responseData);
|
||||||
} else if (responseData.data?.data && Array.isArray(responseData.data.data)) {
|
if (parsed.data && Array.isArray(parsed.data)) {
|
||||||
dataCount = responseData.data.data.length;
|
dataCount = parsed.data.length;
|
||||||
|
} else if (parsed.data?.data && Array.isArray(parsed.data.data)) {
|
||||||
|
dataCount = parsed.data.data.length;
|
||||||
|
}
|
||||||
|
processingTime = parsed.processing_time || parsed.generated_time || '';
|
||||||
|
} catch (e) {
|
||||||
|
// 如果不是 JSON,说明是纯文本,不需要统计这些数据
|
||||||
|
dataCount = 0;
|
||||||
|
processingTime = '';
|
||||||
}
|
}
|
||||||
processingTime = responseData.processing_time || responseData.generated_time || '';
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('解析响应数据失败:', error);
|
console.warn('解析响应数据失败:', error);
|
||||||
@@ -258,6 +274,14 @@ const getRequestDataPreview = (record: any) => {
|
|||||||
const hasValidData = (record: any) => {
|
const hasValidData = (record: any) => {
|
||||||
try {
|
try {
|
||||||
if (record.responseData) {
|
if (record.responseData) {
|
||||||
|
// responseData 可能是纯文本(AI 生成的审计报告内容),也可能是 JSON 对象
|
||||||
|
// 对于纯文本,只要有内容就认为有效
|
||||||
|
if (typeof record.responseData === 'string') {
|
||||||
|
// 如果是字符串,检查是否非空
|
||||||
|
return record.responseData.trim().length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是对象,尝试解析 JSON
|
||||||
const responseData = JSON.parse(record.responseData);
|
const responseData = JSON.parse(record.responseData);
|
||||||
const hasData = (responseData.data && Array.isArray(responseData.data) && responseData.data.length > 0) ||
|
const hasData = (responseData.data && Array.isArray(responseData.data) && responseData.data.length > 0) ||
|
||||||
(responseData.data?.data && Array.isArray(responseData.data.data) && responseData.data.data.length > 0);
|
(responseData.data?.data && Array.isArray(responseData.data.data) && responseData.data.data.length > 0);
|
||||||
@@ -265,13 +289,15 @@ const hasValidData = (record: any) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('检查数据有效性失败:', error);
|
console.warn('检查数据有效性失败:', error);
|
||||||
|
// 如果解析失败,但有 responseData 字符串,也认为有效(说明是纯文本)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelect = (record: any) => {
|
const handleSelect = (record: any) => {
|
||||||
if (!hasValidData(record)) return;
|
if (!hasValidData(record)) return;
|
||||||
emit('select', record);
|
emit('select', record, props.chapter);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -170,45 +170,34 @@
|
|||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- 单内容部分 -->
|
<!-- 单内容部分 -->
|
||||||
<template v-if="!item.children">
|
<template v-if="!item.children">
|
||||||
<a-textarea
|
<div class="content-with-ai-button">
|
||||||
v-model:value="item.content"
|
<a-textarea
|
||||||
:rows="item.rows || 8"
|
v-model:value="item.content"
|
||||||
:placeholder="'点击(AI生成)按钮让AI为您生成该部分内容,或直接填入'"
|
:rows="item.rows || 8"
|
||||||
class="content-textarea"
|
:placeholder="'点击 (AI 生成) 按钮让 AI 为您生成该部分内容,或直接填入'"
|
||||||
style="margin-top: 16px; background-color: #f0fdf4"
|
class="content-textarea"
|
||||||
/>
|
style="background-color: #f0fdf4"
|
||||||
|
/>
|
||||||
<div style="margin-top: 12px;">
|
<a-button
|
||||||
<div class="question-prompt">AI小助手</div>
|
type="primary"
|
||||||
<div class="textarea-with-button" style="width: 600px">
|
size="large"
|
||||||
<a-textarea
|
@click="generateContent(index)"
|
||||||
v-model:value="item.suggestion"
|
:loading="item.generating"
|
||||||
:rows="3"
|
class="ai-generate-btn"
|
||||||
placeholder="请输入您的要求并回车..."
|
>
|
||||||
class="suggestion-textarea-inner"
|
<template #icon>
|
||||||
@pressEnter="generateContent(index)"
|
<RobotOutlined/>
|
||||||
/>
|
</template>
|
||||||
<a-button
|
AI 生成
|
||||||
type="danger"
|
</a-button>
|
||||||
size="small"
|
|
||||||
@click="generateContent(index)"
|
|
||||||
:loading="item.generating"
|
|
||||||
class="send-button-inner"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<RobotOutlined/>
|
|
||||||
</template>
|
|
||||||
发送
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 多内容部分 -->
|
<!-- 多内容部分 -->
|
||||||
<template v-else>
|
<template v-if="item.children">
|
||||||
<div v-for="(child, childIndex) in item.children" :key="childIndex" class="child-section" style="border-left: 3px solid #1890ff; padding-left: 16px; margin-bottom: 20px;">
|
<div v-for="(child, childIndex) in item.children" :key="childIndex" class="child-section">
|
||||||
<div class="child-title" style="display: flex; align-items: center; justify-content: space-between;">
|
<div class="child-header">
|
||||||
<span style="font-weight: bold;">{{ child.name }}</span>
|
<span class="child-title">{{ `(${childIndex + 1})${child.name}` }}</span>
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -236,10 +225,10 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="large"
|
||||||
@click.stop="generateContent(index, childIndex)"
|
@click.stop="generateContent(index, childIndex)"
|
||||||
:loading="child.generating"
|
:loading="child.generating"
|
||||||
class="child-action-button ai-generate-button"
|
class="ai-generate-btn"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<RobotOutlined/>
|
<RobotOutlined/>
|
||||||
@@ -253,34 +242,8 @@
|
|||||||
:rows="child.rows || 6"
|
:rows="child.rows || 6"
|
||||||
:placeholder="child.placeholder"
|
:placeholder="child.placeholder"
|
||||||
class="content-textarea"
|
class="content-textarea"
|
||||||
style="margin-top: 12px; background-color: #f0fdf4"
|
style="background-color: #f0fdf4"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- AI小助手功能 -->
|
|
||||||
<div style="margin-top: 12px">
|
|
||||||
<div class="question-prompt">AI小助手</div>
|
|
||||||
<div class="textarea-with-button" style="width: 600px">
|
|
||||||
<a-textarea
|
|
||||||
v-model:value="child.suggestion"
|
|
||||||
:rows="3"
|
|
||||||
placeholder="请输入优化提示词并回车..."
|
|
||||||
class="suggestion-textarea-inner"
|
|
||||||
@pressEnter="generateContent(index, childIndex)"
|
|
||||||
/>
|
|
||||||
<a-button
|
|
||||||
type="danger"
|
|
||||||
size="small"
|
|
||||||
@click="generateContent(index, childIndex)"
|
|
||||||
:loading="child.generating"
|
|
||||||
class="send-button-inner"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<RobotOutlined/>
|
|
||||||
</template>
|
|
||||||
发送
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-card>
|
</a-card>
|
||||||
@@ -1807,24 +1770,68 @@ export default {
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-with-ai-button {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.ant-textarea {
|
||||||
|
min-height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-generate-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
z-index: 10;
|
||||||
|
background-color: #722ed1 !important;
|
||||||
|
border-color: #722ed1 !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #9254de !important;
|
||||||
|
border-color: #9254de !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(114, 46, 209, 0.4) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.child-section {
|
.child-section {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
border-bottom: 1px dashed #e8e8e8;
|
border-bottom: 1px dashed #e8e8e8;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.child-title {
|
.child-header {
|
||||||
font-weight: 600;
|
display: flex;
|
||||||
font-size: 15px;
|
align-items: center;
|
||||||
color: #333;
|
justify-content: space-between;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 12px;
|
||||||
padding-left: 8px;
|
padding: 12px 16px;
|
||||||
border-left: 3px solid #1890ff;
|
background: #f5f7fa;
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
border-left: 3px solid #1890ff;
|
||||||
|
|
||||||
|
.child-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-generate-btn {
|
||||||
|
background-color: #722ed1 !important;
|
||||||
|
border-color: #722ed1 !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #9254de !important;
|
||||||
|
border-color: #9254de !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(114, 46, 209, 0.4) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-textarea {
|
.content-textarea {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user