first
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<el-form-item ref="formAddress" :label="label" :prop="prop">
|
||||
<el-select v-model="currentProvince" clearable placeholder="省" @change="changeProvince">
|
||||
<el-option v-for="(_, name) in pca" :key="name" :label="name" :value="name"/>
|
||||
</el-select>
|
||||
<el-select v-model="currentCity" clearable placeholder="市" @change="changeCity">
|
||||
<el-option v-for="(_, name) in cities" :key="name" :label="name" :value="name"/>
|
||||
</el-select>
|
||||
<el-select v-model="currentCounty" clearable placeholder="区" @change="changeCounty">
|
||||
<el-option v-for="item in counties" :key="item" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref, computed } from 'vue'
|
||||
import pca from '@/utils/pca.json'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FormAddress',
|
||||
props: {
|
||||
prop: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '省/市/区',
|
||||
},
|
||||
province: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
city: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
county: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup (props, context) {
|
||||
const cities = computed(() => pca[props.province] || [])
|
||||
const counties = computed(() => pca[props.province] && pca[props.province][props.city] ? pca[props.province][props.city] : [])
|
||||
|
||||
let currentProvince = computed({
|
||||
get: () => props.province,
|
||||
set: (val) => {
|
||||
context.emit('update:province', val)
|
||||
},
|
||||
})
|
||||
let currentCity = computed({
|
||||
get: () => props.city,
|
||||
set: (val) => {
|
||||
context.emit('update:city', val)
|
||||
},
|
||||
})
|
||||
let currentCounty = computed({
|
||||
get: () => props.county,
|
||||
set: (val) => {
|
||||
context.emit('update:county', val)
|
||||
},
|
||||
})
|
||||
|
||||
const changeProvince = (val) => {
|
||||
currentCity = ''
|
||||
currentCounty = ''
|
||||
context.emit('changeProvince', val)
|
||||
}
|
||||
const changeCity = (val) => {
|
||||
currentCounty = ''
|
||||
context.emit('changeCity', val)
|
||||
}
|
||||
const changeCounty = (val) => {
|
||||
context.emit('changeCounty', val)
|
||||
}
|
||||
|
||||
return {
|
||||
pca,
|
||||
cities,
|
||||
counties,
|
||||
|
||||
currentProvince,
|
||||
currentCity,
|
||||
currentCounty,
|
||||
|
||||
changeProvince,
|
||||
changeCity,
|
||||
changeCounty,
|
||||
}
|
||||
},
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div class="upload-order-file">
|
||||
<el-upload
|
||||
size="mini"
|
||||
ref="upload"
|
||||
:on-success="fileUploadSuccess"
|
||||
:before-upload="beforeFileUpload"
|
||||
:on-preview="onPreview"
|
||||
:on-remove="fileRemove"
|
||||
:on-error="onError"
|
||||
name="file"
|
||||
:file-list="fileList"
|
||||
:action="fileUploadHost"
|
||||
:data="fileUploadData"
|
||||
:headers="headers"
|
||||
list-type="picture-card"
|
||||
:limit="0"
|
||||
accept="image/*"
|
||||
>
|
||||
<template #default>
|
||||
<div class="default-slot">
|
||||
<slot name="default">
|
||||
<el-icon class="default-icon">
|
||||
<plus/>
|
||||
</el-icon>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-dialog v-model="showPreview" top="5vh">
|
||||
<el-image :src="showImage" class="preview-image" fit="contain"></el-image>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { defineComponent, ref, computed, reactive, unref, readonly, toRefs } from 'vue'
|
||||
import { Plus, ZoomIn, Delete, ArrowLeft, ArrowRight, Check } from '@element-plus/icons'
|
||||
import { useOss } from '@/components/form/upload/oss'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useLocal } from '@/components/form/upload/local'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'imageUpload',
|
||||
props: {
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
beforeUpload: {
|
||||
type: Function,
|
||||
default: function () {
|
||||
return true
|
||||
},
|
||||
},
|
||||
host: {
|
||||
type: String,
|
||||
default: import.meta.env.VITE_BASE_API + '/file/upload',
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'local', //local oss
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '148px',
|
||||
},
|
||||
},
|
||||
components: { Plus, ZoomIn, Delete, ArrowLeft, ArrowRight, Check },
|
||||
setup (props, context) {
|
||||
const showPreview = ref(false)
|
||||
const showImage = ref('')
|
||||
|
||||
let fileList = computed(() => props.modelValue ? [{ url: props.modelValue, status: 'success' }] : [])
|
||||
|
||||
let fileUpload = reactive({
|
||||
fileUploadHost: '',
|
||||
fileUploadData: {},
|
||||
beforeFileUpload: null,
|
||||
headers: {},
|
||||
})
|
||||
|
||||
if (props.type === 'oss') {
|
||||
fileUpload = useOss(props.beforeUpload, props.multiple)
|
||||
} else {
|
||||
fileUpload = useLocal(props.beforeUpload, props.host)
|
||||
}
|
||||
|
||||
function removeImage (file) {
|
||||
let fList = unref(fileList)
|
||||
const index = fList.findIndex(f => f.url === file.url)
|
||||
fList.splice(index, 1)
|
||||
updateValue(fList)
|
||||
}
|
||||
|
||||
function updateValue (_fileList) {
|
||||
let fList = unref(_fileList)
|
||||
context.emit(
|
||||
'update:modelValue',
|
||||
fList.length ? fList[0].url : '',
|
||||
)
|
||||
}
|
||||
|
||||
function fileRemove (file, _fileList) {
|
||||
updateValue(_fileList)
|
||||
}
|
||||
|
||||
function onError () {
|
||||
|
||||
}
|
||||
|
||||
function fileUploadSuccess (response, file, _fileList) {
|
||||
file.url = response?.data?.url || file.url
|
||||
if (_fileList.length > 1) {
|
||||
_fileList.splice(0, 1)
|
||||
}
|
||||
if (_fileList.every(f => f.status === 'success')) {
|
||||
updateValue(_fileList)
|
||||
}
|
||||
}
|
||||
|
||||
function onPreview (file) {
|
||||
showImage.value = file.url
|
||||
showPreview.value = true
|
||||
}
|
||||
|
||||
return {
|
||||
fileList,
|
||||
|
||||
...toRefs(fileUpload),
|
||||
|
||||
fileRemove,
|
||||
onError,
|
||||
fileUploadSuccess,
|
||||
|
||||
onPreview,
|
||||
removeImage,
|
||||
|
||||
showPreview,
|
||||
showImage,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.upload-order-file {
|
||||
|
||||
::v-deep(.el-upload-list__item-thumbnail) {
|
||||
object-fit: contain;
|
||||
|
||||
}
|
||||
|
||||
::v-deep(.el-upload--picture-card) {
|
||||
width: v-bind(width);
|
||||
height: v-bind(width);
|
||||
}
|
||||
|
||||
::v-deep(.el-upload-list__item) {
|
||||
width: v-bind(width);
|
||||
height: v-bind(width);
|
||||
}
|
||||
|
||||
::v-deep(.el-progress) {
|
||||
width: v-bind(width) !important;
|
||||
height: v-bind(width) !important;
|
||||
}
|
||||
|
||||
::v-deep(.el-progress-circle) {
|
||||
width: v-bind(width) !important;
|
||||
height: v-bind(width) !important;
|
||||
}
|
||||
|
||||
|
||||
.default-slot {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.default-icon {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
width: 100%;
|
||||
|
||||
::v-deep(img) {
|
||||
max-height: 700px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,272 @@
|
||||
<template>
|
||||
<div class="upload-order-file">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
:on-success="fileUploadSuccess"
|
||||
:before-upload="beforeFileUpload"
|
||||
:on-remove="fileRemove"
|
||||
:on-exceed="onExceed"
|
||||
:on-error="onError"
|
||||
name="file"
|
||||
:multiple="multiple"
|
||||
:file-list="fileList"
|
||||
:action="fileUploadHost"
|
||||
:data="fileUploadData"
|
||||
:headers="headers"
|
||||
list-type="picture-card"
|
||||
:limit="limit"
|
||||
accept="image/*"
|
||||
:drag="drag"
|
||||
>
|
||||
<template #default>
|
||||
<div class="default-slot">
|
||||
<slot name="default">
|
||||
<div>
|
||||
<el-icon class="default-icon">
|
||||
<plus/>
|
||||
</el-icon>
|
||||
<div class="drag-tips">点击上传<span v-if="drag">或直接拖入文件</span></div>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<template #file="{file}">
|
||||
<img
|
||||
v-if="file.status === 'success'"
|
||||
class="el-upload-list__item-thumbnail"
|
||||
:src="file.url"
|
||||
alt=""
|
||||
>
|
||||
<label class="el-upload-list__item-status-label">
|
||||
<el-icon color="white">
|
||||
<check/>
|
||||
</el-icon>
|
||||
</label>
|
||||
<el-progress
|
||||
v-if="file.status === 'uploading'"
|
||||
type="circle"
|
||||
:stroke-width="6"
|
||||
:percentage="parseInt(file.percentage)"
|
||||
/>
|
||||
<span v-else-if="file.status === 'success'" class="el-upload-list__item-actions">
|
||||
<el-icon class="el-upload-list__item-icon" @click="leftImage(file)"><arrow-left/></el-icon>
|
||||
<el-icon class="el-upload-list__item-icon" @click="removeImage(file)"><Delete/></el-icon>
|
||||
<el-icon class="el-upload-list__item-icon" @click="rightImage(file)"><arrow-right/></el-icon>
|
||||
</span>
|
||||
</template>
|
||||
</el-upload>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { defineComponent, ref, computed, reactive, unref, readonly, toRefs } from 'vue'
|
||||
import { Plus, ZoomIn, Delete, ArrowLeft, ArrowRight, Check } from '@element-plus/icons'
|
||||
import { useOss } from '@/components/form/upload/oss'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useLocal } from '@/components/form/upload/local'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'imagesUpload',
|
||||
props: {
|
||||
drag: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
beforeUpload: {
|
||||
type: Function,
|
||||
default: function () {
|
||||
return true
|
||||
},
|
||||
},
|
||||
host: {
|
||||
type: String,
|
||||
default: import.meta.env.VITE_BASE_API + '/file/upload',
|
||||
},
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return []
|
||||
},
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'local', //local oss
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '148px',
|
||||
},
|
||||
},
|
||||
components: { Plus, ZoomIn, Delete, ArrowLeft, ArrowRight, Check },
|
||||
setup (props, context) {
|
||||
|
||||
let fileList = computed(() => props.modelValue.map(url => { return { url, status: 'success' } }))
|
||||
|
||||
let fileUpload = reactive({
|
||||
fileUploadHost: '',
|
||||
fileUploadData: {},
|
||||
beforeFileUpload: null,
|
||||
headers: {},
|
||||
})
|
||||
|
||||
if (props.type === 'oss') {
|
||||
fileUpload = useOss(props.beforeUpload, props.multiple)
|
||||
} else {
|
||||
fileUpload = useLocal(props.beforeUpload, props.host)
|
||||
}
|
||||
|
||||
function leftImage (file) {
|
||||
let fList = unref(fileList)
|
||||
const index = fList.findIndex(f => f.url === file.url)
|
||||
if (index === 0 || index === -1) {
|
||||
return
|
||||
}
|
||||
fList[index] = fList.splice(index - 1, 1, fList[index])[0]
|
||||
updateValue(fList)
|
||||
}
|
||||
|
||||
function rightImage (file) {
|
||||
let fList = unref(fileList)
|
||||
const index = fList.findIndex(f => f.url === file.url)
|
||||
if (index === fList.length - 1 || index === -1) {
|
||||
return
|
||||
}
|
||||
fList[index] = fList.splice(index + 1, 1, fList[index])[0]
|
||||
updateValue(fList)
|
||||
}
|
||||
|
||||
function removeImage (file) {
|
||||
let fList = unref(fileList)
|
||||
const index = fList.findIndex(f => f.url === file.url)
|
||||
fList.splice(index, 1)
|
||||
updateValue(fList)
|
||||
}
|
||||
|
||||
function updateValue (_fileList) {
|
||||
let fList = unref(_fileList)
|
||||
context.emit(
|
||||
'update:modelValue',
|
||||
fList.filter(f => f.status === 'success').map(file => file.url),
|
||||
)
|
||||
}
|
||||
|
||||
function fileRemove (file, _fileList) {
|
||||
updateValue(_fileList)
|
||||
}
|
||||
|
||||
function onError () {
|
||||
|
||||
}
|
||||
|
||||
function fileUploadSuccess (response, file, _fileList) {
|
||||
file.url = response?.data?.url || file.url
|
||||
if (_fileList.every(f => f.status === 'success')) {
|
||||
updateValue(_fileList)
|
||||
}
|
||||
}
|
||||
|
||||
function onExceed () {
|
||||
ElMessage.error('超出数量限制')
|
||||
}
|
||||
|
||||
return {
|
||||
fileList,
|
||||
|
||||
...toRefs(fileUpload),
|
||||
|
||||
onExceed,
|
||||
fileRemove,
|
||||
onError,
|
||||
fileUploadSuccess,
|
||||
|
||||
leftImage,
|
||||
rightImage,
|
||||
removeImage,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.upload-order-file {
|
||||
::v-deep(.el-upload-dragger) {
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
::v-deep(.el-upload--picture-card) {
|
||||
width: v-bind(width);
|
||||
height: v-bind(width);
|
||||
}
|
||||
|
||||
::v-deep(.el-upload-list__item) {
|
||||
width: v-bind(width);
|
||||
height: v-bind(width);
|
||||
}
|
||||
|
||||
::v-deep(.el-progress) {
|
||||
width: v-bind(width) !important;
|
||||
height: v-bind(width) !important;
|
||||
}
|
||||
|
||||
::v-deep(.el-progress-circle) {
|
||||
width: v-bind(width) !important;
|
||||
height: v-bind(width) !important;
|
||||
}
|
||||
|
||||
.drag-tips {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
|
||||
::v-deep(.el-upload-list__item) {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
::v-deep(.el-upload-list) {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.el-upload-list__item-thumbnail {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.el-upload-list__item-actions {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-upload-list__item-icon {
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.default-slot {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.default-icon {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { getToken } from '@/utils/auth'
|
||||
|
||||
export function useLocal (beforeUp, host) {
|
||||
const fileUploadData = {}
|
||||
const fileUploadHost = host
|
||||
const headers = { 'api-token': getToken() }
|
||||
const beforeFileUpload = async (file) => {
|
||||
if (beforeUp) {
|
||||
const br = await beforeUp(file)
|
||||
if (!br) { return Promise.reject() }
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
return {
|
||||
fileUploadData,
|
||||
fileUploadHost,
|
||||
beforeFileUpload,
|
||||
headers,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { ossToken } from '@/api/file'
|
||||
import { random_filename } from '@/utils/file'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
export function useOss (beforeUp, multiple) {
|
||||
let fileUploadData = reactive({
|
||||
policy: '',
|
||||
OSSAccessKeyId: '',
|
||||
success_action_status: '200', // 让服务端返回200,不然,默认会返回204
|
||||
callback: '',
|
||||
signature: '',
|
||||
'x:dir': '',
|
||||
})
|
||||
const fileExpire = ref(0)
|
||||
const fileUploadHost = ref('')
|
||||
|
||||
const beforeFileUpload = async (file) => {
|
||||
if (beforeUp) {
|
||||
const br = await beforeUp(file)
|
||||
if (!br) { return Promise.reject() }
|
||||
}
|
||||
|
||||
const now = Date.parse(new Date()) / 1000
|
||||
if (fileExpire.value < now) {
|
||||
const res = await ossToken()
|
||||
const obj = JSON.parse(res.data)
|
||||
fileExpire.value = parseInt(obj['expire'])
|
||||
fileUploadData.policy = obj['policy']
|
||||
fileUploadData.OSSAccessKeyId = obj['accessid']
|
||||
fileUploadData.callback = obj['callback']
|
||||
fileUploadData.signature = obj['signature']
|
||||
fileUploadData['x:dir'] = obj['dir']
|
||||
fileUploadHost.value = obj['host']
|
||||
}
|
||||
//多选文件时需要这个,不然每个文件上传的都是一样的data
|
||||
if (multiple) {
|
||||
await new Promise(resolve => {
|
||||
setTimeout(() => { resolve() }, 50)
|
||||
})
|
||||
}
|
||||
fileUploadData['x:origin_filename'] = file.name
|
||||
fileUploadData.key = fileUploadData['x:dir'] + random_filename(file.name)
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
return {
|
||||
fileUploadHost,
|
||||
fileUploadData,
|
||||
beforeFileUpload,
|
||||
headers: {},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user