Browse Source

change wrod and timetip

master
godo 6 months ago
parent
commit
d5604bc12e
  1. 8
      CHANGELOG.md
  2. 2
      README.md
  3. 3
      frontend/auto-imports.d.ts
  4. 12
      frontend/components.d.ts
  5. 1492
      frontend/package-lock.json
  6. 2
      frontend/package.json
  7. 5559
      frontend/pnpm-lock.yaml
  8. 142
      frontend/public/docx/assets/index.2a68c9e8.js
  9. 142
      frontend/public/docx/assets/index.30955838.js
  10. 142
      frontend/public/docx/assets/index.3842052e.js
  11. 142
      frontend/public/docx/assets/index.4e9c2fed.js
  12. 141
      frontend/public/docx/assets/index.77c27592.js
  13. 141
      frontend/public/docx/assets/index.97977da0.js
  14. 142
      frontend/public/docx/assets/index.9cb6c062.js
  15. 2
      frontend/public/docx/index.html
  16. 20
      frontend/src/components/setting/SetLang.vue
  17. 9
      frontend/src/components/taskbar/DateTimePop.vue
  18. 519
      frontend/src/components/taskbar/DateTimeShow.vue
  19. 18
      frontend/src/system/index.ts
  20. 2
      frontend/src/system/initBuiltin.ts
  21. 33
      frontend/src/system/window/BrowserWindow.ts
  22. 2
      frontend/src/system/window/Dialog.ts
  23. 2
      packages/word/src/plugins/docx/exportDocx.ts
  24. 107
      packages/word/src/plugins/docx/importDocx.ts

8
CHANGELOG.md

@ -42,11 +42,15 @@ bug梳理:
8. excel读取原始文件兼容性问题
9. word读取原始文件兼容性
### 后续开
### 后续开
1. 优化内网聊天
2. 新增 权限管理 文件加密 以及远程存储服务端(企业版本)
3. 应用商店重构 陆续会新增php/node/go/java
4. 文档可上传图片
5. 文件搜索功能
6. 应用商店添加我的世界https://mc.163.com/exp/
6. 应用商店添加我的世界https://mc.163.com/exp/
7. 文件点存储按钮,需选择存储目录
8. 开发文档增加docker部署
9. word格式问题以及导出名字不对
10. 美化日程提醒弹窗

2
README.md

@ -22,6 +22,8 @@
- 修复截图/截屏路径
- 修复更换存储将路径后系统不重置的问题
- 新增文件密码箱(系统设置里),可根据不同文件进行加密存储
- 美化日程提醒弹窗
- 修复word格式问题以及导出名字不对
## 🏭 第三阶段目标(十二月底发布)
1. **文档处理与Markdown智能升级**

3
frontend/auto-imports.d.ts

