|
|
@@ -73,7 +73,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, onMounted, computed, nextTick, watch } from 'vue'
|
|
|
+import { ref, computed, watch } from 'vue'
|
|
|
import GC from './tools/gc'
|
|
|
import dayjs from 'dayjs'
|
|
|
import '@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css'
|
|
|
@@ -114,8 +114,6 @@ GC.Spread.Sheets.Designer.LicenseKey = designerKey
|
|
|
GC.Spread.Sheets.LicenseKey = licenseKey
|
|
|
|
|
|
const designer = ref(null)
|
|
|
-const spread = ref(null)
|
|
|
-const designerRef = ref(null)
|
|
|
const navTitle = ref('通用编辑器')
|
|
|
const navButtons = ref([])
|
|
|
const floatingInputVisible = ref(false)
|
|
|
@@ -196,6 +194,7 @@ function getSheetBindingPathData(sheet, dataSource) {
|
|
|
const boundFields = new Set()
|
|
|
const tableMap = new Map()
|
|
|
|
|
|
+ // 扫描模板文件中的数据填充槽标识(键)
|
|
|
for (let row = 0; row < sheet.getRowCount(); row++) {
|
|
|
for (let col = 0; col < sheet.getColumnCount(); col++) {
|
|
|
const bindingPath = sheet.getBindingPath(row, col)
|
|
|
@@ -205,6 +204,7 @@ function getSheetBindingPathData(sheet, dataSource) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 扫描模板文件中所有子表及其对应的数据填充槽标识
|
|
|
const tables = sheet.tables.all() || []
|
|
|
if (tables.length > 0) {
|
|
|
tables.forEach(function (table) {
|
|
|
@@ -225,9 +225,11 @@ function getSheetBindingPathData(sheet, dataSource) {
|
|
|
const boundFieldsArray = [...boundFields].filter(Boolean)
|
|
|
if (boundFieldsArray.length === 0) return {}
|
|
|
|
|
|
+ // 根据模板文件数据值槽的需要,过滤数据值容器的数据(而且是按整个数据结构层次的过滤)
|
|
|
function recombineDataSource(dataSourceObj, prekey, boundFieldsArray) {
|
|
|
const filterResult = {}
|
|
|
for (const key in dataSourceObj) {
|
|
|
+ // 如果key对应属性值是对象,那么按需向下层处理
|
|
|
if (is(dataSourceObj[key], 'Object')) {
|
|
|
const nextKey = !prekey ? key : `${prekey}.${key}`
|
|
|
if (boundFieldsArray.findIndex((field) => field.indexOf(nextKey) >= 0) >= 0) {
|
|
|
@@ -236,6 +238,8 @@ function getSheetBindingPathData(sheet, dataSource) {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
+ // 如果key对应属性值是对象数组,那么对sheet中的子表数据填充槽进行处理
|
|
|
+ // 也就是说,数组处理上,基本数据值类型一般就是一个单元格的填充,但是对象类型说明是一张子表填充
|
|
|
if (is(dataSourceObj[key], 'Array') && dataSourceObj[key].every((x) => is(x, 'Object'))) {
|
|
|
if (boundFieldsArray.includes(key)) {
|
|
|
filterResult[key] = Object.entries(dataSourceObj[key]).map(([i, item]) => {
|
|
|
@@ -260,30 +264,32 @@ function getSheetBindingPathData(sheet, dataSource) {
|
|
|
return newDataSource
|
|
|
}
|
|
|
|
|
|
+// 生成属性键,并填充对应默认值
|
|
|
function generateDefaultData(schema) {
|
|
|
const result = {}
|
|
|
for (const key in schema.properties) {
|
|
|
- result[key] = generatePropertyValue(schema.properties[key])
|
|
|
+ result[key] = generatePropertyDefaultValue(schema.properties[key])
|
|
|
}
|
|
|
return result
|
|
|
}
|
|
|
|
|
|
-function generatePropertyValue(property) {
|
|
|
+// 为属性填充默认值
|
|
|
+function generatePropertyDefaultValue(property) {
|
|
|
if (property.type === 'array' && property.items) {
|
|
|
- if (property.items.type === 'object' && property.items.properties) {
|
|
|
- const itemValue = {}
|
|
|
- for (const itemKey in property.items.properties) {
|
|
|
- itemValue[itemKey] = generatePropertyValue(property.items.properties[itemKey])
|
|
|
- }
|
|
|
- return [itemValue]
|
|
|
+ if (property.items.type !== 'object' || !property.items.properties) {
|
|
|
+ return ['']
|
|
|
+ }
|
|
|
+ const itemValue = {}
|
|
|
+ for (const itemKey in property.items.properties) {
|
|
|
+ itemValue[itemKey] = generatePropertyDefaultValue(property.items.properties[itemKey])
|
|
|
}
|
|
|
- return ['']
|
|
|
+ return [itemValue]
|
|
|
}
|
|
|
|
|
|
if (property.properties) {
|
|
|
const objValue = {}
|
|
|
for (const objKey in property.properties) {
|
|
|
- objValue[objKey] = generatePropertyValue(property.properties[objKey])
|
|
|
+ objValue[objKey] = generatePropertyDefaultValue(property.properties[objKey])
|
|
|
}
|
|
|
return objValue
|
|
|
}
|
|
|
@@ -291,6 +297,11 @@ function generatePropertyValue(property) {
|
|
|
return ''
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 为属性填充非默认数据值
|
|
|
+ * @param target 属性值为默认值的键值数据容器
|
|
|
+ * @param source 填充数据到键值容器的数据源头
|
|
|
+ */
|
|
|
function deepMergeSchemaValue(target, source) {
|
|
|
const result = { ...target }
|
|
|
|
|
|
@@ -304,22 +315,17 @@ function deepMergeSchemaValue(target, source) {
|
|
|
}
|
|
|
|
|
|
if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
|
|
|
- if (sourceValue.length > 0) {
|
|
|
- result[key] = sourceValue
|
|
|
- } else {
|
|
|
- result[key] = targetValue
|
|
|
- }
|
|
|
+ result[key] = sourceValue.length > 0 ? sourceValue : targetValue
|
|
|
} else if (
|
|
|
typeof targetValue === 'object' &&
|
|
|
targetValue !== null &&
|
|
|
typeof sourceValue === 'object' &&
|
|
|
sourceValue !== null
|
|
|
) {
|
|
|
- if (Object.keys(sourceValue).length === 0) {
|
|
|
- result[key] = targetValue
|
|
|
- } else {
|
|
|
- result[key] = deepMergeSchemaValue(targetValue, sourceValue)
|
|
|
- }
|
|
|
+ result[key] =
|
|
|
+ Object.keys(sourceValue).length === 0
|
|
|
+ ? targetValue
|
|
|
+ : deepMergeSchemaValue(targetValue, sourceValue)
|
|
|
} else if (sourceValue !== undefined && sourceValue !== '') {
|
|
|
result[key] = sourceValue
|
|
|
}
|
|
|
@@ -362,48 +368,56 @@ function generateAndReturnDataSourceOADate(dataSource) {
|
|
|
return dataSource
|
|
|
}
|
|
|
|
|
|
-function watchingCellValuesChange(activedSheet, sheets) {
|
|
|
- activedSheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (sender, args) {
|
|
|
- const bindingPathName = activedSheet.getBindingPath(args.row, args.col)
|
|
|
- if (bindingPathName) {
|
|
|
- try {
|
|
|
- for (const sheet of sheets) {
|
|
|
- const dataSource = sheet.getDataSource()?.getSource() || {}
|
|
|
- if (
|
|
|
- !dataSource.hasOwnProperty(bindingPathName) ||
|
|
|
- (activedSheet.name() === sheet.name() && activedSheet.__ID__ === sheet.__ID__)
|
|
|
- )
|
|
|
- continue
|
|
|
-
|
|
|
- const tables = sheet.tables?.all() || []
|
|
|
- for (let i = 0; i < tables.length; i++) {
|
|
|
- const table = sheet.tables.all()[i]
|
|
|
- table.expandBoundRows(true)
|
|
|
+// 监听值变化(用户通过UI操作变化值会被监听,代码去变化值不会被监听),进行dataSource的同步(发生事件以外的sheet)
|
|
|
+// 因为每个sheet用了同一个dataSource(这里不是同一个实例,但是是数据结构和值相同),为了保持这个dataSource的一致,所以要更新其他sheet的datasource
|
|
|
+function registerCellValuesChangeEventHandlerForEverySheet(sheets) {
|
|
|
+ sheets.forEach((activedSheet) => {
|
|
|
+ activedSheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (sender, args) {
|
|
|
+ const bindingPathName = activedSheet.getBindingPath(args.row, args.col)
|
|
|
+ if (bindingPathName) {
|
|
|
+ try {
|
|
|
+ // 处理其他sheet的dataSource
|
|
|
+ for (const sheet of sheets) {
|
|
|
+ const dataSource = sheet.getDataSource()?.getSource() || {}
|
|
|
+ if (
|
|
|
+ !dataSource.hasOwnProperty(bindingPathName) ||
|
|
|
+ (activedSheet.name() === sheet.name() && activedSheet.__ID__ === sheet.__ID__)
|
|
|
+ )
|
|
|
+ continue
|
|
|
+
|
|
|
+ const tables = sheet.tables?.all() || []
|
|
|
+ for (let i = 0; i < tables.length; i++) {
|
|
|
+ const table = sheet.tables.all()[i]
|
|
|
+ table.expandBoundRows(true)
|
|
|
+ }
|
|
|
+ const newDataSource = new GC.Spread.Sheets.Bindings.CellBindingSource({
|
|
|
+ ...dataSource,
|
|
|
+ [bindingPathName]: args.newValue,
|
|
|
+ })
|
|
|
+ sheet.setDataSource(newDataSource)
|
|
|
}
|
|
|
- const newDataSource = new GC.Spread.Sheets.Bindings.CellBindingSource({
|
|
|
- ...dataSource,
|
|
|
- [bindingPathName]: args.newValue,
|
|
|
- })
|
|
|
- sheet.setDataSource(newDataSource)
|
|
|
+ } catch (err) {
|
|
|
+ console.error('监听单元格出错啦', err)
|
|
|
}
|
|
|
- } catch (err) {
|
|
|
- console.error('监听单元格出错啦', err)
|
|
|
}
|
|
|
- }
|
|
|
+ })
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-function handleUserEventCallBack(designerInstance) {
|
|
|
+function registerZoomEventHandler(designerInstance) {
|
|
|
if (!designerInstance) return
|
|
|
const spreadInstance = designerInstance?.getWorkbook()
|
|
|
if (Object.prototype.toString.call(spreadInstance) !== '[object Object]') return
|
|
|
+ // 缩放事件
|
|
|
spreadInstance.bind(GC.Spread.Sheets.Events.ViewZooming, function (sender, args) {
|
|
|
const activedSheet = spreadInstance.getActiveSheet()
|
|
|
const minZoom = calcSheetZoom(activedSheet)
|
|
|
+ // 如果缩小,限制其最小是sheet铺满屏幕,否则不再缩小
|
|
|
if (args.newZoomFactor < minZoom) args.cancel = true
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+// 计算sheet铺满屏幕的缩放比例
|
|
|
function calcSheetZoom(sheet) {
|
|
|
const screenWidth = window.screen.width
|
|
|
const usedRange = sheet.getUsedRange(GC.Spread.Sheets.UsedRangeType.style)
|
|
|
@@ -417,13 +431,9 @@ function calcSheetZoom(sheet) {
|
|
|
return 1 + (screenWidth - scrollbarWidth - totalWidth) / totalWidth
|
|
|
}
|
|
|
|
|
|
-function setActiveSheetZoom(sheet) {
|
|
|
- sheet?.zoom(calcSheetZoom(sheet))
|
|
|
-}
|
|
|
-
|
|
|
function initDesignerSheetConfig(sheet) {
|
|
|
sheet?.zoom(1)
|
|
|
- setActiveSheetZoom(sheet)
|
|
|
+ sheet?.zoom(calcSheetZoom(sheet))
|
|
|
sheet.options.rowHeaderVisible = false
|
|
|
sheet.options.colHeaderVisible = false
|
|
|
sheet.setActiveCell(null)
|
|
|
@@ -442,6 +452,7 @@ function getDefaultSchema(designerInstance) {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+// 设置数据到模板文件,渲染对应数据
|
|
|
function setDataSource(designerInstance, schemaData, dataSourceValues) {
|
|
|
dataSourceValues =
|
|
|
!is(dataSourceValues, 'Object') && is(dataSourceValues, 'String')
|
|
|
@@ -456,15 +467,14 @@ function setDataSource(designerInstance, schemaData, dataSourceValues) {
|
|
|
const resultDataSource = deepMergeSchemaValue(formatterSource, dataSourceValues)
|
|
|
|
|
|
const spreadInstance = designerInstance.getWorkbook()
|
|
|
+ registerCellValuesChangeEventHandlerForEverySheet(spreadInstance.sheets)
|
|
|
for (const sheet of spreadInstance.sheets) {
|
|
|
const tables = sheet.tables?.all() || []
|
|
|
for (let i = 0; i < tables.length; i++) {
|
|
|
- const table = sheet.tables.all()[i]
|
|
|
+ const table = tables[i]
|
|
|
table.expandBoundRows(true)
|
|
|
}
|
|
|
const filterResultDataSource = getSheetBindingPathData(sheet, resultDataSource)
|
|
|
- watchingCellValuesChange(sheet, spreadInstance.sheets)
|
|
|
-
|
|
|
const dataSource = new GC.Spread.Sheets.Bindings.CellBindingSource(filterResultDataSource)
|
|
|
sheet.setDataSource(dataSource)
|
|
|
}
|
|
|
@@ -809,22 +819,22 @@ function isInMergedRange(mergedRange, row, col) {
|
|
|
}
|
|
|
|
|
|
function handleWorkbookInitialized(spreadInstance) {
|
|
|
- console.log('spreadInstance............:', spreadInstance)
|
|
|
-
|
|
|
- // spread.value = spreadInstance
|
|
|
designer.value = spreadInstance
|
|
|
|
|
|
- handleUserEventCallBack(designer.value)
|
|
|
+ registerZoomEventHandler(designer.value)
|
|
|
designer.value.setData('isRibbonCollapse', true)
|
|
|
|
|
|
- if (props.businessConfig && props.templateData) {
|
|
|
- initGenericEditor()
|
|
|
+ const templateData = props.templateData
|
|
|
+ const businessConfig = props.businessConfig
|
|
|
+ if (businessConfig && templateData) {
|
|
|
+ initGenericEditorUI(businessConfig.ui)
|
|
|
+ loadTemplateData(props.templateBlob, templateData)
|
|
|
} else {
|
|
|
console.error('没有获取到业务配置和模板数据')
|
|
|
}
|
|
|
|
|
|
- if (props.templateData && props.templateData.pathNameMapping) {
|
|
|
- fieldNameMapping.value = props.templateData.pathNameMapping
|
|
|
+ if (templateData && templateData.pathNameMapping) {
|
|
|
+ fieldNameMapping.value = templateData.pathNameMapping
|
|
|
console.log('字段名映射已初始化:', fieldNameMapping.value)
|
|
|
} else {
|
|
|
fieldNameMapping.value = []
|
|
|
@@ -832,18 +842,10 @@ function handleWorkbookInitialized(spreadInstance) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function initGenericEditor() {
|
|
|
- const config = props.businessConfig
|
|
|
- const templateData = props.templateData
|
|
|
-
|
|
|
- navTitle.value = config.ui.title
|
|
|
- generateNavButtons(config.ui)
|
|
|
- loadTemplateData(templateData)
|
|
|
-}
|
|
|
+function initGenericEditorUI(uiConfig) {
|
|
|
+ navTitle.value = uiConfig.title
|
|
|
|
|
|
-function generateNavButtons(uiConfig) {
|
|
|
navButtons.value = []
|
|
|
-
|
|
|
const cancelBtn = {
|
|
|
text: uiConfig.cancelButtonText || '取消',
|
|
|
className: '',
|
|
|
@@ -882,29 +884,32 @@ function handleNavButtonClick(button) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function loadTemplateData(templateData) {
|
|
|
- console.log('loadtemplate...............')
|
|
|
+/**
|
|
|
+ * 加载模板文件和数据,
|
|
|
+ * @param templateBlob 模板文件,是模板数据的基础容器
|
|
|
+ * @param templateData 模板数据,填充模板文件中对应的数据格
|
|
|
+ */
|
|
|
+function loadTemplateData(templateBlob, templateData) {
|
|
|
+ console.log('触发模板渲染加载。。。')
|
|
|
if (!designer.value || !templateData) return
|
|
|
|
|
|
const spreadInstance = designer.value.getWorkbook()
|
|
|
spreadInstance.touchToolStrip.clear()
|
|
|
|
|
|
- if (props.templateBlob) {
|
|
|
+ if (templateBlob) {
|
|
|
console.log('开始加载模板文件')
|
|
|
|
|
|
try {
|
|
|
- const blob = base64ToBlob(props.templateBlob, 'application/ssjson')
|
|
|
+ const blob = base64ToBlob(templateBlob, 'application/ssjson')
|
|
|
|
|
|
spreadInstance.open(
|
|
|
blob,
|
|
|
() => {
|
|
|
console.log('模板文件加载成功!')
|
|
|
- const activedSheet = spreadInstance.getActiveSheet()
|
|
|
- initDesignerSheetConfig(activedSheet)
|
|
|
+ initDesignerSheetConfig(spreadInstance.getActiveSheet())
|
|
|
|
|
|
if (templateData.schema) {
|
|
|
- setDefaultSchema(designer.value, templateData.schema)
|
|
|
- setDataSource(designer.value, templateData.schema, templateData.data)
|
|
|
+ initDataSource(designer.value, templateData)
|
|
|
}
|
|
|
handleSheetTableCopyTo(designer.value, true)
|
|
|
initSpreadInputEvents(spreadInstance)
|
|
|
@@ -930,18 +935,19 @@ function loadTemplateData(templateData) {
|
|
|
console.log('创建了新工作表')
|
|
|
}
|
|
|
|
|
|
- setDefaultSchema(designer.value, templateData.schema)
|
|
|
- console.log('schema模板设置完成')
|
|
|
-
|
|
|
- setDataSource(designer.value, templateData.schema, templateData.data)
|
|
|
- console.log('数据设置完成')
|
|
|
+ initDataSource(designer.value, templateData)
|
|
|
|
|
|
spreadInstance.repaint()
|
|
|
handleSheetTableCopyTo(designer.value, true)
|
|
|
initSpreadInputEvents(spreadInstance)
|
|
|
}
|
|
|
|
|
|
- console.log('模板数据加载完成')
|
|
|
+ console.log('模板数据加载完成。。。')
|
|
|
+}
|
|
|
+
|
|
|
+function initDataSource(designer, templateData) {
|
|
|
+ setDefaultSchema(designer, templateData.schema)
|
|
|
+ setDataSource(designer, templateData.schema, templateData.data)
|
|
|
}
|
|
|
|
|
|
function initSpreadInputEvents(spreadInstance) {
|
|
|
@@ -1069,17 +1075,12 @@ watch(
|
|
|
() => props.templateBlob,
|
|
|
(newBlob, oldBlob) => {
|
|
|
if (newBlob && newBlob !== oldBlob && designer.value && props.templateData) {
|
|
|
- console.log('templateBlob 发生变化,重新加载模板')
|
|
|
- loadTemplateData(props.templateData)
|
|
|
+ console.log('templateBlob 发生变化,重新加载模板,数据:', props.templateData)
|
|
|
+ loadTemplateData(props.templateBlob, props.templateData)
|
|
|
}
|
|
|
},
|
|
|
)
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- console.time('initDesigner')
|
|
|
- console.timeEnd('initDesigner')
|
|
|
-})
|
|
|
-
|
|
|
defineExpose({
|
|
|
onWebViewResize,
|
|
|
updateDataSource,
|
|
|
@@ -1090,15 +1091,15 @@ defineExpose({
|
|
|
|
|
|
<style scoped>
|
|
|
* {
|
|
|
- margin: 0;
|
|
|
- padding: 0;
|
|
|
box-sizing: border-box;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
}
|
|
|
|
|
|
.spread-designer-generic {
|
|
|
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
height: 100vh;
|
|
|
overflow: hidden;
|
|
|
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
}
|
|
|
|
|
|
.main-container {
|
|
|
@@ -1107,29 +1108,29 @@ defineExpose({
|
|
|
}
|
|
|
|
|
|
.navigator-bar {
|
|
|
+ box-sizing: border-box;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- padding: 0 16px;
|
|
|
- background-color: #f8f9fa;
|
|
|
- border-bottom: 1px solid #e9cef;
|
|
|
height: clamp(44px, 8vw, 56px);
|
|
|
min-height: 44px;
|
|
|
- box-sizing: border-box;
|
|
|
+ padding: 0 16px;
|
|
|
+ background-color: #f8f9fa;
|
|
|
+ border-bottom: 1px solid #e9ecef;
|
|
|
}
|
|
|
|
|
|
.nav-left {
|
|
|
- flex: 1;
|
|
|
display: flex;
|
|
|
+ flex: 1;
|
|
|
align-items: center;
|
|
|
}
|
|
|
|
|
|
.back-btn {
|
|
|
- background: none;
|
|
|
- border: none;
|
|
|
+ padding: 8px;
|
|
|
font-size: 18px;
|
|
|
cursor: pointer;
|
|
|
- padding: 8px;
|
|
|
+ background: none;
|
|
|
+ border: none;
|
|
|
border-radius: 4px;
|
|
|
transition: background-color 0.2s;
|
|
|
}
|
|
|
@@ -1140,29 +1141,29 @@ defineExpose({
|
|
|
|
|
|
.nav-title {
|
|
|
flex: 1;
|
|
|
- text-align: center;
|
|
|
font-size: clamp(16px, 4vw, 18px);
|
|
|
font-weight: 600;
|
|
|
color: #333;
|
|
|
+ text-align: center;
|
|
|
}
|
|
|
|
|
|
.nav-right {
|
|
|
- flex: 1;
|
|
|
display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
+ flex: 1;
|
|
|
gap: 8px;
|
|
|
+ justify-content: flex-end;
|
|
|
}
|
|
|
|
|
|
.nav-btn {
|
|
|
padding: 6px 12px;
|
|
|
- border: 1px solid #dee2e6;
|
|
|
- border-radius: 4px;
|
|
|
- background-color: #fff;
|
|
|
- color: #495057;
|
|
|
font-size: clamp(12px, 3vw, 14px);
|
|
|
+ color: #495057;
|
|
|
+ white-space: nowrap;
|
|
|
cursor: pointer;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid #dee2e6;
|
|
|
+ border-radius: 4px;
|
|
|
transition: all 0.2s;
|
|
|
- white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.nav-btn:hover {
|
|
|
@@ -1170,8 +1171,8 @@ defineExpose({
|
|
|
}
|
|
|
|
|
|
.nav-btn.primary {
|
|
|
- background-color: #007bff;
|
|
|
color: white;
|
|
|
+ background-color: #007bff;
|
|
|
border-color: #007bff;
|
|
|
}
|
|
|
|
|
|
@@ -1180,8 +1181,8 @@ defineExpose({
|
|
|
}
|
|
|
|
|
|
.nav-btn.warning {
|
|
|
- background-color: #e6a23c;
|
|
|
color: white;
|
|
|
+ background-color: #e6a23c;
|
|
|
border-color: #e6a23c;
|
|
|
}
|
|
|
|
|
|
@@ -1194,10 +1195,10 @@ defineExpose({
|
|
|
width: 100%;
|
|
|
height: 40px;
|
|
|
padding: 8px 32px 8px 12px;
|
|
|
- border: 1px solid #d9d9d9;
|
|
|
- border-radius: 4px;
|
|
|
font-size: 14px;
|
|
|
resize: none;
|
|
|
+ border: 1px solid #d9d9d9;
|
|
|
+ border-radius: 4px;
|
|
|
outline: none;
|
|
|
}
|
|
|
|
|
|
@@ -1206,103 +1207,103 @@ defineExpose({
|
|
|
}
|
|
|
|
|
|
.clear-btn {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ right: 8px;
|
|
|
+ z-index: 2;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
width: 24px;
|
|
|
height: 24px;
|
|
|
- border-radius: 12px;
|
|
|
- background: #f0f0f0;
|
|
|
- border: none;
|
|
|
- color: #666;
|
|
|
font-size: 16px;
|
|
|
font-weight: bold;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- position: absolute;
|
|
|
- right: 8px;
|
|
|
- top: 50%;
|
|
|
- transform: translateY(-50%);
|
|
|
+ color: #666;
|
|
|
cursor: pointer;
|
|
|
- z-index: 2;
|
|
|
+ background: #f0f0f0;
|
|
|
+ border: none;
|
|
|
+ border-radius: 12px;
|
|
|
+ transform: translateY(-50%);
|
|
|
}
|
|
|
|
|
|
.clear-btn:hover {
|
|
|
- background: #e0e0e0;
|
|
|
color: #333;
|
|
|
+ background: #e0e0e0;
|
|
|
}
|
|
|
|
|
|
.floating-field-name-display {
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ align-items: center;
|
|
|
+ height: 35px;
|
|
|
+ padding: 6px 12px;
|
|
|
+ margin-right: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
font-size: 12px;
|
|
|
+ line-height: 1.2;
|
|
|
color: #666;
|
|
|
- padding: 6px 12px;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
background: #f5f5f5;
|
|
|
border-radius: 4px;
|
|
|
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- height: 35px;
|
|
|
- line-height: 1.2;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex: 1;
|
|
|
- margin-right: 8px;
|
|
|
}
|
|
|
|
|
|
.floating-input-container {
|
|
|
position: fixed;
|
|
|
- left: 0;
|
|
|
right: 0;
|
|
|
bottom: 0;
|
|
|
+ left: 0;
|
|
|
z-index: 9999;
|
|
|
display: block;
|
|
|
+ min-height: 85px;
|
|
|
+ padding: 8px 12px 12px 12px;
|
|
|
background: white;
|
|
|
border-top: 1px solid #e0e0e0;
|
|
|
- padding: 8px 12px 12px 12px;
|
|
|
- min-height: 85px;
|
|
|
transition: all 0.3s ease;
|
|
|
}
|
|
|
|
|
|
.floating-input-container.keyboard-visible {
|
|
|
+ position: fixed !important;
|
|
|
bottom: var(--keyboard-height, 0);
|
|
|
+ z-index: 10000;
|
|
|
min-height: 105px;
|
|
|
max-height: 345px;
|
|
|
- position: fixed !important;
|
|
|
- z-index: 10000;
|
|
|
}
|
|
|
|
|
|
.floating-toolbar {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- margin-top: 4px;
|
|
|
- padding: 0 2px;
|
|
|
height: 35px;
|
|
|
+ padding: 0 2px;
|
|
|
+ margin-top: 4px;
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
.button-group {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
gap: 8px;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
|
|
|
.prev-cell-btn {
|
|
|
- background: #007aff;
|
|
|
- color: white;
|
|
|
- border: none;
|
|
|
- border-radius: 4px;
|
|
|
- padding: 6px 12px;
|
|
|
- font-size: 12px;
|
|
|
- font-weight: 500;
|
|
|
- cursor: pointer;
|
|
|
+ position: relative;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- transition: all 0.2s ease;
|
|
|
+ min-width: 60px;
|
|
|
height: 35px;
|
|
|
+ padding: 6px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
line-height: 1;
|
|
|
- min-width: 60px;
|
|
|
- position: relative;
|
|
|
+ color: white;
|
|
|
+ cursor: pointer;
|
|
|
+ background: #007aff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 4px;
|
|
|
+ transition: all 0.2s ease;
|
|
|
}
|
|
|
|
|
|
.prev-cell-btn:hover:not(:disabled) {
|
|
|
@@ -1320,29 +1321,29 @@ defineExpose({
|
|
|
}
|
|
|
|
|
|
.prev-cell-btn:disabled {
|
|
|
- background: #cccccc;
|
|
|
color: #999999;
|
|
|
cursor: not-allowed;
|
|
|
+ background: #cccccc;
|
|
|
opacity: 0.7;
|
|
|
}
|
|
|
|
|
|
.next-cell-btn {
|
|
|
- background: #007aff;
|
|
|
- color: white;
|
|
|
- border: none;
|
|
|
- border-radius: 4px;
|
|
|
- padding: 6px 12px;
|
|
|
- font-size: 12px;
|
|
|
- font-weight: 500;
|
|
|
- cursor: pointer;
|
|
|
+ position: relative;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- transition: all 0.2s ease;
|
|
|
+ min-width: 60px;
|
|
|
height: 35px;
|
|
|
+ padding: 6px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
line-height: 1;
|
|
|
- min-width: 60px;
|
|
|
- position: relative;
|
|
|
+ color: white;
|
|
|
+ cursor: pointer;
|
|
|
+ background: #007aff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 4px;
|
|
|
+ transition: all 0.2s ease;
|
|
|
}
|
|
|
|
|
|
.next-cell-btn:hover:not(:disabled) {
|
|
|
@@ -1360,37 +1361,37 @@ defineExpose({
|
|
|
}
|
|
|
|
|
|
.next-cell-btn:disabled {
|
|
|
- background: #cccccc;
|
|
|
color: #999999;
|
|
|
cursor: not-allowed;
|
|
|
+ background: #cccccc;
|
|
|
opacity: 0.7;
|
|
|
}
|
|
|
|
|
|
.dialog-overlay {
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
- left: 0;
|
|
|
right: 0;
|
|
|
bottom: 0;
|
|
|
- background-color: rgba(0, 0, 0, 0.5);
|
|
|
+ left: 0;
|
|
|
+ z-index: 10001;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- z-index: 10001;
|
|
|
+ background-color: rgba(0, 0, 0, 0.5);
|
|
|
}
|
|
|
|
|
|
.dialog-content {
|
|
|
- background-color: white;
|
|
|
+ max-width: 80%;
|
|
|
padding: 20px;
|
|
|
+ background-color: white;
|
|
|
border-radius: 8px;
|
|
|
- max-width: 80%;
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
}
|
|
|
|
|
|
.modal-message {
|
|
|
font-size: 16px;
|
|
|
+ line-height: 1.5;
|
|
|
color: #333;
|
|
|
text-align: center;
|
|
|
- line-height: 1.5;
|
|
|
}
|
|
|
</style>
|