fix(镜像管理): 国际化配置+layout布局适应+修改逻辑+样式
parent
c6361112fa
commit
4348cfffea
|
@ -8,6 +8,11 @@ export default defineConfig({
|
|||
request: {},
|
||||
layout: false,
|
||||
outputPath: 'serve/dist',
|
||||
locale: {
|
||||
default: 'zh-CN',
|
||||
antd: true, // 启用 antd 国际化
|
||||
baseNavigator: true,
|
||||
},
|
||||
// 路由配置
|
||||
routes: [
|
||||
{
|
||||
|
@ -31,9 +36,9 @@ export default defineConfig({
|
|||
component: '@/pages/userList',
|
||||
},
|
||||
{
|
||||
path:"/terminal",
|
||||
component: '@/pages/terminal',
|
||||
}
|
||||
path: '/terminal',
|
||||
component: '@/pages/terminal',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"@ant-design/pro-components": "^2.4.4",
|
||||
"@umijs/max": "^4.4.11",
|
||||
"antd": "^5.4.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"spark-md5": "^3.0.2",
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
|
|
|
@ -117,7 +117,10 @@ const MainLayout: React.FC = () => {
|
|||
</div>
|
||||
</Header>
|
||||
|
||||
<Content className="main-content">
|
||||
<Content
|
||||
className="main-content"
|
||||
style={{ height: 'calc(100vh - 64px)', overflow: 'auto' }}
|
||||
>
|
||||
<Outlet />
|
||||
</Content>
|
||||
</Layout>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { IMAGES_TYPE_MAP } from '@/constants/images.constants';
|
|||
import { uploadChunkAPI } from '@/services/images';
|
||||
import { Alert, Button, message, Modal, Progress, Upload } from 'antd';
|
||||
import { UploadProps } from 'antd/lib/upload';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import SparkMD5 from 'spark-md5';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
|
@ -92,6 +92,33 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
const fileSize = useRef<number>(0); // 文件大小
|
||||
const abortController = useRef<AbortController | null>(null); // 用于取消上传
|
||||
|
||||
// 添加重置状态函数
|
||||
const resetState = () => {
|
||||
setUploadProgress(0);
|
||||
setIsUploading(false);
|
||||
setUploadStatus('ready');
|
||||
setUploadMessage('');
|
||||
completedChunks.current = 0;
|
||||
totalChunks.current = 0;
|
||||
fileId.current = '';
|
||||
fileName.current = '';
|
||||
fileSize.current = 0;
|
||||
uploadQueue.current = [];
|
||||
|
||||
// 如果有正在进行的上传,先中止
|
||||
if (abortController.current) {
|
||||
abortController.current.abort();
|
||||
abortController.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 当弹窗关闭时重置状态
|
||||
useEffect(() => {
|
||||
if (!visible) {
|
||||
resetState();
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
// 5. 分块计算文件MD5
|
||||
const calculateMD5InChunks = (
|
||||
file: Blob,
|
||||
|
@ -158,8 +185,6 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
formData.append('shard_index', index.toString());
|
||||
formData.append('shard_total', totalChunks.current.toString());
|
||||
|
||||
// 这里应该调用实际的上传API
|
||||
// 示例: await uploadChunkAPI(formData);
|
||||
await uploadChunkAPI(formData, abortController.current?.signal);
|
||||
// 模拟上传过程
|
||||
// await new Promise((resolve) =>
|
||||
|
@ -186,6 +211,7 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
// 3. 处理上传队列:每次处理最多 MAX_CONCURRENT 个分片
|
||||
const processUploadQueue = async () => {
|
||||
const promises: Promise<void>[] = [];
|
||||
let hasError = false; // 添加错误标记
|
||||
|
||||
// 同时处理最多 MAX_CONCURRENT 个分片
|
||||
for (
|
||||
|
@ -196,34 +222,49 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
const processChunk = async () => {
|
||||
while (
|
||||
uploadQueue.current.length > 0 &&
|
||||
!abortController.current?.signal.aborted
|
||||
!abortController.current?.signal.aborted &&
|
||||
!hasError // 添加错误检查,出错时停止处理新分片
|
||||
) {
|
||||
const chunkItem = uploadQueue.current.shift();
|
||||
if (chunkItem) {
|
||||
const { chunk, index } = chunkItem;
|
||||
const success = await uploadChunk(chunk, index);
|
||||
if (success) {
|
||||
completedChunks.current += 1;
|
||||
const progress = Math.round(
|
||||
(completedChunks.current / totalChunks.current) * 100,
|
||||
);
|
||||
setUploadProgress(progress);
|
||||
|
||||
// 所有分片上传完成
|
||||
if (completedChunks.current === totalChunks.current) {
|
||||
setIsUploading(false);
|
||||
setUploadStatus('success');
|
||||
setUploadMessage('文件上传成功!正在处理中,请稍后查看列表。');
|
||||
message.success('文件上传成功!系统正在处理,请稍后查看列表。');
|
||||
onImportSuccess?.();
|
||||
if (success) {
|
||||
// 只有在没有错误的情况下才更新进度
|
||||
if (!hasError) {
|
||||
completedChunks.current += 1;
|
||||
const progress = Math.round(
|
||||
(completedChunks.current / totalChunks.current) * 100,
|
||||
);
|
||||
setUploadProgress(progress);
|
||||
|
||||
// 所有分片上传完成
|
||||
if (completedChunks.current === totalChunks.current) {
|
||||
setIsUploading(false);
|
||||
setUploadStatus('success');
|
||||
setUploadMessage(
|
||||
'文件上传成功!正在处理中,请稍后查看列表。',
|
||||
);
|
||||
message.success(
|
||||
'文件上传成功!系统正在处理,请稍后查看列表。',
|
||||
);
|
||||
onImportSuccess?.();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 上传失败处理
|
||||
if (!abortController.current?.signal.aborted) {
|
||||
if (!abortController.current?.signal.aborted && !hasError) {
|
||||
hasError = true; // 设置错误标记
|
||||
setIsUploading(false);
|
||||
setUploadStatus('error');
|
||||
setUploadMessage('文件上传失败,请重试');
|
||||
message.error('文件上传失败');
|
||||
|
||||
// 中止其他正在进行的上传
|
||||
if (abortController.current) {
|
||||
abortController.current.abort();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -253,7 +294,8 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
totalChunks.current = Math.ceil(file.size / CHUNK_SIZE);
|
||||
uploadQueue.current = [];
|
||||
|
||||
setUploadMessage(`正在分析文件... 共 ${totalChunks.current} 个分片`);
|
||||
setUploadMessage(`正在分析文件... `);
|
||||
// setUploadMessage(`正在分析文件... 共 ${totalChunks.current} 个分片`);
|
||||
|
||||
// 创建分片并添加到队列
|
||||
for (let i = 0; i < totalChunks.current; i++) {
|
||||
|
@ -263,7 +305,8 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
uploadQueue.current.push({ chunk, index: i });
|
||||
}
|
||||
|
||||
setUploadMessage(`开始上传文件,共 ${totalChunks.current} 个分片`);
|
||||
setUploadMessage(`开始上传文件... `);
|
||||
// setUploadMessage(`开始上传文件,共 ${totalChunks.current} 个分片`);
|
||||
|
||||
// 创建新的AbortController
|
||||
abortController.current = new AbortController();
|
||||
|
@ -328,10 +371,7 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
message="重要提示"
|
||||
description={
|
||||
<div>
|
||||
<div>
|
||||
1.
|
||||
文件上传需要时间,请耐心等待。
|
||||
</div>
|
||||
<div>1. 文件上传需要时间,请耐心等待。</div>
|
||||
<div>
|
||||
2. 文件上传中请勿刷新或者离开页面,否则会导致文件上传失败。
|
||||
</div>
|
||||
|
@ -368,23 +408,32 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
marginBottom: 8,
|
||||
}}
|
||||
>
|
||||
<span>上传进度</span>
|
||||
<span>{uploadProgress}%</span>
|
||||
<span style={{ width: '70px' }}>上传进度</span>
|
||||
<div style={{ flex: 1, marginRight: 10 }}>
|
||||
<Progress
|
||||
percent={uploadProgress}
|
||||
status={
|
||||
uploadStatus === 'error'
|
||||
? 'exception'
|
||||
: uploadStatus === 'success'
|
||||
? 'success'
|
||||
: 'normal'
|
||||
}
|
||||
format={(percent) => `${percent}%`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Progress
|
||||
percent={uploadProgress}
|
||||
status={uploadStatus === 'error' ? 'exception' : 'normal'}
|
||||
/>
|
||||
|
||||
{uploadMessage && (
|
||||
<div style={{ marginTop: 8, textAlign: 'center' }}>
|
||||
<span>{uploadMessage}</span>
|
||||
</div>
|
||||
)}
|
||||
{/* {isUploading && (
|
||||
{isUploading && (
|
||||
<div style={{ marginTop: 12, textAlign: 'center' }}>
|
||||
<Button onClick={cancelUpload}>取消上传</Button>
|
||||
</div>
|
||||
)} */}
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -397,6 +446,9 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
onCancel={() => {
|
||||
if (isUploading) {
|
||||
cancelUpload();
|
||||
} else {
|
||||
// 如果不是上传状态,直接重置状态
|
||||
resetState();
|
||||
}
|
||||
onCancel();
|
||||
}}
|
||||
|
@ -406,6 +458,8 @@ const ImportModal: React.FC<ImportModalProps> = ({
|
|||
onClick={() => {
|
||||
if (isUploading) {
|
||||
cancelUpload();
|
||||
} else {
|
||||
resetState();
|
||||
}
|
||||
onCancel();
|
||||
}}
|
||||
|
|
|
@ -1,94 +1,163 @@
|
|||
// 页面头部样式
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
// 镜像列表样式
|
||||
.image-list {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
.search-box {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
.search-input {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
// 镜像列表样式
|
||||
.image-list {
|
||||
padding: 10px;
|
||||
.image-detail {
|
||||
.detail-item {
|
||||
margin-bottom: 16px;
|
||||
|
||||
label {
|
||||
.images-list-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
.images-list-table {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
// 表格适应样式
|
||||
.ant-table-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-spin-nested-loading {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-spin-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-table {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-table-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-table-body {
|
||||
flex: 1;
|
||||
overflow-y: auto !important;
|
||||
|
||||
table {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.image-detail {
|
||||
.detail-item {
|
||||
margin-bottom: 16px;
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0 0 100px;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 个人资料样式
|
||||
.profile-page {
|
||||
.profile-content {
|
||||
.profile-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.profile-info {
|
||||
h3 {
|
||||
margin: 0 0 4px 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
p {
|
||||
margin: 8px 0 0 100px;
|
||||
margin: 0;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 个人资料样式
|
||||
.profile-page {
|
||||
.profile-content {
|
||||
.profile-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.profile-info {
|
||||
h3 {
|
||||
margin: 0 0 4px 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.quick-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.quick-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.profile-content {
|
||||
.profile-header {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.quick-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.profile-content {
|
||||
.profile-header {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.quick-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
SettingOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { TableProps } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
|
@ -19,7 +20,7 @@ import {
|
|||
Tooltip,
|
||||
} from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ModalDetailShow, ImportModal } from './components/modalShow/modalShow';
|
||||
import { ImportModal, ModalDetailShow } from './components/modalShow/modalShow';
|
||||
import './index.less';
|
||||
|
||||
import { ReactComponent as RefreshIcon } from '@/assets/icons/refresh.svg';
|
||||
|
@ -62,6 +63,12 @@ const ImageList: React.FC = () => {
|
|||
JSON.stringify(tableParams.filters),
|
||||
JSON.stringify(tableParams.keywords),
|
||||
]);
|
||||
|
||||
/**
|
||||
* 表格参数转换
|
||||
* @param params - 表格参数对象,包含分页、过滤、排序等信息
|
||||
* @returns 转换后的接口参数对象
|
||||
*/
|
||||
const getRandomuserParams = (params: IMAGES.TableParams) => {
|
||||
const {
|
||||
pagination,
|
||||
|
@ -111,11 +118,14 @@ const ImageList: React.FC = () => {
|
|||
if (imagesRes.error_code === ERROR_CODE) {
|
||||
setImages(imagesRes.data.data || []);
|
||||
setLoading(false);
|
||||
// 直接使用后端返回的分页信息
|
||||
setTableParams((prev) => ({
|
||||
...prev,
|
||||
pagination: {
|
||||
...prev.pagination,
|
||||
current: imagesRes.data.paging.page_num || 1,
|
||||
total: imagesRes.data.paging.total || 0,
|
||||
pageSize: imagesRes.data.paging.page_size || 10,
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
|
@ -268,6 +278,7 @@ const ImageList: React.FC = () => {
|
|||
dataIndex: 'create_time',
|
||||
key: 'create_time',
|
||||
width: 180,
|
||||
render:(text:string)=><Tooltip>{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}</Tooltip>,
|
||||
...(visibleColumns['create_time'] ? {} : { hidden: true }),
|
||||
},
|
||||
{
|
||||
|
@ -297,6 +308,7 @@ const ImageList: React.FC = () => {
|
|||
},
|
||||
].filter((column) => !column.hidden);
|
||||
|
||||
// 处理表格分页、过滤和排序变化
|
||||
const handleTableChange: TableProps<IMAGES.ImageItem>['onChange'] = (
|
||||
pagination,
|
||||
filters,
|
||||
|
@ -323,28 +335,27 @@ const ImageList: React.FC = () => {
|
|||
loadImages();
|
||||
};
|
||||
|
||||
// 导入成功后的回调
|
||||
// 导入镜像成功后的回调
|
||||
const handleImportSuccess = () => {
|
||||
// 可以在这里添加导入成功后的处理逻辑
|
||||
// 例如:刷新列表或显示提示信息
|
||||
setTimeout(() => {
|
||||
loadImages(); // 一段时间后刷新列表查看是否有新导入的镜像
|
||||
loadImages();
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
// 自定义分页配置
|
||||
const paginationConfig = {
|
||||
...tableParams.pagination,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
pageSizeOptions: ['10', '20', '50', '100'],
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="image-list">
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Button onClick={() => setImportModalVisible(true)}>导入</Button>
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
||||
<div className="search-box">
|
||||
<Button onClick={() => setImportModalVisible(true)}>导入</Button>
|
||||
<div className="search-input">
|
||||
<Input.Search
|
||||
placeholder="镜像名称"
|
||||
value={searchText}
|
||||
|
@ -378,21 +389,19 @@ const ImageList: React.FC = () => {
|
|||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
<Table
|
||||
columns={filteredColumns}
|
||||
dataSource={images}
|
||||
rowKey="image_id"
|
||||
loading={loading}
|
||||
pagination={tableParams.pagination}
|
||||
onChange={handleTableChange}
|
||||
// pagination={{
|
||||
// total: images.length,
|
||||
// pageSize: 10,
|
||||
// showSizeChanger: true,
|
||||
// showQuickJumper: true,
|
||||
// showTotal: (total) => `共 ${total} 条记录`,
|
||||
// }}
|
||||
/>
|
||||
<div className="images-list-container">
|
||||
<div className="images-list-table">
|
||||
<Table
|
||||
columns={filteredColumns}
|
||||
dataSource={images}
|
||||
rowKey="image_id"
|
||||
loading={loading}
|
||||
pagination={paginationConfig}
|
||||
onChange={handleTableChange}
|
||||
scroll={{ y: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{detailVisible ? (
|
||||
<ModalDetailShow
|
||||
|
|
|
@ -3827,7 +3827,7 @@ date-fns@2.x:
|
|||
dependencies:
|
||||
"@babel/runtime" "^7.21.0"
|
||||
|
||||
dayjs@1.x, dayjs@^1.11.10, dayjs@^1.11.11, dayjs@^1.11.7:
|
||||
dayjs@1.x, dayjs@^1.11.10, dayjs@^1.11.11, dayjs@^1.11.13, dayjs@^1.11.7:
|
||||
version "1.11.13"
|
||||
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
|
||||
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
|
||||
|
@ -9412,16 +9412,7 @@ string-convert@^0.2.0:
|
|||
resolved "https://registry.npmmirror.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97"
|
||||
integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
|
@ -9511,14 +9502,7 @@ string_decoder@~1.1.1:
|
|||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
|
@ -10276,16 +10260,7 @@ word-wrap@^1.2.5:
|
|||
resolved "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
|
||||
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
|
|
Loading…
Reference in New Issue