@ -3,6 +3,7 @@
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
@ -71,6 +72,6 @@ declare global {
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

12
frontend/components.d.ts

@ -50,6 +50,7 @@ declare module 'vue' {
DateNote: typeof import('./src/components/builtin/DateNote.vue')['default']
DateTime: typeof import('./src/components/taskbar/DateTime.vue')['default']
DateTimePop: typeof import('./src/components/taskbar/DateTimePop.vue')['default']
DateTimeShow: typeof import('./src/components/taskbar/DateTimeShow.vue')['default']
DeskItem: typeof import('./src/components/desktop/DeskItem.vue')['default']
Desktop: typeof import('./src/components/desktop/Desktop.vue')['default']
DesktopBackground: typeof import('./src/components/desktop/DesktopBackground.vue')['default']
@ -60,18 +61,26 @@ declare module 'vue' {
DownModelInfo: typeof import('./src/components/ai/DownModelInfo.vue')['default']
EditFileName: typeof import('./src/components/builtin/EditFileName.vue')['default']
EditType: typeof import('./src/components/builtin/EditType.vue')['default']
ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBadge: typeof import('element-plus/es')['ElBadge']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCol: typeof import('element-plus/es')['ElCol']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput']
ElOption: typeof import('element-plus/es')['ElOption']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
@ -79,10 +88,13 @@ declare module 'vue' {
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSlider: typeof import('element-plus/es')['ElSlider']
ElSpace: typeof import('element-plus/es')['ElSpace']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElText: typeof import('element-plus/es')['ElText']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
Error: typeof import('./src/components/taskbar/Error.vue')['default']
FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default']
FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default']

1492
frontend/package-lock.json

File diff suppressed because it is too large

2
frontend/package.json

@ -17,7 +17,7 @@
"file-saver": "^2.0.5",
"js-md5": "^0.8.3",
"jszip": "^3.10.1",
"lunar-typescript": "^1.7.5",
"lunar-typescript": "^1.7.6",
"moment": "^2.30.1",
"pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0",

5559
frontend/pnpm-lock.yaml

File diff suppressed because it is too large

142
frontend/public/docx/assets/index.2a68c9e8.js

File diff suppressed because one or more lines are too long

142
frontend/public/docx/assets/index.30955838.js

File diff suppressed because one or more lines are too long

142
frontend/public/docx/assets/index.3842052e.js

File diff suppressed because one or more lines are too long

142
frontend/public/docx/assets/index.4e9c2fed.js

File diff suppressed because one or more lines are too long

141
frontend/public/docx/assets/index.77c27592.js

File diff suppressed because one or more lines are too long

141
frontend/public/docx/assets/index.97977da0.js

File diff suppressed because one or more lines are too long

142
frontend/public/docx/assets/index.9cb6c062.js

File diff suppressed because one or more lines are too long

2
frontend/public/docx/index.html

@ -6,7 +6,7 @@
<link rel="icon" type="image/png" href="./assets/favicon.fbfa22e6.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>word</title>
<script type="module" crossorigin src="./assets/index.5f048ec4.js"></script>
<script type="module" crossorigin src="./assets/index.3842052e.js"></script>
<link rel="modulepreload" href="./assets/vendor.d13e5cc9.js">
<link rel="stylesheet" href="./assets/index.ec407d42.css">
</head>

20
frontend/src/components/setting/SetLang.vue

@ -38,15 +38,16 @@
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { Dialog } from "@/system";
import { ElMessageBox } from 'element-plus'
import { t, getLang, setLang } from "@/i18n";
import { useI18n } from 'vue-i18n';
const { locale } = useI18n()
const showDialog = ref(false);
const langList = [
{
label: "中文",
@ -70,11 +71,16 @@ const selectItem = (index: number) => {
async function submit() {
setLang(modelvalue.value);
locale.value = modelvalue.value;
Dialog.showMessageBox({
message: t("save.success"),
title: t("language"),
type: "info",
});
ElMessageBox.alert(t("save.success"), t("language"), {
confirmButtonText: 'OK',
})
//showDialog.value = false
// Dialog.showMessageBox({
// message: t("save.success"),
// title: t("language"),
// type: "info",
// });
}
</script>
<style scoped>

9
frontend/src/components/taskbar/DateTimePop.vue

@ -31,10 +31,10 @@
</div>
</div>
</div>
<div class="date-bottom">
<!-- <div class="date-bottom">
<div class="add-sch">
<input type="text" placeholder="添加日程或提醒" v-model="alertText" /><br />
<!-- -->
<input
type="number"
:max="24"
@ -43,7 +43,6 @@
@blur="checkAlert()"
/>
<!-- -->
<input type="number" :max="60" :min="0" v-model="alertMin" @blur="checkAlert()" />
<WinButton @click="addAlert">确定</WinButton>
@ -66,7 +65,7 @@
<WinButton @click.stop="deleteAlert(index)">删除</WinButton>
</div>
</div>
</div>
</div> -->
</div>
</template>
<script setup lang="ts">
@ -292,7 +291,7 @@ function clickDetail(item: { text: string; time: number }) {
bottom: 0;
right: 0;
width: 320px;
height: 600px;
height: 380px;
background-color: #f5f5f5; /* 更接近Win10的背景颜色 */
border: 1px solid #e5e5e5; /* 边框颜色调整 */
user-select: none;

519
frontend/src/components/taskbar/DateTimeShow.vue

@ -0,0 +1,519 @@
<script setup lang="ts">
import { reactive, watch } from 'vue'
import { Solar, SolarMonth, SolarWeek, HolidayUtil } from 'lunar-typescript'
const now = Solar.fromDate(new Date())
class Day {
public month: number = 0
public day: number = 0
public lunarDay: string = ''
public lunarMonth: string = ''
public yearGanZhi: string = ''
public yearShengXiao: string = ''
public monthGanZhi: string = ''
public dayGanZhi: string = ''
public ymd: string = ''
public desc: string = ''
public isToday: boolean = false
public isSelected: boolean = false
public isRest: boolean = false
public isHoliday: boolean = false
public festivals: string[] = []
public yi: string[] = []
public ji: string[] = []
}
class Week {
public days: Day[] = []
}
class Month {
public heads: string[] = []
public weeks: Week[] = []
}
class Holiday {
public name: string = ''
public month: number = 0
}
const state = reactive({
year: now.getYear(),
month: now.getMonth(),
weekStart: 1,
selected: new Day(),
data: new Month(),
holidays: new Array<Holiday>(),
holidayMonth: 0
})
function buildDay(d: Solar) {
const ymd = d.toYmd()
const lunar = d.getLunar()
const day = new Day()
day.month = d.getMonth()
day.day = d.getDay()
day.lunarMonth = lunar.getMonthInChinese()
day.lunarDay = lunar.getDayInChinese()
day.yearGanZhi = lunar.getYearInGanZhi()
day.yearShengXiao = lunar.getYearShengXiao()
day.monthGanZhi = lunar.getMonthInGanZhi()
day.dayGanZhi = lunar.getDayInGanZhi()
day.ymd = ymd
day.isToday = ymd == now.toYmd()
day.isSelected = ymd == state.selected.ymd
if (day.isToday && state.selected.day === 0) {
state.selected = day
}
const solarFestivals = d.getFestivals()
solarFestivals.forEach(f => {
day.festivals.push(f)
})
d.getOtherFestivals().forEach(f => {
day.festivals.push(f)
})
lunar.getFestivals().forEach(f => {
day.festivals.push(f)
})
lunar.getOtherFestivals().forEach(f => {
day.festivals.push(f)
})
let rest = false
if (d.getWeek() === 6 || d.getWeek() === 0) {
rest = true
}
const holiday = HolidayUtil.getHoliday(ymd)
if (holiday) {
rest = !holiday.isWork()
}
day.isHoliday = !!holiday
day.isRest = rest
day.yi = lunar.getDayYi()
day.ji = lunar.getDayJi()
let desc = lunar.getDayInChinese()
const jq = lunar.getJieQi()
if (jq) {
desc = jq
} else if (lunar.getDay() === 1) {
desc = lunar.getMonthInChinese() + '月'
} else if (solarFestivals.length > 0) {
const f = solarFestivals[0]
if (f.length < 4) {
desc = f
}
}
day.desc = desc
return day
}
function render() {
const month = new Month()
const weeks: SolarWeek[] = []
const solarWeeks = SolarMonth.fromYm(parseInt(state.year + '', 10), parseInt(state.month + '', 10)).getWeeks(state.weekStart)
solarWeeks.forEach(w => {
weeks.push(w)
})
while (weeks.length < 6) {
weeks.push(weeks[weeks.length - 1].next(1, false))
}
weeks.forEach(w => {
const week = new Week()
const heads: string[] = []
w.getDays().forEach(d => {
heads.push(d.getWeekInChinese())
week.days.push(buildDay(d))
})
month.heads = heads
month.weeks.push(week)
})
state.data = month
const holidays: Holiday[] = []
HolidayUtil.getHolidays(state.year).forEach(h => {
const holiday = new Holiday()
holiday.name = h.getName()
holiday.month = parseInt(h.getTarget().substring(5, 7), 10)
const exists = holidays.some(a => {
return a.name == holiday.name
})
if (!exists) {
holidays.push(holiday)
}
})
state.holidays = holidays
}
function onSelect(day: Day) {
state.selected = day
}
function onBack() {
state.holidayMonth = 0
state.year = now.getYear()
state.month = now.getMonth()
state.selected = buildDay(now)
}
render()
watch(() => state.year, () => {
render()
})
watch(() => state.month, () => {
render()
})
watch(() => state.selected, () => {
render()
})
watch(() => state.holidayMonth, (newVal) => {
const month = parseInt(newVal + '', 10)
if (month > 0) {
state.month = month
render()
}
})
</script>
<template>
<div class="date-pop" @mousedown.stop="">
<div class="calendar">
<div class="container">
<div class="bar">
<div>
<input v-model="state.year">
</div>
<div>
<select v-model="state.month">
<option :value="i" v-for="i in 12">{{ i }}</option>
</select>
</div>
<div>
<select v-model="state.holidayMonth">
<option value="0">假期安排</option>
<option :value="h.month" v-for="h in state.holidays">{{ h.name }}</option>
</select>
</div>
<div>
<div class="button" @click="onBack">返回今天</div>
</div>
</div>
<ul class="head">
<li v-for="head in state.data.heads">{{ head }}</li>
</ul>
<ul class="body">
<li v-for="week in state.data.weeks">
<ol>
<li @click="onSelect(day)" v-for="day in week.days"
:class="{ today: day.isToday, selected: day.isSelected, other: day.month != state.month, rest: day.isRest, holiday: day.isHoliday }">
<div class="inner">
<b>{{ day.day }}</b>
<i>{{ day.desc }}</i>
<u v-if="day.isHoliday">{{ day.isRest ? '' : '' }}</u>
</div>
</li>
</ol>
</li>
</ul>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.date-pop {
position: absolute;
bottom: 0;
right: 0;
width: 450px;
height: 465px;
background-color: #fff; /* 更接近Win10的背景颜色 */
border: 1px solid #e5e5e5; /* 边框颜色调整 */
user-select: none;
box-sizing: border-box;
z-index: 100;
}
.calendar * {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.calendar {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
border-radius: 5px;
margin: 0;
// box-sizing: border-box;
// border: 2px solid #4E6EF2;
display: flex;
height: 465px;
overflow: hidden;
.container {
padding-top: 14px;
.bar {
position: relative;
display: flex;
height: 30px;
padding: 0 10px;
margin-bottom: 24px;
div {
position: relative;
flex: 1;
text-align: center;
}
div.button {
position: absolute;
right: 0;
width: 68px;
height: 30px;
line-height: 30px;
text-align: center;
background: #F5F5F6;
border-radius: 6px;
color: #333;
cursor: pointer;
font-size: 13px;
}
input,
select {
border: 1px solid #D7D9E0;
box-sizing: border-box;
padding: 7px;
border-radius: 6px;
line-height: 1;
cursor: pointer;
position: relative;
background: #FFFFFF;
width: 80px;
margin-right: 6px;
text-align: center;
}
select {
appearance: none;
}
}
ul,
ol {
list-style: none;
width: 448px;
}
ul.head {
li {
float: left;
width: 64px;
height: 36px;
font-size: 13px;
text-align: center;
}
}
ul.body {
ol {
li {
float: left;
width: 64px;
position: relative;
height: 60px;
padding: 2px;
cursor: pointer;
text-align: center;
div.inner {
padding: 4px;
border-radius: 6px;
border: 2px solid transparent;
b {
display: block;
font-weight: normal;
height: 22px;
font-size: 18px;
color: #000;
}
i {
display: block;
font-style: normal;
color: #333;
font-size: 12px;
}
u {
position: absolute;
text-decoration: none;
left: 7px;
top: 7px;
color: #626675;
font-size: 12px;
line-height: 12px;
}
}
}
li.other {
filter: alpha(opacity=40);
opacity: 0.4;
}
li:hover {
div.inner {
border: 2px solid #BDBFC8;
}
}
li.selected {
div.inner {
border: 2px solid #BDBFC8;
}
}
li.holiday {
div.inner {
background: #f5f5f6;
b {
text-align: center;
}
}
}
li.holiday.rest {
div.inner {
background: #FDE3E4;
}
}
li.rest {
div.inner {
b {
color: #F73131;
text-align: center;
}
u {
color: #F73131;
}
}
}
li.today {
div.inner {
border: 2px solid #4E6EF2 !important;
}
}
}
}
}
.side {
background: #4E6EF2;
width: 112px;
color: #fff;
.ymd {
line-height: 45px;
font-size: 13px;
}
.day {
position: relative;
width: 80px;
height: 80px;
margin: 0 auto;
line-height: 80px;
font-size: 52px;
background: rgba(255, 255, 255, 0.5);
border-radius: 12px;
text-align: center;
}
.lunar {
margin-top: 6px;
div {
font-size: 13px;
line-height: 21px;
text-align: center;
}
}
.festival {
position: relative;
margin-top: 13px;
padding-left: 22px;
padding-right: 14px;
text-align: justify;
color: #FFF;
font-size: 12px;
line-height: 16px;
}
.festival::before {
content: '';
position: absolute;
top: 6px;
left: 16px;
width: 3px;
height: 3px;
background: #fff;
border-radius: 50%;
}
.yiji {
position: relative;
margin-top: 12px;
padding-top: 12px;
background: rgba(255, 255, 255, 0.15);
height: 80%;
text-align: center;
.yi {
float: left;
width: 50%;
div {
font-size: 12px;
line-height: 20px;
}
}
.ji {
float: right;
width: 50%;
div {
font-size: 12px;
line-height: 20px;
}
}
b {
display: block;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
margin: 0 auto;
font-style: normal;
font-size: 24px;
color: #fff;
}
}
}
}
</style>

18
frontend/src/system/index.ts

@ -238,13 +238,17 @@ export class System {
if (!system) return;
const fileUrl = getFileUrl();
if (!fileUrl) return;
fetchGet(`${fileUrl}/desktop`).then(res => res.json()).then(res => {
if (res && res.code == 0) {
system._rootState.apps.splice(0, system._rootState.apps.length, ...res.data.apps);
system._rootState.menulist.splice(0, system._rootState.menulist.length, ...res.data.menulist);
}
})
try {
fetchGet(`${fileUrl}/desktop`).then(res => res.json()).then(res => {
if (res && res.code == 0) {
system._rootState.apps.splice(0, system._rootState.apps.length, ...res.data.apps);
system._rootState.menulist.splice(0, system._rootState.menulist.length, ...res.data.menulist);
}
})
} catch (error) {
console.log(error)
}
}

2
frontend/src/system/initBuiltin.ts

@ -213,6 +213,6 @@ export function initBuiltinFileOpener(system: System) {
const dateTimeT = new Tray({
component: "DateTime",
});
dateTimeT.setContextMenu("DateTimePop", 320, 700);
dateTimeT.setContextMenu("DateTimeShow", 450, 465);
}

33
frontend/src/system/window/BrowserWindow.ts

@ -16,10 +16,10 @@ export interface BrowserWindowConstructorOptions {
content?: BrowserWindowContent;
config?: any;
icon: string;
path?:string;
url?:string;
ext?:Array<string> | undefined;
eventType?:string | undefined;
path?: string;
url?: string;
ext?: Array<string> | undefined;
eventType?: string | undefined;
width: number;
height: number;
x: number;
@ -75,10 +75,10 @@ class BrowserWindow {
id: number;
children: Array<BrowserWindow> = [];
content?: ReturnType<typeof defineComponent> | string;
path:string|undefined;
url:string|undefined;
ext?:Array<string> | undefined;
eventType?:string | undefined;
path: string | undefined;
url: string | undefined;
ext?: Array<string> | undefined;
eventType?: string | undefined;
config: any;
eventer: Eventer = new Eventer();
constructor(option?: BrowserWindowOption) {
@ -89,14 +89,15 @@ class BrowserWindow {
this.ext = this._option.ext;
this.eventType = this._option.eventType;
//console.log(this._option.content)
if (typeof this._option.content === 'string') {
//this.content = markRaw(this._option.content);
this.content = this._option.content;
}
else {
this.content = markRaw(this._option.content);
//this.content = this._option.content;
if (this._option.content) {
if (typeof this._option.content === 'string') {
//this.content = markRaw(this._option.content);
this.content = this._option.content;
}
else {
this.content = markRaw(this._option.content);
//this.content = this._option.content;
}
}
const rootState = useSystem()._rootState;

2
frontend/src/system/window/Dialog.ts

@ -10,7 +10,7 @@ class Dialog {
title?: string;
buttons?: string[];
}) {
console.log('弹窗',option)
//console.log('弹窗',option)
const opt = Object.assign(
{
message: '',

2
packages/word/src/plugins/docx/exportDocx.ts

@ -224,7 +224,7 @@ export default function (command: Command) {
})
if(isFile){
Packer.toBlob(doc).then(blob => {
saveAs(blob, `${fileName}.docx`)
saveAs(blob, `${fileName}`)
})
}else{
Packer.toBase64String(doc).then((base64:any) => {

107
packages/word/src/plugins/docx/importDocx.ts

@ -1,6 +1,7 @@
import { Command } from '../../editor'
import mammoth from 'mammoth'
import _ from 'lodash'
declare module '../../editor' {
interface Command {
executeImportDocx(options: IImportDocxOption): void
@ -10,27 +11,104 @@ declare module '../../editor' {
export interface IImportDocxOption {
arrayBuffer: ArrayBuffer
}
function transformElement(element:any) {
function transformElement(element: any) {
if (element.children) {
const children = _.map(element.children, transformElement);
element = {...element, children: children};
const children = _.map(element.children, transformElement);
element = { ...element, children: children };
}
if (element.type === "paragraph") {
element = transformParagraph(element);
element = transformParagraph(element);
}
if (element.type === "table") {
element = transformTable(element);
}
if (element.type === "hyperlink") {
element = transformHyperlink(element);
}
// if (element.type === "listItem") {
// element = transformListItem(element);
// }
return element;
}
function transformParagraph(element:any) {
function transformParagraph(element: any) {
if (element.alignment === "center" && !element.styleId) {
return {...element, styleId: "Heading2"};
} else {
return element;
return { ...element, styleId: "Heading2" };
}
// 处理换行符
if (element.text) {
element.text = element.text.replace(/\n/g, '<br>');
}
// 保留居中 h1 的样式
if (element.styleId === "Heading1" && element.alignment === "center") {
return { ...element, alignment: "center" };
}
if (element.styleId === "Heading2" && element.alignment === "center") {
return { ...element, alignment: "center" };
}
if (element.styleId === "Heading3" && element.alignment === "center") {
return { ...element, alignment: "center" };
}
return element;
}
function transformTable(element: any) {
const rows = element.children.map((row: any) => {
const cells = row.children.map((cell: any) => {
let cellStyle = '';
// 处理单元格的背景色
if (cell.backgroundColor) {
cellStyle += `background-color: ${cell.backgroundColor}; `;
}
// 处理单元格的文字对齐方式
if (cell.alignment) {
cellStyle += `text-align: ${cell.alignment}; `;
}
// 处理单元格的边框
if (cell.border) {
cellStyle += `border: ${cell.border}; `;
}
return `<td style="${cellStyle}">${cell.text}</td>`;
});
return `<tr>${cells.join('')}</tr>`;
});
// 处理表格的整体样式
let tableStyle = '';
if (element.border) {
tableStyle += `border-collapse: collapse; border: ${element.border}; `;
}
if (element.backgroundColor) {
tableStyle += `background-color: ${element.backgroundColor}; `;
}
return { ...element, text: `<table style="${tableStyle}">${rows.join('')}</table>` };
}
function transformHyperlink(element: any) {
return { ...element, text: `<a href="${element.href}">${element.text}</a>` };
}
const waitImgWH = (value: string) => new Promise((resolve) => {
const dom = document.createElement('div')
dom.innerHTML = value
setTimeout(() => {
resolve(dom.innerHTML)
}, 0)
})
export default function (command: Command) {
return async function (options: IImportDocxOption) {
const { arrayBuffer } = options
@ -46,6 +124,9 @@ export default function (command: Command) {
"p[style-name='Heading 4'] => h4:fresh",
"p[style-name='Heading 5'] => h5:fresh",
"p[style-name='Heading 6'] => h6:fresh",
"p[style-name='Section Title'] => h1:fresh\n",
"p[style-name='Subsection Title'] => h2:fresh",
"p[style-name='Equation'] => span.math-display:fresh",
"p[style-name='Title'] => h1:fresh",
"p[style-name='Subtitle'] => h2:fresh",
"p[style-name='Quote'] => blockquote",
@ -59,7 +140,8 @@ export default function (command: Command) {
"i => em",
"u => u",
"strike => del",
"comment-reference => sup"
"comment-reference => sup",
"a => a"
],
convertImage: mammoth.images.imgElement(function (image) {
return image.read("base64").then(function (imageBuffer) {
@ -68,9 +150,10 @@ export default function (command: Command) {
};
});
})
})
});
const value: any = result.value.includes('<img') ? await waitImgWH(result.value) : result.value
command.executeSetHTML({
main: result.value
main: value
})
}
}
}
Loading…
Cancel
Save