This commit is contained in:
shijing 2025-12-05 14:01:57 +08:00
commit 74e0abc0c2
3 changed files with 355 additions and 25 deletions

320
components/xtUpload.vue Normal file
View File

@ -0,0 +1,320 @@
<template>
<view style="width: 100%;">
<button @click="choseFiles" size="mini" type="primary" :disabled="disabled">选择</button>
<view v-for="(item, index) in fileList" :key="index" style="height: 16px; margin-bottom: 12px;">
<view style="display:flex; justify-content: space-between;">
<view style="color:blue" @click="preview(item)">{{ item.name }}</view>
<view style="color:red;font-weight: bold;" @click="handleRemove(index)" v-if="disabled == false">×</view>
</view>
<view style="height:2px"></view>
<progress :percent="item.percent" activeColor="#4caf50" backgroundColor="#e0e0e0" stroke-width="2" />
</view>
</view>
</template>
<script setup>
// FILE_TYPE_DOC = 10
// FILE_TYPE_VIDEO = 20
// FILE_TYPE_AUDIO = 30
// FILE_TYPE_PIC = 40
// FILE_TYPE_OTHER = 50
import config from '@/utils/config.js'
import { ref, onMounted, watch, defineEmits } from 'vue';
const emit = defineEmits(["update:modelValue", "update:obj"]);
const props = defineProps({
xtype: { type: String, default: "path" }, // path id
modelValue: { type: [Array, String], default: "pending" },
obj: { type: Object, default: () => ({}) },
accept: { type: String, default: '' },
countMax: { type: Number, default: 1 },
sizeMax: { type: Number, default: 1024 * 1024 * 5 },
disabled: { type: Boolean, default: false },
});
// reactive([]) ref
const fileList = ref([])
const disabled = ref(props.disabled)
// header / action
const header = {
Authorization: `Bearer ${uni.getStorageSync('access')}`
}
const action = `${config.baseUrl}/file/`
const inited = ref(false)
onMounted(() => {
checkPropsUntilReady()
})
const checkPropsUntilReady = () => {
if (inited.value) return
if (props.modelValue !== "pending") {
initFileList()
inited.value = true
return
}
// 200ms
setTimeout(checkPropsUntilReady, 200)
}
const changeVal = () => {
let val = null;
if (props.xtype == "id") {
if (props.countMax > 1){
val= []
fileList.value.forEach(item => {
if(item.id){
val.push(item.id)
}
})
}else if (props.countMax == 1){
val = null;
if (fileList.value && fileList.value.length > 0 && fileList.value[0].id) {
val = fileList.value[0].id
}
}
}else if (props.xtype == "path"){
if (props.countMax > 1){
val = []
fileList.value.forEach(item => {
if(item.path && item.percent == 100){
val.push(item.path)
}
})
}else if (props.countMax == 1){
val = null;
if (fileList.value && fileList.value.length > 0 && fileList.value[0].path && fileList.value[0].percent == 100) {
val = fileList.value[0].path
}
}
}
let obj = null;
emit("update:modelValue", val)
if (props.countMax > 1) {
obj = fileList.value
emit("update:obj", obj)
}else{
if (fileList.value && fileList.value.length > 0) {
obj = fileList.value[0]
emit("update:obj", obj)
} else {
emit("update:obj", obj)
}
}
console.log(val, obj)
}
const getFileType = (path) =>{
let type = path.substring(path.lastIndexOf('.') + 1, path.length).toLowerCase()
if (type === 'png' || type === 'jpg' || type === 'jpeg' || type === 'gif' || type === 'bmp') {
return 40
}
else if (type === 'mp4' || type === 'avi' || type === 'rmvb') {
return 20
}
else if (type === 'mp3' || type === 'wav' || type === 'wma') {
return 30
}
return 10
}
/**
* 初始化 fileList
*/
const initFileList = () => {
if (props.countMax > 1) {
let clist = []
// xtype = id
if (props.xtype === "id" && Array.isArray(props.obj) && props.obj.length > 0) {
props.obj.forEach(item => {
clist.push({
...item,
url: `${config.hostUrl}${item.path}`,
percent: 100
})
})
fileList.value = clist
}
else if (props.xtype === "path" && props.modelValue) {
props.modelValue.forEach(item => {
clist.push({
name: item.substring(item.lastIndexOf('/') + 1, item.length),
path: item,
url: `${config.hostUrl}${item}`,
percent: 100,
type: getFileType(item)
})
})
fileList.value = clist
}
} else if (props.countMax == 1) {
let clist = []
if (props.xtype === "id" && props.modelValue) {
clist.push({
...props.obj,
url: `${config.hostUrl}${props.obj.path}`,
percent: 100
})
fileList.value = clist
} else if (props.xtype === "path" && props.modelValue) {
clist.push({
name: item.substring(item.lastIndexOf('/') + 1, item.length),
path: props.modelValue,
url: `${config.hostUrl}${props.modelValue}`,
percent: 100,
type: getFileType(props.obj.path)
})
fileList.value = clist
}
}
}
const handleRemove = (index) => {
let upTask = fileList.value[index].upTask
if (upTask) {
upTask.abort()
}
fileList.value.splice(index, 1)
changeVal()
}
const preview = (item) => {
if (item.type == 40) {
// 40 URL
const urls = fileList.value
.filter(file => file.type === 40)
.map(file => file.url)
//
const currentIndex = urls.indexOf(item.url)
uni.previewImage({
current: currentIndex >= 0 ? currentIndex : 0,
urls: urls,
fail: function(err) {
console.log(err);
uni.showToast({
title: "预览失败",
icon: "none"
})
}
})
} else if (item.type == 10) {
window.open(item.url, '_blank');
// uni.downloadFile({
// url: item.url,
// success: function (res) {
// var filePath = res.tempFilePath;
// uni.openDocument({
// filePath: filePath,
// showMenu: true,
// success: function (res) {
// console.log('');
// }
// });
// },
// fail: function (err) {
// console.log(":", err)
// uni.showToast({
// title: "",
// icon: "none"
// })
// }
// });
} else if (item.type == 20) {
uni.showToast({
title: "暂不支持预览该文件",
icon : 'none'
})
} else if (item.type == 30) {
uni.showToast({
title: "暂不支持预览该文件",
icon : 'none'
})
} else {
uni.showToast({
title: "暂不支持预览该文件",
icon : 'none'
})
}
}
const choseFiles = () => {
if (fileList.value.length >= props.countMax) {
uni.showToast({
title: `最多只能上传${props.countMax}个文件`,
icon: 'none'
})
return
}
uni.chooseFile({
count: props.countMax - fileList.value.length,
success(res) {
const tempFiles = res.tempFiles;
tempFiles.forEach(item => {
//
if (item.size > props.sizeMax * 1024 * 1024) {
uni.showToast({
title: `文件大小不能超过${props.sizeMax}M`,
icon: 'none'
})
return;
}
//
const upTask = uni.uploadFile({
url: action,
filePath: item.path,
name: 'file',
formData: {},
header: header,
success: (uploadRes) => {
const data = JSON.parse(uploadRes.data || "{}")
if (data) {
fileList.value.forEach((file, index) => {
if (file.path === item.path) {
fileList.value[index].url = `${config.hostUrl}${data.path}`
fileList.value[index].path = data.path
fileList.value[index].percent = 100
fileList.value[index].id = data.id
fileList.value[index].upTask = null
}
})
// console.log("fv", fileList.value)
changeVal()
}
},
fail: (err) => {
console.log("上传失败:", err)
}
})
//
fileList.value.push({
name: item.name,
url: null,
path: item.path,
percent: 0,
type: getFileType(item.name),
upTask: upTask
})
// 🔥
upTask.onProgressUpdate((res) => {
fileList.value.forEach((file, index) => {
if (file.path === item.path) {
fileList.value[index].percent = res.progress
}
})
});
})
}
})
}
</script>

