feat: 使用prettierrc对代码进行格式化

This commit is contained in:
piexlMax(奇淼
2024-11-09 10:32:26 +08:00
parent 87a4ce17e1
commit 7d9af64f6d
139 changed files with 12677 additions and 12656 deletions
+34 -35
View File
@@ -27,42 +27,41 @@
</template>
<script setup>
defineOptions({
name: 'ArrayCtrl',
})
import { nextTick, ref } from 'vue'
const inputValue = ref('')
const inputVisible = ref(false)
const InputRef = ref(null)
const modelValue = defineModel()
defineProps({
editable: {
type: Boolean,
default: () => false
}
})
const handleClose = (tag) => {
modelValue.value.splice(modelValue.value.indexOf(tag), 1)
}
const showInput = () => {
inputVisible.value = true
nextTick(() => {
InputRef.value?.input?.focus()
defineOptions({
name: 'ArrayCtrl'
})
}
const handleInputConfirm = () => {
if (inputValue.value) {
modelValue.value.push(inputValue.value)
import { nextTick, ref } from 'vue'
const inputValue = ref('')
const inputVisible = ref(false)
const InputRef = ref(null)
const modelValue = defineModel()
defineProps({
editable: {
type: Boolean,
default: () => false
}
})
const handleClose = (tag) => {
modelValue.value.splice(modelValue.value.indexOf(tag), 1)
}
const showInput = () => {
inputVisible.value = true
nextTick(() => {
InputRef.value?.input?.focus()
})
}
const handleInputConfirm = () => {
if (inputValue.value) {
modelValue.value.push(inputValue.value)
}
inputVisible.value = false
inputValue.value = ''
}
inputVisible.value = false
inputValue.value = ''
}
</script>
+17 -14
View File
@@ -3,14 +3,17 @@
未经授权的商用使用可能会被我们的资产搜索引擎爬取,并可能导致后续索赔。索赔金额将不低于高级授权费的十倍。请您遵守版权法律法规,尊重知识产权。
-->
<template>
<div class="flex flex-col md:flex-row gap-2 items-center text-sm text-slate-700 dark:text-slate-500 justify-center py-2">
<div
class="flex flex-col md:flex-row gap-2 items-center text-sm text-slate-700 dark:text-slate-500 justify-center py-2"
>
<div class="text-center">
<span class="mr-1">Powered by</span>
<span>
<a
class="font-bold text-active"
href="https://github.com/flipped-aurora/gin-vue-admin"
>Gin-Vue-Admin</a>
>Gin-Vue-Admin</a
>
</span>
</div>
<slot />
@@ -20,22 +23,22 @@
<a
class="font-bold text-active"
href="https://github.com/flipped-aurora"
>flipped-aurora团队</a>
>flipped-aurora团队</a
>
</span>
</div>
</div>
</template>
<script setup>
defineOptions({
name: 'BottomInfo'
})
<script setup>
defineOptions({
name: 'BottomInfo'
})
console.log(
`%c powered by %c flipped-aurorae %c`,
'background:#0081ff; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
'background:#354855; padding: 1px 5px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;',
'background:transparent'
)
console.log(
`%c powered by %c flipped-aurorae %c`,
'background:#0081ff; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
'background:#354855; padding: 1px 5px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;',
'background:transparent'
)
</script>
+32 -34
View File
@@ -14,43 +14,41 @@
/>
</template>
<script setup>
import { ref, nextTick } from 'vue';
import VCharts from 'vue-echarts';
import { useWindowResize } from '@/hooks/use-windows-resize'
<script setup>
import { ref, nextTick } from 'vue'
import VCharts from 'vue-echarts'
import { useWindowResize } from '@/hooks/use-windows-resize'
defineProps({
options: {
type: Object,
default() {
return {};
defineProps({
options: {
type: Object,
default() {
return {}
}
},
},
autoResize: {
type: Boolean,
default: true,
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: '100%',
},
});
const renderChart = ref(false);
nextTick(() => {
renderChart.value = true;
});
useWindowResize(()=>{
renderChart.value = false;
autoResize: {
type: Boolean,
default: true
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '100%'
}
})
const renderChart = ref(false)
nextTick(() => {
renderChart.value = true;
});
})
renderChart.value = true
})
useWindowResize(() => {
renderChart.value = false
nextTick(() => {
renderChart.value = true
})
})
</script>
<style scoped lang="less"></style>
+152 -150
View File
@@ -10,20 +10,16 @@
v-model="searchInput"
class="quick-input"
placeholder="请输入你需要快捷到达的功能"
>
/>
</template>
<div
v-for="(option,index) in options"
:key="index"
>
<div v-for="(option, index) in options" :key="index">
<div v-if="option.children.length" class="quick-title">
{{ option.label }}
</div>
<div
v-if="option.children.length"
class="quick-title"
>{{ option.label }}</div>
<div
v-for="(item,key) in option.children"
:key="index+'-'+key"
v-for="(item, key) in option.children"
:key="index + '-' + key"
class="quick-item"
@click="item.func"
>
@@ -40,158 +36,164 @@
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useRouterStore } from '@/pinia/modules/router'
import { useAppStore,useUserStore } from '@/pinia'
defineOptions({
name: 'CommandMenu',
})
const appStore = useAppStore()
const userStore = useUserStore()
import { reactive, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useRouterStore } from '@/pinia/modules/router'
import { useAppStore, useUserStore } from '@/pinia'
defineOptions({
name: 'CommandMenu'
})
const appStore = useAppStore()
const userStore = useUserStore()
const router = useRouter()
const route = useRouter()
const routerStore = useRouterStore()
const dialogVisible = ref(false)
const searchInput = ref('')
const options = reactive([])
const deepMenus = (menus) => {
const arr = []
menus.forEach(menu => {
if (menu.children && menu.children.length > 0) {
arr.push(...deepMenus(menu.children))
} else {
if (menu.meta.title && menu.meta.title.indexOf(searchInput.value) > -1) {
arr.push({
label: menu.meta.title,
func: () => changeRouter(menu)
})
const router = useRouter()
const route = useRouter()
const routerStore = useRouterStore()
const dialogVisible = ref(false)
const searchInput = ref('')
const options = reactive([])
const deepMenus = (menus) => {
const arr = []
menus.forEach((menu) => {
if (menu.children && menu.children.length > 0) {
arr.push(...deepMenus(menu.children))
} else {
if (
menu.meta.title &&
menu.meta.title.indexOf(searchInput.value) > -1
) {
arr.push({
label: menu.meta.title,
func: () => changeRouter(menu)
})
}
}
})
return arr
}
const addQuickMenu = () => {
const option = {
label: '跳转',
children: []
}
})
return arr
}
const addQuickMenu = () => {
const option = {
label: '跳转',
children: []
const menus = deepMenus(routerStore.asyncRouters[0].children)
option.children.push(...menus)
options.push(option)
}
const menus = deepMenus(routerStore.asyncRouters[0].children)
option.children.push(...menus)
options.push(option)
}
const addQuickOption = () => {
const option = {
label: '操作',
children: []
}
const quickArr = [
{
label: '亮色主题',
func: () => changeMode('light')
}, {
label: '暗色主题',
func: () => changeMode('dark')
}, {
label: '退出登录',
func: () => userStore.LoginOut()
const addQuickOption = () => {
const option = {
label: '操作',
children: []
}
]
option.children.push(...quickArr.filter(item => item.label.indexOf(searchInput.value) > -1))
options.push(option)
}
addQuickMenu()
addQuickOption()
const open = () => {
dialogVisible.value = true
}
const changeRouter = (e) => {
const index = e.name
const query = {}
const params = {}
routerStore.routeMap[index]?.parameters &&
routerStore.routeMap[index]?.parameters.forEach((item) => {
if (item.type === 'query') {
query[item.key] = item.value
} else {
params[item.key] = item.value
}
})
if (index === route.name) return
if (e.name.indexOf('http://') > -1 || e.name.indexOf('https://') > -1) {
window.open(e.name)
} else {
router.push({ name: index, query, params })
const quickArr = [
{
label: '亮色主题',
func: () => changeMode('light')
},
{
label: '暗色主题',
func: () => changeMode('dark')
},
{
label: '退出登录',
func: () => userStore.LoginOut()
}
]
option.children.push(
...quickArr.filter((item) => item.label.indexOf(searchInput.value) > -1)
)
options.push(option)
}
dialogVisible.value = false
}
const changeMode = (e) => {
if (e === null) {
appStore.toggleTheme(false )
return
}
appStore.toggleTheme(true )
}
const close = () => {
dialogVisible.value = false
}
defineExpose({ open })
watch(searchInput, () => {
options.length = 0
addQuickMenu()
addQuickOption()
})
const open = () => {
dialogVisible.value = true
}
const changeRouter = (e) => {
const index = e.name
const query = {}
const params = {}
routerStore.routeMap[index]?.parameters &&
routerStore.routeMap[index]?.parameters.forEach((item) => {
if (item.type === 'query') {
query[item.key] = item.value
} else {
params[item.key] = item.value
}
})
if (index === route.name) return
if (e.name.indexOf('http://') > -1 || e.name.indexOf('https://') > -1) {
window.open(e.name)
} else {
router.push({ name: index, query, params })
}
dialogVisible.value = false
}
const changeMode = (e) => {
if (e === null) {
appStore.toggleTheme(false)
return
}
appStore.toggleTheme(true)
}
const close = () => {
dialogVisible.value = false
}
defineExpose({ open })
watch(searchInput, () => {
options.length = 0
addQuickMenu()
addQuickOption()
})
</script>
<style lang="scss">
.overlay {
border-radius: 4px;
.el-dialog__header{
padding:0 !important;
margin-right:0 !important;
}
.el-dialog__body{
padding: 12px !important;
height: 50vh;
overflow: auto !important;
}
.quick-title{
margin-top: 8px;
font-size: 12px;
font-weight: 600;
color: #666;
}
.quick-input{
@apply bg-gray-50 dark:bg-gray-800;
color: #666;
border-radius: 4px 4px 0 0;
border:none;
padding: 12px 16px;
box-sizing: border-box;
width: 100%;
font-size: 16px;
border-bottom: 1px solid #ddd;
}
.quick-item{
font-size: 14px;
padding: 8px;
margin: 4px 0;
&:hover{
@apply bg-gray-200 dark:bg-slate-500;
cursor: pointer;
border-radius: 4px;
.overlay {
border-radius: 4px;
.el-dialog__header {
padding: 0 !important;
margin-right: 0 !important;
}
.el-dialog__body {
padding: 12px !important;
height: 50vh;
overflow: auto !important;
}
.quick-title {
margin-top: 8px;
font-size: 12px;
font-weight: 600;
color: #666;
}
.quick-input {
@apply bg-gray-50 dark:bg-gray-800;
color: #666;
border-radius: 4px 4px 0 0;
border: none;
padding: 12px 16px;
box-sizing: border-box;
width: 100%;
font-size: 16px;
border-bottom: 1px solid #ddd;
}
.quick-item {
font-size: 14px;
padding: 8px;
margin: 4px 0;
&:hover {
@apply bg-gray-200 dark:bg-slate-500;
cursor: pointer;
border-radius: 4px;
}
}
}
}
</style>
+58 -72
View File
@@ -1,28 +1,12 @@
<template>
<span class="headerAvatar ">
<span class="headerAvatar">
<template v-if="picType === 'avatar'">
<el-avatar
v-if="userStore.userInfo.headerImg"
:size="30"
:src="avatar"
/>
<el-avatar
v-else
:size="30"
:src="noAvatar"
/>
<el-avatar v-if="userStore.userInfo.headerImg" :size="30" :src="avatar" />
<el-avatar v-else :size="30" :src="noAvatar" />
</template>
<template v-if="picType === 'img'">
<img
v-if="userStore.userInfo.headerImg"
:src="avatar"
class="avatar"
>
<img
v-else
:src="noAvatar"
class="avatar"
>
<img v-if="userStore.userInfo.headerImg" :src="avatar" class="avatar" />
<img v-else :src="noAvatar" class="avatar" />
</template>
<template v-if="picType === 'file'">
<el-image
@@ -36,69 +20,71 @@
</template>
<script setup>
import noAvatarPng from '@/assets/noBody.png'
import { useUserStore } from '@/pinia/modules/user'
import { computed, ref } from 'vue'
import noAvatarPng from '@/assets/noBody.png'
import { useUserStore } from '@/pinia/modules/user'
import { computed, ref } from 'vue'
defineOptions({
name: 'CustomPic'
})
defineOptions({
name: 'CustomPic'
})
const props = defineProps({
picType: {
type: String,
required: false,
default: 'avatar'
},
picSrc: {
type: String,
required: false,
default: ''
},
preview: {
type: Boolean,
default: false
}
})
const path = ref(import.meta.env.VITE_BASE_API + '/')
const noAvatar = ref(noAvatarPng)
const userStore = useUserStore()
const avatar = computed(() => {
if (props.picSrc === '') {
if (userStore.userInfo.headerImg !== '' && userStore.userInfo.headerImg.slice(0, 4) === 'http') {
return userStore.userInfo.headerImg
const props = defineProps({
picType: {
type: String,
required: false,
default: 'avatar'
},
picSrc: {
type: String,
required: false,
default: ''
},
preview: {
type: Boolean,
default: false
}
return path.value + userStore.userInfo.headerImg
} else {
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
return props.picSrc
}
return path.value + props.picSrc
}
})
const file = computed(() => {
if (props.picSrc && props.picSrc.slice(0, 4) !== 'http') {
return path.value + props.picSrc
}
return props.picSrc
})
const previewSrcList = computed(() => props.preview ? [file.value] : [])
})
const path = ref(import.meta.env.VITE_BASE_API + '/')
const noAvatar = ref(noAvatarPng)
const userStore = useUserStore()
const avatar = computed(() => {
if (props.picSrc === '') {
if (
userStore.userInfo.headerImg !== '' &&
userStore.userInfo.headerImg.slice(0, 4) === 'http'
) {
return userStore.userInfo.headerImg
}
return path.value + userStore.userInfo.headerImg
} else {
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
return props.picSrc
}
return path.value + props.picSrc
}
})
const file = computed(() => {
if (props.picSrc && props.picSrc.slice(0, 4) !== 'http') {
return path.value + props.picSrc
}
return props.picSrc
})
const previewSrcList = computed(() => (props.preview ? [file.value] : []))
</script>
<style scoped>
.headerAvatar{
.headerAvatar {
display: flex;
justify-content: center;
align-items: center;
margin-right: 8px;
}
.file{
}
.file {
width: 80px;
height: 80px;
position: relative;
}
}
</style>
+51 -50
View File
@@ -1,58 +1,59 @@
<template>
<el-button
type="primary"
icon="download"
@click="exportExcelFunc"
>导出</el-button>
<el-button type="primary" icon="download" @click="exportExcelFunc"
>导出</el-button
>
</template>
<script setup>
const props = defineProps({
templateId: {
type: String,
required: true
},
condition: {
type: Object,
default: () => ({})
},
limit: {
type: Number,
default: 0
},
offset: {
type: Number,
default: 0
},
order: {
type: String,
default: ''
}
})
const props = defineProps({
templateId: {
type: String,
required: true
},
condition: {
type: Object,
default: () => ({})
},
limit: {
type: Number,
default: 0
},
offset: {
type: Number,
default: 0
},
order: {
type: String,
default: ''
}
})
import { ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus'
const exportExcelFunc = async() => {
if (props.templateId === '') {
ElMessage.error('组件未设置模板ID')
return
}
const baseUrl = import.meta.env.VITE_BASE_API
const paramsCopy = JSON.parse(JSON.stringify(props.condition))
if (props.limit) {
paramsCopy.limit = props.limit
}
if (props.offset) {
paramsCopy.offset = props.offset
}
if (props.order) {
paramsCopy.order = props.order
}
const params = Object.entries(paramsCopy)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&')
const url = `${baseUrl}/sysExportTemplate/exportExcel?templateID=${props.templateId}${params ? '&' + params : ''}`
const exportExcelFunc = async () => {
if (props.templateId === '') {
ElMessage.error('组件未设置模板ID')
return
}
const baseUrl = import.meta.env.VITE_BASE_API
const paramsCopy = JSON.parse(JSON.stringify(props.condition))
if (props.limit) {
paramsCopy.limit = props.limit
}
if (props.offset) {
paramsCopy.offset = props.offset
}
if (props.order) {
paramsCopy.order = props.order
}
const params = Object.entries(paramsCopy)
.map(
([key, value]) =>
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
)
.join('&')
const url = `${baseUrl}/sysExportTemplate/exportExcel?templateID=${props.templateId}${params ? '&' + params : ''}`
window.open(url, '_blank')
}
window.open(url, '_blank')
}
</script>
@@ -1,28 +1,26 @@
<template>
<el-button
type="primary"
icon="download"
@click="exportTemplate"
>下载模板</el-button>
<el-button type="primary" icon="download" @click="exportTemplate"
>下载模板</el-button
>
</template>
<script setup>
const props = defineProps({
templateId: {
type: String,
required: true
}
})
const props = defineProps({
templateId: {
type: String,
required: true
}
})
import { ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus'
const exportTemplate = async() => {
if (props.templateId === '') {
ElMessage.error('组件未设置模板ID')
return
const exportTemplate = async () => {
if (props.templateId === '') {
ElMessage.error('组件未设置模板ID')
return
}
const baseUrl = import.meta.env.VITE_BASE_API
const url = `${baseUrl}/sysExportTemplate/exportTemplate?templateID=${props.templateId}`
window.open(url, '_blank')
}
const baseUrl = import.meta.env.VITE_BASE_API
const url = `${baseUrl}/sysExportTemplate/exportTemplate?templateID=${props.templateId}`
window.open(url, '_blank')
}
</script>
+21 -27
View File
@@ -5,38 +5,32 @@
:on-success="handleSuccess"
:multiple="false"
>
<el-button
type="primary"
icon="upload"
class="ml-3"
>
导入
</el-button>
<el-button type="primary" icon="upload" class="ml-3"> 导入 </el-button>
</el-upload>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus'
const baseUrl = import.meta.env.VITE_BASE_API
const baseUrl = import.meta.env.VITE_BASE_API
const props = defineProps({
templateId: {
type: String,
required: true
const props = defineProps({
templateId: {
type: String,
required: true
}
})
const emit = defineEmits(['on-success'])
const url = `${baseUrl}/sysExportTemplate/importExcel?templateID=${props.templateId}`
const handleSuccess = (res) => {
if (res.code === 0) {
ElMessage.success('导入成功')
emit('on-success')
} else {
ElMessage.error(res.msg)
}
}
})
const emit = defineEmits(['on-success'])
const url = `${baseUrl}/sysExportTemplate/importExcel?templateID=${props.templateId}`
const handleSuccess = (res) => {
if (res.code === 0) {
ElMessage.success('导入成功')
emit('on-success')
} else {
ElMessage.error(res.msg)
}
}
</script>
+22 -26
View File
@@ -1,35 +1,31 @@
<template>
<vue-office-docx
:src="docx"
@rendered="rendered"
/>
<vue-office-docx :src="docx" @rendered="rendered" />
</template>
<script>
export default {
name: 'Docx'
}
export default {
name: 'Docx'
}
</script>
<script setup>
import { ref, watch } from 'vue'
import { ref, watch } from 'vue'
// 引入VueOfficeDocx组件
import VueOfficeDocx from '@vue-office/docx'
// 引入相关样式
import '@vue-office/docx/lib/index.css'
// 引入VueOfficeDocx组件
import VueOfficeDocx from '@vue-office/docx'
// 引入相关样式
import '@vue-office/docx/lib/index.css'
const model = defineModel({
type: String,
})
const model = defineModel({
type: String
})
const docx = ref(null)
watch(
() => model,
value => { docx.value = value },
{ immediate: true }
)
const rendered = () => {
}
const docx = ref(null)
watch(
() => model,
(value) => {
docx.value = value
},
{ immediate: true }
)
const rendered = () => {}
</script>
<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>
+29 -26
View File
@@ -1,33 +1,36 @@
<template>
<VueOfficeExcel :src="excel" @rendered="renderedHandler" @error="errorHandler" style="height: 100vh;width: 100vh"/>
<VueOfficeExcel
:src="excel"
@rendered="renderedHandler"
@error="errorHandler"
style="height: 100vh; width: 100vh"
/>
</template>
<script>
export default {
name: 'Excel'
}
export default {
name: 'Excel'
}
</script>
<script setup>
//引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
//引入相关样式
import '@vue-office/excel/lib/index.css'
import {ref, watch} from 'vue'
//引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
//引入相关样式
import '@vue-office/excel/lib/index.css'
import { ref, watch } from 'vue'
const props = defineProps({
modelValue: {
type: String,
default: () => ""
}
})
const excel = ref('')
watch(() => props.modelValue, val => excel.value = val, {immediate: true})
const renderedHandler = () => {
}
const errorHandler = () => {
}
const props = defineProps({
modelValue: {
type: String,
default: () => ''
}
})
const excel = ref('')
watch(
() => props.modelValue,
(val) => (excel.value = val),
{ immediate: true }
)
const renderedHandler = () => {}
const errorHandler = () => {}
</script>
<style>
</style>
<style></style>
+29 -33
View File
@@ -1,53 +1,49 @@
<template>
<div class="border border-solid border-gray-100 h-full w-full">
<el-row>
<div v-if="ext==='docx'">
<div v-if="ext === 'docx'">
<Docx v-model="fullFileURL" />
</div>
<div v-else-if="ext==='pdf'">
<div v-else-if="ext === 'pdf'">
<Pdf v-model="fullFileURL" />
</div>
<div v-else-if="ext==='xlsx'">
<div v-else-if="ext === 'xlsx'">
<Excel v-model="fullFileURL" />
</div>
<div v-else-if="ext==='image'">
<el-image
:src="fullFileURL"
lazy
/>
<div v-else-if="ext === 'image'">
<el-image :src="fullFileURL" lazy />
</div>
</el-row>
</div>
</template>
<script>
export default {
name: 'Office'
}
export default {
name: 'Office'
}
</script>
<script setup>
import { ref, watch, computed } from 'vue'
import Docx from '@/components/office/docx.vue'
import Pdf from '@/components/office/pdf.vue'
import Excel from '@/components/office/excel.vue'
import { ref, watch, computed } from 'vue'
import Docx from '@/components/office/docx.vue'
import Pdf from '@/components/office/pdf.vue'
import Excel from '@/components/office/excel.vue'
const path = ref(import.meta.env.VITE_BASE_API)
const path = ref(import.meta.env.VITE_BASE_API)
const model = defineModel({ type: String})
const model = defineModel({ type: String })
const fileUrl = ref('')
const ext = ref('')
watch(
() => model,
val => {
fileUrl.value = val
const fileExt = val.split('.')[1] || ''
const image = ['png', 'jpg', 'jpeg', 'gif']
ext.value = image.includes(fileExt) ? 'image' : fileExt
},
{ immediate: true }
)
const fullFileURL = computed(() => {
return path.value + '/' + fileUrl.value
})
const fileUrl = ref('')
const ext = ref('')
watch(
() => model,
(val) => {
fileUrl.value = val
const fileExt = val.split('.')[1] || ''
const image = ['png', 'jpg', 'jpeg', 'gif']
ext.value = image.includes(fileExt) ? 'image' : fileExt
},
{ immediate: true }
)
const fullFileURL = computed(() => {
return path.value + '/' + fileUrl.value
})
</script>
+30 -27
View File
@@ -1,36 +1,39 @@
<template>
<vue-office-pdf
:src="pdf"
@rendered="renderedHandler"
@error="errorHandler"
:src="pdf"
@rendered="renderedHandler"
@error="errorHandler"
/>
</template>
<script>
export default {
name: "Pdf"
}
export default {
name: 'Pdf'
}
</script>
<script setup>
import {ref, watch} from "vue"
import { ref, watch } from 'vue'
//引入VueOfficeDocx组件
import VueOfficePdf from "@vue-office/pdf";
//引入相关样式
import '@vue-office/docx/lib/index.css'
console.log("pdf===>")
const props = defineProps({
modelValue: {
type: String,
default: () => ""
//引入VueOfficeDocx组件
import VueOfficePdf from '@vue-office/pdf'
//引入相关样式
import '@vue-office/docx/lib/index.css'
console.log('pdf===>')
const props = defineProps({
modelValue: {
type: String,
default: () => ''
}
})
const pdf = ref(null)
watch(
() => props.modelValue,
(val) => (pdf.value = val),
{ immediate: true }
)
const renderedHandler = () => {
console.log('pdf 加载成功')
}
})
const pdf = ref(null)
watch(() => props.modelValue, val => pdf.value = val, {immediate: true})
const renderedHandler = () => {
console.log("pdf 加载成功")
}
const errorHandler = () => {
console.log("pdf 错误")
}
</script>
const errorHandler = () => {
console.log('pdf 错误')
}
</script>
+52 -53
View File
@@ -8,7 +8,7 @@
<Editor
v-model="valueHtml"
class="overflow-y-hidden mt-0.5"
style="height: 18rem;"
style="height: 18rem"
:default-config="editorConfig"
mode="default"
@onCreated="handleCreated"
@@ -18,70 +18,69 @@
</template>
<script setup>
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import '@wangeditor/editor/dist/css/style.css' // 引入 css
const basePath = import.meta.env.VITE_BASE_API
const basePath = import.meta.env.VITE_BASE_API
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { ElMessage } from 'element-plus'
import { getUrl } from '@/utils/image'
import { ElMessage } from 'element-plus'
import { getUrl } from '@/utils/image'
const emits = defineEmits(['change', 'update:modelValue'])
const emits = defineEmits(['change', 'update:modelValue'])
const change = (editor) => {
emits('change', editor)
emits('update:modelValue', valueHtml.value)
}
const props = defineProps({
modelValue: {
type: String,
default: ''
const change = (editor) => {
emits('change', editor)
emits('update:modelValue', valueHtml.value)
}
})
const editorRef = shallowRef()
const valueHtml = ref('')
const props = defineProps({
modelValue: {
type: String,
default: ''
}
})
const toolbarConfig = {}
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
fieldName: 'file',
server: basePath + '/fileUploadAndDownload/upload?noSave=1',
customInsert(res, insertFn) {
if (res.code === 0) {
const urlPath = getUrl(res.data.file.url)
insertFn(urlPath, res.data.file.name)
return
const editorRef = shallowRef()
const valueHtml = ref('')
const toolbarConfig = {}
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
fieldName: 'file',
server: basePath + '/fileUploadAndDownload/upload?noSave=1',
customInsert(res, insertFn) {
if (res.code === 0) {
const urlPath = getUrl(res.data.file.url)
insertFn(urlPath, res.data.file.name)
return
}
ElMessage.error(res.msg)
}
ElMessage.error(res.msg)
}
}
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const handleCreated = (editor) => {
editorRef.value = editor
valueHtml.value = props.modelValue
}
watch(() => props.modelValue, () => {
valueHtml.value = props.modelValue
})
const handleCreated = (editor) => {
editorRef.value = editor
valueHtml.value = props.modelValue
}
watch(
() => props.modelValue,
() => {
valueHtml.value = props.modelValue
}
)
</script>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>
+36 -36
View File
@@ -11,48 +11,48 @@
</div>
</template>
<script setup>
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor } from '@wangeditor/editor-for-vue'
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor } from '@wangeditor/editor-for-vue'
const emits = defineEmits(['change', 'update:modelValue'])
const editorConfig = ref({
readOnly: true
})
const change = (editor) => {
emits('change', editor)
emits('update:modelValue', valueHtml.value)
}
const props = defineProps({
modelValue: {
type: String,
default: ''
const emits = defineEmits(['change', 'update:modelValue'])
const editorConfig = ref({
readOnly: true
})
const change = (editor) => {
emits('change', editor)
emits('update:modelValue', valueHtml.value)
}
})
const editorRef = shallowRef()
const valueHtml = ref('')
const props = defineProps({
modelValue: {
type: String,
default: ''
}
})
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const editorRef = shallowRef()
const valueHtml = ref('')
const handleCreated = (editor) => {
editorRef.value = editor
valueHtml.value = props.modelValue
}
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
watch(() => props.modelValue, () => {
valueHtml.value = props.modelValue
})
const handleCreated = (editor) => {
editorRef.value = editor
valueHtml.value = props.modelValue
}
watch(
() => props.modelValue,
() => {
valueHtml.value = props.modelValue
}
)
</script>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>
+48 -54
View File
@@ -12,76 +12,70 @@
:accept="accept"
class="upload-btn"
>
<el-button type="primary">
上传文件
</el-button>
<el-button type="primary"> 上传文件 </el-button>
</el-upload>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
defineOptions({
name: 'UploadCommon'
})
defineOptions({
name: 'UploadCommon',
})
defineProps({
limit: {
type: Number,
default: 3
},
accept: {
type: String,
default: ''
}
})
defineProps({
limit: {
type: Number,
default: 3
},
accept: {
type: String,
default: ''
},
})
const fullscreenLoading = ref(false)
const model = defineModel({ type: Array })
const fullscreenLoading = ref(false)
const fileList = ref(model.value)
const model = defineModel({ type: Array })
const emits = defineEmits(['on-success', 'on-error'])
const fileList = ref(model.value)
const uploadSuccess = (res) => {
const { data, code } = res
if (code !== 0) {
ElMessage({
type: 'error',
message: '上传失败' + res.msg
})
fileList.value.pop()
return
}
model.value.push({
name: data.file.name,
url: data.file.url
})
emits('on-success', res)
}
const emits = defineEmits(['on-success', 'on-error'])
const uploadRemove = (file) => {
const index = model.value.indexOf(file)
if (index > -1) {
model.value.splice(index, 1)
fileList.value = model.value
}
}
const uploadSuccess = (res) => {
const { data,code } = res
if(code !== 0){
const uploadError = (err) => {
ElMessage({
type: 'error',
message: '上传失败'+res.msg
message: '上传失败'
})
fileList.value.pop()
return
fullscreenLoading.value = false
emits('on-error', err)
}
model.value.push({
name: data.file.name,
url: data.file.url
})
emits('on-success', res)
}
const uploadRemove = (file) => {
const index = model.value.indexOf(file)
if (index > -1) {
model.value.splice(index, 1)
fileList.value = model.value
}
}
const uploadError = (err) => {
ElMessage({
type: 'error',
message: '上传失败'
})
fullscreenLoading.value = false
emits('on-error',err)
}
</script>
@@ -15,10 +15,15 @@
muted
preload="metadata"
>
<source :src="getUrl(model) + '#t=1'">
<source :src="getUrl(model) + '#t=1'" />
</video>
<img v-if="model&&!isVideoExt(model)" class="w-full h-full" :src="getUrl(model)" alt="图片">
<img
v-if="model && !isVideoExt(model)"
class="w-full h-full"
:src="getUrl(model)"
alt="图片"
/>
<div
v-if="model"
class="left-0 top-0 hidden text-gray-600 group-hover:bg-gray-600 group-hover:bg-opacity-30 w-full h-full group-hover:flex justify-center items-center absolute z-10"
@@ -42,24 +47,23 @@
</div>
</template>
<script setup>
import { getUrl, isVideoExt } from '@/utils/image'
import { Delete, Plus } from '@element-plus/icons-vue'
import { getUrl, isVideoExt } from '@/utils/image'
import { Delete, Plus } from '@element-plus/icons-vue'
defineProps({
model: {
default: '',
type: String
defineProps({
model: {
default: '',
type: String
}
})
const emits = defineEmits(['chooseItem', 'deleteItem'])
const chooseItem = () => {
emits('chooseItem')
}
})
const emits = defineEmits(['chooseItem', 'deleteItem'])
const chooseItem = () => {
emits('chooseItem')
}
const deleteItem = () => {
emits('deleteItem')
}
const deleteItem = () => {
emits('deleteItem')
}
</script>
+214 -203
View File
@@ -1,96 +1,80 @@
<template>
<div>
<selectComponent
v-if="!props.multiple"
:model="model"
@chooseItem="openChooseImg"
@deleteItem="openChooseImg"
v-if="!props.multiple"
:model="model"
@chooseItem="openChooseImg"
@deleteItem="openChooseImg"
/>
<div
v-else
class="w-full gap-4 flex flex-wrap"
>
<div v-else class="w-full gap-4 flex flex-wrap">
<selectComponent
v-for="(item, index) in model"
:key="index"
:model="item"
@chooseItem="openChooseImg"
@deleteItem="deleteImg(index)"
v-for="(item, index) in model"
:key="index"
:model="item"
@chooseItem="openChooseImg"
@deleteItem="deleteImg(index)"
/>
<selectComponent
v-if="model?.length < props.maxUpdateCount || props.maxUpdateCount === 0"
@chooseItem="openChooseImg"
@deleteItem="openChooseImg"
v-if="
model?.length < props.maxUpdateCount || props.maxUpdateCount === 0
"
@chooseItem="openChooseImg"
@deleteItem="openChooseImg"
/>
</div>
<el-drawer
v-model="drawer"
title="媒体库"
size="650px"
>
<warning-bar
title="点击“文件名/备注”可以编辑文件名或者备注内容。"
/>
<el-drawer v-model="drawer" title="媒体库" size="650px">
<warning-bar title="点击“文件名/备注”可以编辑文件名或者备注内容。" />
<div class="gva-btn-list gap-2">
<upload-common
:image-common="imageCommon"
@on-success="getImageList"
/>
<upload-common :image-common="imageCommon" @on-success="getImageList" />
<upload-image
:image-url="imageUrl"
:file-size="512"
:max-w-h="1080"
@on-success="getImageList"
:image-url="imageUrl"
:file-size="512"
:max-w-h="1080"
@on-success="getImageList"
/>
<el-input
v-model="search.keyword"
class="keyword"
placeholder="请输入文件名或备注"
v-model="search.keyword"
class="keyword"
placeholder="请输入文件名或备注"
/>
<el-button
type="primary"
icon="search"
@click="getImageList"
>
<el-button type="primary" icon="search" @click="getImageList">
查询
</el-button>
</div>
<div class="flex flex-wrap gap-4">
<div
v-for="(item,key) in picList"
:key="key"
class="w-40"
>
<div class="w-40 h-40 border rounded overflow-hidden border-dashed border-gray-300 cursor-pointer relative group">
<div v-for="(item, key) in picList" :key="key" class="w-40">
<div
class="w-40 h-40 border rounded overflow-hidden border-dashed border-gray-300 cursor-pointer relative group"
>
<el-image
:key="key"
:src="getUrl(item.url)"
fit="cover"
class="w-full h-full relative"
@click="chooseImg(item.url)"
:key="key"
:src="getUrl(item.url)"
fit="cover"
class="w-full h-full relative"
@click="chooseImg(item.url)"
>
<template #error>
<el-icon
v-if="isVideoExt(item.url || '')"
:size="32"
class="absolute top-[calc(50%-16px)] left-[calc(50%-16px)]"
v-if="isVideoExt(item.url || '')"
:size="32"
class="absolute top-[calc(50%-16px)] left-[calc(50%-16px)]"
>
<VideoPlay />
</el-icon>
<video
v-if="isVideoExt(item.url || '')"
class="w-full h-full object-cover"
muted
preload="metadata"
@click="chooseImg(item.url)"
v-if="isVideoExt(item.url || '')"
class="w-full h-full object-cover"
muted
preload="metadata"
@click="chooseImg(item.url)"
>
<source :src="getUrl(item.url) + '#t=1'">
<source :src="getUrl(item.url) + '#t=1'" />
您的浏览器不支持视频播放
</video>
<div
v-else
class="w-full h-full object-cover flex items-center justify-center"
v-else
class="w-full h-full object-cover flex items-center justify-center"
>
<el-icon :size="32">
<icon-picture />
@@ -98,179 +82,206 @@
</div>
</template>
</el-image>
<div class="absolute -right-1 top-1 w-8 h-8 group-hover:inline-block hidden" @click="deleteCheck(item)">
<div
class="absolute -right-1 top-1 w-8 h-8 group-hover:inline-block hidden"
@click="deleteCheck(item)"
>
<el-icon :size="16"><CircleClose /></el-icon>
</div>
</div>
<div
class="overflow-hidden text-nowrap overflow-ellipsis text-center w-full"
@click="editFileNameFunc(item)"
class="overflow-hidden text-nowrap overflow-ellipsis text-center w-full"
@click="editFileNameFunc(item)"
>
{{ item.name }}
</div>
</div>
</div>
<el-pagination
:current-page="page"
:page-size="pageSize"
:total="total"
:style="{'justify-content':'center'}"
layout="total, prev, pager, next, jumper"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
:current-page="page"
:page-size="pageSize"
:total="total"
:style="{ 'justify-content': 'center' }"
layout="total, prev, pager, next, jumper"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
/>
</el-drawer>
</div>
</template>
<script setup>
import { getUrl, isVideoExt } from '@/utils/image'
import { ref } from 'vue'
import { getFileList, editFileName, deleteFile } from '@/api/fileUploadAndDownload'
import UploadImage from '@/components/upload/image.vue'
import UploadCommon from '@/components/upload/common.vue'
import WarningBar from '@/components/warningBar/warningBar.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Picture as IconPicture } from '@element-plus/icons-vue'
import selectComponent from '@/components/selectImage/selectComponent.vue'
import { getUrl, isVideoExt } from '@/utils/image'
import { ref } from 'vue'
import {
getFileList,
editFileName,
deleteFile
} from '@/api/fileUploadAndDownload'
import UploadImage from '@/components/upload/image.vue'
import UploadCommon from '@/components/upload/common.vue'
import WarningBar from '@/components/warningBar/warningBar.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Picture as IconPicture } from '@element-plus/icons-vue'
import selectComponent from '@/components/selectImage/selectComponent.vue'
const imageUrl = ref('')
const imageCommon = ref('')
const imageUrl = ref('')
const imageCommon = ref('')
const search = ref({})
const page = ref(1)
const total = ref(0)
const pageSize = ref(20)
const search = ref({})
const page = ref(1)
const total = ref(0)
const pageSize = ref(20)
const model = defineModel({ type: [String, Array] })
const model = defineModel({ type: [String, Array] })
const props = defineProps({
multiple: {
type: Boolean,
default: false
},
fileType: {
type: String,
default: ''
},
maxUpdateCount: {
type: Number,
default: 0
}
})
const deleteImg = (index) => {
model.value.splice(index, 1)
}
const handleSizeChange = (val) => {
pageSize.value = val
getImageList()
}
const handleCurrentChange = (val) => {
page.value = val
getImageList()
}
const editFileNameFunc = async(row) => {
ElMessageBox.prompt('请输入文件名或者备注', '编辑', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /\S/,
inputErrorMessage: '不能为空',
inputValue: row.name
}).then(async({ value }) => {
row.name = value
const res = await editFileName(row)
if (res.code === 0) {
ElMessage({
type: 'success',
message: '编辑成功!',
})
getImageList()
const props = defineProps({
multiple: {
type: Boolean,
default: false
},
fileType: {
type: String,
default: ''
},
maxUpdateCount: {
type: Number,
default: 0
}
}).catch(() => {
ElMessage({
type: 'info',
message: '取消修改'
})
})
}
const drawer = ref(false)
const picList = ref([])
const deleteImg = (index) => {
model.value.splice(index, 1)
}
const imageTypeList = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp']
const videoTyteList = ['mp4', 'avi', 'rmvb', 'rm', 'asf', 'divx', 'mpg', 'mpeg', 'mpe', 'wmv', 'mkv', 'vob']
const handleSizeChange = (val) => {
pageSize.value = val
getImageList()
}
const listObj = {
image: imageTypeList,
video: videoTyteList
}
const handleCurrentChange = (val) => {
page.value = val
getImageList()
}
const chooseImg = (url) => {
if (props.fileType) {
const typeSuccess = listObj[props.fileType].some(item => {
if (url.includes(item)) {
return true
}
const editFileNameFunc = async (row) => {
ElMessageBox.prompt('请输入文件名或者备注', '编辑', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /\S/,
inputErrorMessage: '不能为空',
inputValue: row.name
})
if (!typeSuccess) {
ElMessage({
type: 'error',
message: '当前类型不支持使用'
.then(async ({ value }) => {
row.name = value
const res = await editFileName(row)
if (res.code === 0) {
ElMessage({
type: 'success',
message: '编辑成功!'
})
getImageList()
}
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消修改'
})
})
}
const drawer = ref(false)
const picList = ref([])
const imageTypeList = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp']
const videoTyteList = [
'mp4',
'avi',
'rmvb',
'rm',
'asf',
'divx',
'mpg',
'mpeg',
'mpe',
'wmv',
'mkv',
'vob'
]
const listObj = {
image: imageTypeList,
video: videoTyteList
}
const chooseImg = (url) => {
if (props.fileType) {
const typeSuccess = listObj[props.fileType].some((item) => {
if (url.includes(item)) {
return true
}
})
if (!typeSuccess) {
ElMessage({
type: 'error',
message: '当前类型不支持使用'
})
return
}
}
if (props.multiple) {
model.value.push(url)
} else {
model.value = url
}
drawer.value = false
}
const openChooseImg = async () => {
if (model.value && !props.multiple) {
model.value = ''
return
}
await getImageList()
drawer.value = true
}
if (props.multiple) {
model.value.push(url)
} else {
model.value = url
}
drawer.value = false
}
const openChooseImg = async() => {
if (model.value && !props.multiple) {
model.value = ''
return
}
await getImageList()
drawer.value = true
}
const getImageList = async() => {
const res = await getFileList({ page: page.value, pageSize: pageSize.value, ...search.value })
if (res.code === 0) {
picList.value = res.data.list
total.value = res.data.total
page.value = res.data.page
pageSize.value = res.data.pageSize
}
}
const deleteCheck = (item) => {
ElMessageBox.confirm('是否删除该文件', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
const res = await deleteFile(item)
if (res.code === 0) {
ElMessage({
type: 'success',
message: '删除成功!',
})
getImageList()
}
}).catch(() => {
ElMessage({
type: 'info',
message: '已取消删除'
const getImageList = async () => {
const res = await getFileList({
page: page.value,
pageSize: pageSize.value,
...search.value
})
})
}
if (res.code === 0) {
picList.value = res.data.list
total.value = res.data.total
page.value = res.data.page
pageSize.value = res.data.pageSize
}
}
const deleteCheck = (item) => {
ElMessageBox.confirm('是否删除该文件', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
const res = await deleteFile(item)
if (res.code === 0) {
ElMessage({
type: 'success',
message: '删除成功!'
})
getImageList()
}
})
.catch(() => {
ElMessage({
type: 'info',
message: '已取消删除'
})
})
}
</script>
+24 -31
View File
@@ -1,39 +1,32 @@
<template>
<svg
:class="svgClass"
v-bind="$attrs"
:color="color"
>
<use
:xlink:href="'#'+name"
rel="external nofollow"
/>
<svg :class="svgClass" v-bind="$attrs" :color="color">
<use :xlink:href="'#' + name" rel="external nofollow" />
</svg>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
name: {
type: String,
required: true
},
color: {
type: String,
default: 'currentColor'
}
})
import { computed } from 'vue'
const props = defineProps({
name: {
type: String,
required: true
},
color: {
type: String,
default: 'currentColor'
}
})
const svgClass = computed(() => {
if (props.name) {
return `svg-icon ${props.name}`
}
return 'svg-icon'
})
const svgClass = computed(() => {
if (props.name) {
return `svg-icon ${props.name}`
}
return 'svg-icon'
})
</script>
<style scoped>
.svg-icon {
@apply w-4 h-4;
fill: currentColor;
vertical-align: middle;
}
.svg-icon {
@apply w-4 h-4;
fill: currentColor;
vertical-align: middle;
}
</style>
+54 -55
View File
@@ -15,62 +15,61 @@
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { isVideoMime, isImageMime } from '@/utils/image'
import { getBaseUrl } from '@/utils/format'
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { isVideoMime, isImageMime } from '@/utils/image'
import { getBaseUrl } from '@/utils/format'
defineOptions({
name: 'UploadCommon',
})
const emit = defineEmits(['on-success'])
const fullscreenLoading = ref(false)
const checkFile = (file) => {
fullscreenLoading.value = true
const isLt500K = file.size / 1024 / 1024 < 0.5 // 500K, @todo 应支持在项目中设置
const isLt5M = file.size / 1024 / 1024 < 5 // 5MB, @todo 应支持项目中设置
const isVideo = isVideoMime(file.type)
const isImage = isImageMime(file.type)
let pass = true
if (!isVideo && !isImage) {
ElMessage.error('上传图片只能是 jpg,png,svg,webp 格式, 上传视频只能是 mp4,webm 格式!')
fullscreenLoading.value = false
pass = false
}
if (!isLt5M && isVideo) {
ElMessage.error('上传视频大小不能超过 5MB')
fullscreenLoading.value = false
pass = false
}
if (!isLt500K && isImage) {
ElMessage.error('未压缩的上传图片大小不能超过 500KB,请使用压缩上传')
fullscreenLoading.value = false
pass = false
}
console.log('upload file check result: ', pass)
return pass
}
const uploadSuccess = (res) => {
const { data } = res
if (data.file) {
emit('on-success', data.file.url)
}
}
const uploadError = () => {
ElMessage({
type: 'error',
message: '上传失败'
defineOptions({
name: 'UploadCommon'
})
fullscreenLoading.value = false
}
const emit = defineEmits(['on-success'])
const fullscreenLoading = ref(false)
const checkFile = (file) => {
fullscreenLoading.value = true
const isLt500K = file.size / 1024 / 1024 < 0.5 // 500K, @todo 应支持在项目中设置
const isLt5M = file.size / 1024 / 1024 < 5 // 5MB, @todo 应支持项目中设置
const isVideo = isVideoMime(file.type)
const isImage = isImageMime(file.type)
let pass = true
if (!isVideo && !isImage) {
ElMessage.error(
'上传图片只能是 jpg,png,svg,webp 格式, 上传视频只能是 mp4,webm 格式!'
)
fullscreenLoading.value = false
pass = false
}
if (!isLt5M && isVideo) {
ElMessage.error('上传视频大小不能超过 5MB')
fullscreenLoading.value = false
pass = false
}
if (!isLt500K && isImage) {
ElMessage.error('未压缩的上传图片大小不能超过 500KB,请使用压缩上传')
fullscreenLoading.value = false
pass = false
}
console.log('upload file check result: ', pass)
return pass
}
const uploadSuccess = (res) => {
const { data } = res
if (data.file) {
emit('on-success', data.file.url)
}
}
const uploadError = () => {
ElMessage({
type: 'error',
message: '上传失败'
})
fullscreenLoading.value = false
}
</script>
+65 -67
View File
@@ -1,4 +1,3 @@
<template>
<div>
<el-upload
@@ -14,79 +13,78 @@
</template>
<script setup>
import ImageCompress from '@/utils/image'
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
import ImageCompress from '@/utils/image'
import { ElMessage } from 'element-plus'
import { getBaseUrl } from '@/utils/format'
defineOptions({
name: 'UploadImage',
})
defineOptions({
name: 'UploadImage'
})
const emit = defineEmits(['on-success'])
const props = defineProps({
imageUrl: {
type: String,
default: ''
},
fileSize: {
type: Number,
default: 2048 // 2M 超出后执行压缩
},
maxWH: {
type: Number,
default: 1920 // 图片长宽上限
}
})
const emit = defineEmits(['on-success'])
const props = defineProps({
imageUrl: {
type: String,
default: ''
},
fileSize: {
type: Number,
default: 2048 // 2M 超出后执行压缩
},
maxWH: {
type: Number,
default: 1920 // 图片长宽上限
}
})
const beforeImageUpload = (file) => {
const isJPG = file.type === 'image/jpeg'
const isPng = file.type === 'image/png'
if (!isJPG && !isPng) {
ElMessage.error('上传头像图片只能是 jpg或png 格式!')
return false
const beforeImageUpload = (file) => {
const isJPG = file.type === 'image/jpeg'
const isPng = file.type === 'image/png'
if (!isJPG && !isPng) {
ElMessage.error('上传头像图片只能是 jpg或png 格式!')
return false
}
const isRightSize = file.size / 1024 < props.fileSize
if (!isRightSize) {
// 压缩
const compress = new ImageCompress(file, props.fileSize, props.maxWH)
return compress.compress()
}
return isRightSize
}
const isRightSize = file.size / 1024 < props.fileSize
if (!isRightSize) {
// 压缩
const compress = new ImageCompress(file, props.fileSize, props.maxWH)
return compress.compress()
const handleImageSuccess = (res) => {
const { data } = res
if (data.file) {
emit('on-success', data.file.url)
}
}
return isRightSize
}
const handleImageSuccess = (res) => {
const { data } = res
if (data.file) {
emit('on-success', data.file.url)
}
}
</script>
<style lang="scss" scoped>
.image-uploader {
border: 1px dashed #d9d9d9;
width: 180px;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader {
border-color: #409eff;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.image {
width: 178px;
height: 178px;
display: block;
}
.image-uploader {
border: 1px dashed #d9d9d9;
width: 180px;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader {
border-color: #409eff;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.image {
width: 178px;
height: 178px;
display: block;
}
</style>
+16 -16
View File
@@ -1,7 +1,7 @@
<template>
<div
class="px-1.5 py-2 flex items-center rounded-sm mt-2 bg-amber-50 gap-2 mb-3 text-amber-500 dark:bg-amber-700 dark:text-gray-200"
:class="href&&'cursor-pointer'"
:class="href && 'cursor-pointer'"
@click="open"
>
<el-icon class="text-xl">
@@ -13,21 +13,21 @@
</div>
</template>
<script setup>
import { WarningFilled } from '@element-plus/icons-vue'
const prop = defineProps({
title: {
type: String,
default: ''
},
href: {
type: String,
default: ''
}
})
import { WarningFilled } from '@element-plus/icons-vue'
const prop = defineProps({
title: {
type: String,
default: ''
},
href: {
type: String,
default: ''
}
})
const open = () => {
if (prop.href) {
window.open(prop.href)
const open = () => {
if (prop.href) {
window.open(prop.href)
}
}
}
</script>