123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- <script setup>
- // import Sheet from '@/components/Sheet.vue'
- import { ref, reactive, computed, onMounted, watch } from 'vue'
- const props = defineProps({
- TableInfo:{
- type:Object,
- default:{}
- }
- })
- const tableHeight = ref(0)
- const disabled = ref(true)
- const cellRef = ref([])
- const rowTable = ref(null);
- const tableData = reactive(props.TableInfo.TableData.Data);
- const freezeData = reactive(props.TableInfo.ExtraConfig.TableFreeze);
- const columnHeader = computed(() => {
- return getColumnHeaderCode(
- props.TableInfo.TableData.Data[0] ? props.TableInfo.TableData.Data[0].length : 0
- );
- });
- const rowHeader = computed(() => {
- let total_length = props.TableInfo.TableData.Data.length;
- return getRowHeaderCode(total_length);
- });
- const minRow = computed(() => {
- return Math.min(props.TableInfo.ExtraConfig.TableFreeze.FreezeStartRow, props.TableInfo.ExtraConfig.TableFreeze.FreezeEndRow)
- });
- const maxRow = computed(() => {
- return Math.max(props.TableInfo.ExtraConfig.TableFreeze.FreezeStartRow, props.TableInfo.ExtraConfig.TableFreeze.FreezeEndRow)
- });
- const maxCol = computed(() => {
- return Math.max(props.TableInfo.ExtraConfig.TableFreeze.FreezeStartCol, props.TableInfo.ExtraConfig.TableFreeze.FreezeEndCol)
- });
- const minCol = computed(() => {
- return Math.min(props.TableInfo.ExtraConfig.TableFreeze.FreezeStartCol, props.TableInfo.ExtraConfig.TableFreeze.FreezeEndCol)
- });
- //手机端pc端不同样式
- const dynamicSty = computed(()=>{
- return isMobile() ? 'mobile-sty' : 'pc-sty';
- })
- //判断是否是手机设备
- function isMobile() {
- // 判断是否是移动设备的正则表达式
- const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
-
- // 获取用户代理信息
- const userAgent = navigator.userAgent;
-
- // 使用正则表达式检查用户代理信息
- return mobileRegex.test(userAgent);
- }
-
- // 字母列标
- function getColumnHeaderCode(len) {
- let tag_arr = [];
- for(let i=0;i<len;i++) tag_arr.push(String.fromCharCode(65+i));
- return tag_arr;
- }
- // 行标
- function getRowHeaderCode(len) {
- let tag_arr = [];
- for(let i=0;i<len;i++) tag_arr.push(String(1+i));
- return tag_arr;
- }
- // 判断展示小数位数值还是原来的值
- function showCellValue(cell){
- // console.log(cell)
- let Value=''
- if("Decimal" in cell&&cell.Decimal!=-1){
- const multiplier = Math.pow(10, cell.Decimal);
- const cellValue=+cell.Value
- Value= cell.Decimal == 0 ? Math.round(cellValue) : Math.round(cellValue * multiplier) / multiplier;
- }else{
- Value=cell.ShowValue
- }
- return Value
- }
- // 初始化单元格横纵坐标
- function initIndex(rindex, cindex, row, col) {
- props.TableInfo.TableData.Data[rindex][cindex]["cIndex"] = cindex;
- props.TableInfo.TableData.Data[rindex][cindex]["rIndex"] = rindex;
- props.TableInfo.TableData.Data[rindex][cindex]["colIndex"] = col;
- props.TableInfo.TableData.Data[rindex][cindex]["rowIndex"] = row;
- }
- onMounted(() => {
- tableHeight.value = rowTable.value ? rowTable.value[0].offsetHeight : 35;
- })
- // 设置背景色及字体颜色
- function getShowCss(style, type = '') {
- const styleCss = JSON.parse(style);
- let color = styleCss.glObj ? styleCss.glObj["color"] : styleCss["color"];
- let BackgroundColor = styleCss.glObj
- ? styleCss.glObj["background-color"]
- : styleCss["background-color"];
- let obj = {
- color: color,
- "background-color": BackgroundColor,
- 'text-align': styleCss.align ? styleCss.align : 'center',
- 'width': styleCss.width ? styleCss.width + 'px' : '140px',
- }
- if (type == 'header') {
- obj = {
- 'width': styleCss.width ? styleCss.width + 'px' : '140px',
- }
- }
- return obj;
- }
- // 是否展示小数
- function isShowDecimal(cell) {
- // // console.log(cell,111)
- const styleCss = cell.ShowStyle ? JSON.parse(cell.ShowStyle) : {};
- let tag = !isNaN(parseFloat(cell.ShowValue)) && isFinite(cell.ShowValue)
- return tag ? !isNaN(parseFloat(styleCss.decimal)) && isFinite(styleCss.decimal) : false
- }
- // 由于在showStyle做了背景色及字体颜色处理,解决判断冲突
- function isShowFormat(style, type = "css") {
- const styleCss = style ? JSON.parse(style) : {};
- let tag =
- type === "css"
- ? styleCss.pn > 0 || styleCss.pn < 0 || ["percent"].includes(styleCss.nt)
- : style.EdbInfoId;
- return tag;
- }
- // 展示小数
- function showDecimalValue(cell) {
- const styleCss = cell.ShowStyle ? JSON.parse(cell.ShowStyle) : {};
- let Value = ''
- if (styleCss.nt == 'percent' && cell.ShowFormatValue.indexOf('%') > -1) {
- if (styleCss.last == 'nt') {
- Value = commonDecimalValue(cell.ShowValue * 100, styleCss.decimal) + '%'
- } else {
- Value = (parseFloat(commonDecimalValue(cell.ShowValue, styleCss.decimal) * 100)) + '%'
- }
- } else {
- Value = parseFloat(commonDecimalValue(cell.ShowValue, styleCss.decimal)).toFixed(styleCss.decimal)
- }
- if (getDecimalPlaces(cell.ShowValue) < styleCss.decimal || styleCss.nt == 'percent') {
- Value = transDecimalPlace(cell.ShowValue + '', { ...styleCss, pn: styleCss.decimal - getDecimalPlaces(cell.ShowValue) + (styleCss.nt == 'percent'&&getDecimalPlaces(cell.ShowValue)!=0 ? 2 : 0) })
- }
- // console.log(cell)
- tableData[cell.rIndex][cell.cIndex].ShowFormatValue = Value;
- return Value
- }
- function commonDecimalValue(values, decimal) {
- const multiplier = Math.pow(10, decimal);
- return decimal == 0 ? Math.round(values) : Math.round(values * multiplier) / multiplier;
- }
- /* 计算小数点位数 */
- function getDecimalPlaces(numStr) {
- // 移除百分号,如果有的话
- numStr = numStr.replace('%', '');
- // 如果没有小数点,说明小数点位数为 0
- if (!numStr.includes('.')) {
- return 0;
- }
- // 获取当前小数点后的位数
- const decimalPlaces = numStr.split('.')[1].length;
- return decimalPlaces;
- }
- /* 增加减少小数点位数 */
- function transDecimalPlace(str,{pn,nt}) {
- if(!isNumberVal(str)) return '';
- let s = str.replace(/%/,''),
- decimalPlaces = getDecimalPlaces(str),
- decimalNum=pn;
- //是否是原数字后设置百分比的
- let transPercent = (nt==='percent'&&!str.endsWith('%')) ? true : false;
- //原百分比设置为数字的
- let transDecimal = (nt==='number'&&str.endsWith('%')) ? true : false
- //后缀 百分号
- let suffix = ((str.endsWith('%')&&nt!=='number')||transPercent) ? '%' : '';
- let num = parseFloat(s);
- if(decimalPlaces===0) { //整数
- if(transPercent) {
- return decimalNum > 0
- ? `${multiply(num,100)}.${'0'.repeat(decimalNum)}${suffix}`
- : `${multiply(num,100)}${suffix}`;
- }
- if(transDecimal) {
- return decimalNum > 0
- ? `${divide(num,100)}${'0'.repeat(decimalNum)}`
- : `${divide(num,100)}`;
- }
- // 补零
- return decimalNum > 0
- ? `${s}.${'0'.repeat(decimalNum)}${suffix}`
- : `${s}${suffix}`;
- }
- if(decimalNum > 0) {
- let addPointStr = `${s}${'0'.repeat(decimalNum)}`;
-
- return transPercent
- ? `${parseFloat(multiply(num,100)).toFixed(decimalPlaces+decimalNum-2)}${suffix}`
- : transDecimal
- ? `${parseFloat(divide(num,100)).toFixed(decimalPlaces+decimalNum+2)}`
- : `${addPointStr}${suffix}`
- }else {
- let maxDecimal = Math.max(0,decimalNum+decimalPlaces);
- let maxDecimalPercent = Math.max(0,maxDecimal-2);
- return transPercent
- ? `${parseFloat(multiply(num,100)).toFixed(maxDecimalPercent)}${suffix}`
- : transDecimal
- ? `${parseFloat(divide(num,100)).toFixed(maxDecimal+2)}`
- : `${parseFloat(num.toFixed(maxDecimal))}${suffix}`
- }
- }
- /* 判断值是否是一个数字或数字字符串 */
- function isNumberVal(value) {
- let reg = /^[-]?(?:\d*\.?\d+|\d+%|\d*\.\d+%)$/;
-
- return reg.test(value);
- }
- // 是否固定列
- function isWithinColRange (index) {
- return rowHeader.value[index] >= minCol.value && rowHeader.value[index] <= maxCol.value
- }
- // 获取某一列的宽度
- function getColumnHeaderWidth (index) {
- return cellRef.value && cellRef.value[index] ? cellRef.value[index].offsetWidth : 104
- }
- </script>
- <template>
- <div class="sheet-show-wrapper">
- <div :class="['table-wrapper',dynamicSty ]" >
- <table
- border="0"
- class="table el-table__body"
- id="myTable"
- :style="disabled ? 'width:100%' : ''"
- ref="tableRef"
- style="position: relative;width: auto;"
- >
- <thead>
- <tr ref="rowTable">
- <!-- 行头 -->
- <th class="th-tg sm" style="width:36px"></th>
- <!-- 列头 -->
- <th
- ref="cellRef"
- :style="TableInfo.TableData.Data[0][index].ShowStyle?getShowCss(TableInfo.TableData.Data[0][index].ShowStyle,'header'):{}"
- v-for="(item, index) in columnHeader"
- :key="index"
- class="th-tg th-col"
- :data-cindex="item"
- :data-rindex="-1"
- >
- {{ item }}
- </th>
- </tr>
- </thead>
- <tbody>
- <tr ref="rowTable" v-for="(row, index) in TableInfo.TableData.Data" :key="index" :style="freezeData ? `top: ${(index- minRow+1)*tableHeight}px;` : ''" :class="freezeData && rowHeader[index] >= minRow && rowHeader[index] <= maxRow ? 'fix' : ''">
- <!-- 行头 -->
- <th
- class="th-tg th-row sm"
- @contextmenu.prevent="rightClickHandle"
- :data-rindex="rowHeader[index]"
- :data-cindex="-1"
- >
- {{ rowHeader[index] }}
- </th>
-
- <td
- v-for="(cell, cell_index) in row"
- :key="`${index}_${cell_index}`"
- :data-rindex="rowHeader[index]"
- :data-cindex="columnHeader[cell_index]"
- :data-datarindex="index"
- :data-datacindex="cell_index"
- :style="[cell.ShowStyle?getShowCss(cell.ShowStyle):{}, freezeData && isWithinColRange(cell_index) ? {left: (cell_index- minCol+1)*getColumnHeaderWidth(cell_index) + 'px'} : '']"
- :class="[freezeData && isWithinColRange(cell_index) ? 'fix-col' : '']"
- :initIndex="initIndex(index,cell_index,rowHeader[index],columnHeader[cell_index])"
- :data-key="cell.Uid"
- v-show="!cell.merData || cell.merData.type!=='merged'"
- :colspan="(cell.merData && cell.merData.type=='merge' && cell.merData.mer)?cell.merData.mer.colspan || 1:1"
- :rowspan="(cell.merData && cell.merData.type=='merge' && cell.merData.mer)?cell.merData.mer.rowspan || 1:1"
- >
- <!-- 插入单元格禁止编辑 -->
- <!-- [4,5,6,7,8].includes(cell.DataType)&&!cell.CanEdit -->
- <template
- v-if="!cell.CanEdit
- ||disabled
- ||(cell.DataType===1&&[1,2].includes(cell.DataTimeType))"
- >
- <!-- 数字格式化显示 -->
- <span
- v-if="cell.ShowStyle"
- :data-rindex="rowHeader[index]"
- :data-cindex="columnHeader[cell_index]"
- :data-datarindex="index"
- :data-datacindex="cell_index"
- :data-key="cell.Uid"
- >
- {{isShowDecimal(cell)?showDecimalValue(cell):isShowFormat(cell.ShowStyle)?cell.ShowFormatValue:cell.DataTime?cell.ShowValue:[8,7,6,5,1].includes(cell.DataType)?cell.ShowValue?cell.ShowValue:'-':cell.Value}}
- </span>
- <span
- :data-rindex="rowHeader[index]"
- :data-cindex="columnHeader[cell_index]"
- :data-datarindex="index"
- :data-datacindex="cell_index"
- :data-key="cell.Uid"
- v-else
- >{{ cell.ShowValue }}</span>
- </template>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="tool sheet-bottom">
- <div class="sheet-source"
- v-if="TableInfo.SourcesFrom&&JSON.parse(TableInfo.SourcesFrom).isShow"
- :style="`
- color: ${ JSON.parse(TableInfo.SourcesFrom).color };
- font-size: ${ JSON.parse(TableInfo.SourcesFrom).fontSize }px;
- `"
- >
- source:<em>{{ JSON.parse(TableInfo.SourcesFrom).text}}</em>
- </div>
- </div>
- </div>
- </template>
- <style lang='scss' scoped>
- // sheet-show-wrapper 相关样式
- .sheet-show-wrapper {
- max-width: 1200px;
- overflow: hidden;
- position: relative;
- margin: 0 auto;
- background: #fff;
- .tool {
- margin-top: 5px;
- span {
- cursor: pointer;
- }
- }
- .sheet-bottom {
- display: flex;
- align-items: center;
- justify-content: space-between;
- white-space: nowrap;
- padding: 0 10px;
- .sheet-source {
- width: 30%;
- min-width: 150px;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
- }
- // 表格相关样式
- .table {
- width: 100%;
- font-size: 14px;
- color: #333;
- td, th {
- width: 104px;
- min-width: 104px;
- height: 35px;
- background: #fff;
- text-align: center;
- word-break: break-all;
- border: none;
- outline-color: #dcdfe6;
- outline-style: solid;
- outline-width: 1px;
- word-wrap: break-word;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- position: relative;
- &:first-child {
- border-left: 1px solid #dcdfe6;
- }
- &.insert {
- background: #FFEFDD;
- }
- &.fix-col {
- position: sticky;
- left: 0;
- z-index: 98; // 表格右键操作弹窗为99
- }
- }
- .th-tg {
- background: #EBEEF5;
- &:hover {
- cursor: pointer;
- background: #ddd;
- }
- &.sm {
- width: 36px;
- min-width: 36px;
- max-width: 36px;
- }
- }
- }
- // 表格行(tr)相关样式
- tr {
- &.fix {
- position: sticky;
- top: 0;
- z-index: 98; // 表格右键操作弹窗为99
- }
- // 可根据需要添加更多tr的样式,例如整行选中效果等
- }
- // 滚动条样式
- ::-webkit-scrollbar {
- width: 6px;
- height: 6px;
- }
- ::-webkit-scrollbar-track {
- background: rgb(239, 239, 239);
- border-radius: 2px;
- }
- ::-webkit-scrollbar-thumb {
- background: #ccc;
- border-radius: 10px;
- &:hover {
- background: #888;
- }
- }
- ::-webkit-scrollbar-corner {
- background: #666;
- }
- // table-wrapper 样式
- .table-wrapper {
- max-width: calc(100vw - 20px);
- max-height: calc(100vh - 400px);
- margin: 0 auto;
- overflow: auto;
- -webkit-overflow-scrolling: touch; /* ios滚动条 */
- }
- // PC端表格样式
- .pc-sty table {
- table-layout: auto;
- td, th {
- width: auto;
- height: auto;
- padding: 0.4em 0;
- }
- }
- // 移动端表格样式
- .mobile-sty table {
- table-layout: auto;
- td, th {
- min-width: 120px;
- height: 40px;
- }
- }
- @media screen and (min-width: 650px) {
- // 滚动条样式
- ::-webkit-scrollbar {
- width: 3px;
- height: 3px;
- }
- ::-webkit-scrollbar-track {
- border-radius: 1px;
- }
- ::-webkit-scrollbar-thumb {
- border-radius: 5px;
- }
-
- // 表格相关样式
- .sheet-show-wrapper {
- .table-wrapper {
- max-height: calc(100vh - 220px);
- }
- .tool {
- margin-top: 3px;
- span {
- cursor: pointer;
- }
- }
- .sheet-bottom {
- padding: 0 5px;
- .sheet-source {
- width: 15%;
- min-width: 75px;
- }
- }
- }
- // 表格相关样式
- .table {
- font-size: 7px;
- td, th {
- width: 52px;
- min-width: 52px;
- height: 17px;
- outline-width: 1px;
- }
- .th-tg {
- &.sm {
- width: 18px;
- min-width: 18px;
- max-width: 18px;
- }
- }
- }
- // 移动端表格样式
- .mobile-sty table {
- table-layout: auto;
- td, th {
- min-width: 60px;
- height: 20px;
- }
- }
- }
- </style>
|