View File

@ -8,26 +8,26 @@
<uni-easyinput v-model="form.name" placeholder="请输入供应商名称" :disabled="mode=='show'"/> <uni-easyinput v-model="form.name" placeholder="请输入供应商名称" :disabled="mode=='show'"/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="物料分类" required> <uni-forms-item label="物料分类" required>
<uni-easyinput v-model="form.material_type" placeholder="请输入物料分类" :disabled="mode=='show'"/> <uni-easyinput v-model="form.material_cate" placeholder="请输入物料分类" :disabled="mode=='show'"/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="物料名称" required> <uni-forms-item label="物料名称" required>
<uni-easyinput v-model="form.material_name" placeholder="请输入物料名称" :disabled="mode=='show'"/> <uni-easyinput v-model="form.material_name" placeholder="请输入物料名称" :disabled="mode=='show'"/>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="调查表" required> <uni-forms-item label="调查表" required>
<uni-file-picker limit="1" file-mediatype="all" v-model="form.survery_form" @success="(e)=>{uploadSuccess('1', e)}"></uni-file-picker> <xtUpload v-model="form.survery_form" v-model:obj="form.survery_form_" xtype="id" :disabled="mode=='show'"></xtUpload>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="营业执照" required> <uni-forms-item label="营业执照" required>
<uni-file-picker limit="1" file-mediatype="all" v-model="form.business_license" @success="uploadSuccess('2')"></uni-file-picker> <xtUpload v-model="form.business_license" v-model:obj="form.business_license_" xtype="id" :disabled="mode=='show'"></xtUpload>
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="质量证书" required> <uni-forms-item label="质量证书" required>
<uni-file-picker limit="1" file-mediatype="all" v-model="form.quality_certificate" @success="uploadSuccess('3')"></uni-file-picker> <xtUpload v-model="form.quality_certificate" v-model:obj="form.quality_certificate_" xtype="id" :disabled="mode=='show'"></xtUpload>
</uni-forms-item> </uni-forms-item>
</uni-forms> </uni-forms>
</scroll-view> </scroll-view>
<view class="footer_fixed"> <view class="footer_fixed">
<button v-if="mode=='edit'" size="mini" @click="handleDel" :loading="saveLoading" :disabled="saveLoading" type="warn"> <!-- <button v-if="mode=='edit'" size="mini" @click="handleDel" :loading="saveLoading" :disabled="saveLoading" type="warn">
删除 删除
</button> </button> -->
<ticketd_b v-if="form.ticket_" :t_id="form.id" :ticket_="form.ticket_" <ticketd_b v-if="form.ticket_" :t_id="form.id" :ticket_="form.ticket_"
:ticket_data="ticket_data" @success="()=>{uni.navigateBack()}" ref="ticketd_b"></ticketd_b> :ticket_data="ticket_data" @success="()=>{uni.navigateBack()}" ref="ticketd_b"></ticketd_b>
<button v-else size="mini" @click="handleSave" :loading="saveLoading" :disabled="saveLoading" type="primary"> <button v-else size="mini" @click="handleSave" :loading="saveLoading" :disabled="saveLoading" type="primary">
@ -41,8 +41,9 @@
import ticketd_b from "../wf/ticketd_b.vue" import ticketd_b from "../wf/ticketd_b.vue"
import ticketd from "../wf/ticketd.vue" import ticketd from "../wf/ticketd.vue"
import {actStateEnum} from "@/utils/enum.js" import {actStateEnum} from "@/utils/enum.js"
import xtUpload from "@/components/xtUpload.vue"
export default { export default {
components: { ticketd_b, ticketd }, components: { ticketd_b, ticketd, xtUpload },
data(){ data(){
return{ return{
saveLoading: false, saveLoading: false,
@ -88,18 +89,25 @@ import {actStateEnum} from "@/utils/enum.js"
} }
}, },
methods:{ methods:{
uploadSuccess(type, e){ handleSave(){
console.log('type', type, e);
console.log('form.material_type',this.form.material_type)
},
async handleSave(id){
let that = this; let that = this;
that.$refs.customForm.validate().then(res => { that.$refs.customForm.validate().then(res => {
that.saveLoading = true;
that.$api.supplierauditCreate(that.form).then(res => {
that.saveLoading = false;
uni.showToast({
title: '提交成功',
icon: 'success'
});
uni.navigateBack()
}).catch(e=>{
that.saveLoading = false;
console.log('err', err);
})
}).catch(err => { }).catch(err => {
console.log('err', err); console.log('err', err);
}) })
let res = await that.$api.supplierauditCreate(that.form)
}, },
} }
} }

