Files
admin-govern/src/views/govern/device/fileService/index.vue

722 lines
23 KiB
Vue
Raw Normal View History

2024-08-30 16:34:06 +08:00
<!-- 文件管理 -->
<template>
<div class="default-main main" :style="{ height: pageHeight.height }">
<div class="main_left">
<DeviceTree @node-click="nodeClick" @init="nodeClick"></DeviceTree>
</div>
<div class="main_right" v-loading="loading">
2024-09-04 15:23:54 +08:00
<div class="right_nav">
<div class="menu" v-if="activePathList.length != 0">
2024-09-25 16:36:53 +08:00
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="(item, index) in activePathList" style="cursor: pointer" :key="index"
@click="handleIntoByPath(item)">
2024-09-04 15:23:54 +08:00
<span>{{ outPutPath(item, index) }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-button :icon="Refresh" @click="handleRestartDevice" type="primary" :loading="deviceRestartLoading">
装置重启
</el-button>
2024-08-30 16:34:06 +08:00
</div>
2024-09-04 15:23:54 +08:00
2024-09-02 18:19:47 +08:00
<div class="filter" v-if="activePathList.length != 0">
2024-09-27 16:22:34 +08:00
<el-input style="width: 200px; height: 32px;-webkit-text-security:disc;" placeholder="请输入文件或文件夹名称"
clearable v-model="filterFileName" type="text"></el-input>
2024-09-04 15:23:54 +08:00
<el-button type="primary" @click="handleSearch" :icon="Search">搜索</el-button>
<el-button @click="handleRefresh" :icon="Refresh">重置</el-button>
2024-09-25 16:36:53 +08:00
<el-upload v-if="activePath != '/'" action="" :auto-upload="false" :show-file-list="false" :on-change="(file: any, fileList: any) => {
handleUpload(file, fileList, activePath)
}
">
2024-09-03 10:52:36 +08:00
<el-button>
文件上传
2024-09-25 16:36:53 +08:00
<el-icon class="el-icon--right">
<Upload />
</el-icon>
2024-09-03 10:52:36 +08:00
</el-button>
</el-upload>
2024-09-11 20:17:38 +08:00
<el-button @click="handleAddNewDir" v-if="activePath != '/'" type="primary" :icon="Plus">
新建文件夹
</el-button>
2024-09-20 10:40:35 +08:00
<div class="upload_progress" v-if="status != 0 && status != 100 && changeType == 'upload'">
正在上传{{ fileName }}
<el-progress :percentage="status" />
<!-- <el-progress :percentage="30" :indeterminate="true">
2024-09-04 15:23:54 +08:00
<el-button text>上传中...</el-button>
2024-09-20 10:40:35 +08:00
</el-progress> -->
2024-09-03 10:52:36 +08:00
</div>
2024-09-02 18:19:47 +08:00
</div>
<div class="list" v-if="dirList.length != 0 && !loading">
2024-09-02 18:19:47 +08:00
<div class="list_item" v-for="(item, index) in dirList" :key="index">
2024-08-30 16:34:06 +08:00
<div class="item_download">
2024-09-25 16:36:53 +08:00
<el-button v-if="activePath && activePath != '/'" type="danger" size="small"
@click="handleDelDirOrFile(item)" circle>
<el-icon>
<Delete />
</el-icon>
2024-09-23 10:17:14 +08:00
</el-button>
2024-09-02 18:19:47 +08:00
<el-button v-if="item?.type == 'file'" size="small" @click="handleDownLoad(item)" circle>
2024-09-25 16:36:53 +08:00
<el-icon>
<Download />
</el-icon>
2024-08-30 16:34:06 +08:00
</el-button>
2024-09-23 10:17:14 +08:00
<!-- <el-popconfirm
width="220"
confirm-button-text="确认"
cancel-button-text="取消"
:title="item?.type == 'file' ? '是否确认删除当前文件?' : '是否确认删除当前文件夹?'"
@confirm="handleDelDirOrFile(item)"
@cancel="cancelEvent"
2024-09-11 20:17:38 +08:00
>
<template #reference>
<el-button v-if="activePath && activePath != '/'" type="danger" size="small" circle>
<el-icon><Delete /></el-icon>
</el-button>
</template>
2024-09-25 16:36:53 +08:00
</el-popconfirm> -->
2024-08-30 16:34:06 +08:00
</div>
2024-09-02 18:19:47 +08:00
<img v-if="item?.type == 'dir'" @click="handleIntoDir(item)" src="@/assets/img/wenjianjia.svg" />
2024-09-25 16:36:53 +08:00
<img class="img_file" @click="handleIntoDir(item)" v-if="item?.type == 'file'"
src="@/assets/img/wenjian.svg" />
2024-09-12 09:56:09 +08:00
<span v-if="!item.type">暂无数据</span>
2024-08-30 16:34:06 +08:00
<p>
{{
item &&
2024-09-25 16:36:53 +08:00
item?.prjDataPath &&
item?.prjDataPath.includes(activePath) &&
item?.prjDataPath.length > activePath.length
2024-09-18 16:39:50 +08:00
? item?.prjDataPath.replace(activePath, ' ').replace('/', ' ')
: item?.prjDataPath.replace('/', ' ')
2024-08-30 16:34:06 +08:00
}}
</p>
</div>
</div>
2024-09-18 16:39:50 +08:00
<el-empty v-if="dirList.length === 0" />
2024-08-30 16:34:06 +08:00
</div>
<popup ref="fileRef"></popup>
2024-09-25 16:36:53 +08:00
<el-dialog v-model="addDeviceDirOpen" :destroy-on-close="true" title="新建文件夹目录" width="500" @closed="close">
<el-form ref="formRef" :model="form"
:rules="{ path: [{ required: true, message: '请输入文件夹名称', trigger: 'blur' }] }">
<el-form-item label="文件夹名称" prop="path">
<el-input v-model="form.path" placeholder="请输入文件夹名称" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="submitDeviceDir">确定</el-button>
</div>
</template>
</el-dialog>
2024-08-30 16:34:06 +08:00
</div>
</template>
<script setup lang="ts">
import DeviceTree from '@/components/tree/govern/deviceTree.vue'
import { mainHeight } from '@/utils/layout'
2024-09-27 16:22:34 +08:00
import { ref, reactive, watch, onMounted, onBeforeUnmount, h } from 'vue'
import { ElMessage, ElMessageBox, ElInput } from 'element-plus'
2024-09-02 18:19:47 +08:00
import {
getDeviceRootPath,
getFileServiceFileOrDir,
downLoadDeviceFile,
2024-09-04 15:23:54 +08:00
uploadDeviceFile,
reStartDevice,
addDeviceDir,
delDeviceDir
2024-09-02 18:19:47 +08:00
} from '@/api/cs-device-boot/fileService.ts'
2024-09-04 15:23:54 +08:00
import {
CirclePlus,
Delete,
EditPen,
ArrowLeft,
ArrowRight,
Download,
Upload,
View,
Check,
Plus,
Refresh,
Search
} from '@element-plus/icons-vue'
2024-08-30 16:34:06 +08:00
import popup from './popup.vue'
2024-09-18 16:39:50 +08:00
import mqtt from 'mqtt'
import { passwordConfirm, updatePassword } from '@/api/user-boot/user'
2024-08-30 16:34:06 +08:00
defineOptions({
name: 'govern/device/fileService'
})
const pageHeight = mainHeight(20)
const loading = ref(false)
//nDid
const nDid = ref<string>('')
// 树节点点击
//当前目录
const activePath = ref<string>('')
//判断是否是根目录
const isRoot = ref<boolean>(true)
2024-08-30 16:34:06 +08:00
//储存所有点击过的目录
2024-09-25 16:36:53 +08:00
const activePathList: any = ref([
])
2024-08-30 16:34:06 +08:00
const nodeClick = (e: any) => {
if (e.level == 2) {
2024-09-12 09:56:09 +08:00
loading.value = true
2024-08-30 16:34:06 +08:00
nDid.value = e.ndid
2024-09-12 09:56:09 +08:00
dirList.value = []
activePathList.value = []
2024-09-18 16:39:50 +08:00
activePath.value = '/'
getFileServiceFileOrDir({ nDid: nDid.value, name: activePath.value, type: 'dir' })
.then((resp: any) => {
if (resp.code == 'A0000') {
dirList.value = resp.data
currentDirList.value = resp.data
activePathList.value = [{ path: activePath.value }]
loading.value = false
}
2024-09-03 10:52:36 +08:00
})
.catch(e => {
loading.value = false
2024-08-30 16:34:06 +08:00
})
}
}
2024-09-02 18:19:47 +08:00
//搜索文件或文件夹
const filterFileName = ref('')
const handleSearch = () => {
let filterList: any = []
2024-09-02 18:19:47 +08:00
dirList.value = currentDirList.value
dirList.value.map(item => {
if (filterFileName.value && item.prjDataPath.includes(filterFileName.value)) {
filterList.push(item)
}
})
if (filterList.length != 0) {
dirList.value = filterList
}
if (!filterFileName) {
dirList.value = currentDirList.value
}
}
//重置搜索
const handleRefresh = () => {
2024-09-12 09:56:09 +08:00
loading.value = true
2024-09-02 18:19:47 +08:00
filterFileName.value = ''
dirList.value = currentDirList.value
2024-09-11 20:17:38 +08:00
reloadCurrentMenu('')
2024-09-02 18:19:47 +08:00
}
2024-09-27 16:22:34 +08:00
const reboot: any = ref('')
const vNode = () => {
return h('div', {}, [
h(ElInput, {
modelValue: reboot.value,
'onUpdate:modelValue': ($event: any) => {
reboot.value = $event;
},
placeholder: '请输入姓名',
type: 'password',
autocomplete: "off",
class: 'displayPass'
}),
]);
};
2024-09-04 15:23:54 +08:00
//装置重启
const deviceRestartLoading = ref<boolean>(false)
const handleRestartDevice = () => {
deviceRestartLoading.value = true
2024-09-18 16:39:50 +08:00
ElMessageBox.prompt('二次校验密码确认', '装置重启', {
confirmButtonText: '确认',
cancelButtonText: '取消',
2024-09-27 16:22:34 +08:00
customClass: 'customInput',
inputType: 'text',
2024-09-25 16:36:53 +08:00
2024-09-04 15:23:54 +08:00
})
2024-09-18 16:39:50 +08:00
.then(({ value }) => {
if (!value) {
ElMessage.warning('请输入密码')
loading.value = false
deviceRestartLoading.value = false
} else {
passwordConfirm(value)
.then((resp: any) => {
if (resp.code == 'A0000') {
reStartDevice({ nDid: nDid.value }).then((res: any) => {
if (res.code == 'A0000') {
deviceRestartLoading.value = false
ElMessage({ message: res.message, type: 'success', duration: 5000 })
}
})
2024-09-18 16:39:50 +08:00
}
})
.catch(e => {
loading.value = false
deviceRestartLoading.value = false
})
}
2024-09-18 16:39:50 +08:00
})
.catch(() => {
deviceRestartLoading.value = false
})
2024-09-04 15:23:54 +08:00
}
2024-08-30 16:34:06 +08:00
// 进入文件夹
const dirList = ref([])
// 当前目录数据
2024-09-02 18:19:47 +08:00
const currentDirList = ref([])
2024-08-30 16:34:06 +08:00
const handleIntoDir = (row: any) => {
2024-09-02 18:19:47 +08:00
if (!row.type || row.type == 'file') return
2024-08-30 16:34:06 +08:00
loading.value = true
const obj = {
nDid: nDid.value,
name: row.prjDataPath,
type: row.type
}
//当前点击的目录
activePath.value = row.prjDataPath
if (activePathList.value.indexOf(obj.name) == -1) {
activePathList.value.push({ path: obj.name })
}
getFileServiceFileOrDir(obj).then(res => {
dirList.value = res.data
loading.value = false
2024-09-02 18:19:47 +08:00
currentDirList.value = res.data
2024-08-30 16:34:06 +08:00
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
2024-09-25 16:36:53 +08:00
isRoot.value = false
}).catch(e => {
loading.value = false
2024-08-30 16:34:06 +08:00
})
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
}
//处理导航栏路径
const outPutPath = (row: any, key: any) => {
let path = ''
2024-09-25 16:36:53 +08:00
if (key == 0) {
path = '/根目录'
}
if (key == 1) {
path = row.path
2024-08-30 16:34:06 +08:00
}
if (key > 1) {
if (row.path.includes(activePathList.value[1].path)) {
path = row.path.replace(activePathList.value[1].path, ' ')
}
if (row.path.split('/').length !== 0) {
path = '/' + row.path.split('/')[row.path.split('/').length - 1]
2024-09-25 16:36:53 +08:00
}
}
2024-09-25 16:36:53 +08:00
return path.split('/')[1]
2024-08-30 16:34:06 +08:00
}
//根据面包屑导航切换
const handleIntoByPath = async (val: any) => {
const obj = {
nDid: nDid.value,
name: val.path,
type: 'dir'
}
activePath.value = val.path
loading.value = true
2024-08-30 16:34:06 +08:00
getFileServiceFileOrDir(obj).then(res => {
dirList.value = res.data
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
loading.value = false
2024-09-25 16:36:53 +08:00
}).catch(e => {
loading.value = false
2024-08-30 16:34:06 +08:00
})
2024-09-25 16:36:53 +08:00
}
const form = ref({
path: ''
})
//新建文件夹弹框flag
const addDeviceDirOpen = ref<boolean>(false)
const close = () => {
addDeviceDirOpen.value = false
}
//打开新建文件夹弹框
const handleAddNewDir = () => {
form.value.path = ''
addDeviceDirOpen.value = true
}
2024-09-11 20:17:38 +08:00
const formRef = ref()
//重新加载当前页面菜单
const reloadCurrentMenu = (msg: string) => {
2024-09-25 16:36:53 +08:00
loading.value = true
2024-09-11 20:17:38 +08:00
getFileServiceFileOrDir({ nDid: nDid.value, name: activePath.value, type: 'dir' }).then((resp: any) => {
if (resp.code == 'A0000') {
2024-09-18 16:39:50 +08:00
loading.value = false
2024-09-11 20:17:38 +08:00
dirList.value = resp.data
currentDirList.value = resp.data
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
2024-09-25 16:36:53 +08:00
loading.value = false
2024-09-11 20:17:38 +08:00
if (!msg) return
2024-09-18 16:39:50 +08:00
ElMessage({ message: msg, type: 'success', duration: 5000 })
2024-09-25 16:36:53 +08:00
2024-09-11 20:17:38 +08:00
}
2024-09-25 16:36:53 +08:00
}).catch(e => {
loading.value = false
2024-09-11 20:17:38 +08:00
})
2024-09-25 16:36:53 +08:00
// setTimeout(() => {
// loading.value = false
// },0)
2024-09-11 20:17:38 +08:00
}
//新建文件夹
const submitDeviceDir = () => {
2024-09-11 20:17:38 +08:00
formRef.value.validate((valid: any) => {
if (valid) {
let obj = {
nDid: nDid.value,
path:
activePath.value == '/'
? activePath.value + form.value.path
: activePath.value + '/' + form.value.path
}
loading.value = true
addDeviceDir(obj).then((res: any) => {
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
2024-09-18 16:39:50 +08:00
// ElMessage({ message: res.message, type: 'success', duration: 5000 })
2024-09-11 20:17:38 +08:00
addDeviceDirOpen.value = false
}
})
}
})
}
//删除文件夹或文件
const handleDelDirOrFile = (row: any) => {
2024-09-25 16:36:53 +08:00
2024-09-23 10:17:14 +08:00
// delDeviceDir({ nDid: nDid.value, path: row.prjDataPath }).then((res: any) => {
// if (res.code == 'A0000') {
// reloadCurrentMenu(res.message)
// // ElMessage({ message: res.message, type: 'success', duration: 5000 })
// }
// })
ElMessageBox.prompt('二次校验密码确认', '删除', {
confirmButtonText: '确认',
cancelButtonText: '取消',
customClass: 'customInput',
inputType: 'text'
})
2024-09-23 10:17:14 +08:00
.then(({ value }) => {
if (!value) {
ElMessage.warning('请输入密码')
2024-09-25 16:36:53 +08:00
} else {
2024-09-25 16:36:53 +08:00
loading.value = true
passwordConfirm(value)
.then((resp: any) => {
if (resp.code == 'A0000') {
delDeviceDir({ nDid: nDid.value, path: row.prjDataPath }).then((res: any) => {
if (res.code == 'A0000') {
2024-09-25 16:36:53 +08:00
reloadCurrentMenu(res.message)
2024-09-25 16:36:53 +08:00
// ElMessage({ message: res.message, type: 'success', duration: 5000 })
}
})
2024-09-23 10:17:14 +08:00
}
})
.catch(e => {
loading.value = false
})
}
2024-09-23 10:17:14 +08:00
})
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
}
const changeType = ref<any>('')
2024-08-30 16:34:06 +08:00
//下载文件
const fileRef = ref()
const handleDownLoad = async (row: any) => {
2024-09-25 16:36:53 +08:00
; (await nDid.value) && fileRef.value && fileRef.value.open(row, nDid.value)
2024-09-20 10:40:35 +08:00
fileName.value = row?.prjDataPath.split('/')[row?.prjDataPath.split('/').length - 1]
localStorage.setItem('fileName', fileName.value)
changeType.value = 'download'
localStorage.setItem('changeType', changeType.value)
2024-09-02 18:19:47 +08:00
}
//上传文件
const fileName = ref<any>('')
2024-09-02 18:19:47 +08:00
const handleUpload = (e: any, fileList: any, row: any) => {
2024-09-11 20:17:38 +08:00
// loading.value=true
2024-09-03 10:52:36 +08:00
fileName.value = e.name
2024-09-20 10:40:35 +08:00
localStorage.setItem('fileName', fileName.value)
changeType.value = 'upload'
localStorage.setItem('changeType', changeType.value)
2024-09-02 18:19:47 +08:00
const obj = {
id: nDid.value,
file: e.raw,
2024-09-03 10:52:36 +08:00
filePath: row || row.prjDataPath
2024-09-02 18:19:47 +08:00
}
2024-09-11 20:17:38 +08:00
uploadDeviceFile(obj).then((res: any) => {
2024-09-02 18:19:47 +08:00
if (res.code == 'A0000') {
2024-09-11 20:17:38 +08:00
reloadCurrentMenu(res.message)
2024-09-20 10:40:35 +08:00
status.value = 100
2024-09-02 18:19:47 +08:00
}
})
2024-08-30 16:34:06 +08:00
}
watch(
() => activePathList.value,
async (val, oldVal) => {
if (val) {
val.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
val.splice(index, 1)
}
})
}
},
{
immediate: true,
deep: true
}
)
2024-09-18 16:39:50 +08:00
const mqttRef = ref()
const connectMqtt = () => {
if (mqttRef.value) {
if (mqttRef.value.connected) {
return
}
}
const options = {
protocolId: 'MQTT',
qos: 2,
clean: true,
connectTimeout: 30 * 1000,
clientId: 'mqttjs' + Math.random(),
username: 't_user',
password: 'njcnpqs'
}
2024-09-20 10:40:35 +08:00
// const url = 'wss://pqmcn.com:8087/mqtt'
const url = 'ws://192.168.1.24:8085/mqtt'
2024-09-18 16:39:50 +08:00
mqttRef.value = mqtt.connect(url, options)
}
connectMqtt()
mqttRef.value.on('connect', (e: any) => {
2024-09-20 10:40:35 +08:00
// ElMessage.success('连接mqtt服务器成功!')
2024-09-18 16:39:50 +08:00
console.log('mqtt客户端已连接....')
2024-09-20 10:40:35 +08:00
// mqttRef.value.subscribe('/Web/Progress')
mqttRef.value.subscribe('/Web/Progress/+')
2024-09-18 16:39:50 +08:00
})
2024-09-20 10:40:35 +08:00
const mqttMessage = ref<any>({})
const status = ref<any>()
2024-09-18 16:39:50 +08:00
mqttRef.value.on('message', (topic: any, message: any) => {
// console.log('🚀 ~ mqttRef.value.on ~ message:', JSON.parse(message))
2024-09-20 10:40:35 +08:00
console.log('mqtt接收到消息', JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message)))))
2024-09-18 16:39:50 +08:00
// "{allStep:\""+times+"\",nowStep:"+i+"}"
2024-09-20 10:40:35 +08:00
let str = JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message))))
mqttMessage.value = eval('(' + str + ')')
status.value = parseInt(Number((mqttMessage.value.nowStep / mqttMessage.value.allStep) * 100))
fileRef.value.setStatus(status.value)
if (status.value == 100) {
status.value = 99
}
2024-09-18 16:39:50 +08:00
})
mqttRef.value.on('error', (error: any) => {
console.log('mqtt连接失败...', error)
mqttRef.value.end()
})
mqttRef.value.on('close', function () {
console.log('mqtt客户端已断开连接.....')
})
2024-09-20 10:40:35 +08:00
onMounted(() => {
2024-09-23 10:17:14 +08:00
status.value = 0
2024-09-20 10:40:35 +08:00
fileName.value = localStorage.getItem('fileName') ? localStorage.getItem('fileName') : ''
changeType.value = localStorage.getItem('changeType') ? localStorage.getItem('changeType') : ''
})
2024-09-18 16:39:50 +08:00
onBeforeUnmount(() => {
if (mqttRef.value) {
mqttRef.value.end()
}
})
2024-08-30 16:34:06 +08:00
</script>
2024-09-18 16:39:50 +08:00
<style lang="scss" scoped>
2024-08-30 16:34:06 +08:00
.main {
display: flex;
justify-content: space-between;
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
.main_left {
// width: 280px;
}
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
.main_right {
overflow: hidden;
flex: 1;
padding: 10px 10px 10px 10px;
2024-09-04 15:23:54 +08:00
//margin-left: 10px;
2024-08-30 16:34:06 +08:00
border: 1px solid #eee;
2024-09-25 16:36:53 +08:00
2024-09-18 16:39:50 +08:00
.el-input__wrapper {
2024-09-20 10:40:35 +08:00
-webkit-text-security: disc !important;
}
2024-09-25 16:36:53 +08:00
2024-09-04 15:23:54 +08:00
.right_nav {
2024-08-30 16:34:06 +08:00
width: 100%;
2024-09-04 15:23:54 +08:00
height: 32px;
2024-08-30 16:34:06 +08:00
display: flex;
2024-09-04 15:23:54 +08:00
justify-content: space-between;
2024-08-30 16:34:06 +08:00
align-items: center;
2024-09-25 16:36:53 +08:00
2024-09-04 15:23:54 +08:00
.menu {
width: 100%;
height: 100%;
display: flex;
justify-content: flex-start;
overflow-x: auto;
align-items: center;
background-color: var(--el-color-primary);
border-radius: 4px;
2024-09-25 16:36:53 +08:00
2024-09-04 15:23:54 +08:00
span {
font-size: 14px;
font-weight: 800;
padding: 0 5px;
color: #fff;
cursor: pointer;
}
}
2024-09-25 16:36:53 +08:00
2024-09-04 15:23:54 +08:00
.el-button {
margin: 0 10px;
2024-08-30 16:34:06 +08:00
}
}
2024-09-04 15:23:54 +08:00
2024-09-02 18:19:47 +08:00
.filter {
width: 100%;
height: 30px;
display: flex;
margin-top: 10px;
justify-content: flex-start;
2024-09-25 16:36:53 +08:00
2024-09-02 18:19:47 +08:00
.el-button {
margin-left: 10px;
}
2024-09-25 16:36:53 +08:00
2024-09-03 10:52:36 +08:00
.upload_progress {
flex: 1;
height: 30px;
display: flex;
align-items: center;
justify-content: flex-start;
margin-left: 10px;
2024-09-25 16:36:53 +08:00
2024-09-03 10:52:36 +08:00
.el-progress {
width: 300px;
margin-left: 10px;
}
}
2024-09-02 18:19:47 +08:00
}
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
.list {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
2024-09-04 15:23:54 +08:00
// justify-content: space-between;
2024-08-30 16:34:06 +08:00
overflow-y: auto;
2024-09-02 18:19:47 +08:00
margin-top: 10px;
2024-09-02 20:59:24 +08:00
max-height: 100%;
2024-08-30 16:34:06 +08:00
padding-bottom: 200px;
z-index: 100;
position: relative;
2024-09-25 16:36:53 +08:00
.list_upload {
position: absolute;
width: 100px;
height: 40px;
right: 20px;
top: 10px;
}
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
.list_item {
flex: none;
width: 23.3%;
height: 100px;
border: 1px solid var(--el-color-primary);
margin: 10px 0.5%;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
border-radius: 6px;
cursor: pointer;
position: relative;
z-index: 1001 !important;
2024-09-25 16:36:53 +08:00
2024-09-02 18:19:47 +08:00
.item_download,
.item_upload {
2024-08-30 16:34:06 +08:00
position: absolute;
top: 10px;
right: 10px;
z-index: 2001;
}
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
.img_file {
width: 60px;
height: 60px;
}
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
img {
width: 50px;
height: 50px;
cursor: pointer !important;
}
2024-09-25 16:36:53 +08:00
2024-08-30 16:34:06 +08:00
p {
margin-top: 10px;
}
}
2024-09-25 16:36:53 +08:00
2024-09-04 15:23:54 +08:00
.list_item:nth-child(4n + 2),
.list_item:nth-child(4n + 3) {
margin: 10px 0.8%;
}
2024-08-30 16:34:06 +08:00
}
}
}
2024-09-25 16:36:53 +08:00
2024-09-11 20:17:38 +08:00
.el-form {
padding: 20px 10px;
box-sizing: border-box;
2024-09-23 10:17:14 +08:00
}
2024-09-25 16:36:53 +08:00
:deep(.el-breadcrumb__separator) {
margin: 0px -10px 0px 0px;
2024-09-11 20:17:38 +08:00
}
2024-09-27 16:22:34 +08:00
2024-08-30 16:34:06 +08:00
</style>
2024-09-27 16:22:34 +08:00
<style lang="scss">
.customInput {
.el-input__inner {
-webkit-text-security: disc !important;
}
}
</style>