Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
V
Vue-Dashboard
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
高源
Vue-Dashboard
Commits
8cbb38c2
Commit
8cbb38c2
authored
Jun 19, 2025
by
Neo Turing
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 更新LAC文件列表视图和文件审核组件
parent
4ff0ebd7
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
252 additions
and
156 deletions
+252
-156
fileListView.vue
src/views/Lac/codes/fileListView.vue
+18
-3
fileReview.vue
src/views/Lac/codes/fileReview.vue
+234
-153
No files found.
src/views/Lac/codes/fileListView.vue
View file @
8cbb38c2
...
@@ -101,7 +101,11 @@
...
@@ -101,7 +101,11 @@
</n-descriptions-item>
</n-descriptions-item>
</n-descriptions>
</n-descriptions>
<div
class=
"modal-footer"
>
<div
class=
"modal-footer"
>
<n-button
type=
"primary"
@
click=
"downloadSingleFile(currentFile!)"
>
<n-button
type=
"primary"
@
click=
"currentFile && downloadSingleFile(currentFile)"
:disabled=
"!currentFile"
>
下载文件
下载文件
</n-button>
</n-button>
<n-button
@
click=
"showPreviewModal = false"
>
<n-button
@
click=
"showPreviewModal = false"
>
...
@@ -115,7 +119,7 @@
...
@@ -115,7 +119,7 @@
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
h
,
ref
,
computed
,
resolveComponent
,
watch
,
withDefaults
,
onBeforeUnmount
}
from
'vue'
;
import
{
h
,
ref
,
computed
,
resolveComponent
,
watch
,
withDefaults
,
onBeforeUnmount
}
from
'vue'
;
import
type
{
DataTableColumns
}
from
'naive-ui'
;
//
import type { DataTableColumns } from 'naive-ui';
interface
FileItem
{
interface
FileItem
{
Kvid
:
string
;
Kvid
:
string
;
...
@@ -650,8 +654,19 @@ function formatFileSize(size: number): string {
...
@@ -650,8 +654,19 @@ function formatFileSize(size: number): string {
// 关闭并传递文件数据
// 关闭并传递文件数据
function closeWithFileData() {
function closeWithFileData() {
emit('update-files', fileData.value);
emit('update-files', fileData.value);
emit('close');
emit('close', fileData.value); // 在关闭时传递当前的文件数据
}
// 获取当前文件列表的方法
function getCurrentFileList() {
return fileData.value;
}
}
// 暴露方法给父组件使用
defineExpose({
getCurrentFileList,
fileData
});
</
script
>
</
script
>
<
style
scoped
>
<
style
scoped
>
...
...
src/views/Lac/codes/fileReview.vue
View file @
8cbb38c2
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
defineEmits
,
defineProps
,
h
,
reactive
,
onMounted
,
withDefaults
,
ref
,
resolveComponent
,
watch
}
from
'vue'
;
import
{
computed
,
defineEmits
,
defineProps
,
h
,
reactive
,
onMounted
,
withDefaults
,
ref
,
resolveComponent
,
watch
}
from
'vue'
;
import
FileListView
from
'./fileListView.vue'
;
// '/codes
/fileListView.vue';
import
FileListView
from
'./fileListView.vue'
;
//'/codes/Vue3/Lab/FileListView.vue'; //'.
/fileListView.vue';
// 主体框架内置的第三方方法通过window对象暴露、供外部组件使用
// 主体框架内置的第三方方法通过window对象暴露、供外部组件使用
const
axios
=
(
window
as
any
).
$axios
;
const
axios
=
(
window
as
any
).
$axios
;
...
@@ -12,18 +12,6 @@ const message = (window as any).$message;
...
@@ -12,18 +12,6 @@ const message = (window as any).$message;
const
dialog
=
(
window
as
any
).
$dialog
;
const
dialog
=
(
window
as
any
).
$dialog
;
// 通过计算属性确定当前的主体色
// 通过计算属性确定当前的主体色
const
isDarkMode
=
computed
(()
=>
themeStore
?.
darkMode
||
false
);
const
isDarkMode
=
computed
(()
=>
themeStore
?.
darkMode
||
false
);
// 根据主题计算文字颜色
const
textColor
=
computed
(()
=>
(
isDarkMode
.
value
?
'rgba(255, 255, 255, 0.85)'
:
'rgba(0, 0, 0, 0.85)'
));
const
legendTextColor
=
computed
(()
=>
(
isDarkMode
.
value
?
'rgba(255, 255, 255, 0.65)'
:
'rgba(0, 0, 0, 0.65)'
));
const
borderColor
=
computed
(()
=>
(
isDarkMode
.
value
?
'#303030'
:
'#ffffff'
));
// CSS变量
const
cssVars
=
computed
(()
=>
({
'--text-color'
:
textColor
.
value
,
'--bg-color'
:
isDarkMode
.
value
?
'#1f1f1f'
:
'#f5f5f5'
,
'--panel-bg'
:
isDarkMode
.
value
?
'#262626'
:
'#ffffff'
,
'--card-bg'
:
isDarkMode
.
value
?
'#303030'
:
'#ffffff'
,
'--border-color'
:
isDarkMode
.
value
?
'#434343'
:
'#e8e8e8'
}));
// 修改FileItem接口,但保留原有字段
// 修改FileItem接口,但保留原有字段
interface
FileItem
{
interface
FileItem
{
...
@@ -37,7 +25,7 @@ interface FileItem {
...
@@ -37,7 +25,7 @@ interface FileItem {
Description
?:
string
;
Description
?:
string
;
StatusType
?:
string
;
StatusType
?:
string
;
ReportKvid
?:
string
;
ReportKvid
?:
string
;
[
key
:
string
]:
any
;
// 添加索引签名,以支持可能出现的其他字段
[
key
:
string
]:
any
;
}
}
// 定义Item对象的接口
// 定义Item对象的接口
...
@@ -50,7 +38,7 @@ interface ItemProps {
...
@@ -50,7 +38,7 @@ interface ItemProps {
const
props
=
withDefaults
(
const
props
=
withDefaults
(
defineProps
<
{
defineProps
<
{
item
?:
ItemProps
;
item
?:
ItemProps
;
active
?:
boolean
;
// 新增:是否激活状态,用于按需加载
active
?:
boolean
;
}
>
(),
}
>
(),
{
{
item
:
()
=>
({}),
item
:
()
=>
({}),
...
@@ -59,30 +47,82 @@ const props = withDefaults(
...
@@ -59,30 +47,82 @@ const props = withDefaults(
);
);
// 状态变量
// 状态变量
const
titleOptions
=
ref
<
any
[]
>
([]);
const
titleOptions
=
ref
<
any
[]
>
([]);
const
selectedStandard
=
reactive
<
any
>
({});
// 存储选中的完整对象
/**
const
fileData
=
ref
<
FileItem
[]
>
([]);
// 改回ref,避免过度响应式
* 🔸 选中的标准对象(可能未充分使用)
* @description 存储选中文件类型的完整对象信息
* @usage ⚠️ 在handleTitleChange中填充,但后续业务逻辑中使用频率较低
*/
const
selectedStandard
=
reactive
<
any
>
({});
/**
* 文件审核数据列表
* @description 存储当前显示的所有文件审核记录
*/
const
fileData
=
ref
<
FileItem
[]
>
([]);
/**
* 加载状态标识
* @description 控制各种异步操作的加载状态显示
*/
const
loading
=
ref
<
boolean
>
(
false
);
const
loading
=
ref
<
boolean
>
(
false
);
// 存储API返回的详细数据
/**
* 存储从props传入的详细数据
* @description 保存父组件传递的item数据的响应式副本
*/
const
detailedData
=
reactive
<
ItemProps
>
({});
const
detailedData
=
reactive
<
ItemProps
>
({});
// 控制fileListView模态框显示
/**
* 控制FileListView模态框显示状态
* @description 控制文件管理模态框的开关
*/
const
showFileListView
=
ref
<
boolean
>
(
false
);
const
showFileListView
=
ref
<
boolean
>
(
false
);
// 存储当前选中的文件行数据
/**
* 当前选中的文件行数据
* @description 存储用户点击查看的文件行完整数据
*/
const
currentFileRow
=
ref
<
FileItem
|
null
>
(
null
);
const
currentFileRow
=
ref
<
FileItem
|
null
>
(
null
);
// 使用ref来避免计算属性的循环更新问题
/**
* FileListView组件引用
* @description 用于调用子组件的方法和访问子组件数据
*/
const
fileListViewRef
=
ref
<
any
>
(
null
);
/**
* 🔸 选中的标准Kvid(可能未充分使用)
* @description 存储当前选择的文件类型ID
* @usage ⚠️ 主要在handleTitleChange和fetchFileDetails中使用
*/
const
selectedStandardKvid
=
ref
<
string
>
(
''
);
const
selectedStandardKvid
=
ref
<
string
>
(
''
);
// 计算是否有数据存在,用于控制NSelect状态
/**
* 计算是否存在文件数据
* @description 用于控制文件类型选择器的禁用状态和清空按钮的显示
* @returns {boolean} 是否有现有的文件审核数据
* @usage 控制NSelect的disabled状态和清空按钮的显示条件
*/
const
hasExistingData
=
computed
(()
=>
{
const
hasExistingData
=
computed
(()
=>
{
return
fileData
.
value
.
length
>
0
;
return
fileData
.
value
.
length
>
0
;
});
});
// 根据选择的标题筛选数据 - 优化性能
/**
* 🔸 过滤后的数据(当前无过滤逻辑)
* @description 原计划用于数据过滤,当前直接返回所有数据
* @returns {FileItem[]} 文件数据数组
* @usage ⚠️ 绑定到NDataTable的:data属性,但无实际过滤功能
*/
const
filteredData
=
computed
(()
=>
{
const
filteredData
=
computed
(()
=>
{
return
fileData
.
value
;
return
fileData
.
value
;
});
});
// 辅助函数:将API的StatusType映射为显示状态
/**
* 状态类型映射函数
* @description 将API返回的StatusType字符串映射为中文显示状态
* @param {string} statusType - API返回的状态类型字符串
* @returns {string} 对应的中文状态显示名称
* @usage 在数据处理和状态显示时使用
*/
const
mapStatusType
=
(
statusType
:
string
)
=>
{
const
mapStatusType
=
(
statusType
:
string
)
=>
{
const
statusMap
:
{
[
key
:
string
]:
string
}
=
{
const
statusMap
:
{
[
key
:
string
]:
string
}
=
{
Unsupported
:
'草稿'
,
Unsupported
:
'草稿'
,
...
@@ -96,21 +136,33 @@ const mapStatusType = (statusType: string) => {
...
@@ -96,21 +136,33 @@ const mapStatusType = (statusType: string) => {
return
statusMap
[
statusType
]
||
'草稿'
;
return
statusMap
[
statusType
]
||
'草稿'
;
};
};
// 辅助函数:根据状态获取颜色
/**
* 状态颜色获取函数
* @description 根据状态类型返回对应的UI显示颜色
* @param {string} status - 状态类型字符串
* @returns {string} 对应状态的十六进制颜色值
* @usage 在表格和标签组件中设置状态颜色
*/
const
getStatusColor
=
(
status
:
string
)
=>
{
const
getStatusColor
=
(
status
:
string
)
=>
{
const
statusColorMap
:
{
[
key
:
string
]:
string
}
=
{
const
statusColorMap
:
{
[
key
:
string
]:
string
}
=
{
BeforeTest
:
'#f56a00'
,
// 橙色 - 待处理
BeforeTest
:
'#f56a00'
,
Asigning
:
'#1890ff'
,
// 蓝色 - 进行中
Asigning
:
'#1890ff'
,
Testing
:
'#722ed1'
,
// 紫色 - 重要评审
Testing
:
'#722ed1'
,
BeforeReview
:
'#eb2f96'
,
// 粉红色 - 测试阶段
BeforeReview
:
'#eb2f96'
,
TestFinished
:
'#13c2c2'
,
// 青色 - 即将完成
TestFinished
:
'#13c2c2'
,
TestCollected
:
'#52c41a'
// 绿色 - 已完成
TestCollected
:
'#52c41a'
};
};
return
statusColorMap
[
status
]
||
'#666'
;
return
statusColorMap
[
status
]
||
'#666'
;
};
};
// 状态映射函数(为模态框标题使用)
/**
const
getStatusInfo
=
(
status
:
number
)
=>
{
* 状态信息获取函数
* @description 根据数字状态码返回包含标签、颜色和类型的状态信息对象
* @param {any} status - 数字状态码
* @returns {object} 包含label、color、type的状态信息对象
* @usage 主要用于模态框标题和状态标签显示
*/
const
getStatusInfo
=
(
status
:
any
)
=>
{
const
statusMap
=
{
const
statusMap
=
{
0
:
{
label
:
'草稿'
,
color
:
'#909399'
,
type
:
'default'
},
0
:
{
label
:
'草稿'
,
color
:
'#909399'
,
type
:
'default'
},
100
:
{
label
:
'待上传'
,
color
:
'#E6A23C'
,
type
:
'warning'
},
100
:
{
label
:
'待上传'
,
color
:
'#E6A23C'
,
type
:
'warning'
},
...
@@ -118,7 +170,14 @@ const getStatusInfo = (status: number) => {
...
@@ -118,7 +170,14 @@ const getStatusInfo = (status: number) => {
200
:
{
label
:
'审核中'
,
color
:
'#F56C6C'
,
type
:
'error'
},
200
:
{
label
:
'审核中'
,
color
:
'#F56C6C'
,
type
:
'error'
},
250
:
{
label
:
'待复核'
,
color
:
'#722ED1'
,
type
:
'warning'
},
250
:
{
label
:
'待复核'
,
color
:
'#722ED1'
,
type
:
'warning'
},
300
:
{
label
:
'不通过'
,
color
:
'#FF7A45'
,
type
:
'error'
},
300
:
{
label
:
'不通过'
,
color
:
'#FF7A45'
,
type
:
'error'
},
2147483647
:
{
label
:
'已通过'
,
color
:
'#67C23A'
,
type
:
'success'
}
2147483647
:
{
label
:
'已通过'
,
color
:
'#67C23A'
,
type
:
'success'
},
Unsupported
:
{
label
:
'草稿'
,
color
:
'#909399'
,
type
:
'default'
},
BeforeTest
:
{
label
:
'待上传'
,
color
:
'#E6A23C'
,
type
:
'warning'
},
Asigning
:
{
label
:
'已上传'
,
color
:
'#409EFF'
,
type
:
'info'
},
Testing
:
{
label
:
'审核中'
,
color
:
'#F56C6C'
,
type
:
'error'
},
BeforeReview
:
{
label
:
'待复核'
,
color
:
'#722ED1'
,
type
:
'warning'
},
TestFinished
:
{
label
:
'不通过'
,
color
:
'#FF7A45'
,
type
:
'error'
},
TestCollected
:
{
label
:
'已通过'
,
color
:
'#67C23A'
,
type
:
'success'
}
};
};
return
statusMap
[
status
as
keyof
typeof
statusMap
]
||
{
return
statusMap
[
status
as
keyof
typeof
statusMap
]
||
{
...
@@ -128,49 +187,52 @@ const getStatusInfo = (status: number) => {
...
@@ -128,49 +187,52 @@ const getStatusInfo = (status: number) => {
};
};
};
};
// 计算当前行的只读状态
/**
* 🔸 计算当前行的只读状态(可能未使用)
* @description 判断当前选中行是否为只读状态(状态值大于150)
* @returns {boolean} 是否为只读状态
* @usage ⚠️ 在模板中可能被引用,但实际业务逻辑中可能不需要
*/
const
isCurrentRowReadonly
=
computed
(()
=>
{
const
isCurrentRowReadonly
=
computed
(()
=>
{
return
currentFileRow
.
value
&&
currentFileRow
.
value
.
Status
>
150
;
return
currentFileRow
.
value
&&
currentFileRow
.
value
.
Status
>
150
;
});
});
// 获取文件类型数据
/**
* 获取文件类型选项数据
* @description 从标准实体接口查询文件审核类型数据,用于下拉选择器
* @returns {Promise<void>} 无返回值,结果存储在titleOptions.value中
* @usage 在组件初始化和激活时调用,用于填充文件类型下拉选择器
*/
async
function
fetchTitleOptions
()
{
async
function
fetchTitleOptions
()
{
console
.
log
(
'🔄 FileReview: 开始加载文件类型数据'
);
try
{
try
{
loading
.
value
=
true
;
loading
.
value
=
true
;
// 调用标准实体查询接口
const
response
=
await
axios
.
post
(
'/Restful/Kivii.Standards.Entities.Standard/Query.json?Type=文件审核'
);
const
response
=
await
axios
.
post
(
'/Restful/Kivii.Standards.Entities.Standard/Query.json?Type=文件审核'
);
// console.log('完整响应数据:', response.data);
// 添加数据存在性检查
if
(
response
.
data
&&
response
.
data
.
Results
)
{
if
(
response
.
data
&&
response
.
data
.
Results
)
{
// 将API返回的数据转换为NSelect需要的格式
titleOptions
.
value
=
response
.
data
.
Results
.
map
((
item
:
any
,
index
:
number
)
=>
({
titleOptions
.
value
=
response
.
data
.
Results
.
map
((
item
:
any
,
index
:
number
)
=>
({
label
:
item
.
Title
,
label
:
item
.
Title
,
value
:
item
.
Kvid
,
value
:
item
.
Kvid
,
// 可以选择以下任一方式存储完整对象信息:
// 方式1:直接将完整对象作为额外属性
fullObject
:
item
fullObject
:
item
}));
}));
}
else
{
}
else
{
// console.error('无效的数据格式:', response.data);
message
.
error
(
'数据格式不正确'
);
message
.
error
(
'数据格式不正确'
);
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
message
.
error
(
'获取文件类型失败'
);
message
.
error
(
'获取文件类型失败'
);
// console.error('获取文件类型失败:', error);
}
finally
{
}
finally
{
loading
.
value
=
false
;
loading
.
value
=
false
;
}
}
}
}
// 获取文件详情数据
/**
* 🔸 获取文件详情数据(可能未使用)
* @description 基于选中的标准Kvid创建文件审核数据记录
* @returns {Promise<void>} 无返回值,结果存储在fileData.value中
* @usage ⚠️ 当前代码中通过handleTitleChange调用,但实际业务流程可能不使用此方法
*/
async
function
fetchFileDetails
()
{
async
function
fetchFileDetails
()
{
if
(
!
selectedStandardKvid
.
value
)
return
;
if
(
!
selectedStandardKvid
.
value
)
return
;
// 如果数据已存在,直接返回(UI已有提示)
if
(
fileData
.
value
.
length
>
0
)
{
if
(
fileData
.
value
.
length
>
0
)
{
return
;
return
;
}
}
...
@@ -194,10 +256,7 @@ async function fetchFileDetails() {
...
@@ -194,10 +256,7 @@ async function fetchFileDetails() {
const
resp
=
await
axios
.
post
(
'/Restful/Kivii.Lims.Entities.ReportItem/Detection.json'
,
data
);
const
resp
=
await
axios
.
post
(
'/Restful/Kivii.Lims.Entities.ReportItem/Detection.json'
,
data
);
if
(
resp
.
data
&&
resp
.
data
.
Results
){
if
(
resp
.
data
&&
resp
.
data
.
Results
){
fileData
.
value
=
resp
.
data
.
Results
.
map
((
item
:
any
)
=>
({
fileData
.
value
=
resp
.
data
.
Results
.
map
((
item
:
any
)
=>
({
// 直接使用API字段名
...
item
,
...
item
,
// 保留转换后的自定义字段
Status
:
mapStatusType
(
item
.
StatusType
),
Status
:
mapStatusType
(
item
.
StatusType
),
StatusColor
:
getStatusColor
(
item
.
StatusType
)
StatusColor
:
getStatusColor
(
item
.
StatusType
)
}));
}));
...
@@ -209,42 +268,39 @@ async function fetchFileDetails() {
...
@@ -209,42 +268,39 @@ async function fetchFileDetails() {
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
message
.
error
(
'获取文件详情失败'
);
message
.
error
(
'获取文件详情失败'
);
// console.error(error);
}
finally
{
}
finally
{
loading
.
value
=
false
;
loading
.
value
=
false
;
}
}
}
}
// 使用报告Kvid获取数据
/**
* 根据报告Kvid获取文件审核数据
* @description 使用报告ID查询已存在的文件审核数据记录
* @param {string} reportKvid - 报告的唯一标识符
* @returns {Promise<void>} 无返回值,结果存储在fileData.value中
* @usage 在组件初始化和props变化时调用,获取现有的文件审核数据
*/
async
function
fetchDataByReportKvid
(
reportKvid
:
string
)
{
async
function
fetchDataByReportKvid
(
reportKvid
:
string
)
{
if
(
!
reportKvid
)
return
;
if
(
!
reportKvid
)
return
;
if
(
reportKvid
===
detailedData
.
Kvid
&&
fileData
.
value
.
length
>
0
)
{
if
(
reportKvid
===
detailedData
.
Kvid
&&
fileData
.
value
.
length
>
0
)
{
console
.
log
(
'🔄 FileReview: 跳过重复请求,使用已缓存的数据'
);
return
;
return
;
}
}
console
.
log
(
'🔄 FileReview: 开始获取文件审核数据,ReportKvid:'
,
reportKvid
);
try
{
try
{
loading
.
value
=
true
;
loading
.
value
=
true
;
const
response
=
await
axios
.
post
(
'/Restful/Kivii.Lims.Entities.ReportItem/QueryEx.json'
,
{
const
response
=
await
axios
.
get
(
'/Restful/Kivii.Lims.Entities.ReportItem/QueryEx.json'
,
{
params
:
{
ReportKvid
:
reportKvid
,
ReportKvid
:
reportKvid
,
OrderBy
:
'SortId,SortIdEx,Kvid'
,
OrderBy
:
'SortId,SortIdEx,Kvid'
,
WorkGroupName
:
'文件审核'
WorkGroupName
:
'文件审核'
}
});
});
if
(
response
.
data
&&
response
.
data
.
Results
&&
response
.
data
.
Results
.
length
>
0
)
{
if
(
response
.
data
&&
response
.
data
.
Results
&&
response
.
data
.
Results
.
length
>
0
)
{
// 直接使用API返回的数据
// fileData.value = response.data.Results;
// fileData.value.forEach((item: any) => {
// item.StatusType = mapStatusType(item.StatusType);
// });
fileData
.
value
=
response
.
data
.
Results
.
map
((
item
:
any
)
=>
({
fileData
.
value
=
response
.
data
.
Results
.
map
((
item
:
any
)
=>
({
// 直接使用API字段名
...
item
,
...
item
,
// 保留转换后的自定义字段
Status
:
mapStatusType
(
item
.
StatusType
),
Status
:
mapStatusType
(
item
.
StatusType
),
StatusColor
:
getStatusColor
(
item
.
StatusType
)
StatusColor
:
getStatusColor
(
item
.
StatusType
)
}));
}));
...
@@ -253,25 +309,27 @@ async function fetchDataByReportKvid(reportKvid: string) {
...
@@ -253,25 +309,27 @@ async function fetchDataByReportKvid(reportKvid: string) {
message
.
info
(
'暂无文件审核数据'
);
message
.
info
(
'暂无文件审核数据'
);
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
// console.error('获取文件审核数据失败:', error);
message
.
error
(
'获取文件审核数据失败,请稍后重试'
);
message
.
error
(
'获取文件审核数据失败,请稍后重试'
);
}
finally
{
}
finally
{
loading
.
value
=
false
;
loading
.
value
=
false
;
}
}
}
}
// 处理标题选择变化
/**
* 🔸 处理文件类型选择变化(可能未使用)
* @description 当用户选择不同的文件类型时触发,同步选中值并获取详情
* @param {string} value - 选中的文件类型Kvid
* @returns {void} 无返回值
* @usage ⚠️ 绑定到NSelect的@update:value事件,但实际业务可能不需要此功能
*/
function
handleTitleChange
(
value
:
string
)
{
function
handleTitleChange
(
value
:
string
)
{
selectedStandardKvid
.
value
=
value
;
// 同步选中值
selectedStandardKvid
.
value
=
value
;
// 获取选中项的完整对象信息
const
selectedOption
=
titleOptions
.
value
.
find
(
option
=>
option
.
value
===
value
);
const
selectedOption
=
titleOptions
.
value
.
find
(
option
=>
option
.
value
===
value
);
if
(
selectedOption
)
{
if
(
selectedOption
)
{
// 清空现有属性
Object
.
keys
(
selectedStandard
).
forEach
(
key
=>
{
Object
.
keys
(
selectedStandard
).
forEach
(
key
=>
{
delete
selectedStandard
[
key
];
delete
selectedStandard
[
key
];
});
});
// 添加新属性
Object
.
keys
(
selectedOption
.
fullObject
).
forEach
(
key
=>
{
Object
.
keys
(
selectedOption
.
fullObject
).
forEach
(
key
=>
{
selectedStandard
[
key
]
=
selectedOption
.
fullObject
[
key
];
selectedStandard
[
key
]
=
selectedOption
.
fullObject
[
key
];
});
});
...
@@ -294,25 +352,20 @@ watch(
...
@@ -294,25 +352,20 @@ watch(
);
);
// 页面加载时按需获取数据
onMounted
(()
=>
{
onMounted
(()
=>
{
// 只有在激活状态下才加载数据
if
(
props
.
active
)
{
if
(
props
.
active
)
{
fetchTitleOptions
();
fetchTitleOptions
();
// 如果有kvid,获取数据
if
(
props
.
item
&&
props
.
item
.
Kvid
&&
props
.
item
.
Kvid
!==
detailedData
.
Kvid
)
{
if
(
props
.
item
&&
props
.
item
.
Kvid
&&
props
.
item
.
Kvid
!==
detailedData
.
Kvid
)
{
fetchDataByReportKvid
(
props
.
item
.
Kvid
);
fetchDataByReportKvid
(
props
.
item
.
Kvid
);
}
}
}
}
});
});
// 监听active属性变化,实现按需加载
watch
(
watch
(
()
=>
props
.
active
,
()
=>
props
.
active
,
(
newActive
)
=>
{
(
newActive
)
=>
{
if
(
newActive
&&
titleOptions
.
value
.
length
===
0
)
{
if
(
newActive
&&
titleOptions
.
value
.
length
===
0
)
{
// 第一次激活且数据未加载时,加载数据
fetchTitleOptions
();
fetchTitleOptions
();
if
(
props
.
item
&&
props
.
item
.
Kvid
&&
props
.
item
.
Kvid
!==
detailedData
.
Kvid
)
{
if
(
props
.
item
&&
props
.
item
.
Kvid
&&
props
.
item
.
Kvid
!==
detailedData
.
Kvid
)
{
...
@@ -323,25 +376,17 @@ watch(
...
@@ -323,25 +376,17 @@ watch(
{
immediate
:
true
}
{
immediate
:
true
}
);
);
// 存储最新的文件列表数据
/**
* 🔸 最新文件列表数据(备用存储)
* @description 备用存储FileListView的实时文件数据,主要通过关闭事件获取数据
* @usage ⚠️ 作为数据同步的备用方案,当前主要逻辑已转移到handleModalClose
*/
const
latestFileListData
=
ref
<
any
[]
>
([]);
const
latestFileListData
=
ref
<
any
[]
>
([]);
// 监听FileListView模态框的显示状态
/**
watch
(
* 表格列配置定义
()
=>
showFileListView
.
value
,
* @description 定义NDataTable的列结构、渲染方式和操作按钮
(
newValue
,
oldValue
)
=>
{
*/
// 当模态框从显示变为隐藏时
if
(
oldValue
===
true
&&
newValue
===
false
)
{
console
.
log
(
'FileListView模态框已关闭,最新文件数据:'
,
latestFileListData
.
value
);
// 这里可以添加您需要的其他处理逻辑
// 例如:调用API保存数据、更新其他组件状态等
handleFileListClosed
(
latestFileListData
.
value
);
}
}
);
// 表格列定义
const
columns
=
ref
<
any
[]
>
([
const
columns
=
ref
<
any
[]
>
([
{
{
title
:
'序号'
,
title
:
'序号'
,
...
@@ -442,20 +487,26 @@ const columns = ref<any[]>([
...
@@ -442,20 +487,26 @@ const columns = ref<any[]>([
}
}
]);
]);
// 查看文件
/**
* 查看文件详情
* @description 打开文件列表模态框,显示指定行的文件详情和管理界面
* @param {FileItem} row - 选中的文件行数据
* @returns {void} 无返回值
* @usage 绑定到表格操作列的"附件"按钮点击事件
*/
function
viewFile
(
row
:
FileItem
)
{
function
viewFile
(
row
:
FileItem
)
{
// 将整个row数据存储到currentFileRow中
currentFileRow
.
value
=
row
;
currentFileRow
.
value
=
row
;
console
.
log
(
'传递给FileListView的数据:'
,
row
);
// 清空之前的文件列表数据
latestFileListData
.
value
=
[];
latestFileListData
.
value
=
[];
// 显示模态框
showFileListView
.
value
=
true
;
showFileListView
.
value
=
true
;
}
}
// 封装删除实体的方法
/**
* 批量删除实体数据
* @description 通用的删除方法,支持批量删除多个文件审核记录
* @param {string[]} kvids - 要删除的记录ID数组
* @returns {Promise<boolean>} 删除操作是否成功
* @usage 被deleteFileRecord和clearAllFileData方法调用
*/
async
function
deleteEntities
(
kvids
:
string
[])
{
async
function
deleteEntities
(
kvids
:
string
[])
{
if
(
!
kvids
||
kvids
.
length
===
0
)
{
if
(
!
kvids
||
kvids
.
length
===
0
)
{
message
.
error
(
'请选择要删除的项目'
);
message
.
error
(
'请选择要删除的项目'
);
...
@@ -477,7 +528,6 @@ async function deleteEntities(kvids: string[]) {
...
@@ -477,7 +528,6 @@ async function deleteEntities(kvids: string[]) {
return
false
;
return
false
;
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'删除文件失败:'
,
error
);
message
.
error
(
'删除文件失败,请稍后重试'
);
message
.
error
(
'删除文件失败,请稍后重试'
);
return
false
;
return
false
;
}
finally
{
}
finally
{
...
@@ -485,23 +535,32 @@ async function deleteEntities(kvids: string[]) {
...
@@ -485,23 +535,32 @@ async function deleteEntities(kvids: string[]) {
}
}
}
}
// 删除文件记录
/**
* 删除单个文件记录
* @description 删除表格中指定的单个文件审核记录
* @param {FileItem} row - 要删除的文件行数据
* @returns {Promise<void>} 无返回值
* @usage 绑定到表格操作列的"删除"按钮确认回调
*/
async
function
deleteFileRecord
(
row
:
FileItem
)
{
async
function
deleteFileRecord
(
row
:
FileItem
)
{
if
(
!
row
.
Kvid
)
{
if
(
!
row
.
Kvid
)
{
message
.
error
(
'无效的文件ID'
);
message
.
error
(
'无效的文件ID'
);
return
;
return
;
}
}
// 调用删除接口
const
success
=
await
deleteEntities
([
row
.
Kvid
]);
const
success
=
await
deleteEntities
([
row
.
Kvid
]);
if
(
success
)
{
if
(
success
)
{
// 从列表中移除
fileData
.
value
=
fileData
.
value
.
filter
(
item
=>
item
.
Kvid
!==
row
.
Kvid
);
fileData
.
value
=
fileData
.
value
.
filter
(
item
=>
item
.
Kvid
!==
row
.
Kvid
);
}
}
}
}
// 清空所有文件数据
/**
* 清空所有文件数据
* @description 删除当前列表中的所有文件审核记录,并重置相关状态
* @returns {void} 无返回值
* @usage 绑定到"清空数据"按钮的点击事件
*/
function
clearAllFileData
()
{
function
clearAllFileData
()
{
dialog
.
warning
({
dialog
.
warning
({
title
:
'确认删除'
,
title
:
'确认删除'
,
...
@@ -514,7 +573,6 @@ function clearAllFileData() {
...
@@ -514,7 +573,6 @@ function clearAllFileData() {
return
;
return
;
}
}
// 收集所有Kvid
const
kvids
=
fileData
.
value
.
map
(
item
=>
item
.
Kvid
).
filter
(
kvid
=>
kvid
);
const
kvids
=
fileData
.
value
.
map
(
item
=>
item
.
Kvid
).
filter
(
kvid
=>
kvid
);
if
(
kvids
.
length
===
0
)
{
if
(
kvids
.
length
===
0
)
{
...
@@ -522,13 +580,11 @@ function clearAllFileData() {
...
@@ -522,13 +580,11 @@ function clearAllFileData() {
return
;
return
;
}
}
// 调用删除接口
const
success
=
await
deleteEntities
(
kvids
);
const
success
=
await
deleteEntities
(
kvids
);
if
(
success
)
{
if
(
success
)
{
fileData
.
value
=
[];
fileData
.
value
=
[];
selectedStandardKvid
.
value
=
''
;
selectedStandardKvid
.
value
=
''
;
// 清空selectedStandard对象
Object
.
keys
(
selectedStandard
).
forEach
(
key
=>
{
Object
.
keys
(
selectedStandard
).
forEach
(
key
=>
{
delete
selectedStandard
[
key
];
delete
selectedStandard
[
key
];
});
});
...
@@ -537,44 +593,83 @@ function clearAllFileData() {
...
@@ -537,44 +593,83 @@ function clearAllFileData() {
});
});
}
}
// 处理模态框关闭
/**
* 防重复调用标志
* @description 防止模态框关闭事件重复触发数据处理逻辑
*/
const
isProcessingClose
=
ref
(
false
);
/**
* 处理模态框关闭事件
* @description 模态框关闭后获取FileListView中的文件数据并进行状态更新处理
* @returns {void} 无返回值
* @usage 绑定到NModal的@after-leave事件,防重复调用机制
*/
function
handleModalClose
()
{
function
handleModalClose
()
{
if
(
isProcessingClose
.
value
)
{
return
;
}
try
{
isProcessingClose
.
value
=
true
;
if
(
fileListViewRef
.
value
&&
currentFileRow
.
value
)
{
const
currentFiles
=
fileListViewRef
.
value
.
getCurrentFileList
?.()
||
[];
handleFileListClosed
(
currentFiles
);
}
currentFileRow
.
value
=
null
;
currentFileRow
.
value
=
null
;
}
finally
{
setTimeout
(()
=>
{
isProcessingClose
.
value
=
false
;
},
100
);
}
}
}
// 处理FileListView实时文件列表更新(实时同步数据)
/**
function
handleFileListUpdate
(
files
:
any
[])
{
* 🔸 处理FileListView组件关闭事件(功能简化)
console
.
log
(
'FileReview: 接收到文件列表实时更新'
,
files
);
* @description 简单关闭模态框,实际数据处理由handleModalClose负责
* @param {any[]} files - 可选的文件数据参数(当前未使用)
// 存储最新的文件列表数据,用于界面关闭时处理
* @returns {void} 无返回值
latestFileListData
.
value
=
[...
files
];
// 深拷贝确保数据独立性
* @usage ⚠️ 绑定到FileListView的@close事件,但主要逻辑已转移到handleModalClose
*/
function
handleFileListViewClose
(
files
?:
any
[])
{
showFileListView
.
value
=
false
;
}
console
.
log
(
`📁 实时数据同步:
${
files
.
length
}
个文件`
);
/**
* 🔸 处理FileListView实时文件更新(备用方法)
* @description 实时同步FileListView中的文件数据变化(主要通过关闭事件获取数据)
* @param {any[]} files - 更新的文件数据数组
* @returns {void} 无返回值
* @usage ⚠️ 绑定到FileListView的@update-files事件,作为备用数据同步方式
*/
function
handleFileListUpdate
(
files
:
any
[])
{
latestFileListData
.
value
=
[...
files
];
}
}
// 处理FileListView界面关闭后的数据处理
/**
* 处理FileListView关闭后的数据处理
* @description 根据FileListView中的文件数量自动更新文件审核记录的状态
* @param {any[]} files - 从FileListView获取的文件数据数组
* @returns {Promise<void>} 无返回值
* @usage 被handleModalClose调用,根据文件数量自动设置状态(0个文件=待上传,>0个文件=已上传)
*/
async
function
handleFileListClosed
(
files
:
any
[])
{
async
function
handleFileListClosed
(
files
:
any
[])
{
console
.
log
(
'🔒 FileListView界面已关闭,开始处理文件数据集合'
);
// 检查当前行状态,如果超过150则直接返回
if
(
!
currentFileRow
.
value
||
currentFileRow
.
value
.
Status
>
150
)
{
if
(
!
currentFileRow
.
value
||
currentFileRow
.
value
.
Status
>
150
)
{
console
.
log
(
'⚠️ 当前状态不允许更新,Status:'
,
currentFileRow
.
value
?.
Status
);
return
;
return
;
}
}
const
fileCount
=
files
.
length
;
const
fileCount
=
files
.
length
;
try
{
try
{
// 根据文件数量确定状态值
const
newStatus
=
fileCount
<=
0
?
100
:
150
;
const
newStatus
=
fileCount
<=
0
?
100
:
150
;
if
(
currentFileRow
.
value
.
Status
===
newStatus
){
const
statusInfo
=
getStatusInfo
(
newStatus
);
// message.info('文件状态未发生变化,无需更新');
if
(
currentFileRow
.
value
.
Status
===
statusInfo
.
label
){
return
;
return
;
}
}
console
.
log
(
`📋 准备更新状态: 文件数量=
${
fileCount
}
, 新状态=
${
newStatus
}
`
);
// 调用更新接口
const
response
=
await
axios
.
post
(
'/Restful/Kivii.Lims.Entities.ReportItem/UpdateEx2.json'
,
{
const
response
=
await
axios
.
post
(
'/Restful/Kivii.Lims.Entities.ReportItem/Update.json'
,
{
Item
:
{
Item
:
{
Kvid
:
currentFileRow
.
value
.
Kvid
,
Kvid
:
currentFileRow
.
value
.
Kvid
,
Status
:
newStatus
Status
:
newStatus
...
@@ -582,39 +677,21 @@ async function handleFileListClosed(files: any[]) {
...
@@ -582,39 +677,21 @@ async function handleFileListClosed(files: any[]) {
});
});
if
(
response
.
data
&&
response
.
data
.
Results
&&
response
.
data
.
Results
.
length
>
0
)
{
if
(
response
.
data
&&
response
.
data
.
Results
&&
response
.
data
.
Results
.
length
>
0
)
{
// 更新成功,同步本地状态
currentFileRow
.
value
.
Status
=
newStatus
;
// 同时更新状态显示文本和颜色
const
statusText
=
newStatus
===
100
?
'待上传'
:
'已上传'
;
const
statusText
=
newStatus
===
100
?
'待上传'
:
'已上传'
;
const
statusColor
=
newStatus
===
100
?
'#E6A23C'
:
'#409EFF'
;
currentFileRow
.
value
.
Status
=
statusText
;
currentFileRow
.
value
.
StatusColor
=
statusColor
;
// 在fileData数组中找到对应项并更新
const
itemIndex
=
fileData
.
value
.
findIndex
(
item
=>
item
.
Kvid
===
response
.
data
.
Results
[
0
].
Kvid
);
const
itemIndex
=
fileData
.
value
.
findIndex
(
item
=>
item
.
Kvid
===
currentFileRow
.
value
?.
Kvid
);
if
(
itemIndex
!==
-
1
)
{
if
(
itemIndex
!==
-
1
)
{
fileData
.
value
[
itemIndex
].
Status
=
statusText
;
fileData
.
value
[
itemIndex
].
Status
=
mapStatusType
(
response
.
data
.
Results
[
0
].
StatusType
)
;
fileData
.
value
[
itemIndex
].
StatusColor
=
statusColor
;
fileData
.
value
[
itemIndex
].
StatusColor
=
getStatusColor
(
response
.
data
.
Results
[
0
].
StatusType
)
;
}
}
message
.
success
(
`状态更新成功:
${
statusText
}
(
${
fileCount
}
个文件)`
);
message
.
success
(
`状态更新成功:
${
statusText
}
(
${
fileCount
}
个文件)`
);
console
.
log
(
'✅ 状态更新成功:'
,
{
记录
ID
:
currentFileRow
.
value
.
Kvid
,
文件数量
:
fileCount
,
新状态
:
newStatus
,
状态描述
:
statusText
});
}
else
{
}
else
{
message
.
error
(
'状态更新失败:'
+
(
response
.
data
?.
Message
||
'未知错误'
));
message
.
error
(
'状态更新失败:'
+
(
response
.
data
?.
Message
||
'未知错误'
));
console
.
error
(
'❌ 状态更新失败:'
,
response
.
data
);
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
message
.
error
(
'状态更新失败,请稍后重试'
);
message
.
error
(
'状态更新失败,请稍后重试'
);
console
.
error
(
'❌ 状态更新异常:'
,
error
);
}
}
}
}
</
script
>
</
script
>
...
@@ -695,11 +772,14 @@ async function handleFileListClosed(files: any[]) {
...
@@ -695,11 +772,14 @@ async function handleFileListClosed(files: any[]) {
<n-space
align=
"center"
:size=
"12"
>
<n-space
align=
"center"
:size=
"12"
>
<span
class=
"modal-title-compact"
>
文件详情 -
{{
currentFileRow
?.
Title
||
'文件列表'
}}
</span>
<span
class=
"modal-title-compact"
>
文件详情 -
{{
currentFileRow
?.
Title
||
'文件列表'
}}
</span>
<n-tag
<n-tag
:type=
"getStatusInfo(currentFileRow?.Status || 0).type as any"
:color=
"
{ color: getStatusInfo(currentFileRow?.Status || 0).color }"
size=
"small"
size=
"small"
:style=
"
{
backgroundColor: getStatusInfo(currentFileRow?.Status).color,
color: 'white',
border: 'none'
}"
>
>
{{
getStatusInfo
(
currentFileRow
?.
Status
||
0
).
label
}}
{{
getStatusInfo
(
currentFileRow
?.
Status
).
label
}}
</n-tag>
</n-tag>
<span
v-if=
"isCurrentRowReadonly"
class=
"readonly-hint-modal"
>
<span
v-if=
"isCurrentRowReadonly"
class=
"readonly-hint-modal"
>
(当前状态不允许上传/删除操作)
(当前状态不允许上传/删除操作)
...
@@ -710,8 +790,9 @@ async function handleFileListClosed(files: any[]) {
...
@@ -710,8 +790,9 @@ async function handleFileListClosed(files: any[]) {
<FileListView
<FileListView
v-if=
"currentFileRow"
v-if=
"currentFileRow"
ref=
"fileListViewRef"
:owner-item=
"currentFileRow"
:owner-item=
"currentFileRow"
@
close=
"
showFileListView = fal
se"
@
close=
"
handleFileListViewClo
se"
@
update-files=
"handleFileListUpdate"
@
update-files=
"handleFileListUpdate"
></FileListView>
></FileListView>
</NModal>
</NModal>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment