|
@@ -0,0 +1,256 @@
|
|
|
+<template>
|
|
|
+ <div class="extract-page-setting-popup" v-if="show">
|
|
|
+ <Dialog :show="show" :dialogName="dialogName" :close="false">
|
|
|
+ <template #header>
|
|
|
+ <p>Extract</p>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <p class="title">{{ $t('documentEditor.dialog.pageRange') }}</p>
|
|
|
+
|
|
|
+ <div class="container">
|
|
|
+ <div class="select-content">
|
|
|
+ <div @click="pageRange = 'all'" class="option"><RadioBtnSel v-if="pageRange === 'all'" /><RadioBtnDis v-else />{{ $t('documentEditor.dialog.allPages') }}</div>
|
|
|
+ <div @click="pageRange = 'odd'" class="option"><RadioBtnSel v-if="pageRange === 'odd'" /><RadioBtnDis v-else />{{ $t('documentEditor.dialog.oddPage') }}</div>
|
|
|
+ <div @click="pageRange = 'even'" class="option"><RadioBtnSel v-if="pageRange === 'even'" /><RadioBtnDis v-else />{{ $t('documentEditor.dialog.evenPage') }}</div>
|
|
|
+ <div @click="pageRange = 'custom'" class="option custom-page">
|
|
|
+ <RadioBtnSel v-if="pageRange === 'custom'" /><RadioBtnDis v-else />{{ $t('documentEditor.dialog.page') }}
|
|
|
+ <div class="addition">
|
|
|
+ <input type="text" v-model="customRange" :placeholder="$t('documentEditor.dialog.pageTip')" @blur="validateCustomRange">
|
|
|
+ <span>/ {{ totalPages }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="check-content">
|
|
|
+ <div class="check-box" @click="separateFile = !separateFile">
|
|
|
+ <div class="check" :class="{'active': separateFile}"><Checkbox v-show="separateFile" /></div>
|
|
|
+ <span>{{ $t('documentEditor.eachPage') }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="check-box" @click="deleteAfter = !deleteAfter">
|
|
|
+ <div class="check" :class="{'active': deleteAfter}"><Checkbox v-show="deleteAfter" /></div>
|
|
|
+ <span>{{ $t('documentEditor.deleteAfter') }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="rect-button white" @click="closeDialog">{{ $t('cancel') }}</div>
|
|
|
+ <div class="rect-button blue" :class="{ 'disabled': pageRange === 'pdf' && (!inputFile || (pageRange === 'custom' && !validCustomRange)) }" @click="confirm">{{ $t('documentEditor.extract') }}</div>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, watch } from 'vue'
|
|
|
+import { useViewerStore } from '@/stores/modules/viewer'
|
|
|
+
|
|
|
+const props = defineProps([ 'selectedPageList', 'totalPages' ])
|
|
|
+const emits = defineEmits(['extractPage'])
|
|
|
+
|
|
|
+const useViewer = useViewerStore()
|
|
|
+
|
|
|
+const dialogName = 'extractPageSettingDialog'
|
|
|
+const show = computed(() => useViewer.isElementOpen(dialogName))
|
|
|
+
|
|
|
+const pageRange = ref('custom')
|
|
|
+const customRange = ref('')
|
|
|
+const validCustomRange = ref('')
|
|
|
+const separateFile = ref(false)
|
|
|
+const deleteAfter = ref(false)
|
|
|
+let initialRange = ''
|
|
|
+
|
|
|
+watch(() => show.value, (newVal, oldVal) => {
|
|
|
+ if (newVal) {
|
|
|
+ const selectedPageStr = props.selectedPageList.map(function(num) {
|
|
|
+ return num + 1
|
|
|
+ }).join(',')
|
|
|
+
|
|
|
+ initialRange = formatText(selectedPageStr)
|
|
|
+ customRange.value = validCustomRange.value = initialRange
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 关闭弹窗
|
|
|
+const closeDialog = () => {
|
|
|
+ useViewer.closeElement(dialogName)
|
|
|
+
|
|
|
+ pageRange.value = 'custom'
|
|
|
+}
|
|
|
+
|
|
|
+// 确认
|
|
|
+const confirm = async () => {
|
|
|
+ const data = {
|
|
|
+ range: pageRange.value === 'custom' ? customRange.value : pageRange.value,
|
|
|
+ separateFile: separateFile.value,
|
|
|
+ deleteAfter: deleteAfter.value
|
|
|
+ }
|
|
|
+ emits('extractPage', data)
|
|
|
+ closeDialog()
|
|
|
+}
|
|
|
+
|
|
|
+// 输入自定义页面范围校验 格式化
|
|
|
+const validateCustomRange = () => {
|
|
|
+ validCustomRange.value = formatText(customRange.value)
|
|
|
+ customRange.value = validCustomRange.value
|
|
|
+}
|
|
|
+const formatText = (inputText) => {
|
|
|
+ const max = props.totalPages
|
|
|
+ const text = inputText.replace(/\s/g, '')
|
|
|
+ const matches = text.match(/\d+-\d+|\d+|\d+/g)
|
|
|
+
|
|
|
+ if (matches) {
|
|
|
+ const sortedNums = matches
|
|
|
+ .flatMap(match => {
|
|
|
+ if (match.includes('-')) {
|
|
|
+ const [start, end] = match.split('-')
|
|
|
+ const smallest = Math.min(start, end)
|
|
|
+ const largest = Math.min(Math.max(start, end), max)
|
|
|
+ return Array.from({ length: largest - smallest + 1 }, (_, i) =>
|
|
|
+ String(Number(smallest) + i)
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ return Math.min(match, max)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .sort((a, b) => a - b)
|
|
|
+
|
|
|
+ const formattedText = []
|
|
|
+
|
|
|
+ let start = sortedNums[0]
|
|
|
+ let prev = sortedNums[0]
|
|
|
+
|
|
|
+ for (let i = 1; i < sortedNums.length; i++) {
|
|
|
+ const current = sortedNums[i]
|
|
|
+
|
|
|
+ const prevNum = Number(prev)
|
|
|
+ const currentNum = Number(current)
|
|
|
+
|
|
|
+ if (currentNum - prevNum > 1) {
|
|
|
+ formattedText.push(formatRange(start, prev))
|
|
|
+ start = current
|
|
|
+ }
|
|
|
+ prev = current
|
|
|
+ }
|
|
|
+ formattedText.push(formatRange(start, prev))
|
|
|
+ return formattedText.join(', ')
|
|
|
+ }
|
|
|
+ return initialRange
|
|
|
+}
|
|
|
+const formatRange = (start, end) => {
|
|
|
+ return (start === end) ? start.toString() : `${start}-${end}`
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.extract-page-setting-popup {
|
|
|
+ .dialog-container {
|
|
|
+ width: 460px;
|
|
|
+ box-shadow: 0px 4px 32px 0px rgba(129, 149, 200, 0.32);
|
|
|
+
|
|
|
+ main {
|
|
|
+ margin-top: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 700;
|
|
|
+ line-height: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .container {
|
|
|
+ margin-top: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ padding: 8px 16px 16px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #F2F3F5;
|
|
|
+
|
|
|
+ .select-content .option:not(:first-child) {
|
|
|
+ margin-top: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .addition {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ span {
|
|
|
+ text-wrap: nowrap;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ input {
|
|
|
+ padding: 0 20px 0 8px;
|
|
|
+ width: 100%;
|
|
|
+ height: 24px;
|
|
|
+ background: var(--c-right-side-content-fillbox-bg);
|
|
|
+ border: 1px solid var(--c-right-side-content-fillbox-border);
|
|
|
+ border-radius: 1px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ input[type="text"]:focus {
|
|
|
+ border-color: #0078D7;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .option.custom-page {
|
|
|
+ padding: 0;
|
|
|
+
|
|
|
+ .addition {
|
|
|
+ flex: 1;
|
|
|
+ margin-left: 20px;
|
|
|
+
|
|
|
+ span {
|
|
|
+ margin-left: 8px;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .check-content {
|
|
|
+ padding: 0 16px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-start;
|
|
|
+
|
|
|
+ .check-box {
|
|
|
+ padding: 5px 0;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ & + .check-box {
|
|
|
+ margin-top: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .check {
|
|
|
+ margin-right: 4px;
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ background: var(--c-right-side-content-fillbox-bg);
|
|
|
+ border: 1px solid var(--c-right-side-content-fillbox-border);
|
|
|
+ border-radius: 1px;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ svg {
|
|
|
+ vertical-align: top;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ span {
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|