273 lines
10 KiB
Vue
273 lines
10 KiB
Vue
<template>
|
||
<!-- 移动端布局 -->
|
||
<el-drawer v-if="isMobile" v-model="dialogVisible" :title="dialogTitle" direction="rtl" size="100%" :close-on-press-escape="true" :destroy-on-close="true" :append-to-body="true" class="mobile-form-drawer">
|
||
<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 class="mobile-form__footer">
|
||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||
<el-button type="primary" @click="submitForm" :loading="formLoading">确 定</el-button>
|
||
</div>
|
||
</div>
|
||
</el-drawer>
|
||
|
||
<!-- PC端布局 -->
|
||
<Dialog v-else v-model="dialogVisible" :title="dialogTitle" width="600px">
|
||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
|
||
<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>
|
||
<el-divider content-position="left">评分标准(满分10分)</el-divider>
|
||
<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>
|
||
<el-form-item label="综合评分" prop="totalScore"><div class="total-score"><span class="score-value">{{ totalScore.toFixed(1) }}分</span><span class="score-level">{{ getScoreLevel(totalScore) }}</span></div></el-form-item>
|
||
<el-form-item label="评价备注" prop="remark"><el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入评价备注(可选)" maxlength="500" show-word-limit /></el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitForm" :loading="formLoading">确定</el-button>
|
||
</template>
|
||
</Dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed } from 'vue'
|
||
import { SupplierEvaluationApi, SupplierEvaluationVO } from '@/api/erp/purchase/supplierEvaluation'
|
||
import { useWindowSize } from '@vueuse/core'
|
||
|
||
const { width } = useWindowSize()
|
||
const isMobile = computed(() => width.value < 768)
|
||
|
||
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 {
|
||
position: sticky;
|
||
bottom: 0;
|
||
background: #fff;
|
||
padding: 12px 16px;
|
||
padding-bottom: calc(12px + env(safe-area-inset-bottom));
|
||
border-top: 1px solid #eee;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
z-index: 10;
|
||
margin: 0 -4px -12px;
|
||
.el-button { flex: 1; height: 40px; font-size: 15px; }
|
||
}
|
||
.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>
|