274 lines
7.6 KiB
Vue
274 lines
7.6 KiB
Vue
|
|
<template>
|
|||
|
|
<Dialog v-model="dialogVisible" :title="dialogTitle" width="100%" fullscreen class="mobile-eval-form-dialog">
|
|||
|
|
<div class="mobile-form-wrapper" v-loading="formLoading">
|
|||
|
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-position="top">
|
|||
|
|
<div class="mobile-form-section">
|
|||
|
|
<div class="mobile-form-section__title">基本信息</div>
|
|||
|
|
<el-form-item label="供应商" prop="supplierName">
|
|||
|
|
<el-input v-model="formData.supplierName" disabled />
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="订单单号" prop="orderNo">
|
|||
|
|
<el-input v-model="formData.orderNo" disabled />
|
|||
|
|
</el-form-item>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="mobile-form-section">
|
|||
|
|
<div class="mobile-form-section__title">评分标准(满分10分)</div>
|
|||
|
|
<el-form-item label="质量评分" prop="qualityScore">
|
|||
|
|
<div class="rating-container">
|
|||
|
|
<el-rate v-model="formData.qualityScore" :max="10" show-score score-template="{value}分" allow-half />
|
|||
|
|
<div class="rating-desc">产品质量、规格符合度、缺陷率等</div>
|
|||
|
|
</div>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="服务评分" prop="serviceScore">
|
|||
|
|
<div class="rating-container">
|
|||
|
|
<el-rate v-model="formData.serviceScore" :max="10" show-score score-template="{value}分" allow-half />
|
|||
|
|
<div class="rating-desc">售前售后服务、响应速度、专业程度等</div>
|
|||
|
|
</div>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="价格评分" prop="priceScore">
|
|||
|
|
<div class="rating-container">
|
|||
|
|
<el-rate v-model="formData.priceScore" :max="10" show-score score-template="{value}分" allow-half />
|
|||
|
|
<div class="rating-desc">价格合理性、性价比、优惠政策等</div>
|
|||
|
|
</div>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="交付评分" prop="deliveryScore">
|
|||
|
|
<div class="rating-container">
|
|||
|
|
<el-rate v-model="formData.deliveryScore" :max="10" show-score score-template="{value}分" allow-half />
|
|||
|
|
<div class="rating-desc">交付及时性、包装质量、物流配送等</div>
|
|||
|
|
</div>
|
|||
|
|
</el-form-item>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="mobile-form-section">
|
|||
|
|
<div class="mobile-form-section__title">综合评分</div>
|
|||
|
|
<div class="total-score">
|
|||
|
|
<span class="score-value">{{ totalScore.toFixed(1) }}分</span>
|
|||
|
|
<span class="score-level">{{ getScoreLevel(totalScore) }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="mobile-form-section">
|
|||
|
|
<div class="mobile-form-section__title">评价备注</div>
|
|||
|
|
<el-form-item prop="remark">
|
|||
|
|
<el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入评价备注(可选)" maxlength="500" show-word-limit />
|
|||
|
|
</el-form-item>
|
|||
|
|
</div>
|
|||
|
|
</el-form>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<template #footer>
|
|||
|
|
<div class="mobile-form-footer">
|
|||
|
|
<el-button @click="dialogVisible = false" style="flex:1">取消</el-button>
|
|||
|
|
<el-button type="primary" @click="submitForm" :loading="formLoading" style="flex:1">确定</el-button>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
</Dialog>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup lang="ts">
|
|||
|
|
import { SupplierEvaluationApi, SupplierEvaluationVO } from '@/api/erp/purchase/supplierEvaluation'
|
|||
|
|
|
|||
|
|
interface SupplierEvaluationForm {
|
|||
|
|
id?: number
|
|||
|
|
supplierId: number
|
|||
|
|
supplierName: string
|
|||
|
|
purchaseOrderId: number
|
|||
|
|
orderNo: string
|
|||
|
|
qualityScore: number
|
|||
|
|
serviceScore: number
|
|||
|
|
priceScore: number
|
|||
|
|
deliveryScore: number
|
|||
|
|
remark: string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const { t } = useI18n()
|
|||
|
|
const message = useMessage()
|
|||
|
|
|
|||
|
|
const dialogVisible = ref(false)
|
|||
|
|
const dialogTitle = ref('')
|
|||
|
|
const formLoading = ref(false)
|
|||
|
|
const formType = ref('')
|
|||
|
|
const formRef = ref()
|
|||
|
|
const formData = ref<SupplierEvaluationForm>({
|
|||
|
|
supplierId: 0,
|
|||
|
|
supplierName: '',
|
|||
|
|
purchaseOrderId: 0,
|
|||
|
|
orderNo: '',
|
|||
|
|
qualityScore: 5,
|
|||
|
|
serviceScore: 5,
|
|||
|
|
priceScore: 5,
|
|||
|
|
deliveryScore: 5,
|
|||
|
|
remark: ''
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const formRules = reactive({
|
|||
|
|
qualityScore: [{ required: true, message: '请评价质量分数', trigger: 'change' }],
|
|||
|
|
serviceScore: [{ required: true, message: '请评价服务分数', trigger: 'change' }],
|
|||
|
|
priceScore: [{ required: true, message: '请评价价格分数', trigger: 'change' }],
|
|||
|
|
deliveryScore: [{ required: true, message: '请评价交付分数', trigger: 'change' }]
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 计算综合评分
|
|||
|
|
const totalScore = computed(() => {
|
|||
|
|
return (formData.value.qualityScore + formData.value.serviceScore +
|
|||
|
|
formData.value.priceScore + formData.value.deliveryScore) / 4
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 获取评分等级
|
|||
|
|
const getScoreLevel = (score: number) => {
|
|||
|
|
if (score >= 9) return '优秀'
|
|||
|
|
if (score >= 8) return '良好'
|
|||
|
|
if (score >= 7) return '一般'
|
|||
|
|
if (score >= 6) return '及格'
|
|||
|
|
return '不及格'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开弹窗
|
|||
|
|
const open = async (type: string, id?: number) => {
|
|||
|
|
dialogVisible.value = true
|
|||
|
|
dialogTitle.value = type === 'create' ? '新增供应商评价' : '修改供应商评价'
|
|||
|
|
formType.value = type
|
|||
|
|
resetForm()
|
|||
|
|
|
|||
|
|
// 修改时,设置数据
|
|||
|
|
if (id) {
|
|||
|
|
formLoading.value = true
|
|||
|
|
try {
|
|||
|
|
const data = await SupplierEvaluationApi.getSupplierEvaluation(id)
|
|||
|
|
formData.value = {
|
|||
|
|
...data,
|
|||
|
|
supplierName: data.supplierName || '',
|
|||
|
|
orderNo: data.orderNo || ''
|
|||
|
|
}
|
|||
|
|
} finally {
|
|||
|
|
formLoading.value = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重置表单
|
|||
|
|
const resetForm = () => {
|
|||
|
|
formData.value = {
|
|||
|
|
supplierId: 0,
|
|||
|
|
supplierName: '',
|
|||
|
|
purchaseOrderId: 0,
|
|||
|
|
orderNo: '',
|
|||
|
|
qualityScore: 5,
|
|||
|
|
serviceScore: 5,
|
|||
|
|
priceScore: 5,
|
|||
|
|
deliveryScore: 5,
|
|||
|
|
remark: ''
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 提交表单
|
|||
|
|
const submitForm = async () => {
|
|||
|
|
if (!formRef.value) return
|
|||
|
|
const valid = await formRef.value.validate()
|
|||
|
|
if (!valid) return
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
formLoading.value = true
|
|||
|
|
const data = {
|
|||
|
|
...formData.value,
|
|||
|
|
totalScore: totalScore.value
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (formType.value === 'create') {
|
|||
|
|
await SupplierEvaluationApi.createSupplierEvaluation(data)
|
|||
|
|
message.success('新增成功')
|
|||
|
|
} else {
|
|||
|
|
await SupplierEvaluationApi.updateSupplierEvaluation(data)
|
|||
|
|
message.success('修改成功')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
dialogVisible.value = false
|
|||
|
|
emit('success')
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('操作失败', error)
|
|||
|
|
} finally {
|
|||
|
|
formLoading.value = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 定义事件
|
|||
|
|
const emit = defineEmits<{
|
|||
|
|
success: []
|
|||
|
|
}>()
|
|||
|
|
|
|||
|
|
// 暴露方法
|
|||
|
|
defineExpose({ open })
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.mobile-form-wrapper {
|
|||
|
|
padding: 0 4px;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
-webkit-overflow-scrolling: touch;
|
|||
|
|
}
|
|||
|
|
.mobile-form-section {
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 10px;
|
|||
|
|
padding: 14px;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
|||
|
|
&__title {
|
|||
|
|
font-size: 15px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #303133;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
padding-bottom: 8px;
|
|||
|
|
border-bottom: 1px solid #f0f0f0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.mobile-form-footer {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 12px;
|
|||
|
|
padding: 0 4px;
|
|||
|
|
}
|
|||
|
|
.rating-container {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
.rating-desc {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #909399;
|
|||
|
|
}
|
|||
|
|
.total-score {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 12px;
|
|||
|
|
padding: 10px 0;
|
|||
|
|
}
|
|||
|
|
.score-value {
|
|||
|
|
font-size: 24px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #409eff;
|
|||
|
|
}
|
|||
|
|
.score-level {
|
|||
|
|
padding: 4px 12px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
background-color: #f0f9ff;
|
|||
|
|
color: #409eff;
|
|||
|
|
border: 1px solid #b3d8ff;
|
|||
|
|
}
|
|||
|
|
:deep(.el-rate) {
|
|||
|
|
height: auto;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
}
|
|||
|
|
:deep(.el-rate__text) {
|
|||
|
|
color: #409eff;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
:deep(.mobile-eval-form-dialog .el-dialog__body) {
|
|||
|
|
padding: 12px;
|
|||
|
|
background: #f5f5f5;
|
|||
|
|
}
|
|||
|
|
:deep(.el-form-item) {
|
|||
|
|
margin-bottom: 14px;
|
|||
|
|
}
|
|||
|
|
</style>
|