View File

@ -15,7 +15,7 @@ import API from '@/utils/api';
const props = defineProps({ const props = defineProps({
workflow_key: {type: String, default: null, required: false}, workflow_key: {type: String, default: null, required: false},
ticket_: {type: Object, default: null, required: false}, ticket_: {type: [Object, String], default: "pending", required: false},
t_id: {type: String, default: null, required: true}, t_id: {type: String, default: null, required: true},
title: {type: String, default: null, required: false}, title: {type: String, default: null, required: false},
submit_b_func: {type: Function, default: null, required: false}, submit_b_func: {type: Function, default: null, required: false},
@ -26,18 +26,20 @@ const workflow = ref(null);
const transitions = ref([]); const transitions = ref([]);
const currentUser = ref(uni.getStorageSync("userInfo").id); const currentUser = ref(uni.getStorageSync("userInfo").id);
onMounted(async () => { onMounted(async () => {
setTimeout(()=>{init()}, 1000) checkPropsUntilReady()
// await init();
// watch(
// () => props.ticket_,
// async (newVal) => {
// if (newVal && Object.keys(newVal).length > 0) {
// await init();
// }
// },
// { deep: true }
// )
}) })
const inited = ref(false)
const checkPropsUntilReady = () => {
if (inited.value) return
if (props.ticket_ !== "pending") {
init()
inited.value = true
return
}
// 200ms
setTimeout(checkPropsUntilReady, 200)
}
const suggestion = ref("") const suggestion = ref("")
const isOwn = ref(false) const isOwn = ref(false)
const ticketId = ref(null) const ticketId = ref(null)