待解决问题1:scoped

本文探讨了在Vue应用中,如何理解scoped样式的作用范围,以及为何将title类名写在非scoped的div上反而能影响到子组件中的h2元素。通过实例解析,解释了CSS选择器优先级和组件内样式穿透现象。

App.vue中设置

<style scoped>
  .title{
    color: red;
  }
</style>

在App的子组件中

<template>
  <div class="demo">
      <h2 class="title">学生姓名:{{name}}</h2>
      <h2>学生性别:{{sex}}</h2>
  </div>
</template>

引用title类名,不起作用。因为一旦定义scoped属性,只能在它的模板使用
但是有疑惑?

<template>
  <div class="demo title">
      <h2 >学生姓名:{{name}}</h2>
      <h2>学生性别:{{sex}}</h2>
  </div>
</template>

我把title写在div中,字体颜色变为红色了,为什么?

<template> <div class="ring-chart-container"> <v-chart :options="chartOption" autoresize style="width: 100%; height: 100%;" /> </div> </template> <script> export default { name: 'OrderStatusRingChart', data() { return { orderData: [{ name: '待付款', value: 120 }, { name: '待发货', value: 95 }, { name: '待收货', value: 80 }, { name: '已完成', value: 300 }, { name: '已取消', value: 25 }, { name: '待评价', value: 70 } ], // 自定义颜色顺序(必须与 data 顺序严格对应) customColors: [ '#F79800', // 待付款 '#B184FF', // 待发货 '#3CC9DF', // 待收货 '#98DF3C', // 已完成 '#D6EF31', // 已取消 '#FFC815' // 待评价 ] }; }, computed: { chartOption() { return { color: this.customColors, // ✅ 应用自定义颜色调色板 tooltip: { trigger: 'item', formatter: '{a}<br/>{b}: {c} ({d}%)' }, series: [{ name: '订单状态', type: 'pie', radius: ['40%', '60%'], // 圆环内外半径 center: ['60%', '50%'], // 图表中心位置 data: this.orderData, roseType: false, label: { show: true, position: 'outside', formatter: '{b|{b}}\n{hr|}\n{per|{d}%}', rich: { b: { fontSize: 14, fontWeight: 'bold', lineHeight: 20 }, hr: { borderColor: '#aaa', width: '100%', borderWidth: 0.5, height: 0, lineHeight: 5 }, per: { fontSize: 16, color: '#F79800' } } }, itemStyle: { borderRadius: 8, borderColor: '#fff', borderWidth: 2 }, emphasis: { scale: true, scaleSize: 5 } }], animationEasing: 'elasticOut', animationDuration: 1200 }; } } }; </script> <style scoped> .ring-chart-container { /* padding: 16px; */ font-family: Arial, sans-serif; width: 100%; height: 100%; /* background-color: #f9f9f9; */ border-radius: 12px; /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */ } </style> 画出的图片靠右移了一点
11-01
<template> <div class="main"> <div class="top"> <el-input style="width: 220px;" placeholder="请输入用户信息" /> <el-input style="width: 220px;" placeholder="请输入旅行信息" /> <el-date-picker type="date" placeholder="请选择开始日期" /> <div class="line"></div> <el-date-picker type="date" placeholder="请选择结束日期" /> <el-button type="primary" :icon="Search">搜索</el-button> </div> <div class="bottom"> <el-table ref="tableRef" row-key="orderStatus" :data="tableData" style="width: 100%"> <el-table-column prop="phone" label="用户信息" width="144" /> <el-table-column prop="trip" label="旅行行程" width="144" /> <el-table-column prop="orderstatus" label="订单状态" width="144" column-key="date" :filters="[ { text: '拒绝', value: '2' }, { text: '待处理', value: '1' }, { text: '已处理', value: '0' }, ]" :filter-method="filterHandler"> <template #default="scope"> <div :class="`status-tag status-${scope.row.orderstatus}`"> {{ formatOrderStatus(scope.row) }} </div> </template> </el-table-column> <el-table-column prop="refundstatus" label="退款状态" width="144"> <template #default="scope"> <div :class="`status-tag refund-${scope.row.refundstatus}`"> {{ formatRefundStatus(scope.row) }} </div> </template> </el-table-column> <el-table-column prop="discount" label="折扣信息" width="144" :formatter="(row) => { const value = row.discount * 10; return `${value % 1 === 0 ? value.toFixed(0) : value.toFixed(1)}折`; }" /> <el-table-column prop="price" label="订单价格" width="144"> <template #default="scope"> <span class="price-value">¥{{ scope.row.price.toFixed(2) }}</span> </template> </el-table-column> <el-table-column prop="transactionprice" label="实际成交价" width="144"> <template #default="scope"> <span class="transaction-value">¥{{ scope.row.transactionprice.toFixed(2) }}</span> </template> </el-table-column> <el-table-column prop="createtime" label="下单时间" width="144"> <template #default="scope"> <div class="time-highlight"> {{ formatTime(scope.row.createtime) }} </div> </template> </el-table-column> <el-table-column prop="shopname" label="门店" width="144" /> <el-table-column label="操作" width="144"> <template #default="scope"> <el-button type="primary" class="detail-btn" @click="handleDetail()">详情</el-button> </template> </el-table-column> <el-table-column label="退款操作" width="144"> <template #default="scope"> <el-button type="danger" class="refund-btn">退款</el-button> </template> </el-table-column> </el-table> <Pagination v-if="pagination.total > 0" :total="pagination.total" :page-size="pagination.pageSize" :current-page="pagination.currentPage" @page-change="handlePageChange" @size-change="handleSizeChange" /> </div> </div> </template> <script setup lang='ts'> import { post } from '@/utils/request'; import { ref, onMounted } from 'vue'; import type { TableColumnCtx, TableInstance } from 'element-plus'; import { Search } from '@element-plus/icons-vue' import { useRouter } from 'vue-router'; import { ElMessage } from 'element-plus'; import dayjs from 'dayjs'; import Pagination from '@/components/Pagination.vue'; const pagination = ref({ total: 0, pageSize: 5, currentPage: 1 }); // 引入中文语言包(如果需要中文显示) import 'dayjs/locale/zh-cn'; dayjs.locale('zh-cn'); // 格式化时间函数 const formatTime = (createtime: string) => { if (!createtime) return '--'; return dayjs(createtime).format('YYYY-MM-DD HH:mm:ss'); } const router = useRouter() interface Order { phone: string; trip: string; orderstatus: number; // 保留原有的 status 属性 refundstatus: number; discount: string; price: number; transactionprice: number; createtime: string; shopname: string; [key: string]: any; // 显式声明索引签名 } interface PaginationParams { pageIndex: number; pageSize: number; [key: string]: any; // 允许其他参数 } interface ApiResponse { msg: string; code: number; dataset: { pageCount: number; orderInfo: Order[]; }; } const tableRef = ref<TableInstance>(); const formatOrderStatus = (row: Order) => { const statusMap: Record<string, string> = { '0': '已处理', '1': '待处理', '2': '拒绝' }; return statusMap[String(row.orderstatus)] || '未知状态'; }; const formatRefundStatus = (row: Order) => { const Rstatus = String(row.refundstatus); const RstatusMap: Record<string, string> = { '0': '未退款', '1': '已退款' } return RstatusMap[Rstatus] || '未知状态'; } // 确保过滤方法正确处理类型 const filterHandler = ( value: string, row: Order, column: TableColumnCtx<Order> ) => { const property = column.property; return String(row[property]) === value; }; const tableData = ref<Order[]>([]) onMounted(() => { getOrder(); }) const getOrder = async () => { try { const params: PaginationParams = { pageIndex: pagination.value.currentPage, pageSize: pagination.value.pageSize, }; const res = await post<ApiResponse>('orders/getOrderInfo', params); if (res.code === 200) { // 确保数据结构正确 if (res.dataset && Array.isArray(res.dataset.orderInfo)) { tableData.value = res.dataset.orderInfo; // 设置总记录数 pagination.value.total = res.dataset.pageCount || 0; console.log('获取的数据:', res.dataset,pagination.value.total); } else { // 处理意外的数据结构 console.error('API 返回了意外的数据结构:', res); ElMessage.error('数据格式错误,请检查 API 响应'); } } else { ElMessage.error(res.msg || '获取数据失败'); } } catch (error) { console.log(error); } } // 处理页码变化 const handlePageChange = (page: number, pageSize: number) => { pagination.value.currentPage = page; getOrder(); }; // 处理每页显示数量变化 const handleSizeChange = (size: number) => { pagination.value.pageSize = size; pagination.value.currentPage = 1; // 重置到第一页 getOrder(); }; // 点击跳转详情 const handleDetail = () => { router.push('/orderDetail') }; </script> <style scoped lang='less'> .line { width: 50px; height: 2px; background-color: #333; } .main { width: 100%; height: 100%; } .top { display: flex; align-items: center; justify-content: right; gap: 15px; padding: 20px; background: linear-gradient(to right, #f8fafc, #f0f7ff); border-radius: 12px; margin-bottom: 25px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03); transition: all 0.3s ease; &:hover { box-shadow: 0 6px 16px rgba(0, 0, 0, 0.05); } } .detail { cursor: pointer; } .bottom { max-width: 1600px; margin: 0 auto; padding: 30px; background: #ffffff; border-radius: 16px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } // 表格样式优化 :deep(.el-table) { --el-table-border-color: #ebeef5; --el-table-header-bg-color: #f5f7fa; --el-table-row-hover-bg-color: #f5f7fa; th { background-color: #f5f7fa; color: #2c3e50; font-weight: 600; font-size: 15px; } } // 状态标签样式 .status-tag { display: inline-block; padding: 6px 12px; border-radius: 20px; font-size: 13px; font-weight: 600; text-align: center; min-width: 70px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } /* 订单状态样式 */ .status-0 { /* 已处理 */ background-color: #e8f5e9; color: #2e7d32; border: 1px solid #c8e6c9; } .status-1 { /* 待处理 */ background-color: #fff8e1; color: #f57f17; border: 1px solid #ffecb3; } .status-2 { /* 拒绝 */ background-color: #ffebee; color: #c62828; border: 1px solid #ffcdd2; } .refund-0 { /* 未退款 */ background-color: #f5f5f5; color: #616161; border: 1px solid #e0e0e0; } .refund-1 { /* 已退款 */ background-color: #e8f5e9; color: #2e7d32; border: 1px solid #c8e6c9; } // 时间高亮样式 .time-highlight { color: #1890ff; font-weight: 600; padding: 5px 10px; border-radius: 6px; background: rgba(24, 144, 255, 0.08); display: inline-block; font-family: 'Courier New', monospace; transition: all 0.3s ease; &:hover { background: rgba(24, 144, 255, 0.15); transform: translateX(2px); } } // 价格样式 .price-value { color: #f56c6c; font-weight: 600; } .transaction-value { color: #67c23a; font-weight: 600; } // 按钮样式 .detail-btn { border-radius: 8px; padding: 8px 15px; background-color: #3498db; border-color: #3498db; transition: all 0.3s ease; &:hover { background-color: #2980b9; transform: scale(1.05); } } .refund-btn { border-radius: 8px; padding: 8px 15px; transition: all 0.3s ease; &:not(:disabled):hover { transform: scale(1.05); box-shadow: 0 0 10px rgba(231, 76, 60, 0.3); } &:disabled { opacity: 0.7; cursor: not-allowed; } } </style><template> <div class="pagination-container"> <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[5, 10, 20, 50]" :size="size" :background="true" :layout="'total, sizes, prev, pager, next, jumper'" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </template> <script setup lang="ts"> import { ref, watch } from 'vue'; import type { ComponentSize } from 'element-plus' const size = ref<ComponentSize>('default') const props = defineProps({ total: { type: Number, required: true, default: 0 }, pageSize: { type: Number, default: 10 }, currentPage: { type: Number, default: 1 } }); const emit = defineEmits(['page-change', 'size-change']); const currentPage = ref(props.currentPage); const pageSize = ref(props.pageSize); // 监听属性变化 watch( () => props.currentPage, (val) => { currentPage.value = val; } ); watch( () => props.pageSize, (val) => { pageSize.value = val; } ); // 处理每页显示数量变化 const handleSizeChange = (val: number) => { pageSize.value = val; emit('size-change', val); emit('page-change', currentPage.value, val); }; // 处理当前页变化 const handleCurrentChange = (val: number) => { currentPage.value = val; emit('page-change', val, pageSize.value); }; </script> <style scoped lang="less"> .pagination-container { margin-top: 20px; display: flex; justify-content: flex-end; padding: 10px 0; background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); .el-pagination { padding: 0 15px; } } </style>分页功能有问题总页数无法正常显示
07-16
<template> <div class="operation-container"> <div class="header"> <h2>{{ $t('config.title') }}</h2> <div> <el-button type="success" size="default" @click="showAddDialog" style="margin-bottom: 10px"> {{ $t('config.addConfig') }} </el-button> </div> </div> <div class="filter-container"> <el-form :model="filter" class="filter-form" label-width="150px"> <el-row :gutter="20" style="margin-bottom: 20px"> <el-col :span="6"> <!-- 主机应用选择 --> <el-form-item :label="$t('config.hostApp')"> <el-select v-model="filter.hostApp" :placeholder="$t('config.selectHostApp')" clearable filterable style="width: 300px" @change="handleFilter" > <el-option v-for="app in hostAppOptions" :key="app" :label="getHostAppLabel(app)" :value="app" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <!-- 卡位置选择 --> <el-form-item :label="$t('config.cardPosition')"> <el-select v-model="filter.cardPosition" :placeholder="$t('config.selectCardPosition')" clearable filterable style="width: 300px" @change="handleFilter" > <el-option v-for="position in cardPositionOptions" :key="position" :label="getCardPositionLabel(position)" :value="position" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <!-- 设备类型选择 --> <el-form-item :label="$t('config.deviceType')"> <el-select v-model="filter.deviceType" :placeholder="$t('config.selectDeviceType')" clearable filterable style="width: 300px" @change="handleFilter" > <el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <!-- 卡片名称查询 --> <el-form-item :label="$t('management.cardName')" prop="cardName"> <el-select v-model="filter.cardName" :placeholder="$t('common.selectCardName')" clearable filterable @change="handleFilter" style="width: 300px" > <el-option v-for="item in cardAddOptions" :key="item.cardName" :label="cardTitleMap[item.cardName] + '-' + item.cardName" :value="item.cardName" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="24"> <el-row type="flex" justify="end"> <el-button @click="resetFields">{{ $t('common.reset') }}</el-button> <el-button type="primary" @click="handleFilter">{{ $t('common.search') }}</el-button> </el-row> </el-col> </el-row> </el-form> </div> <!-- 批量操作工具栏 --> <div class="batch-toolbar"> <el-button type="warning" size="small" @click="betaOrStopOrFullPublish('batchRuleSet')" icon="CircleCheck" > {{ $t('config.batchConfigCardRules') }} </el-button> <el-button type="success" size="small" @click="betaOrStopOrFullPublish('full')" icon="CircleCheck" > {{ $t('config.batchFullPublish') }} </el-button> <el-button type="danger" size="small" @click="betaOrStopOrFullPublish('stop')" icon="CircleCheck" > {{ $t('config.batchStopPublish') }} </el-button> </div> <el-table :data="tableData" :fit="true" border style="width: 100%" :empty-text="$t('common.noData')" v-loading="loading" class="github-table" ref="tableRef" @expand-change="handleExpandChange" :expand-row-keys="defaultExpandedRows" row-key="id" > <!-- 展开/收起列 --> <el-table-column type="expand" width="60"> <template #header> <el-icon :size="13" class="expand-icon" @click.stop="toggleExpandAll"> <component :is="isAllExpanded ? 'ArrowDown' : 'ArrowRight'" /> </el-icon> </template> <template #default="{ row }"> <div class="version-container"> <el-table :data="versionTablesData[row.id]?.tableData || []" :fit="true" border stripe style="width: 100%" :empty-text="$t('common.noData')" v-loading="versionTablesData[row.id]?.loading" class="github-table" :ref="`versionTable_${row.id}`" :row-key="(row) => row.cardVer" > <el-table-column width="40" type="selection" reserve-selection /> <el-table-column prop="cardVer" :label="$t('version.version')" align="center" /> <el-table-column prop="status" :label="$t('management.cardPackageStatus')" align="center" > <template #default="{ row }"> <el-tag :type="row.status === 0 ? 'success' : 'danger'"> {{ row.status === 0 ? $t('management.listed') : $t('management.unlisted') }} </el-tag> </template> </el-table-column> <el-table-column prop="cardTags" :label="$t('version.tags')" align="center"> <template #default="{ row }"> <div :class="{ 'tag-cell': row.cardTags?.slice(0, 3)?.length > 1 }"> <!-- 显示前N个可见标签 --> <div v-for="tag in row.cardTags?.slice(0, 3)" :key="tag"> <el-tag v-if="tag.length > 10" class="table-tag" @click="handleTagClick(tag)"> {{ truncateText(tag, 10) }} </el-tag> <el-tag v-else> {{ tag }} </el-tag> </div> <!-- 折叠剩余标签 --> <el-popover v-if="row.cardTags?.slice(3)?.length > 0" placement="bottom" trigger="hover" :width="300" > <template #reference> <el-tag class="more-tag">+{{ row.cardTags?.slice(3)?.length }}</el-tag> </template> <div class="hidden-tags-container"> <el-tag v-for="tag in row.cardTags?.slice(3)" :key="tag" class="hidden-tag"> {{ tag }} </el-tag> </div> </el-popover> </div> </template> </el-table-column> <el-table-column prop="deviceTypes" :label="$t('version.supportedDevices')" align="center" > <template #default="{ row }"> <div class="vertical-tags-container"> <el-tag v-for="type in row.deviceTypes.join(',').split(',')" :key="type" class="content-fit-tag" > {{ deviceTypeFilter(type) }} </el-tag> </div> </template> </el-table-column> <el-table-column prop="minorsMode" :label="$t('version.minorsMode')" align="center"> <template #default="{ row }"> <el-tag :type="row.minorsMode === 1 ? 'success' : 'warning'"> {{ row.minorsMode === 1 ? $t('version.available') : $t('version.unavailable') }} </el-tag> </template> </el-table-column> <el-table-column :label="$t('version.multiLangDesc')" width="150" align="center"> <template #default="{ row }"> <div> <el-button size="small" @click="handleShowJson(row.cardMultiLang, $t('version.multiLangDesc'))" > {{ $t('version.viewJson') }} </el-button> </div> </template> </el-table-column> <el-table-column :label="$t('version.capabilities')" width="150" align="center"> <template #default="{ row }"> <div> <el-button size="small" @click="handleShowJson(row.services, $t('version.capabilities'))" > {{ $t('version.viewJson') }} </el-button> </div> </template> </el-table-column> <el-table-column prop="publishStatus" :label="$t('config.releaseStatus')" align="center" > <template #default="{ row }"> <div v-if="row.publishStatus === 0"> {{ $t('config.releaseStatusEnum.toBeReleased') }} </div> <div v-if="row.publishStatus === 1"> {{ $t('config.releaseStatusEnum.crowdtestingRelease') }} </div> <div v-if="row.publishStatus === 2"> {{ $t('config.releaseStatusEnum.fullRelease') }} </div> </template> </el-table-column> <el-table-column :label="$t('common.actions')" width="300" fixed="right" align="center" > <template #default="{ row: version }"> <div style="flex-wrap: wrap; align-items: center; gap: 4px; min-height: 32px"> <el-button size="small" @click="actionsTo(row.id, 'edit', version)" >{{ $t('common.edit') }} </el-button> <el-button type="danger" style="margin-left: 9px" size="small" @click="actionsTo(row.id, 'stop', version)" v-if="version.publishStatus !== 0" >{{ $t('crowdTesting.stopPublish') }} </el-button> <el-button type="success" style="margin-left: 9px" size="small" @click="actionsTo(row.id, 'full', version)" v-if="version.publishStatus === 1" >{{ $t('crowdTesting.fullPublish') }} </el-button> </div> </template> </el-table-column> </el-table> <div> <el-pagination size="default" @size-change="(val) => handleVersionSizeChange(row.id, val)" @current-change="(val) => handleVersionCurrentChange(row.id, val)" :current-page="versionCurrentPage" :page-sizes="[10, 20, 50, 100]" :page-size="versionPageSize" layout="total, prev, pager, next,sizes, jumper" :total="versionTablesData[row.id]?.total" /> </div> </div> </template> </el-table-column> <!-- 选择框列 --> <el-table-column prop="hostApp" :label="$t('config.hostApp')" align="center" width="300px"> <template #default="scope"> <el-tooltip :content="scope.row.hostApp"> <span class="text-ellipsis">{{ getHostAppLabel(scope.row.hostApp) }}</span> </el-tooltip> </template> </el-table-column> <el-table-column prop="cardPosition" :label="$t('config.cardPosition')" align="center"> <template #default="scope"> <el-tooltip :content="scope.row.cardPosition"> <span class="text-ellipsis">{{ getCardPositionLabel(scope.row.cardPosition) }}</span> </el-tooltip> </template> </el-table-column> <el-table-column prop="deviceType" :label="$t('config.deviceType')" align="center" width="150" > <template #default="scope"> {{ getDeviceType(scope.row.deviceType) }} </template> </el-table-column> <el-table-column prop="cardName" :label="$t('management.cardName')" align="center"> <template #default="scope"> <el-tooltip :content="scope.row.cardName"> <span class="text-ellipsis">{{ cardTitleMap[scope.row.cardName] || scope.row.cardName }}</span> </el-tooltip> </template> </el-table-column> <!-- 索引列 --> <el-table-column prop="index" :label="$t('config.sortIndex')" align="center" width="150"> <template #default="scope"> {{ basicCardObj[scope.row.cardName]?.cardType === 2 ? '/' : scope.row.index }} </template> </el-table-column> <el-table-column :label="$t('common.actions')" fixed="right" align="center"> <template #default="{ row, $index }"> <div class="action-buttons"> <el-button type="primary" size="small" @click="batchUpdateIndex($index, row)" v-if="basicCardObj[row.cardName]?.cardType !== 2" > {{ $t('config.modifyCardOrder') }} </el-button> <el-button size="small" type="danger" @click="handleDelete($index, row)" >{{ $t('common.delete') }} </el-button> </div> </template> </el-table-column> </el-table> <div> <el-pagination size="default" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" layout="total, prev, pager, next,sizes, jumper" :total="total" > </el-pagination> </div> <AddCardConfig :dialogVisible="dialogVisible" :title="dialogTitle" :form-data="form" :host-app-options="hostAppOptions" :card-position-options="cardPositionOptions" :device-type-options="deviceTypeOptions" :card-options="cardAddOptions" :card-obj="basicCardObj" :is-edit="currentIndex !== -1" :cancel="handleCancel" v-if="dialogVisible" :cardTitleMap="cardTitleMap" :getHostAppLabel="getHostAppLabel" :getCardPositionLabel="getCardPositionLabel" /> <!-- JSON查看对话框 --> <JsonViewerDialog :jsonViewerVisible="jsonViewerVisible" :jsonViewerTitle="jsonViewerTitle" :formattedJson="formattedJson" :close="closeShowJson" /> <EditCardIndex :config="rowData" :dialogVisible="batchUpdateIndexDialogVisible" v-if="batchUpdateIndexDialogVisible" :cancel="cancel" :cardTitleMap="cardTitleMap" :getHostAppLabel="getHostAppLabel" :getCardPositionLabel="getCardPositionLabel" /> <BatchSetRule :dialogVisible="batchRuleSetDialogVisible" :cancel="cancel" :cardOptions="cardAddOptions" :cardTitleMap="cardTitleMap" :ruleDtoList="ruleDtoList" /> <EditCardVersionCrowdTesting :visible="showDialog" v-model:visible="showDialog" :testRowData="testRowData" :getHostAppLabel="getHostAppLabel" :getCardPositionLabel="getCardPositionLabel" /> </div> </template> <script setup> import { useGlobalMaps } from '@/utils/util.ts' const { maps, initGlobalMaps } = useGlobalMaps() const getHostAppLabel = (app) => maps.value.hostAppMap[app] || app const getCardPositionLabel = (app) => maps.value.cardPositionMap[app] || app </script> <script> import { ElMessage, ElMessageBox } from 'element-plus' import enumInfo from '@/constants/EnumInfo.ts' import { requestHandler } from '@/utils/request' import axios from 'axios' import EditCardVersionCrowdTesting from './components/EditCardVersionCrowdTesting.vue' import AddCardConfig from './components/AddCardConfig.vue' import EditCardIndex from './components/EditCardIndex.vue' import BatchSetRule from './components/BatchSetRule.vue' import JsonViewerDialog from '@/components/JsonViewerDialog.vue' import { initGlobalMaps, useGlobalMaps } from '@/utils/util.ts'; import { useStore } from '@/store' import { getCardOptions } from '@/service' const store = useStore(); export default { components: { EditCardVersionCrowdTesting, EditCardIndex, AddCardConfig, BatchSetRule, JsonViewerDialog }, data() { return { loading: false, dialogVisible: false, batchRuleSetDialogVisible: false, batchUpdateIndexDialogVisible: false, rowData: {}, dialogTitle: this.$t('config.addOperationConfig'), currentIndex: -1, tableData: [], versionTablesData: {}, // Changed from versionTables to store version data by card ID cardOptions: [], cardAddOptions: [], defaultExpandedRows: [], basicCardObj: {}, currentPage: 1, pageSize: 10, total: 0, basicCardObject: {}, jsonViewerVisible: false, jsonViewerTitle: '', formattedJson: '', filter: { hostApp: '', cardPosition: '', deviceType: '', cardName: '', publishStatus: '' }, form: { hostApp: '', cardPosition: '', deviceType: 'phone', cardName: '', index: 1 }, versionLoading: false, versionCurrentPage: 1, versionPageSize: 10, versionTotal: 0, tagVisible: false, showDialog: false, tagContent: '', testRowData: {}, basic: { cardName: '', provider: '', dimension: '', disable: null }, isAllExpanded: false, cardTitleMap: new Map(), ruleDtoList: [] } }, computed: { hostAppOptions() { return [...new Set(this.cardOptions.map((item) => item.hostApp))] }, cardPositionOptions() { return [...new Set(this.cardOptions.map((item) => item.cardPosition))] }, deviceTypeOptions() { return enumInfo.deviceType() } }, async mounted() { await initGlobalMaps() this.queryCardOptions() this.fetchCardList() this.cardAddOptions = await getCardOptions() this.basicCardObj = this.cardAddOptions.reduce((map, obj) => { map[obj.cardName] = obj return map }, {}) const targetLang = store.language this.cardTitleMap = this.cardAddOptions.reduce((map, card) => { // 先设置一个作为兜底 map[card.cardName] = card.cardName if (card.cardMultiLang && card.cardMultiLang.length > 0) { // 将cardMultiLang数组转换为{cardName: cardTitle}的对象 for (const langItem of card.cardMultiLang) { if (langItem.language === targetLang) { map[card.cardName] = langItem.cardTitle || card.cardName } } } return map }, {}) }, methods: { fetchCardVersionConfig(cardConfigId, config) { if (!this.versionTablesData[cardConfigId]) { this.versionTablesData[cardConfigId] = { loading: false, tableData: [], currentPage: 1, pageSize: 10, total: 0 } } this.versionTablesData[cardConfigId].loading = true const queryData = { cardName: config.cardName, hostApp: config.hostApp, deviceType: config.deviceType, cardOpId: cardConfigId, pageNumber: this.versionTablesData[cardConfigId].currentPage || 1, pageSize: this.versionTablesData[cardConfigId].pageSize || 10, pageInfo: { pageSize: this.versionTablesData[cardConfigId].pageSize || 10, offset: this.versionTablesData[cardConfigId].currentPage || 1 } } axios .post('/v1/card/version-op/page-query', queryData) .then((response) => { if (response?.data?.code === 0) { this.versionTablesData[cardConfigId]['tableData'] = response.data.opList?.map((item) => ({ ...item, hostApp: config.hostApp, deviceType: config.deviceType, cardPosition: config.cardPosition })) || [] this.versionTablesData[cardConfigId]['total'] = response.data.count || 0 this.versionTablesData[cardConfigId]['config'] = config } else { ElMessage.error(response?.data?.message || this.$t('common.getListFailed')) } }) .finally(() => { this.versionTablesData[cardConfigId]['loading'] = false }) }, cancel() { this.batchUpdateIndexDialogVisible = false this.batchRuleSetDialogVisible = false }, deviceTypeFilter(input) { if (!input) return null const found = enumInfo.deviceType().find((ent) => ent.value === input) return found ? found.label : '' }, truncateText(text, maxLength = 6) { return text.length > maxLength ? `${text.slice(0, maxLength)}...` : text }, handleTagClick(tag) { this.tagContent = tag this.tagVisible = true }, actionsTo(cardConfigId, type, row) { if (type === 'beta' && !row.testRules) { ElMessage.error(this.$t('config.checkRules')) } else { let tempRow = JSON.parse(JSON.stringify(row)) this.testRowData = { action: type, hostApp: this.versionTablesData[cardConfigId].config.hostApp, cardName: this.versionTablesData[cardConfigId].config.cardName, cardVer: tempRow.cardVer, testRules: tempRow.testRules, cardOpId: cardConfigId, publishStatus: tempRow.publishStatus } this.showDialog = true } }, handleVersionSizeChange(cardConfigId, val) { this.versionTablesData[cardConfigId].pageSize = val this.versionTablesData[cardConfigId].currentPage = 1 this.versionPageSize = val this.fetchCardVersionConfig(cardConfigId, this.versionTablesData[cardConfigId].config) }, handleVersionCurrentChange(cardConfigId, val) { this.versionTablesData[cardConfigId].currentPage = val this.versionCurrentPage = val this.fetchCardVersionConfig(cardConfigId, this.versionTablesData[cardConfigId].config) }, toggleExpandAll() { this.isAllExpanded = !this.isAllExpanded this.tableData.forEach((row) => { this.$refs.tableRef.toggleRowExpansion(row, this.isAllExpanded) }) }, handleExpandChange(row, expandedRows) { if (expandedRows.includes(row) && !row.versionDataLoaded) { row.versionDataLoaded = true this.versionTablesData[row.id] = { ...this.versionTablesData[row.id], config: row } this.fetchCardVersionConfig(row.id, row) } }, betaOrStopOrFullPublish(type) { const ruleDtoList = [] Object.keys(this.versionTablesData).forEach((cardConfigId) => { const table = this.$refs[`versionTable_${cardConfigId}`] if (table && table.getSelectionRows) { ruleDtoList.push( ...table.getSelectionRows().map((item) => ({ cardOpId: cardConfigId, hostApp: item.hostApp, cardPosition: item.cardPosition, deviceType: item.deviceType, cardName: item.cardName, cardTitle: this.cardTitleMap[item.cardName] || item.cardName, cardVer: item.cardVer, status: item.publishStatus, testRules: item.testRules })) ) } }) if (ruleDtoList.length === 0) { ElMessage.error(this.$t('config.selectAtLeastOneRecord')) return } if (ruleDtoList.length > 20) { ElMessage.error(this.$t('config.selectMaxRecords')) return } // 众测发布 if (type === 'batchRuleSet') { const firstRecord = ruleDtoList[0] const inconsistentFields = [] if (ruleDtoList.some((item) => item.hostApp !== firstRecord.hostApp)) { inconsistentFields.push(this.$t('config.hostApp')) } if (ruleDtoList.some((item) => item.cardPosition !== firstRecord.cardPosition)) { inconsistentFields.push(this.$t('config.cardPosition')) } if (ruleDtoList.some((item) => item.deviceType !== firstRecord.deviceType)) { inconsistentFields.push(this.$t('config.deviceType')) } if (inconsistentFields.length > 0) { const fieldsText = inconsistentFields.join('、') ElMessage.error( this.$t('config.inconsistentFieldsError', { fields: fieldsText }) ) return } // 筛选既不是众测发布也不是待发布状态的条数 const invalidRecords = ruleDtoList.filter((item) => item.status !== 0 && item.status !== 1) if (invalidRecords.length) { // 提取不符合要求的卡片名和版本号 const invalidItems = invalidRecords .map((item) => `${item.cardTitle}(${item.cardVer})`) .join('、') ElMessage.error( this.$t('config.invalidRecordsBatchConfigCardRule', { count: invalidRecords.length, items: invalidItems, requiredStatus: `${this.$t('config.betaRelease')}${ store.isEnglish ? ' ' : '' }${this.$t('common.or')}${store.isEnglish ? ' ' : ''}${this.$t( 'config.pendingRelease' )}` }) ) return } this.batchRuleSetDialogVisible = true this.ruleDtoList = ruleDtoList return } if (type === 'stop') { // 获取状态为0(不符合要求)的记录 const invalidRecords = ruleDtoList.filter((item) => item.status === 0) if (invalidRecords.length) { // 提取不符合要求的卡片名和版本号 const invalidItems = invalidRecords .map((item) => `${item.cardTitle}(${item.cardVer})`) .join('、') ElMessage.error( this.$t('config.invalidRecordsForStop', { count: invalidRecords.length, items: invalidItems, requiredStatus: `${this.$t('config.betaRelease')}${ store.isEnglish ? ' ' : '' }${this.$t('common.or')}${store.isEnglish ? ' ' : ''}${this.$t( 'config.fullRelease' )}` }) ) return } } if (type === 'full') { // 获取状态不为1(不符合全量发布要求)的记录 const invalidRecords = ruleDtoList.filter((item) => item.status !== 1) if (invalidRecords.length) { // 提取不符合要求的卡片名和版本号 const invalidItems = invalidRecords .map((item) => `${item.cardTitle}(${item.cardVer})`) .join('、') ElMessage.error( this.$t('config.invalidRecordsForFullRelease', { count: invalidRecords.length, items: invalidItems, requiredStatus: this.$t('config.betaRelease') }) ) return } } let status if (type === 'beta') { status = 1 } else if (type === 'full') { status = 2 } else { status = 0 } requestHandler({ url: '/v1/card/version-op/batch-update', data: { ruleDtoList: ruleDtoList, status: status } }) }, resetFields() { Object.assign(this.filter, { hostApp: '', cardPosition: '', deviceType: '', cardName: '', publishStatus: '' }) this.handleFilter() }, getDeviceType(type) { if (type === '') { return null } const _deviceType = this.deviceTypeOptions.find((ent) => { return ent.value === type }) if (_deviceType) { return _deviceType.label } return '' }, fetchCardList() { this.tableData = [] this.loading = true const queryData = { hostApp: this.filter.hostApp || null, cardPosition: this.filter.cardPosition || null, deviceType: this.filter.deviceType || null, cardName: this.filter.cardName || null, publishStatus: this.filter.publishStatus, pageNumber: this.currentPage, pageSize: this.pageSize } axios .post('/v1/card/operation/page-query', queryData) .then((response) => { if (response && response.data && response.data.code === 0) { this.tableData = response.data.cardOpConfigs || [] this.total = response.data.count || 0 // 默认展开第一行(取第一行的row-key值) if (this.tableData.length > 0) { this.defaultExpandedRows = [this.tableData[0].id] this.fetchCardVersionConfig(this.tableData[0].id, this.tableData[0]) } } else { ElMessage.error(response.data.message || this.$t('common.getListFailed')) } }) .finally(() => { this.loading = false }) }, queryCardOptions() { const queryData = { pageNumber: 1, pageSize: 1000 } axios.post('/v1/card/operation/page-query', queryData).then((response) => { if (response && response.data && response.data.code === 0) { this.cardOptions = response.data.cardOpConfigs } }) }, showAddDialog() { this.dialogTitle = this.$t('config.addOperationConfig') this.dialogVisible = true this.currentIndex = -1 this.form = {} }, handleEdit(index, row) { this.dialogTitle = this.$t('config.editOperationConfig') Object.assign(this.form, row) this.currentIndex = index this.dialogVisible = true }, handleCancel() { this.dialogVisible = false }, batchUpdateIndex(index, row) { Object.assign(this.form, row) this.currentIndex = index this.batchUpdateIndexDialogVisible = true this.rowData = row }, handleDelete(index, row) { ElMessageBox.confirm(this.$t('common.confirmDelete'), this.$t('common.warning'), { confirmButtonText: this.$t('common.confirm'), cancelButtonText: this.$t('common.cancel'), type: 'warning' }).then(() => { requestHandler({ url: '/v1/card/operation/delete', data: { id: row.id } }) }) }, handleSizeChange(val) { this.pageSize = val this.currentPage = 1 this.fetchCardList() }, handleCurrentChange(val) { this.currentPage = val this.fetchCardList() }, handleFilter() { this.currentPage = 1 this.fetchCardList() this.isAllExpanded = false }, handleShowJson(jsonStr, title) { try { this.formattedJson = jsonStr this.jsonViewerTitle = title this.jsonViewerVisible = true } catch (e) { ElMessage.error(this.$t('common.jsonFormatError') + e) } }, closeShowJson() { this.jsonViewerVisible = false } } } </script> <style scoped> .operation-container { padding: 20px; background-color: #fff; border-radius: 6px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .filter-container { margin-bottom: 20px; display: flex; flex-wrap: wrap; gap: 10px; } .github-table { --el-table-border-color: #e1e4e8; --el-table-header-bg-color: #f6f8fa; --el-table-row-hover-bg-color: #f6f8fa; } .github-table :deep(.el-table__header th) { background-color: #f6f8fa; color: #24292e; font-weight: 600; } .github-table :deep(.el-table__body td) { padding: 12px 0; } .filter-container { padding: 20px; margin-bottom: 20px; border-radius: 4px; } .batch-toolbar { margin-bottom: 15px; display: flex; align-items: center; gap: 10px; } .batch-toolbar { margin-bottom: 15px; display: flex; align-items: center; gap: 12px; } /* 修改行的样式 */ :deep(.el-table .modified-row) { --el-table-tr-bg-color: rgba(var(--el-color-success-rgb), 0.08); } .expand-icon { vertical-align: middle; cursor: pointer; color: rgb(96, 98, 102); } /* 垂直排列容器 - 完全居中方案 */ .vertical-tags-container { display: grid; justify-items: center; /* 水平居中 */ gap: 6px; padding: 2px 0; width: 100%; } /* 自适应宽度标签 */ .content-fit-tag { width: max-content; /* 宽度严格包裹内容 */ margin: 0 auto !important; /* 双重居中保障 */ padding: 0 10px; display: block; /* 使margin:auto生效 */ } .version-container { padding: 20px; background-color: #fff; border-radius: 6px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .github-table { --el-table-border-color: #e1e4e8; --el-table-header-bg-color: #f6f8fa; --el-table-row-hover-bg-color: #f6f8fa; } .github-table :deep(.el-table__header th) { background-color: #f6f8fa; color: #24292e; font-weight: 600; } .github-table :deep(.el-table__body td) { padding: 12px 0; } /* 表格标签专用样式 */ .tag-cell { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-height: 32px; } .table-tag { max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; transition: all 0.2s; } .more-tag { background: var(--el-color-info-light-8); border: none; color: var(--el-color-info); } .hidden-tags-container { display: flex; flex-wrap: wrap; gap: 8px; max-height: 200px; overflow-y: auto; padding: 8px; } .tag-cell { display: flex; justify-content: center; /* 水平居中 */ align-items: center; /* 垂直居中 */ flex-wrap: wrap; /* 允许标签换行 */ gap: 4px; /* 标签间距 */ width: 100%; /* 确保占据全部宽度 */ } </style> 这个是我的CardConfig <template> <el-dialog v-model="visible" :title="title" width="60%" :before-close="resetForm"> <el-steps :active="activeStep" simple style="margin-bottom: 20px" v-if="!isEdit"> <el-step :title="title" /> <el-step :title="$t('config.crowdTestRules')" /> </el-steps> <!-- Step 1: Card Configuration --> <el-form v-show="activeStep === 0" ref="cardFormRef" :model="form" :rules="rules" label-width="150px" label-position="left" > <el-form-item :label="$t('config.hostApp')" prop="hostApp"> <el-select filterable v-model="form.hostApp" :placeholder="$t('config.selectHostApp')" style="width: 100%" allow-create :disabled="isEdit" > <el-option v-for="app in hostAppOptions" :key="app" :label="getHostAppLabel(app)" :value="app" /> </el-select> </el-form-item> <el-form-item :label="$t('config.cardPosition')" prop="cardPosition"> <el-select filterable v-model="form.cardPosition" :placeholder="$t('config.selectCardPosition')" style="width: 100%" :disabled="isEdit" allow-create > <el-option v-for="position in cardPositionOptions" :key="position" :label="getCardPositionLabel(position)" :value="position" /> </el-select> </el-form-item> <el-form-item :label="$t('management.cardName')" prop="cardName"> <el-select v-model="form.cardName" :placeholder="$t('common.selectCardName')" style="width: 100%" filterable :disabled="isEdit" @change="selectCard" popper-class="wider-select-popper" > <el-option v-for="item in cardOptions" :key="item.cardName" :label="`${cardTitleMap[item.cardName]}-${item.cardName}`" :value="item.cardName" style="width: 800px" /> </el-select> </el-form-item> <el-form-item :label="$t('config.deviceType')" prop="deviceType"> <el-select filterable v-model="form.deviceType" :placeholder="$t('config.selectDeviceType')" :disabled="isEdit" style="width: 100%" > <el-option v-for="item in deviceTypeOptions.filter( (item) => availableDeviceTypeOptions.indexOf(item.value) !== -1 )" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item :label="$t('config.sortIndex')" prop="index" v-if="form.cardType !== 2"> <el-input-number v-model="form.index" :min="1" :max="100" size="default" style="width: 100%" /> </el-form-item> </el-form> <!-- Step 2: Crowd Testing Rules --> <el-form v-show="activeStep === 1" v-if="!isEdit" ref="testRulesFormRef" :model="testRules" :rules="testRulesRules" label-width="150px" label-position="left" > <el-form-item :label="$t('version.cardVer')" prop="cardVer" required> <el-select v-model="testRules.cardVer" :placeholder="$t('version.cardVer')" style="width: 100%" filterable > <el-option v-for="version in cardVersionOptions" :key="version" :label="version" :value="version" /> </el-select> </el-form-item> <el-form-item :label="$t('config.configMethod')" prop="configMethod" required> <el-radio-group v-model="testRules.configMethod" @change="changeConfigMethod"> <el-radio value="template">{{ $t('config.useTemplate') }}</el-radio> <el-radio value="manual">{{ $t('config.manualSetup') }}</el-radio> </el-radio-group> </el-form-item> <el-form-item v-if="testRules.configMethod === 'template'" :label="$t('config.ruleTemplate')" prop="templateId" > <el-select v-model="testRules.templateId" :placeholder="$t('config.selectTemplate')" style="width: 100%" filterable @change="handleTemplateChange" > <el-option v-for="template in ruleTemplateOptions" :key="template.id" :label="template.ruleName" :value="template.id" /> </el-select> </el-form-item> <CardRules :action="'edit'" :formData="group" ref="cardRulesFormRef" @rules-changed="handleRulesChanged" /> </el-form> <template #footer> <el-button @click="resetForm()">{{ $t('common.cancel') }}</el-button> <el-button v-if="activeStep === 0" @click="submitForm" type="primary"> {{ $t('common.save') }} </el-button> <el-button v-if="activeStep > 0" @click="prevStep">{{ $t('common.prev') }}</el-button> <el-button v-if="activeStep < 1 && !isEdit" type="primary" @click="nextStep"> {{ $t('common.next') }} </el-button> <el-button v-if="activeStep === 1" @click="saveAndPublish(1)" type="primary"> {{ $t('common.saveAndBetaPublish') }} </el-button> </template> </el-dialog> </template> <script> import { ElMessage } from 'element-plus' import validator from '@/utils/ValidateUtil.ts' import { requestHandler } from '@/utils/request' import axios from 'axios' import CardRules from '../../testrule/components/CardRules.vue' import { useGlobalMaps } from '@/utils/util.ts' import { reactive } from 'vue' export default { setup() { const maps = reactive({ hostAppMap: {}, cardPositionMap: {}, providerMap: {} }) const getHostAppLabel = (app) => maps.hostAppMap[app] || app const getCardPositionLabel = (app) => maps.cardPositionMap[app] || app return { getHostAppLabel, getCardPositionLabel, maps } }, components: { CardRules }, props: { cancel: Function, dialogVisible: { type: Boolean, default: false }, title: { type: String, default: '' }, formData: Object, hostAppOptions: { type: Array, default: () => [] }, cardPositionOptions: { type: Array, default: () => [] }, deviceTypeOptions: { type: Array, default: () => [] }, cardOptions: { type: Array, default: () => [] }, isEdit: { type: Boolean, default: false }, getHostAppLabel: Function, getCardPositionLabel: Function, cardTitleMap: Object }, emits: ['update:visible', 'success'], computed: { visible: function () { return this.dialogVisible } }, data() { return { formRef: {}, testRulesFormRef: {}, activeStep: 0, form: { hostApp: this.formData.hostApp, cardPosition: this.formData.cardPosition, deviceType: this.formData.deviceType, cardName: this.formData.cardName, id: this.formData.id, cardType: 0, index: this.formData.index || 1 }, group: { testRules: [ { id: Date.now(), items: [ { op: 'equal', key: '', values: [] } ] } ] }, testRules: { cardVer: '', configMethod: 'template', templateId: '' }, rules: { hostApp: [ { required: true, message: this.$t('config.selectHostApp'), trigger: 'change' }, { pattern: validator.hostApp, message: this.$t('config.validHostApp'), trigger: ['blur', 'change', 'input'] } ], cardPosition: [ { required: true, message: this.$t('config.selectCardPosition'), trigger: 'change' }, { pattern: validator.cardPosition, message: this.$t('config.validPosition'), trigger: ['blur', 'change'] } ], deviceType: [ { required: true, message: this.$t('config.selectDeviceType'), trigger: 'change' } ], cardName: [ { required: true, message: this.$t('common.selectCardName'), trigger: 'change' } ], index: [ { required: true, message: this.$t('config.enterCardIndex'), trigger: 'blur' }, { pattern: validator.integer, message: this.$t('common.validNumber'), trigger: 'blur' }, { validator: (_, val) => val <= 2147483647, message: this.$t('common.validNumber') } ] }, testRulesRules: { cardVer: [{ required: true, message: this.$t('version.cardVer'), trigger: 'change' }], templateId: [ { required: true, message: this.$t('config.selectTemplate'), trigger: 'change', when: () => this.testRules.configMethod === 'template' } ] }, cardVersionOptions: [], availableDeviceTypeOptions: [], ruleTemplateOptions: [] } }, watch: { formData() { this.form = JSON.parse(JSON.stringify(this.formData)) }, isEdit() {}, 'form.cardName'(newVal) { if (newVal && this.activeStep === 1) { this.loadCardVersions() } } }, created() { this.initMaps() // 组件创建时初始化 }, methods: { selectCard() { // 设置卡片类型 const item = this.cardOptions.find((ent) => { return ent.cardName === this.form.cardName }) this.form.cardType = item.cardType // 查询版本 const queryData = { pageNumber: 1, pageSize: 1000, cardName: this.form.cardName } axios.post('/v2/card/version/page-query', queryData).then((response) => { if (response && response.data && response.data.code === 0) { this.availableDeviceTypeOptions = [ ...new Set(response.data.cardVersions.flatMap((item) => item.deviceTypes)) ] this.form.deviceType = null } }) }, // 新增处理规则变化的方法 handleRulesChanged(newRules) { this.group.testRules = newRules }, async nextStep() { try { await this.$refs.cardFormRef.validate() this.activeStep++ this.loadCardVersions() this.loadRuleTemplates() } catch (error) { console.error('Validation failed:', error) } }, prevStep() { this.activeStep-- }, handleTemplateChange(selectedId) { // 从 ruleTemplateOptions 中找到选中的 template const selectedTemplate = this.ruleTemplateOptions.find( (template) => template.id === selectedId ) if (selectedTemplate) { this.group = { testRules: selectedTemplate.testRules } } }, changeConfigMethod(configMethod) { if (configMethod === 'manual') { this.group = { testRules: [ { id: Date.now(), items: [ { op: 'equal', key: '', values: [] } ] } ] } } else { this.handleTemplateChange(this.testRules.templateId) } }, loadCardVersions() { const queryData = { pageNumber: 1, pageSize: 1000, cardName: this.form.cardName, deviceTypes: [this.form.deviceType] } axios.post('/v2/card/version/page-query', queryData).then((response) => { if (response && response.data && response.data.code === 0) { this.cardVersionOptions = [ ...new Set(response.data.cardVersions.map((item) => item.cardVer)) ] } }) }, loadRuleTemplates() { const queryData = { pageNumber: 1, pageSize: 1000, hostApp: this.form.hostApp } axios.post('/v1/card/test-rule/page-query', queryData).then((response) => { if (response && response.data && response.data.code === 0) { this.ruleTemplateOptions = response.data.testRuleDtos } }) }, async submitForm() { try { await Promise.all([this.$refs.cardFormRef.validate()]) const cardNameToIndex = {} const index = this.form.cardType === 2 ? 0 : this.form.index || 1 this.form.index = index cardNameToIndex[this.form.cardName] = index const requestData = { ...this.form, testRules: this.testRules, cardIndexMap: cardNameToIndex } const url = this.isEdit ? '/v1/card/operation/batch-update-index' : '/v1/card/operation/insert' await requestHandler({ url, data: requestData }) this.$emit('success') this.cancel() } catch (error) { // 处理后端返回的重复错误 (code 100001) if (error.response?.data.code === 100001) { ElMessage.error(this.$t('config.cardDuplicateIndexError')) return } if (error.message) { ElMessage.error(error.message || this.$t('common.operationFailed')) } } }, async saveAndPublish(status) { try { await Promise.all([ this.$refs.cardFormRef.validate(), this.$refs.testRulesFormRef.validate(), this.$refs.cardRulesFormRef.validate() ]) this.form.index = this.form.cardType === 2 ? 0 : this.form.index || 1 const requestData = { ...this.form, next: { cardName: this.form.cardName, cardVer: this.testRules.cardVer, status: status, testRules: this.group.testRules } } const url = '/v1/card/operation/insert' await requestHandler({ url, data: requestData }) this.$emit('success') this.cancel() } catch (error) { console.error('Submit failed:', error) } }, resetForm() { this.cancel() this.activeStep = 0 if (this.$refs.cardFormRef) { this.$refs.cardFormRef.resetFields() } if (this.$refs.testRulesFormRef) { this.$refs.testRulesFormRef.resetFields() } this.form = { hostApp: '', cardPosition: '', deviceType: 'phone', cardName: '', index: 1 } this.testRules = { cardVer: '', configMethod: 'template', templateId: '' } this.group = null }, async initMaps() { const { maps, initGlobalMaps } = useGlobalMaps() await initGlobalMaps() // 手动将 ref 值赋给 data(失去响应性,需注意) this.maps = maps.value } } } </script> <style scoped> /* 扩大 el-select 下拉框的宽度 */ .wider-select-popper .el-select-dropdown__list { min-width: 600px !important; width: 100% !important; max-width: 800px; } </style> 这个是我的addCardConfig 我怎么修改才能修改下拉框背景宽度?
11-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值