You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

642 lines
17 KiB

<template>
<div class="consistency-content">
<!-- 对比文件类型选择 -->
<div class="section comparison-section">
<h3 class="section-title">选择对比文件类型</h3>
<p class="section-description">选择需要与合同进行一致性对比的文件类型</p>
<div class="comparison-options">
<div
class="comparison-card"
:class="{ selected: selectedComparisons.includes('tender') }"
@click="toggleComparison('tender')"
>
<div class="card-header">
<CheckCircleOutlined v-if="selectedComparisons.includes('tender')" class="check-icon" />
招标文件
</div>
<div class="card-body">
<h3>与招标文件对比</h3>
<p class="card-desc">检查合同条款是否与招标文件要求一致</p>
</div>
</div>
<div
class="comparison-card"
:class="{ selected: selectedComparisons.includes('bid') }"
@click="toggleComparison('bid')"
>
<div class="card-header">
<CheckCircleOutlined v-if="selectedComparisons.includes('bid')" class="check-icon" />
投标文件
</div>
<div class="card-body">
<h3>与投标文件对比</h3>
<p class="card-desc">检查合同是否履行投标承诺和要求</p>
</div>
</div>
<div
class="comparison-card"
:class="{ selected: selectedComparisons.includes('negotiation') }"
@click="toggleComparison('negotiation')"
>
<div class="card-header">
<CheckCircleOutlined v-if="selectedComparisons.includes('negotiation')" class="check-icon" />
谈判记录
</div>
<div class="card-body">
<h3>与谈判记录对比</h3>
<p class="card-desc">检查合同是否体现谈判确定的内容</p>
</div>
</div>
</div>
</div>
<!-- 检查维度选择 -->
<div class="section dimension-section">
<h3 class="section-title">选择检查维度</h3>
<p class="section-description">选择需要进行一致性检查的关键维度</p>
<div class="dimension-options">
<div
class="dimension-card"
:class="{ selected: selectedDimensions.includes('technical') }"
@click="toggleDimension('technical')"
>
<div class="card-header">
<CheckCircleOutlined v-if="selectedDimensions.includes('technical')" class="check-icon" />
技术规格
</div>
<div class="card-body">
<h3>技术规格一致性</h3>
<p class="card-desc">检查技术参数性能指标质量标准等</p>
</div>
</div>
<div
class="dimension-card"
:class="{ selected: selectedDimensions.includes('commercial') }"
@click="toggleDimension('commercial')"
>
<div class="card-header">
<CheckCircleOutlined v-if="selectedDimensions.includes('commercial')" class="check-icon" />
商务条款
</div>
<div class="card-body">
<h3>商务条款一致性</h3>
<p class="card-desc">检查价格付款方式结算条件等</p>
</div>
</div>
<div
class="dimension-card"
:class="{ selected: selectedDimensions.includes('service') }"
@click="toggleDimension('service')"
>
<div class="card-header">
<CheckCircleOutlined v-if="selectedDimensions.includes('service')" class="check-icon" />
服务要求
</div>
<div class="card-body">
<h3>服务要求一致性</h3>
<p class="card-desc">检查服务内容服务标准售后保障等</p>
</div>
</div>
<div
class="dimension-card"
:class="{ selected: selectedDimensions.includes('delivery') }"
@click="toggleDimension('delivery')"
>
<div class="card-header">
<CheckCircleOutlined v-if="selectedDimensions.includes('delivery')" class="check-icon" />
交付条件
</div>
<div class="card-body">
<h3>交付条件一致性</h3>
<p class="card-desc">检查交付时间交付地点验收标准等</p>
</div>
</div>
</div>
</div>
<!-- 偏离检查级别 -->
<div class="section deviation-section">
<h3 class="section-title">偏离检查级别</h3>
<p class="section-description">设置对偏离情况的检查严格程度</p>
<div class="deviation-options">
<div
class="deviation-card"
:class="{ selected: selectedDeviationLevel === 'strict' }"
@click="selectDeviationLevel('strict')"
>
<div class="card-icon">
<ExclamationCircleOutlined />
</div>
<div class="card-title">严格检查</div>
<div class="card-desc">任何偏离都需要标记和说明</div>
</div>
<div
class="deviation-card"
:class="{ selected: selectedDeviationLevel === 'standard' }"
@click="selectDeviationLevel('standard')"
>
<div class="card-icon">
<WarningOutlined />
</div>
<div class="card-title">标准检查</div>
<div class="card-desc">检查重要偏离和实质性变更</div>
</div>
<div
class="deviation-card"
:class="{ selected: selectedDeviationLevel === 'flexible' }"
@click="selectDeviationLevel('flexible')"
>
<div class="card-icon">
<InfoCircleOutlined />
</div>
<div class="card-title">灵活检查</div>
<div class="card-desc">主要关注关键要素的偏离</div>
</div>
</div>
</div>
<!-- 关键要素优先级 -->
<div class="section priority-section">
<h3 class="section-title">关键要素优先级</h3>
<p class="section-description">设置不同要素的检查优先级</p>
<div class="priority-settings">
<div class="priority-item">
<div class="priority-label">价格金额</div>
<div class="priority-selector">
<div class="priority-buttons">
<div
class="priority-btn"
:class="{ active: priorities.price === 'high' }"
@click="setPriority('price', 'high')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.price === 'medium' }"
@click="setPriority('price', 'medium')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.price === 'low' }"
@click="setPriority('price', 'low')"
>
</div>
</div>
</div>
</div>
<div class="priority-item">
<div class="priority-label">技术参数</div>
<div class="priority-selector">
<div class="priority-buttons">
<div
class="priority-btn"
:class="{ active: priorities.technical === 'high' }"
@click="setPriority('technical', 'high')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.technical === 'medium' }"
@click="setPriority('technical', 'medium')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.technical === 'low' }"
@click="setPriority('technical', 'low')"
>
</div>
</div>
</div>
</div>
<div class="priority-item">
<div class="priority-label">交付时间</div>
<div class="priority-selector">
<div class="priority-buttons">
<div
class="priority-btn"
:class="{ active: priorities.delivery === 'high' }"
@click="setPriority('delivery', 'high')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.delivery === 'medium' }"
@click="setPriority('delivery', 'medium')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.delivery === 'low' }"
@click="setPriority('delivery', 'low')"
>
</div>
</div>
</div>
</div>
<div class="priority-item">
<div class="priority-label">服务承诺</div>
<div class="priority-selector">
<div class="priority-buttons">
<div
class="priority-btn"
:class="{ active: priorities.service === 'high' }"
@click="setPriority('service', 'high')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.service === 'medium' }"
@click="setPriority('service', 'medium')"
>
</div>
<div
class="priority-btn"
:class="{ active: priorities.service === 'low' }"
@click="setPriority('service', 'low')"
>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 特别关注点 -->
<div class="section focus-section">
<h3 class="section-title">特别关注点可选</h3>
<p class="section-description">指定需要特别关注的一致性检查要点</p>
<div class="focus-input">
<Input.TextArea
v-model:value="specialFocus"
placeholder="请输入特别关注的一致性要点,如特定技术指标、关键商务条款、重要服务承诺等..."
:rows="3"
:maxlength="500"
show-count
size="large"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { Input } from 'ant-design-vue';
import {
CheckCircleOutlined,
ExclamationCircleOutlined,
WarningOutlined,
InfoCircleOutlined
} from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
// 状态变量
const selectedComparisons = ref<string[]>(['tender', 'bid']); // 默认选择招标文件和投标文件
const selectedDimensions = ref<string[]>(['technical', 'commercial', 'delivery']); // 默认选择技术、商务、交付
const selectedDeviationLevel = ref<string>('standard'); // 默认选择标准检查
const specialFocus = ref<string>(''); // 特别关注点
// 优先级设置
const priorities = reactive({
price: 'high',
technical: 'high',
delivery: 'medium',
service: 'medium'
});
// 切换对比文件类型
const toggleComparison = (comparison: string) => {
const index = selectedComparisons.value.indexOf(comparison);
if (index > -1) {
selectedComparisons.value.splice(index, 1);
} else {
selectedComparisons.value.push(comparison);
}
};
// 切换检查维度
const toggleDimension = (dimension: string) => {
const index = selectedDimensions.value.indexOf(dimension);
if (index > -1) {
selectedDimensions.value.splice(index, 1);
} else {
selectedDimensions.value.push(dimension);
}
};
// 选择偏离检查级别
const selectDeviationLevel = (level: string) => {
selectedDeviationLevel.value = level;
};
// 设置优先级
const setPriority = (key: string, level: string) => {
priorities[key] = level;
};
// 获取数据的方法,供父组件调用
const getData = () => {
// 检查是否选择了对比文件类型
if (selectedComparisons.value.length === 0) {
message.warning('请至少选择一种对比文件类型');
return null;
}
// 检查是否选择了检查维度
if (selectedDimensions.value.length === 0) {
message.warning('请至少选择一个检查维度');
return null;
}
return {
type: 'consistency',
comparisons: selectedComparisons.value,
dimensions: selectedDimensions.value,
deviationLevel: selectedDeviationLevel.value,
priorities: { ...priorities },
specialFocus: specialFocus.value || undefined,
};
};
// 暴露getData方法
defineExpose({
getData
});
</script>
<style lang="less" scoped>
.consistency-content {
padding: 16px;
}
// 各部分通用样式
.section {
margin-bottom: 24px;
border-bottom: 1px dashed #eee;
padding-bottom: 16px;
&:last-child {
border-bottom: none;
}
}
.section-title {
font-size: 16px;
margin-bottom: 6px;
font-weight: 500;
color: #333;
}
.section-description {
color: #666;
margin-bottom: 16px;
font-size: 14px;
}
// 对比文件类型选择
.comparison-options {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.comparison-card {
flex: 1;
min-width: 280px;
border: 2px solid #e8e8e8;
border-radius: 6px;
overflow: hidden;
transition: all 0.3s;
cursor: pointer;
&:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border-color: #13c2c2;
transform: translateY(-2px);
}
&.selected {
border-color: #13c2c2;
box-shadow: 0 0 0 2px rgba(19, 194, 194, 0.2);
background-color: #e6fffb;
}
}
// 检查维度选择
.dimension-options {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.dimension-card {
border: 2px solid #e8e8e8;
border-radius: 6px;
overflow: hidden;
transition: all 0.3s;
cursor: pointer;
&:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border-color: #13c2c2;
transform: translateY(-2px);
}
&.selected {
border-color: #13c2c2;
box-shadow: 0 0 0 2px rgba(19, 194, 194, 0.2);
background-color: #e6fffb;
}
}
.card-header {
background-color: #f7f7f7;
padding: 8px;
font-weight: 500;
font-size: 14px;
text-align: center;
color: #333;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
.comparison-card.selected &,
.dimension-card.selected & {
background-color: #13c2c2;
color: white;
}
.check-icon {
font-size: 16px;
}
}
.card-body {
padding: 12px;
text-align: center;
h3 {
margin: 0 0 6px 0;
font-size: 14px;
font-weight: 500;
color: #333;
}
.card-desc {
margin: 0;
font-size: 12px;
color: #666;
line-height: 1.4;
}
}
// 偏离检查级别
.deviation-options {
display: flex;
gap: 12px;
justify-content: center;
}
.deviation-card {
flex: 1;
max-width: 250px;
border: 2px solid #e8e8e8;
border-radius: 6px;
padding: 16px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
border-color: #13c2c2;
box-shadow: 0 2px 8px rgba(19, 194, 194, 0.15);
}
&.selected {
border-color: #13c2c2;
background-color: #e6fffb;
box-shadow: 0 0 0 2px rgba(19, 194, 194, 0.2);
}
}
.card-icon {
font-size: 24px;
color: #13c2c2;
margin-bottom: 8px;
}
.card-title {
font-size: 14px;
font-weight: 500;
margin-bottom: 6px;
color: #333;
}
.card-desc {
font-size: 12px;
color: #666;
line-height: 1.4;
}
// 优先级设置
.priority-settings {
background-color: #f9f9f9;
border-radius: 6px;
padding: 16px;
}
.priority-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
}
.priority-label {
font-size: 14px;
font-weight: 500;
color: #333;
min-width: 80px;
}
.priority-buttons {
display: flex;
gap: 6px;
}
.priority-btn {
padding: 4px 12px;
border: 2px solid #e8e8e8;
border-radius: 16px;
cursor: pointer;
transition: all 0.3s;
font-size: 12px;
font-weight: 500;
color: #666;
&:hover {
border-color: #13c2c2;
color: #13c2c2;
}
&.active {
border-color: #13c2c2;
background-color: #13c2c2;
color: white;
}
}
// 特别关注点
.focus-input {
margin-top: 16px;
:deep(.ant-input) {
font-size: 14px !important;
border-radius: 6px !important;
&:focus {
border-color: #13c2c2;
box-shadow: 0 0 0 2px rgba(19, 194, 194, 0.2);
}
}
:deep(.ant-input-data-count) {
color: #999;
font-size: 12px;
}
}
</style>