700 lines
22 KiB
Vue
700 lines
22 KiB
Vue
<template>
|
||
<div class="aps-quick-sheet excel-theme">
|
||
<div class="sheet-toolbar">
|
||
<div class="sheet-actions">
|
||
<el-button size="small" icon="el-icon-refresh" @click="loadRows">刷新</el-button>
|
||
<el-button size="small" type="primary" icon="el-icon-finished" :loading="saving" @click="saveAll">保存</el-button>
|
||
<el-button size="small" icon="el-icon-plus" @click="addRow">新增行</el-button>
|
||
<el-button size="small" icon="el-icon-download" @click="exportCsv">导出</el-button>
|
||
<el-button size="small" icon="el-icon-setting" @click="columnSettingVisible = true">列设置</el-button>
|
||
<el-date-picker
|
||
v-model="filter.range"
|
||
type="daterange"
|
||
range-separator="至"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
value-format="yyyy-MM-dd"
|
||
size="small"
|
||
style="width: 240px"
|
||
@change="onFilterChange"
|
||
/>
|
||
</div>
|
||
<div class="preset-bar">
|
||
<span class="preset-title">预设方案:</span>
|
||
<el-button
|
||
v-for="line in lineOptions"
|
||
:key="line.lineId"
|
||
size="mini"
|
||
plain
|
||
@click="applyPreset(line)"
|
||
>
|
||
{{ line.lineName || line.lineCode || ('产线' + line.lineId) }}
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sheet-body">
|
||
<el-table
|
||
ref="quickSheetTable"
|
||
v-loading="loading"
|
||
:data="displayRows"
|
||
border
|
||
size="mini"
|
||
class="excel-table"
|
||
>
|
||
<el-table-column label="序号" width="60" align="center" fixed="left">
|
||
<template slot-scope="scope">
|
||
{{ ((pager.pageNum - 1) * pager.pageSize) + scope.$index + 1 }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
v-for="(col, colIndex) in displayColumns"
|
||
:key="col.prop || col.label"
|
||
:label="col.label"
|
||
:prop="col.prop"
|
||
:width="col.width"
|
||
:min-width="col.minWidth"
|
||
:align="col.align || 'center'"
|
||
:fixed="fixedProps.includes(col.prop) ? 'left' : false"
|
||
:show-overflow-tooltip="col.showOverflowTooltip !== false"
|
||
>
|
||
<template slot-scope="scope">
|
||
<template v-if="isTimeField(col.prop)">
|
||
<el-date-picker
|
||
v-model="scope.row[col.prop]"
|
||
type="datetime"
|
||
value-format="yyyy-MM-dd HH:mm:ss"
|
||
size="mini"
|
||
style="width: 100%"
|
||
@change="onCellChange(scope.row)"
|
||
@input="onCellChange(scope.row)"
|
||
@keydown.native.enter.prevent="focusNextCell(scope.$index, colIndex, 'down')"
|
||
@keydown.native.tab.prevent="focusNextCell(scope.$index, colIndex, 'right')"
|
||
/>
|
||
</template>
|
||
<template v-else>
|
||
<el-autocomplete
|
||
v-if="col.prop === 'lineName'"
|
||
v-model="scope.row[col.prop]"
|
||
size="mini"
|
||
clearable
|
||
:fetch-suggestions="queryLineHistory"
|
||
@select="onLineHistorySelect(scope.row)"
|
||
@input="onLineHistoryInput(scope.row)"
|
||
@keydown.native.enter.prevent="focusNextCell(scope.$index, colIndex, 'down')"
|
||
@keydown.native.tab.prevent="focusNextCell(scope.$index, colIndex, 'right')"
|
||
/>
|
||
<el-input
|
||
v-else
|
||
v-model="scope.row[col.prop]"
|
||
size="mini"
|
||
clearable
|
||
@input="onCellChange(scope.row)"
|
||
@keydown.native.enter.prevent="focusNextCell(scope.$index, colIndex, 'down')"
|
||
@keydown.native.tab.prevent="focusNextCell(scope.$index, colIndex, 'right')"
|
||
/>
|
||
</template>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="70" fixed="right" align="center">
|
||
<template slot-scope="scope">
|
||
<el-button type="text" size="mini" @click="clearRow(scope.row)">清空</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="pager-wrap">
|
||
<el-pagination
|
||
small
|
||
background
|
||
layout="prev, pager, next, total"
|
||
:current-page.sync="pager.pageNum"
|
||
:page-size="pager.pageSize"
|
||
:total="totalRows"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div v-if="missingRows.length" class="missing-tip">
|
||
<div v-for="msg in missingRows" :key="msg" class="missing-item">{{ msg }}</div>
|
||
</div>
|
||
<el-drawer
|
||
title="列设置"
|
||
:visible.sync="columnSettingVisible"
|
||
direction="rtl"
|
||
size="55%"
|
||
append-to-body
|
||
@open="resetColumnDraft">
|
||
<div class="col-setting-body">
|
||
<div class="col-setting-toolbar">
|
||
<el-button size="mini" @click="restoreDefaultColumns">恢复默认</el-button>
|
||
<el-button size="mini" @click="resetColumnDraft">重置</el-button>
|
||
<el-button size="mini" type="primary" @click="saveColumnSettings">保存</el-button>
|
||
</div>
|
||
|
||
<div class="col-section">
|
||
<div class="col-section-title">固定列(最多5列)</div>
|
||
<draggable v-model="fixedColumnList" handle=".drag-handle" animation="200" class="col-setting-grid">
|
||
<div v-for="item in fixedColumnList" :key="`fixed-${item.prop}`" class="col-setting-item">
|
||
<i class="el-icon-rank drag-handle" />
|
||
<span class="col-label">{{ item.label }}</span>
|
||
<el-button type="text" size="mini" @click="removeFromFixed(item.prop)">移除</el-button>
|
||
</div>
|
||
</draggable>
|
||
</div>
|
||
|
||
<div class="col-section">
|
||
<div class="col-section-title">其他列</div>
|
||
<draggable v-model="normalColumnList" handle=".drag-handle" animation="200" class="col-setting-grid">
|
||
<div v-for="item in normalColumnList" :key="`normal-${item.prop}`" class="col-setting-item">
|
||
<i class="el-icon-rank drag-handle" />
|
||
<span class="col-label">{{ item.label }}</span>
|
||
<el-button type="text" size="mini" @click="addToFixed(item.prop)">加入固定</el-button>
|
||
</div>
|
||
</draggable>
|
||
</div>
|
||
</div>
|
||
</el-drawer>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { fetchQuickSheetList, fetchQuickSheetPreset, saveQuickSheet, exportQuickSheet, deleteQuickSheetRow } from '@/api/aps/quickSheet'
|
||
import { listProductionLine } from '@/api/wms/productionLine'
|
||
import { getTemplateByKey } from './sheets/templates'
|
||
import { saveAs } from 'file-saver'
|
||
import draggable from 'vuedraggable'
|
||
|
||
export default {
|
||
name: 'ApsQuickSheet',
|
||
components: { draggable },
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
saving: false,
|
||
rows: [],
|
||
lineOptions: [],
|
||
lineHistory: [],
|
||
dirtyIds: new Set(),
|
||
autoSaveTimer: null,
|
||
templateKey: 'unified',
|
||
filter: {
|
||
range: []
|
||
},
|
||
pager: {
|
||
pageNum: 1,
|
||
pageSize: 25
|
||
},
|
||
columnSettingVisible: false,
|
||
columnSettingList: [],
|
||
fixedColumnList: [],
|
||
normalColumnList: []
|
||
}
|
||
},
|
||
computed: {
|
||
currentTemplate() {
|
||
return getTemplateByKey(this.templateKey)
|
||
},
|
||
flatColumns() {
|
||
const res = []
|
||
const loop = (cols) => {
|
||
;(cols || []).forEach(c => {
|
||
if (c.children && c.children.length) loop(c.children)
|
||
else res.push(c)
|
||
})
|
||
}
|
||
loop(this.currentTemplate.columns || [])
|
||
return res.filter(c => c && c.prop)
|
||
},
|
||
displayColumns() {
|
||
const setting = this.columnSettingList || []
|
||
const hasSetting = setting.length > 0
|
||
const base = this.flatColumns
|
||
|
||
const selected = hasSetting
|
||
? setting.filter(i => i.visible).map(i => base.find(c => c.prop === i.prop)).filter(Boolean)
|
||
: base
|
||
|
||
const selectedSet = new Set(selected.map(c => c.prop))
|
||
const rest = base.filter(c => !selectedSet.has(c.prop))
|
||
return [...selected, ...rest]
|
||
},
|
||
fixedProps() {
|
||
return (this.columnSettingList || []).filter(i => i.visible && i.fixed).map(i => i.prop).slice(0, 5)
|
||
},
|
||
displayRows() {
|
||
const [startAfter, endBefore] = this.filter.range || []
|
||
const filtered = this.rows.filter(r => {
|
||
if (!r.startTime) return true
|
||
const d = String(r.startTime).slice(0, 10)
|
||
if (startAfter && d < startAfter) return false
|
||
if (endBefore && d > endBefore) return false
|
||
return true
|
||
})
|
||
const start = (this.pager.pageNum - 1) * this.pager.pageSize
|
||
const page = filtered.slice(start, start + this.pager.pageSize)
|
||
if (page.length < this.pager.pageSize) {
|
||
return page.concat(this.buildEmptyRows(this.pager.pageSize - page.length))
|
||
}
|
||
return page
|
||
},
|
||
totalRows() {
|
||
const [startAfter, endBefore] = this.filter.range || []
|
||
return this.rows.filter(r => {
|
||
if (!r.startTime) return true
|
||
const d = String(r.startTime).slice(0, 10)
|
||
if (startAfter && d < startAfter) return false
|
||
if (endBefore && d > endBefore) return false
|
||
return true
|
||
}).length
|
||
},
|
||
missingRows() {
|
||
return this.collectMissing(this.displayRows)
|
||
}
|
||
},
|
||
created() {
|
||
const today = new Date()
|
||
const start = `${today.getFullYear()}-${`${today.getMonth() + 1}`.padStart(2, '0')}-${`${today.getDate()}`.padStart(2, '0')}`
|
||
this.filter.range = [start, '']
|
||
this.initColumnSettings()
|
||
this.loadRows()
|
||
this.loadLines()
|
||
window.addEventListener('keydown', this.handleGlobalKeydown)
|
||
},
|
||
beforeDestroy() {
|
||
if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
|
||
this.persistColumnSettings()
|
||
window.removeEventListener('keydown', this.handleGlobalKeydown)
|
||
},
|
||
methods: {
|
||
handleGlobalKeydown(e) {
|
||
const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.userAgent)
|
||
const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey
|
||
if (ctrlOrCmd && (e.key === 's' || e.key === 'S')) {
|
||
e.preventDefault()
|
||
this.saveAll(false)
|
||
}
|
||
},
|
||
focusNextCell(visibleRowIndex, colIndex, direction) {
|
||
const pageStart = (this.pager.pageNum - 1) * this.pager.pageSize
|
||
const targetRow = direction === 'down' ? visibleRowIndex + 1 : visibleRowIndex
|
||
const targetCol = direction === 'right' ? colIndex + 1 : colIndex
|
||
if (targetCol >= this.displayColumns.length) return
|
||
|
||
const globalRowIndex = pageStart + targetRow
|
||
if (globalRowIndex >= this.rows.length) {
|
||
this.rows.push(this.buildEmptyRow())
|
||
}
|
||
|
||
this.$nextTick(() => {
|
||
const wrappers = this.$el.querySelectorAll('.excel-table .el-table__body-wrapper tbody tr')
|
||
const tr = wrappers[targetRow]
|
||
if (!tr) return
|
||
const tds = tr.querySelectorAll('td')
|
||
const td = tds[targetCol + 1]
|
||
if (!td) return
|
||
const input = td.querySelector('input, textarea, .el-input__inner')
|
||
if (input) input.focus()
|
||
})
|
||
},
|
||
async loadLines() {
|
||
const res = await listProductionLine({ pageNum: 1, pageSize: 1000 })
|
||
this.lineOptions = res.rows || []
|
||
},
|
||
async loadRows() {
|
||
this.loading = true
|
||
try {
|
||
const res = await fetchQuickSheetList()
|
||
this.rows = (res.data || []).map(r => this.normalizeRow(r))
|
||
this.lineHistory = this.rows
|
||
.map(r => r.lineName)
|
||
.filter(v => v && v.trim())
|
||
.filter((v, i, arr) => arr.indexOf(v) === i)
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
buildEmptyRows(count) {
|
||
return Array.from({ length: count }).map(() => this.buildEmptyRow())
|
||
},
|
||
async applyPreset(line) {
|
||
if (!line || !line.lineId) return
|
||
const res = await fetchQuickSheetPreset({ lineId: line.lineId })
|
||
const preset = res.data || []
|
||
if (!preset.length) return
|
||
const targetRow = this.rows.find(r => !r.lineId && !r.lineName) || this.buildEmptyRow()
|
||
const base = this.normalizeRow(preset[0])
|
||
Object.keys(base).forEach(k => {
|
||
if (k === 'quickSheetId') return
|
||
targetRow[k] = base[k]
|
||
})
|
||
targetRow.lineId = line.lineId
|
||
targetRow.lineName = line.lineName || line.lineCode || ''
|
||
if (!this.rows.includes(targetRow)) {
|
||
this.rows.push(targetRow)
|
||
}
|
||
if (this.rows.length < 25) {
|
||
this.rows = this.rows.concat(this.buildEmptyRows(25 - this.rows.length))
|
||
}
|
||
this.markDirty(targetRow)
|
||
this.scheduleAutoSave()
|
||
},
|
||
onCellChange(row) {
|
||
if (row && !this.rows.includes(row)) {
|
||
this.rows.push(row)
|
||
}
|
||
this.markDirty(row)
|
||
this.scheduleAutoSave()
|
||
},
|
||
queryLineHistory(query, cb) {
|
||
const list = this.lineHistory || []
|
||
const q = (query || '').trim().toLowerCase()
|
||
const res = list
|
||
.filter(item => !q || String(item).toLowerCase().includes(q))
|
||
.map(item => ({ value: item }))
|
||
cb(res)
|
||
},
|
||
onLineHistoryInput(row) {
|
||
if (!row) return
|
||
if (row.lineId && row.lineName && row.lineName.trim() !== String(row.lineName).trim()) {
|
||
row.lineId = null
|
||
}
|
||
this.onCellChange(row)
|
||
},
|
||
onLineHistorySelect(row) {
|
||
return () => {
|
||
this.onCellChange(row)
|
||
}
|
||
},
|
||
onFilterChange() {
|
||
this.pager.pageNum = 1
|
||
},
|
||
normalizeRow(row) {
|
||
const base = this.buildEmptyRow()
|
||
Object.keys(base).forEach(k => {
|
||
if (row && row[k] !== undefined && row[k] !== null) base[k] = row[k]
|
||
})
|
||
const idVal = row ? (row.quickSheetId !== undefined && row.quickSheetId !== null ? row.quickSheetId : row.id) : null
|
||
base.quickSheetId = idVal != null ? idVal : null
|
||
return base
|
||
},
|
||
buildEmptyRow() {
|
||
const row = { quickSheetId: null }
|
||
this.flatColumns.forEach(col => {
|
||
if (!col.prop) return
|
||
row[col.prop] = ''
|
||
})
|
||
return row
|
||
},
|
||
isRowEmpty(row) {
|
||
if (!row) return true
|
||
return !this.flatColumns.some(col => col.prop && row[col.prop])
|
||
},
|
||
isTimeField(prop) {
|
||
return prop === 'startTime' || prop === 'endTime'
|
||
},
|
||
isLeadingColumn(col) {
|
||
if (!col || !col.prop) return false
|
||
return this.leadingPropsByRole.includes(col.prop)
|
||
},
|
||
initColumnSettings() {
|
||
const key = this.getColumnSettingKey()
|
||
const stored = localStorage.getItem(key)
|
||
const base = this.flatColumns.map((col, idx) => ({ prop: col.prop, label: col.label, visible: true, fixed: idx < 5 }))
|
||
if (!stored) {
|
||
this.columnSettingList = base
|
||
this.resetColumnDraft()
|
||
return
|
||
}
|
||
try {
|
||
const parsed = JSON.parse(stored)
|
||
if (!Array.isArray(parsed)) {
|
||
this.columnSettingList = base
|
||
this.resetColumnDraft()
|
||
return
|
||
}
|
||
const savedProps = parsed.map(i => i.prop)
|
||
const extras = base.filter(i => !savedProps.includes(i.prop))
|
||
this.columnSettingList = [...parsed.filter(i => base.some(b => b.prop === i.prop)).map(i => {
|
||
const match = base.find(b => b.prop === i.prop)
|
||
return { ...match, visible: i.visible !== false, fixed: i.fixed === true }
|
||
}), ...extras]
|
||
this.resetColumnDraft()
|
||
} catch (e) {
|
||
this.columnSettingList = base
|
||
this.resetColumnDraft()
|
||
}
|
||
},
|
||
resetColumnDraft() {
|
||
const fixed = (this.columnSettingList || []).filter(i => i.visible && i.fixed).slice(0, 5)
|
||
const normal = (this.columnSettingList || []).filter(i => !i.fixed || !i.visible)
|
||
this.fixedColumnList = fixed.map(i => ({ ...i, visible: true, fixed: true }))
|
||
this.normalColumnList = normal.map(i => ({ ...i, fixed: false }))
|
||
},
|
||
saveColumnSettings() {
|
||
const fixed = (this.fixedColumnList || []).map(i => ({ ...i, visible: true, fixed: true }))
|
||
const normal = (this.normalColumnList || []).map(i => ({ ...i, fixed: false }))
|
||
this.columnSettingList = [...fixed, ...normal]
|
||
this.persistColumnSettings()
|
||
this.columnSettingVisible = false
|
||
this.pager.pageNum = 1
|
||
this.loadRows().finally(() => {
|
||
this.$nextTick(() => {
|
||
this.$refs.quickSheetTable && this.$refs.quickSheetTable.doLayout && this.$refs.quickSheetTable.doLayout()
|
||
})
|
||
})
|
||
},
|
||
addToFixed(prop) {
|
||
if ((this.fixedColumnList || []).length >= 5) {
|
||
this.$message.warning('固定列最多5列')
|
||
return
|
||
}
|
||
const idx = this.normalColumnList.findIndex(i => i.prop === prop)
|
||
if (idx < 0) return
|
||
const item = this.normalColumnList.splice(idx, 1)[0]
|
||
this.fixedColumnList.push({ ...item, visible: true, fixed: true })
|
||
},
|
||
removeFromFixed(prop) {
|
||
const idx = this.fixedColumnList.findIndex(i => i.prop === prop)
|
||
if (idx < 0) return
|
||
const item = this.fixedColumnList.splice(idx, 1)[0]
|
||
this.normalColumnList.unshift({ ...item, fixed: false })
|
||
},
|
||
persistColumnSettings() {
|
||
const key = this.getColumnSettingKey()
|
||
const payload = (this.columnSettingList || []).map(item => ({
|
||
prop: item.prop,
|
||
label: item.label,
|
||
visible: item.visible !== false,
|
||
fixed: item.fixed === true
|
||
}))
|
||
localStorage.setItem(key, JSON.stringify(payload))
|
||
},
|
||
restoreDefaultColumns() {
|
||
const base = this.flatColumns.map((col, idx) => ({ prop: col.prop, label: col.label, visible: true, fixed: idx < 5 }))
|
||
this.columnSettingList = base
|
||
this.resetColumnDraft()
|
||
},
|
||
getColumnSettingKey() {
|
||
return `apsQuickSheetColumns_${this.templateKey}`
|
||
},
|
||
markDirty(row) {
|
||
if (!row) return
|
||
if (!row._tmpId) row._tmpId = Math.random().toString(36).slice(2)
|
||
this.dirtyIds.add(row._tmpId)
|
||
},
|
||
async clearRow(row) {
|
||
if (!row) return
|
||
if (!row.quickSheetId) {
|
||
this.flatColumns.forEach(col => {
|
||
if (!col.prop) return
|
||
row[col.prop] = ''
|
||
})
|
||
row.quickSheetId = null
|
||
return
|
||
}
|
||
await deleteQuickSheetRow(row.quickSheetId)
|
||
this.flatColumns.forEach(col => {
|
||
if (!col.prop) return
|
||
row[col.prop] = ''
|
||
})
|
||
row.quickSheetId = null
|
||
},
|
||
scheduleAutoSave() {
|
||
if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
|
||
this.autoSaveTimer = setTimeout(() => {
|
||
this.saveAll(true)
|
||
}, 800)
|
||
},
|
||
async saveAll(isAuto = false, payload) {
|
||
const rows = payload && payload.rows
|
||
? payload.rows
|
||
: this.rows.filter(r => r && r._tmpId && this.dirtyIds.has(r._tmpId))
|
||
.map(r => ({
|
||
...r,
|
||
quickSheetId: r.quickSheetId || null
|
||
}))
|
||
if (!rows.length) {
|
||
if (!isAuto) this.$message.warning('暂无可保存数据')
|
||
return
|
||
}
|
||
const missing = this.collectMissing(rows)
|
||
if (missing.length && !isAuto) {
|
||
this.$message.warning(`必填项未填写:${missing.join(';')}`)
|
||
return
|
||
}
|
||
this.saving = true
|
||
try {
|
||
await saveQuickSheet({ rows })
|
||
if (!isAuto) this.$message.success('保存成功')
|
||
rows.forEach(r => {
|
||
if (r._tmpId) this.dirtyIds.delete(r._tmpId)
|
||
})
|
||
} finally {
|
||
this.saving = false
|
||
}
|
||
},
|
||
exportCsv() {
|
||
this.loading = true
|
||
exportQuickSheet()
|
||
.then(blob => {
|
||
const filename = `quick_sheet_${new Date().getTime()}.xlsx`
|
||
saveAs(new Blob([blob], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), filename)
|
||
})
|
||
.finally(() => {
|
||
this.loading = false
|
||
})
|
||
},
|
||
addRow() {
|
||
this.rows.unshift(this.buildEmptyRow())
|
||
this.pager.pageNum = 1
|
||
},
|
||
collectMissing(rows) {
|
||
const msgs = []
|
||
rows.forEach((row, idx) => {
|
||
if (this.isRowEmpty(row)) return
|
||
const line = idx + 1
|
||
const missing = []
|
||
if (!row.lineName && !row.lineId) missing.push('产线')
|
||
if (!row.planCode) missing.push('计划号')
|
||
if (!row.startTime) missing.push('开始时间')
|
||
if (!row.endTime) missing.push('结束时间')
|
||
if (missing.length) {
|
||
msgs.push(`第${line}行缺少${missing.join('、')}`)
|
||
}
|
||
})
|
||
return msgs
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.aps-quick-sheet {
|
||
padding: 8px;
|
||
background: #f7f9fc;
|
||
}
|
||
|
||
.sheet-toolbar,
|
||
.sheet-body {
|
||
border: 1px solid #eef2f7;
|
||
border-radius: 8px;
|
||
background: #fff;
|
||
}
|
||
|
||
.sheet-toolbar {
|
||
margin-bottom: 8px;
|
||
padding: 8px 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
}
|
||
|
||
.sheet-actions { display: flex; gap: 8px; }
|
||
|
||
.preset-bar { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #667085; }
|
||
.preset-title { font-weight: 600; color: #475467; }
|
||
|
||
::v-deep .excel-table {
|
||
border: 1px solid #edf1f7;
|
||
}
|
||
::v-deep .excel-table th.el-table__cell {
|
||
background: #fafbfe;
|
||
color: #5d6b82;
|
||
font-weight: 600;
|
||
border-right: 1px solid #edf1f7;
|
||
border-bottom: 1px solid #edf1f7;
|
||
padding: 4px 0;
|
||
}
|
||
::v-deep .excel-table td.el-table__cell {
|
||
border-right: 1px solid #f0f2f6;
|
||
border-bottom: 1px solid #f0f2f6;
|
||
padding: 1px 2px;
|
||
}
|
||
::v-deep .excel-table .el-table__row:hover > td {
|
||
background-color: #f7faff !important;
|
||
}
|
||
|
||
::v-deep .el-input__inner {
|
||
border-radius: 0;
|
||
height: 26px;
|
||
line-height: 26px;
|
||
border: none;
|
||
box-shadow: none;
|
||
background: transparent;
|
||
}
|
||
|
||
::v-deep .el-input__inner:focus {
|
||
border: none;
|
||
box-shadow: inset 0 0 0 1px #4a90e2;
|
||
background: #fff;
|
||
}
|
||
|
||
.missing-tip {
|
||
margin-top: 8px;
|
||
padding: 8px 12px;
|
||
background: #fff7e6;
|
||
border: 1px solid #ffd591;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
color: #d46b08;
|
||
}
|
||
|
||
.missing-item {
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.col-setting-body {
|
||
padding: 12px;
|
||
height: calc(100% - 12px);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.col-setting-toolbar {
|
||
margin-bottom: 10px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.col-section {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.col-section-title {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.col-setting-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 8px;
|
||
}
|
||
|
||
.col-setting-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 8px 10px;
|
||
border: 1px solid #ebeef5;
|
||
border-radius: 6px;
|
||
background: #fff;
|
||
margin-bottom: 0;
|
||
min-height: 38px;
|
||
}
|
||
|
||
.col-setting-item:hover {
|
||
border-color: #d9ecff;
|
||
background: #f5faff;
|
||
}
|
||
|
||
.drag-handle {
|
||
cursor: move;
|
||
color: #909399;
|
||
}
|
||
|
||
</style>
|