mirror of
https://gitee.com/xiangheng/x_admin.git
synced 2025-10-07 09:01:18 +08:00
优化素材中心
This commit is contained in:
@@ -15,34 +15,34 @@
|
||||
"outdated": "pnpm outdated"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@highlightjs/vue-plugin": "^2.1.0",
|
||||
"@logicflow/core": "^2.0.16",
|
||||
"@logicflow/extension": "^2.0.21",
|
||||
"@logicflow/core": "^2.1.2",
|
||||
"@logicflow/extension": "^2.1.3",
|
||||
"@vueuse/core": "^13.5.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.8.4",
|
||||
"axios": "^1.11.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"css-color-function": "^1.3.3",
|
||||
"dayjs": "^1.11.13",
|
||||
"dayjs": "^1.11.18",
|
||||
"echarts": "^5.6.0",
|
||||
"element-plus": "^2.10.4",
|
||||
"element-plus": "^2.11.1",
|
||||
"highlight.js": "^11.11.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.3",
|
||||
"query-string": "^9.1.1",
|
||||
"rolldown-vite": "^7.0.9",
|
||||
"query-string": "^9.2.2",
|
||||
"rolldown-vite": "^7.1.9",
|
||||
"spark-md5": "^3.0.2",
|
||||
"vform3-builds": "^3.0.10",
|
||||
"vue": "^3.5.16",
|
||||
"vue": "^3.5.21",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-echarts": "^7.0.3",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue3-video-play": "^1.3.2",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vxe-table": "^4.14.4"
|
||||
"vxe-table": "^4.16.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.11.0",
|
||||
@@ -50,10 +50,10 @@
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^5.0.1",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.1",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.27.0",
|
||||
@@ -71,7 +71,7 @@
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-style-import": "^2.0.0",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-tsc": "^3.0.1"
|
||||
"vue-tsc": "^3.0.6"
|
||||
},
|
||||
"overrides": {
|
||||
"vite": "npm:rolldown-vite@latest"
|
||||
|
@@ -35,7 +35,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
// import { Sketch } from 'vue-color'
|
||||
// import ColorFill from './icon/ColorFill.vue'
|
||||
// import ColorText from './icon/ColorText.vue'
|
||||
@@ -51,7 +51,7 @@ import AreaSelect from './icon/AreaSelect.vue'
|
||||
let fileHandle
|
||||
|
||||
async function getFile() {
|
||||
;[fileHandle] = await window.showOpenFilePicker()
|
||||
;[fileHandle] = await (window as any).showOpenFilePicker()
|
||||
console.log('fileHandle', fileHandle)
|
||||
}
|
||||
|
||||
@@ -149,6 +149,8 @@ export default {
|
||||
}
|
||||
},
|
||||
$_changeLineType(value) {
|
||||
console.log('value', value)
|
||||
|
||||
const { lf, activeEdges } = this.$props
|
||||
const { graphModel } = lf
|
||||
lf.setDefaultEdgeType(value)
|
||||
|
@@ -34,6 +34,7 @@ import UserTask from './UserTask.vue'
|
||||
import FieldAuth from './FieldAuth.vue'
|
||||
import Gateway from './Gateway.vue'
|
||||
import type { NodeType, PropertiesType, FormFieldListType, FieldListType } from './property.type'
|
||||
|
||||
defineOptions({
|
||||
name: 'PropertyPanel'
|
||||
})
|
||||
|
@@ -22,13 +22,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Importing necessary functions and components
|
||||
import { ref, onMounted, useTemplateRef } from 'vue'
|
||||
import LogicFlow from '@logicflow/core'
|
||||
import { LogicFlow } from '@logicflow/core'
|
||||
|
||||
import { SelectionSelect, Menu, BpmnElement, MiniMap } from '@logicflow/extension'
|
||||
import type { NodeType, PropertiesType } from './PropertyPanel/property.type'
|
||||
// import '@logicflow/core/dist/style/index.css'
|
||||
// import '@logicflow/extension/lib/style/index.css'
|
||||
|
||||
import '@logicflow/core/lib/style/index.css'
|
||||
import '@logicflow/extension/lib/style/index.css'
|
||||
|
||||
@@ -57,7 +56,7 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
// Define refs for reactive data and component references
|
||||
const lf = ref(null) // Reference to LogicFlow instance
|
||||
const lf = ref<LogicFlow>(null) // Reference to LogicFlow instance
|
||||
const activeEdges = ref([]) // Reactive array for active edges
|
||||
const diagramRef = useTemplateRef<HTMLInputElement>('diagramRef') // Reference to the diagram container
|
||||
const PropertyPanelRef = useTemplateRef<InstanceType<typeof PropertyPanel>>('PropertyPanelRef') // Reference to the PropertyPanel component
|
||||
@@ -69,15 +68,9 @@ onMounted(() => {
|
||||
|
||||
// Function to initialize LogicFlow
|
||||
function initLogicFlow(data) {
|
||||
// 引入框选插件
|
||||
// LogicFlow.use(SelectionSelect)
|
||||
// LogicFlow.use(Menu)
|
||||
// LogicFlow.use(BpmnElement)
|
||||
// LogicFlow.use(MiniMap)
|
||||
// Creating a new LogicFlow instance
|
||||
const logicFlowInstance = new LogicFlow({
|
||||
plugins: [SelectionSelect, Menu, MiniMap, BpmnElement],
|
||||
container: diagramRef.value, // Setting the container where LogicFlow will be rendered
|
||||
container: diagramRef.value,
|
||||
overlapMode: 1,
|
||||
// allowResize: true,
|
||||
autoWrap: true,
|
||||
@@ -106,7 +99,7 @@ function initLogicFlow(data) {
|
||||
|
||||
// Setting default edge type and rendering initial data
|
||||
logicFlowInstance.setDefaultEdgeType('pro-polyline')
|
||||
logicFlowInstance.extension.menu?.addMenuConfig({
|
||||
;(logicFlowInstance.extension.menu as Menu).addMenuConfig({
|
||||
nodeMenu: [
|
||||
{
|
||||
text: '属性配置',
|
||||
@@ -117,14 +110,14 @@ function initLogicFlow(data) {
|
||||
]
|
||||
})
|
||||
logicFlowInstance.render(data)
|
||||
logicFlowInstance.extension.miniMap?.show()
|
||||
;(logicFlowInstance.extension.miniMap as MiniMap).show()
|
||||
// Assigning the LogicFlow instance to the 'lf' ref
|
||||
lf.value = logicFlowInstance
|
||||
|
||||
// Event listener for node clicks
|
||||
lf.value.on('node:dbclick', (e) => {
|
||||
console.log('dbclick on node', e.data, props.fieldList)
|
||||
PropertyPanelRef.value.open(e.data, props.fieldList)
|
||||
PropertyPanelRef.value.open(e.data as NodeType, props.fieldList)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -142,10 +135,7 @@ function setProperties(node: NodeType, item: PropertiesType) {
|
||||
|
||||
lf.value.setProperties(node.id, item)
|
||||
}
|
||||
// function setZIndex(node, type) {
|
||||
// lf.value.setElementZIndex(node.id, type)
|
||||
// }
|
||||
// Function to import data into the LogicFlow instance
|
||||
|
||||
function importData(text) {
|
||||
lf.value.renderRawData(text)
|
||||
}
|
||||
@@ -182,9 +172,9 @@ async function getData() {
|
||||
formData: any
|
||||
treeToList: any
|
||||
}>((resolve, reject) => {
|
||||
const data = lf.value.getGraphData()
|
||||
const nodes = data.nodes
|
||||
const edges = data.edges
|
||||
const data: any = lf.value.getGraphData()
|
||||
const nodes = data?.nodes || []
|
||||
const edges = data?.edges || []
|
||||
|
||||
let haveMoreChildNode = false
|
||||
const sourceNodeIdSum = {} // Node ID -> child nodes mapping
|
||||
|
@@ -58,5 +58,6 @@ export default defineComponent({
|
||||
<style>
|
||||
.svg-icon-container {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,14 +1,29 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="file-item relative" :style="{ height: fileSize, width: fileSize }">
|
||||
<el-image class="image" v-if="type == 'image'" fit="contain" lazy :src="uri"></el-image>
|
||||
<video class="video" v-else-if="type == 'video'" :src="uri"></video>
|
||||
<el-image
|
||||
class="image"
|
||||
v-if="fileType == 'image'"
|
||||
fit="contain"
|
||||
lazy
|
||||
:src="uri"
|
||||
></el-image>
|
||||
<video class="video" v-else-if="fileType == 'video'" :src="uri"></video>
|
||||
<div
|
||||
v-if="type == 'video'"
|
||||
class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] rounded-full w-5 h-5 flex justify-center items-center bg-[rgba(0,0,0,0.3)]"
|
||||
v-if="fileType == 'video'"
|
||||
class="absolute left-1/2 top-1/2 rounded-full w-[30px] h-[30px] flex justify-center items-center bg-[rgba(0,0,0,0.3)]"
|
||||
style="transform: translate(-50%, -50%)"
|
||||
>
|
||||
<icon name="el-icon-CaretRight" :size="18" color="#fff" />
|
||||
</div>
|
||||
<div
|
||||
v-if="fileType == 'audio'"
|
||||
class="absolute left-1/2 top-1/2 rounded-full w-[30px] h-[30px] flex justify-center items-center bg-[rgba(0,0,0,0.3)]"
|
||||
style="transform: translate(-50%, -50%)"
|
||||
>
|
||||
<icon name="el-icon-CaretRight" :size="16" color="#fff" />
|
||||
</div>
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
@@ -16,6 +31,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { GetFileType } from '@/enums/fileEnums'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
// 图片地址
|
||||
@@ -35,16 +52,10 @@ export default defineComponent({
|
||||
},
|
||||
emits: ['close'],
|
||||
computed: {
|
||||
type() {
|
||||
const imageExt = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
|
||||
const videoExt = ['mp4', 'avi', 'mov']
|
||||
if (imageExt.includes(this.ext)) {
|
||||
return 'image'
|
||||
}
|
||||
if (videoExt.includes(this.ext)) {
|
||||
return 'video'
|
||||
}
|
||||
return 'file'
|
||||
fileType() {
|
||||
const fileType = GetFileType(this.uri)
|
||||
|
||||
return fileType
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@@ -85,8 +85,8 @@ export function useCate() {
|
||||
// 处理文件的钩子函数
|
||||
export function useFile(
|
||||
cateId: Ref<string | number>,
|
||||
ext: string[],
|
||||
limit: Ref<number>,
|
||||
ext: Ref<string[]>,
|
||||
limit: number,
|
||||
size: number
|
||||
) {
|
||||
const tableRef = shallowRef()
|
||||
@@ -99,6 +99,7 @@ export function useFile(
|
||||
ext: ext,
|
||||
cid: cateId
|
||||
})
|
||||
|
||||
const { pager, getLists, resetPage } = usePaging({
|
||||
fetchFun: fileList,
|
||||
params: fileParams,
|
||||
@@ -141,8 +142,8 @@ export function useFile(
|
||||
select.value.splice(index, 1)
|
||||
return
|
||||
}
|
||||
if (select.value.length == limit.value) {
|
||||
if (limit.value == 1) {
|
||||
if (select.value.length == limit) {
|
||||
if (limit == 1) {
|
||||
select.value = []
|
||||
select.value.push(item)
|
||||
return
|
||||
@@ -157,7 +158,7 @@ export function useFile(
|
||||
select.value = []
|
||||
}
|
||||
|
||||
const cancelSelete = (id: number) => {
|
||||
const cancelSelect = (id: number) => {
|
||||
select.value = select.value.filter((item: any) => item.id != id)
|
||||
}
|
||||
const selectItems = (items: any[]) => {
|
||||
@@ -194,7 +195,7 @@ export function useFile(
|
||||
batchFileMove,
|
||||
selectFile,
|
||||
clearSelect,
|
||||
cancelSelete,
|
||||
cancelSelect,
|
||||
selectAll,
|
||||
selectItems,
|
||||
handleFileRename
|
||||
|
@@ -32,7 +32,7 @@
|
||||
v-if="data.id > 0"
|
||||
:hide-on-click="false"
|
||||
>
|
||||
<span class="muted m-r-10">···</span>
|
||||
<span class="p-1 mr-[5px]">···</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<popover-input
|
||||
@@ -67,34 +67,37 @@
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center p-2 border-t border-br">
|
||||
<div class="flex justify-center pt-2 border-t border-br">
|
||||
<popover-input
|
||||
v-perms="['admin:common:album:cateAdd']"
|
||||
@confirm="handleAddCate"
|
||||
size="default"
|
||||
width="400px"
|
||||
width="500px"
|
||||
:limit="20"
|
||||
show-limit
|
||||
teleported
|
||||
>
|
||||
<el-button> 添加分组 </el-button>
|
||||
<el-button>添加分组</el-button>
|
||||
</popover-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="material__center flex flex-col">
|
||||
<div class="operate-btn flex">
|
||||
<div class="flex-1 flex">
|
||||
<upload
|
||||
v-perms="['admin:common:upload:image']"
|
||||
class="mr-3"
|
||||
:data="{ cid: cateId }"
|
||||
:ext="ext"
|
||||
:show-progress="true"
|
||||
@change="refresh"
|
||||
<el-tabs
|
||||
v-if="mode == 'page' && defaultFileType == 'all'"
|
||||
v-model="activeFileType"
|
||||
@tab-change="handleTabChange"
|
||||
>
|
||||
<el-button type="primary">本地上传</el-button>
|
||||
</upload>
|
||||
</div>
|
||||
<el-tab-pane
|
||||
v-for="item in FileTabsMap"
|
||||
:label="item.name"
|
||||
:name="item.fileType"
|
||||
:key="item.fileType"
|
||||
>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="flex flex-col">
|
||||
<div class="operate-btn flex">
|
||||
<div class="flex-1 flex"></div>
|
||||
<el-input
|
||||
class="w-60"
|
||||
placeholder="请输入名称"
|
||||
@@ -109,6 +112,17 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<upload
|
||||
v-perms="['admin:common:upload:file']"
|
||||
class="ml-3"
|
||||
:data="{ cid: cateId }"
|
||||
:ext="ext"
|
||||
:show-progress="true"
|
||||
@change="refresh"
|
||||
>
|
||||
<el-button type="primary">本地上传</el-button>
|
||||
</upload>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="material-center__content flex flex-col flex-1 mb-1 min-h-0">
|
||||
@@ -127,7 +141,6 @@
|
||||
<file-item
|
||||
:uri="row.uri"
|
||||
file-size="50px"
|
||||
:ext="row.ext"
|
||||
@click.stop="handlePreview(row.uri)"
|
||||
></file-item>
|
||||
</template>
|
||||
@@ -140,9 +153,9 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="大小" prop="size" min-width="100"> </el-table-column>
|
||||
<el-table-column label="格式" prop="ext" min-width="100"></el-table-column>
|
||||
<el-table-column label="格式" prop="ext" min-width="80"></el-table-column>
|
||||
|
||||
<el-table-column prop="createTime" label="上传时间" min-width="100" />
|
||||
<el-table-column prop="createTime" label="上传时间" min-width="160" />
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="inline-block" v-perms="['admin:common:album:albumRename']">
|
||||
@@ -150,7 +163,7 @@
|
||||
@confirm="handleFileRename($event, row.id)"
|
||||
size="default"
|
||||
:value="row.name"
|
||||
width="400px"
|
||||
width="500px"
|
||||
:limit="50"
|
||||
show-limit
|
||||
teleported
|
||||
@@ -175,27 +188,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div
|
||||
class="flex flex-1 justify-center items-center"
|
||||
v-if="!pager.loading && !pager.lists.length"
|
||||
>
|
||||
暂无数据~
|
||||
</div>
|
||||
</div>
|
||||
<div class="material-center__footer flex justify-between items-center mt-2">
|
||||
<div class="flex">
|
||||
<template v-if="mode == 'page'">
|
||||
<!-- <span class="mr-3">
|
||||
<el-checkbox
|
||||
:disabled="!pager.lists.length"
|
||||
v-model="isCheckAll"
|
||||
@change="selectAll"
|
||||
:indeterminate="isIndeterminate"
|
||||
>
|
||||
当页全选
|
||||
</el-checkbox>
|
||||
</span> -->
|
||||
<el-button
|
||||
v-perms="['admin:common:album:albumDel']"
|
||||
:disabled="!select.length"
|
||||
@@ -206,9 +202,9 @@
|
||||
<popup
|
||||
v-perms="['admin:common:album:albumMove']"
|
||||
class="ml-3 inline"
|
||||
@confirm="batchFileMove"
|
||||
:disabled="!select.length"
|
||||
title="移动文件"
|
||||
@confirm="batchFileMove"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button :disabled="!select.length">移动</el-button>
|
||||
@@ -246,12 +242,8 @@
|
||||
<ul class="select-lists flex flex-col p-t-3">
|
||||
<li class="mb-4" v-for="item in select" :key="item.id">
|
||||
<div class="select-item">
|
||||
<del-wrap @close="cancelSelete(item.id)">
|
||||
<file-item
|
||||
:uri="item.uri"
|
||||
file-size="100px"
|
||||
:ext="item.ext"
|
||||
></file-item>
|
||||
<del-wrap @close="cancelSelect(item.id)">
|
||||
<file-item :uri="item.uri" file-size="100px"></file-item>
|
||||
</del-wrap>
|
||||
</div>
|
||||
</li>
|
||||
@@ -264,29 +256,22 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, toRefs, ref, watch } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { FileTabsMap } from '@/enums/fileEnums'
|
||||
import { onMounted, ref, watch, computed } from 'vue'
|
||||
import { FileExt } from '@/enums/fileEnums'
|
||||
|
||||
import { useCate, useFile } from './hook'
|
||||
import FileItem from './file.vue'
|
||||
import Preview from './preview.vue'
|
||||
const props = defineProps({
|
||||
fileSize: {
|
||||
type: String,
|
||||
default: '100px'
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
ext: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => []
|
||||
defaultFileType: {
|
||||
type: String,
|
||||
default: 'all'
|
||||
},
|
||||
// type: {
|
||||
// type: String,
|
||||
// default: 'image'
|
||||
// },
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'picker'
|
||||
@@ -297,20 +282,8 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['change'])
|
||||
const { limit } = toRefs(props)
|
||||
// const typeValue = computed<number>(() => {
|
||||
// switch (props.type) {
|
||||
// case 'image':
|
||||
// return 10
|
||||
// case 'video':
|
||||
// return 20
|
||||
// case 'file':
|
||||
// return 30
|
||||
// default:
|
||||
// return 0
|
||||
// }
|
||||
// })
|
||||
// const visible: Ref<boolean> = inject('visible')
|
||||
// const { limit } = toRefs(props)
|
||||
|
||||
const previewUrl = ref('')
|
||||
const showPreview = ref(false)
|
||||
const {
|
||||
@@ -324,6 +297,23 @@ const {
|
||||
handleCatSelect
|
||||
} = useCate()
|
||||
|
||||
const activeFileType = ref(props.defaultFileType)
|
||||
|
||||
const ext = computed(() => {
|
||||
if (activeFileType.value) {
|
||||
return FileExt[activeFileType.value]
|
||||
}
|
||||
return []
|
||||
})
|
||||
const listExt = computed(() => {
|
||||
if (activeFileType.value == 'all') {
|
||||
return []
|
||||
}
|
||||
if (activeFileType.value) {
|
||||
return FileExt[activeFileType.value]
|
||||
}
|
||||
return []
|
||||
})
|
||||
const {
|
||||
tableRef,
|
||||
moveId,
|
||||
@@ -338,15 +328,23 @@ const {
|
||||
batchFileMove,
|
||||
|
||||
clearSelect,
|
||||
cancelSelete,
|
||||
cancelSelect,
|
||||
|
||||
selectItems,
|
||||
handleFileRename
|
||||
} = useFile(cateId, props.ext, limit, props.pageSize)
|
||||
} = useFile(cateId, listExt, props.limit, props.pageSize)
|
||||
function handleSelectionChange(val: any[]) {
|
||||
console.log('handleSelectionChange', val)
|
||||
// console.log('handleSelectionChange', val)
|
||||
// if (props.limit && val.length > props.limit) {
|
||||
// return false
|
||||
// }
|
||||
selectItems(val)
|
||||
// multipleSelection.value = val
|
||||
}
|
||||
const handleTabChange = () => {
|
||||
// activeFileType.value = tab
|
||||
console.log('handleTabChange', activeFileType.value)
|
||||
|
||||
getFileList()
|
||||
}
|
||||
const getData = async () => {
|
||||
await getCateLists()
|
||||
@@ -386,7 +384,8 @@ watch(
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
props.mode == 'page' && getData()
|
||||
// props.mode == 'page' && getData()
|
||||
getData()
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="material-select">
|
||||
<div class="material-picker">
|
||||
<popup
|
||||
ref="popupRef"
|
||||
width="830px"
|
||||
width="1200px"
|
||||
custom-class="body-padding"
|
||||
:title="`选择${tipsText}`"
|
||||
@confirm="handleConfirm"
|
||||
@@ -24,7 +24,6 @@
|
||||
<file-item
|
||||
:uri="excludeDomain ? getImageUrl(element) : element"
|
||||
:file-size="size"
|
||||
:type="type"
|
||||
></file-item>
|
||||
</del-wrap>
|
||||
<div class="operation-btns text-xs text-center">
|
||||
@@ -61,21 +60,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-scrollbar>
|
||||
|
||||
<div class="material-wrap">
|
||||
<material
|
||||
ref="materialRef"
|
||||
mode="page"
|
||||
:type="type"
|
||||
mode="picker"
|
||||
defaultFileType="image"
|
||||
:ext="ext"
|
||||
:file-size="fileSize"
|
||||
:limit="meterialLimit"
|
||||
:limit="materialLimit"
|
||||
@change="selectChange"
|
||||
/>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</popup>
|
||||
|
||||
<preview v-model="showPreview" :url="previewUrl" :type="type" />
|
||||
<preview v-model="showPreview" :url="previewUrl" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -88,6 +87,8 @@ import Material from './index.vue'
|
||||
import Preview from './preview.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useThrottleFn } from '@vueuse/core'
|
||||
import { FileExt } from '@/enums/fileEnums'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Popup,
|
||||
@@ -154,6 +155,10 @@ export default defineComponent({
|
||||
const currentIndex = ref(-1)
|
||||
const { disabled, limit, modelValue } = toRefs(props)
|
||||
const { getImageUrl } = useAppStore()
|
||||
|
||||
const ext = computed(() => {
|
||||
return FileExt[props.type]
|
||||
})
|
||||
const tipsText = computed(() => {
|
||||
switch (props.type) {
|
||||
case 'image':
|
||||
@@ -168,7 +173,7 @@ export default defineComponent({
|
||||
const showUpload = computed(() => {
|
||||
return props.limit - fileList.value.length > 0
|
||||
})
|
||||
const meterialLimit: any = computed(() => {
|
||||
const materialLimit: any = computed(() => {
|
||||
if (!isAdd.value) {
|
||||
return 1
|
||||
}
|
||||
@@ -240,12 +245,13 @@ export default defineComponent({
|
||||
provide('limit', props.limit)
|
||||
provide('hiddenUpload', props.hiddenUpload)
|
||||
return {
|
||||
ext,
|
||||
popupRef,
|
||||
materialRef,
|
||||
fileList,
|
||||
tipsText,
|
||||
handleConfirm,
|
||||
meterialLimit,
|
||||
materialLimit,
|
||||
showUpload,
|
||||
showPopup,
|
||||
selectChange,
|
||||
@@ -261,7 +267,7 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.material-select {
|
||||
.material-picker {
|
||||
.material-upload,
|
||||
.material-preview {
|
||||
position: relative;
|
||||
@@ -301,7 +307,7 @@ export default defineComponent({
|
||||
}
|
||||
.material-wrap {
|
||||
min-width: 720px;
|
||||
height: 430px;
|
||||
@apply border-t border-b border-br;
|
||||
height: calc(100vh - 170px);
|
||||
border-top: 1px var(--el-border-color) solid;
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-show="modelValue">
|
||||
<div v-if="type == 'image'">
|
||||
<div v-if="fileType == 'image'">
|
||||
<el-image-viewer
|
||||
v-if="previewLists.length"
|
||||
:url-list="previewLists"
|
||||
@@ -8,8 +8,8 @@
|
||||
@close="handleClose"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="type == 'video'">
|
||||
<el-dialog v-model="visible" width="740px" title="视频预览" :before-close="handleClose">
|
||||
<div v-if="fileType == 'video' || fileType == 'audio'">
|
||||
<el-dialog v-model="visible" width="900px" title="视频预览" :before-close="handleClose">
|
||||
<video-player ref="playerRef" :src="url" width="100%" height="450px" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, useTemplateRef, watch, computed, nextTick } from 'vue'
|
||||
import { GetFileType } from '@/enums/fileEnums'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
@@ -33,17 +35,8 @@ const props = defineProps({
|
||||
// }
|
||||
})
|
||||
|
||||
const type = computed(() => {
|
||||
const imageExt = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
|
||||
const videoExt = ['mp4', 'avi', 'mov']
|
||||
const ext = props.url.split('.').pop()
|
||||
if (imageExt.includes(ext)) {
|
||||
return 'image'
|
||||
}
|
||||
if (videoExt.includes(ext)) {
|
||||
return 'video'
|
||||
}
|
||||
return 'file'
|
||||
const fileType = computed(() => {
|
||||
return GetFileType(props.url)
|
||||
})
|
||||
|
||||
const playerRef = useTemplateRef('playerRef')
|
||||
|
@@ -14,7 +14,7 @@
|
||||
:on-error="handleError"
|
||||
:accept="getAccept"
|
||||
>
|
||||
<slot></slot>{{ getAccept }}
|
||||
<slot></slot>
|
||||
</el-upload>
|
||||
<el-dialog
|
||||
v-if="showProgress && fileList.length"
|
||||
@@ -59,11 +59,6 @@ export default defineComponent({
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => []
|
||||
},
|
||||
// 上传文件类型
|
||||
type: {
|
||||
type: String,
|
||||
default: 'image'
|
||||
},
|
||||
// 是否支持多选
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
|
@@ -36,7 +36,7 @@ const options = reactive({
|
||||
loop: false, //循环播放
|
||||
mirror: false, //镜像画面
|
||||
ligthOff: false, //关灯模式
|
||||
volume: 0.3, //默认音量大小
|
||||
volume: 1, //默认音量大小
|
||||
control: true, //是否显示控制器
|
||||
title: '', //视频名称
|
||||
poster: '', //封面
|
||||
@@ -59,7 +59,7 @@ const onPause = (event: any) => {
|
||||
}
|
||||
|
||||
const onTimeupdate = (event: any) => {
|
||||
console.log(event, '时间更新')
|
||||
// console.log(event, '时间更新')
|
||||
}
|
||||
const onCanplay = (event: any) => {
|
||||
console.log(event, '可以播放')
|
||||
|
87
admin/src/enums/fileEnums.ts
Normal file
87
admin/src/enums/fileEnums.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
export const imageExt = ['png', 'jpg', 'jpeg', 'gif', 'ico', 'bmp', 'webp', 'avif']
|
||||
export const videoExt = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'rmvb']
|
||||
export const audioExt = ['mp3', 'wav', 'aac', 'flac']
|
||||
export const officeExt = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'txt']
|
||||
export const fileExt = ['zip', '7z', 'rar']
|
||||
export const All_EXT = [...imageExt, ...videoExt, ...audioExt, ...fileExt]
|
||||
|
||||
// 获取文件类型
|
||||
export function GetFileType(url: string) {
|
||||
const ext = url.split('.').pop()
|
||||
|
||||
if (officeExt.includes(ext)) {
|
||||
return 'office'
|
||||
}
|
||||
if (audioExt.includes(ext)) {
|
||||
return 'audio'
|
||||
}
|
||||
if (imageExt.includes(ext)) {
|
||||
return 'image'
|
||||
}
|
||||
if (videoExt.includes(ext)) {
|
||||
return 'video'
|
||||
}
|
||||
return 'file'
|
||||
}
|
||||
// 获取文件类型上传的accept
|
||||
function getAccept(ext: string[]) {
|
||||
return ext
|
||||
.map((item) => {
|
||||
return `.${item}`
|
||||
})
|
||||
.join(',')
|
||||
}
|
||||
export const FileTabsMap = [
|
||||
{
|
||||
name: '全部',
|
||||
fileType: 'all',
|
||||
accept: getAccept(All_EXT),
|
||||
ext: []
|
||||
},
|
||||
{
|
||||
name: '图片',
|
||||
fileType: 'image',
|
||||
accept: getAccept(imageExt),
|
||||
ext: imageExt
|
||||
},
|
||||
{
|
||||
name: '视频',
|
||||
fileType: 'video',
|
||||
accept: getAccept(videoExt),
|
||||
ext: videoExt
|
||||
},
|
||||
{
|
||||
name: '音频',
|
||||
fileType: 'audio',
|
||||
accept: getAccept(audioExt),
|
||||
ext: audioExt
|
||||
},
|
||||
{
|
||||
name: '文档',
|
||||
fileType: 'office',
|
||||
accept: getAccept(officeExt),
|
||||
ext: officeExt
|
||||
},
|
||||
{
|
||||
name: '文件',
|
||||
fileType: 'file',
|
||||
accept: getAccept(fileExt),
|
||||
ext: fileExt
|
||||
}
|
||||
]
|
||||
export const FileExt = {
|
||||
all: All_EXT,
|
||||
image: imageExt,
|
||||
video: videoExt,
|
||||
audio: audioExt,
|
||||
office: officeExt,
|
||||
file: fileExt
|
||||
}
|
||||
export const FileAccept = {
|
||||
all: getAccept(All_EXT),
|
||||
image: getAccept(imageExt),
|
||||
video: getAccept(videoExt),
|
||||
audio: getAccept(audioExt),
|
||||
office: getAccept(officeExt),
|
||||
file: getAccept(fileExt)
|
||||
}
|
@@ -8,6 +8,7 @@ export interface FileUploaderOptions {
|
||||
chunkSize?: number
|
||||
onSuccess?: (filePath: string) => void
|
||||
onError?: (error: Error) => void
|
||||
onCalculateMD5Progress?: (percent: number) => void
|
||||
onUploadProgress?: (
|
||||
chunkIndex: number,
|
||||
chunkCount: number,
|
||||
@@ -43,6 +44,10 @@ export default class FileUploader {
|
||||
this.startChunkIndex = -1
|
||||
this.onError(error)
|
||||
}
|
||||
calculateMD5Progress(chunkIndex: number, chunkTotal: number) {
|
||||
const chunkPercent = Math.floor((chunkIndex / chunkTotal) * 100)
|
||||
this.onCalculateMD5Progress(chunkPercent)
|
||||
}
|
||||
uploadProgress(chunkIndex: number, chunkLoaded: number, chunkTotal: number) {
|
||||
// 计算百分比
|
||||
const chunkPercent = Math.floor((chunkLoaded / chunkTotal) * 100)
|
||||
@@ -52,6 +57,7 @@ export default class FileUploader {
|
||||
onChunkSuccess: FileUploaderOptions['onChunkSuccess'] = function () {}
|
||||
onChunkError: FileUploaderOptions['onChunkError'] = function () {}
|
||||
onError: FileUploaderOptions['onError'] = function () {}
|
||||
onCalculateMD5Progress: FileUploaderOptions['onCalculateMD5Progress'] = function () {}
|
||||
onUploadProgress: FileUploaderOptions['onUploadProgress'] = function () {}
|
||||
|
||||
/**
|
||||
@@ -103,21 +109,21 @@ export default class FileUploader {
|
||||
this.fileSize = file.size
|
||||
this.chunkCount = Math.ceil(this.file.size / this.chunkSize)
|
||||
}
|
||||
readerFile(file: File): Promise<ArrayBuffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!file) {
|
||||
return reject(new Error('读取文件失败'))
|
||||
}
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
resolve(e.target?.result as ArrayBuffer)
|
||||
}
|
||||
reader.onerror = (e) => {
|
||||
reject(e)
|
||||
}
|
||||
reader.readAsArrayBuffer(file)
|
||||
})
|
||||
}
|
||||
// readerFile(file: File): Promise<ArrayBuffer> {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// if (!file) {
|
||||
// return reject(new Error('读取文件失败'))
|
||||
// }
|
||||
// const reader = new FileReader()
|
||||
// reader.onload = (e) => {
|
||||
// resolve(e.target?.result as ArrayBuffer)
|
||||
// }
|
||||
// reader.onerror = (e) => {
|
||||
// reject(e)
|
||||
// }
|
||||
// reader.readAsArrayBuffer(file)
|
||||
// })
|
||||
// }
|
||||
getAbortControllerSignal() {
|
||||
const controller = new AbortController()
|
||||
this.abortControllers.push(controller)
|
||||
@@ -148,8 +154,10 @@ export default class FileUploader {
|
||||
}
|
||||
this.uploading = true
|
||||
|
||||
const arrayBuffer = await this.readerFile(this.file)
|
||||
const fileMd5 = this.getMd5(arrayBuffer)
|
||||
// const arrayBuffer = await this.readerFile(this.file)
|
||||
console.time('SparkMD5')
|
||||
const fileMd5 = await this.calculateMD5(this.file)
|
||||
console.timeEnd('SparkMD5')
|
||||
this.fileMd5 = fileMd5 + '_' + this.fileSize
|
||||
const isExistFilePath = await this.checkFileExist()
|
||||
|
||||
@@ -167,19 +175,58 @@ export default class FileUploader {
|
||||
this.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查上传状态
|
||||
getMd5(arrayBuffer: ArrayBuffer): string {
|
||||
if (!this.uploading) {
|
||||
return
|
||||
}
|
||||
console.time('SparkMD5')
|
||||
/**
|
||||
* 计算文件的MD5值
|
||||
* @param file
|
||||
* @returns
|
||||
*/
|
||||
async calculateMD5(file: File) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const spark = new SparkMD5.ArrayBuffer()
|
||||
spark.append(arrayBuffer)
|
||||
const hash = spark.end()
|
||||
console.timeEnd('SparkMD5')
|
||||
return hash
|
||||
const reader = new FileReader()
|
||||
const chunkSize = 10 * 1024 * 1024 // 10MB 分块
|
||||
let currentChunk = 0
|
||||
const chunks = Math.ceil(file.size / chunkSize)
|
||||
|
||||
reader.onload = function (e) {
|
||||
spark.append(e.target.result) // 添加数组缓冲区
|
||||
currentChunk++
|
||||
|
||||
if (currentChunk < chunks) {
|
||||
loadNext()
|
||||
} else {
|
||||
resolve(spark.end())
|
||||
}
|
||||
}
|
||||
|
||||
reader.onerror = function () {
|
||||
reject('文件读取错误')
|
||||
}
|
||||
|
||||
function loadNext() {
|
||||
console.log('md5进度', currentChunk, chunks)
|
||||
this.calculateMD5Progress(currentChunk, chunks)
|
||||
|
||||
const start = currentChunk * chunkSize
|
||||
const end = Math.min(start + chunkSize, file.size)
|
||||
reader.readAsArrayBuffer(file.slice(start, end))
|
||||
}
|
||||
|
||||
loadNext()
|
||||
})
|
||||
}
|
||||
// 计算文件的MD5值
|
||||
// getMd5(arrayBuffer: ArrayBuffer): string {
|
||||
// if (!this.uploading) {
|
||||
// return
|
||||
// }
|
||||
// console.time('SparkMD5')
|
||||
// const spark = new SparkMD5.ArrayBuffer()
|
||||
// spark.append(arrayBuffer)
|
||||
// const hash = spark.end()
|
||||
// console.timeEnd('SparkMD5')
|
||||
// return hash
|
||||
// }
|
||||
// 检查文件是否存在,可实现秒传
|
||||
async checkFileExist(): Promise<string> {
|
||||
if (!this.uploading) {
|
||||
|
@@ -1,72 +1,22 @@
|
||||
<template>
|
||||
<div class="material-index">
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane
|
||||
v-for="item in tabsMap"
|
||||
:label="item.name"
|
||||
:name="item.name"
|
||||
:index="item.name"
|
||||
:key="item.name"
|
||||
lazy
|
||||
>
|
||||
<material
|
||||
:ext="item.ext"
|
||||
mode="page"
|
||||
file-size="120px"
|
||||
:limit="-1"
|
||||
:page-size="10"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
<MaterialComponent mode="page" :limit="-1" :page-size="10" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import material from '@/components/material/index.vue'
|
||||
import MaterialComponent from '@/components/material/index.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'materialCenter'
|
||||
})
|
||||
const tabsMap = [
|
||||
{
|
||||
// type: '',
|
||||
name: '全部',
|
||||
ext: []
|
||||
},
|
||||
{
|
||||
// type: 'image',
|
||||
name: '图片',
|
||||
ext: ['jpg', 'jpeg', 'png', 'gif', 'bmp']
|
||||
},
|
||||
{
|
||||
// type: 'video',
|
||||
name: '视频',
|
||||
ext: ['mp4', 'avi', 'mov']
|
||||
},
|
||||
{
|
||||
// type: 'pdf',
|
||||
name: 'pdf',
|
||||
ext: ['pdf']
|
||||
}
|
||||
]
|
||||
const activeTab = ref('image')
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.material-index {
|
||||
min-width: 700px;
|
||||
:deep(.el-tabs) {
|
||||
height: calc(100vh - 180px);
|
||||
|
||||
.el-tabs__content,
|
||||
.el-tab-pane {
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
height: calc(100vh - 135px);
|
||||
overflow: hidden;
|
||||
background-color: white;
|
||||
padding: 0 5px 5px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -65,42 +65,6 @@
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="text-right">
|
||||
<!-- <el-button
|
||||
v-perms="['admin:monitor_client:add']"
|
||||
type="primary"
|
||||
@click="handleAdd()"
|
||||
>
|
||||
<template #icon>
|
||||
<icon name="el-icon-Plus" />
|
||||
</template>
|
||||
新增
|
||||
</el-button>
|
||||
<upload
|
||||
v-perms="['admin:monitor_client:ImportFile']"
|
||||
class="ml-3 mr-3"
|
||||
:url="monitor_client_import_file"
|
||||
:data="{ cid: 0 }"
|
||||
type="file"
|
||||
:show-progress="true"
|
||||
@change="resetPage"
|
||||
>
|
||||
<el-button type="primary">
|
||||
<template #icon>
|
||||
<icon name="el-icon-Upload" />
|
||||
</template>
|
||||
导入
|
||||
</el-button>
|
||||
</upload>
|
||||
<el-button
|
||||
v-perms="['admin:monitor_client:ExportFile']"
|
||||
type="primary"
|
||||
@click="exportFile"
|
||||
>
|
||||
<template #icon>
|
||||
<icon name="el-icon-Download" />
|
||||
</template>
|
||||
导出
|
||||
</el-button> -->
|
||||
<el-button
|
||||
v-perms="['admin:monitor_client:delBatch']"
|
||||
type="danger"
|
||||
|
@@ -72,7 +72,7 @@
|
||||
class="ml-3 mr-3"
|
||||
:url="monitor_project_import_file"
|
||||
:data="{ cid: 0 }"
|
||||
type="file"
|
||||
:ext="['xlsx']"
|
||||
:show-progress="true"
|
||||
@change="resetPage"
|
||||
>
|
||||
|
@@ -37,7 +37,7 @@
|
||||
class="ml-3 mr-3"
|
||||
:url="adminImportFile"
|
||||
:data="{ cid: 0 }"
|
||||
type="file"
|
||||
:ext="['xlsx']"
|
||||
:show-progress="true"
|
||||
@change="resetPage"
|
||||
>
|
||||
|
@@ -47,7 +47,7 @@
|
||||
class="ml-3 mr-3"
|
||||
:url="user_protocol_import_file"
|
||||
:data="{ cid: 0 }"
|
||||
type="file"
|
||||
:ext="['xlsx']"
|
||||
:show-progress="true"
|
||||
@change="resetPage"
|
||||
>
|
||||
|
@@ -69,11 +69,14 @@
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSubmit">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<footer-btns>
|
||||
<!-- <footer-btns>
|
||||
<el-button type="primary" @click="handleSubmit">保存</el-button>
|
||||
</footer-btns>
|
||||
</footer-btns> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -105,7 +108,7 @@ const rules = reactive<object>({
|
||||
{
|
||||
required: true,
|
||||
message: '头像不能为空',
|
||||
trigger: ['change']
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
nickname: [
|
||||
|
@@ -20,13 +20,13 @@ var FileConfig = fileConfig{
|
||||
PublicPrefix: "/api/uploads",
|
||||
// 上传文件路径
|
||||
UploadDirectory: "/tmp/uploads/x_admin_go/",
|
||||
UploadImageSize: 10 * 1024 * 1024, // 10MB
|
||||
UploadVideoSize: 500 * 1024 * 1024, // 500MB
|
||||
UploadImageSize: 20 * 1024 * 1024, // 20MB
|
||||
UploadVideoSize: 2000 * 1024 * 1024, // 2000MB
|
||||
UploadFileSize: 1024 * 1024 * 1024, //1GB
|
||||
// 上传图片扩展
|
||||
UploadImageExt: []string{"png", "jpg", "jpeg", "gif", "ico", "bmp", "webp", "avif"},
|
||||
// 上传视频扩展
|
||||
UploadVideoExt: []string{"mp4", "mp3", "avi", "flv", "rmvb", "mov"},
|
||||
// 上传音视频扩展
|
||||
UploadVideoExt: []string{"mp4", "avi", "flv", "wmv", "rmvb", "mov", "mp3", "wav", "flac", "m4a"},
|
||||
|
||||
UploadFileExt: []string{"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "zip", "rar", "7z", "txt"},
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ type UserProtocol struct {
|
||||
Id int `gorm:"primarykey;comment:''"` //
|
||||
Title string `gorm:"comment:'标题'"` // 标题
|
||||
Content string `gorm:"comment:'协议内容'"` // 协议内容
|
||||
Sort core.NullFloat `gorm:"comment:'排序'"` // 排序
|
||||
// Sort core.NullFloat `gorm:"comment:'排序'"` // 排序
|
||||
IsDelete soft_delete.DeletedAt `gorm:"not null;default:0;softDelete:flag,DeletedAtField:DeleteTime;comment:'是否删除: 0=否, 1=是'"`
|
||||
CreateTime core.NullTime `gorm:"autoCreateTime;comment:'创建时间'"` // 创建时间
|
||||
UpdateTime core.NullTime `gorm:"autoUpdateTime;comment:'更新时间'"` // 更新时间
|
||||
|
@@ -134,7 +134,7 @@ func (sd storageDriver) checkFile(fileName string, fileSize int64) (e error) {
|
||||
} else if util.ToolsUtil.Contains(config.FileConfig.UploadVideoExt, fileExt) {
|
||||
// 视频文件
|
||||
if fileSize > config.FileConfig.UploadVideoSize {
|
||||
return response.Failed.SetMessage("上传视频不能超出限制: " + strconv.FormatInt(config.FileConfig.UploadVideoSize/1024/1024, 10) + "M")
|
||||
return response.Failed.SetMessage("上传音视频不能超出限制: " + strconv.FormatInt(config.FileConfig.UploadVideoSize/1024/1024, 10) + "M")
|
||||
}
|
||||
} else if util.ToolsUtil.Contains(config.FileConfig.UploadFileExt, fileExt) {
|
||||
// 文件
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
type UserProtocolListReq struct {
|
||||
Title *string // 标题
|
||||
Content *string // 协议内容
|
||||
Sort *float64 // 排序
|
||||
// Sort *float64 // 排序
|
||||
CreateTimeStart *string // 开始创建时间
|
||||
CreateTimeEnd *string // 结束创建时间
|
||||
UpdateTimeStart *string // 开始更新时间
|
||||
@@ -19,7 +19,7 @@ type UserProtocolListReq struct {
|
||||
type UserProtocolAddReq struct {
|
||||
Title *string // 标题
|
||||
Content *string // 协议内容
|
||||
Sort core.NullFloat // 排序
|
||||
// Sort core.NullFloat // 排序
|
||||
}
|
||||
|
||||
// UserProtocolEditReq 用户协议编辑参数
|
||||
@@ -27,7 +27,7 @@ type UserProtocolEditReq struct {
|
||||
Id int //
|
||||
Title *string // 标题
|
||||
Content *string // 协议内容
|
||||
Sort core.NullFloat // 排序
|
||||
// Sort core.NullFloat // 排序
|
||||
}
|
||||
|
||||
// UserProtocolDetailReq 用户协议详情参数
|
||||
@@ -50,7 +50,7 @@ type UserProtocolResp struct {
|
||||
Id int //
|
||||
Title string // 标题
|
||||
Content string // 协议内容
|
||||
Sort core.NullFloat // 排序
|
||||
// Sort core.NullFloat // 排序
|
||||
CreateTime core.NullTime // 创建时间
|
||||
UpdateTime core.NullTime // 更新时间
|
||||
}
|
||||
|
@@ -48,9 +48,6 @@ func (albSrv albumService) AlbumList(adminId uint, page request.PageReq, listReq
|
||||
albumModel = albumModel.Where("ext in ?", listReq.Ext)
|
||||
}
|
||||
|
||||
// if listReq.Type > 0 {
|
||||
// albumModel = albumModel.Where("type = ?", listReq.Type)
|
||||
// }
|
||||
// 总数
|
||||
var count int64
|
||||
err := albumModel.Count(&count).Error
|
||||
@@ -134,7 +131,7 @@ func (albSrv albumService) AlbumAdd(addReq commonSchema.CommonAlbumAddReq) (res
|
||||
//}
|
||||
convert_util.Copy(&alb, addReq)
|
||||
err := albSrv.db.Create(&alb).Error
|
||||
if e = response.CheckErr(err, "Album添加失败"); e != nil {
|
||||
if e = response.CheckErr(err, "相册添加失败"); e != nil {
|
||||
return
|
||||
}
|
||||
return alb.ID, nil
|
||||
@@ -144,7 +141,7 @@ func (albSrv albumService) AlbumAdd(addReq commonSchema.CommonAlbumAddReq) (res
|
||||
func (albSrv albumService) AlbumDel(ids []uint) (e error) {
|
||||
var albums []common_model.Album
|
||||
err := albSrv.db.Where("id in ? AND is_delete = ?", ids, 0).Find(&albums).Error
|
||||
if e = response.CheckErr(err, "AlbumDel Find err"); e != nil {
|
||||
if e = response.CheckErr(err, "相册文件查找失败"); e != nil {
|
||||
return
|
||||
}
|
||||
if len(albums) == 0 {
|
||||
@@ -152,7 +149,7 @@ func (albSrv albumService) AlbumDel(ids []uint) (e error) {
|
||||
}
|
||||
err = albSrv.db.Model(&common_model.Album{}).Where("id in ?", ids).Updates(
|
||||
common_model.Album{IsDelete: 1, DeleteTime: util.NullTimeUtil.Now()}).Error
|
||||
e = response.CheckErr(err, "AlbumDel UpdateColumn err")
|
||||
e = response.CheckErr(err, "相册文件删除失败")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -169,7 +166,7 @@ func (albSrv albumService) CateList(adminId uint, listReq commonSchema.CommonCat
|
||||
cateModel = cateModel.Where("name like ?", "%"+listReq.Name+"%")
|
||||
}
|
||||
err := cateModel.Find(&cates).Error
|
||||
if e = response.CheckErr(err, "Cate列表获取失败"); e != nil {
|
||||
if e = response.CheckErr(err, "分类列表获取失败"); e != nil {
|
||||
return
|
||||
}
|
||||
cateResps := []commonSchema.CommonCateListResp{}
|
||||
@@ -181,11 +178,17 @@ func (albSrv albumService) CateList(adminId uint, listReq commonSchema.CommonCat
|
||||
func (albSrv albumService) CateAdd(adminId uint, addReq commonSchema.CommonCateAddReq) (e error) {
|
||||
|
||||
var cate common_model.AlbumCate
|
||||
// 查询分类是否存在
|
||||
albSrv.db.Where("admin_id = ? AND pid=? AND name = ? AND is_delete = ?", adminId, addReq.Pid, addReq.Name, 0).Limit(1).First(&cate)
|
||||
if cate.ID > 0 {
|
||||
return response.AssertArgumentError.SetMessage("分类已存在!")
|
||||
}
|
||||
|
||||
convert_util.Copy(&cate, addReq)
|
||||
cate.AdminId = adminId
|
||||
|
||||
err := albSrv.db.Create(&cate).Error
|
||||
e = response.CheckErr(err, "Cate添加失败")
|
||||
e = response.CheckErr(err, "分类添加失败")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -196,12 +199,19 @@ func (albSrv albumService) CateRename(id uint, name string) (e error) {
|
||||
if e = response.CheckErrDBNotRecord(err, "分类已不存在!"); e != nil {
|
||||
return
|
||||
}
|
||||
if e = response.CheckErr(err, "CateRename First err"); e != nil {
|
||||
if e = response.CheckErr(err, "重命名失败"); e != nil {
|
||||
return
|
||||
}
|
||||
var cate2 common_model.AlbumCate
|
||||
// 查询分类是否存在
|
||||
albSrv.db.Where("admin_id = ? AND pid=? AND name = ? AND is_delete = ? AND id <> ?", cate.AdminId, cate.Pid, name, 0, cate.ID).Limit(1).First(&cate2)
|
||||
if cate2.ID > 0 {
|
||||
return response.AssertArgumentError.SetMessage("分类“" + name + "”已存在!")
|
||||
}
|
||||
|
||||
cate.Name = name
|
||||
err = albSrv.db.Save(&cate).Error
|
||||
e = response.CheckErr(err, "CateRename Save err")
|
||||
e = response.CheckErr(err, "分类重命名失败")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -212,11 +222,11 @@ func (albSrv albumService) CateDel(id uint) (e error) {
|
||||
if e = response.CheckErrDBNotRecord(err, "分类已不存在!"); e != nil {
|
||||
return
|
||||
}
|
||||
if e = response.CheckErr(err, "Cate待删除数据查找失败"); e != nil {
|
||||
if e = response.CheckErr(err, "待删除数据查找失败"); e != nil {
|
||||
return
|
||||
}
|
||||
r := albSrv.db.Where("cid = ? AND is_delete = ?", id, 0).Limit(1).Find(&common_model.Album{})
|
||||
if e = response.CheckErr(r.Error, "CateDel Find err"); e != nil {
|
||||
if e = response.CheckErr(r.Error, "分类数据使用失败"); e != nil {
|
||||
return
|
||||
}
|
||||
if r.RowsAffected > 0 {
|
||||
|
@@ -66,7 +66,7 @@
|
||||
class="ml-3 mr-3"
|
||||
:url="{{{.ModuleName}}}_import_file"
|
||||
:data="{ cid: 0 }"
|
||||
type="file"
|
||||
:ext="['xlsx']"
|
||||
:show-progress="true"
|
||||
@change="resetPage"
|
||||
>
|
||||
|
@@ -42,9 +42,9 @@ func (service userProtocolService) GetModel(listReq schema.UserProtocolListReq)
|
||||
if listReq.Content != nil {
|
||||
dbModel = dbModel.Where("content = ?", *listReq.Content)
|
||||
}
|
||||
if listReq.Sort != nil {
|
||||
dbModel = dbModel.Where("sort = ?", *listReq.Sort)
|
||||
}
|
||||
// if listReq.Sort != nil {
|
||||
// dbModel = dbModel.Where("sort = ?", *listReq.Sort)
|
||||
// }
|
||||
if listReq.CreateTimeStart != nil {
|
||||
dbModel = dbModel.Where("create_time >= ?", *listReq.CreateTimeStart)
|
||||
}
|
||||
|
Reference in New Issue
Block a user