You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

369 lines
8.0 KiB

11 months ago
10 months ago
11 months ago
11 months ago
10 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
10 months ago
10 months ago
10 months ago
11 months ago
10 months ago
11 months ago
11 months ago
10 months ago
10 months ago
10 months ago
11 months ago
10 months ago
11 months ago
  1. <template>
  2. <div class="paper-selector" :class="{ 'horizontal-mode': horizontalMode }">
  3. <!-- 垂直模式的标题 -->
  4. <div v-if="!horizontalMode" class="selector-header">
  5. <h4>纸张设置</h4>
  6. <el-tooltip content="选择合适的纸张尺寸以获得最佳设计效果" placement="top">
  7. <i class="el-icon-info"></i>
  8. </el-tooltip>
  9. </div>
  10. <!-- 纸张类型选择 -->
  11. <div class="paper-type-select">
  12. <el-select
  13. :value="normalizedSelectedPaper"
  14. @change="handlePaperChange"
  15. placeholder="选择纸张类型"
  16. size="small"
  17. :loading="loading"
  18. :style="horizontalMode ? 'width: 120px;' : 'width: 100%;'"
  19. filterable
  20. >
  21. <el-option
  22. v-for="option in paperOptions"
  23. :key="option.value"
  24. :label="option.label"
  25. :value="option.value"
  26. >
  27. <span style="float: left">{{ option.label }}</span>
  28. <span v-if="!horizontalMode" style="float: right; color: #8492a6; font-size: 12px">
  29. {{ option.description }}
  30. </span>
  31. </el-option>
  32. </el-select>
  33. </div>
  34. </div>
  35. </template>
  36. <script>
  37. import { getPaperOptions, getCanvasSize, PAPER_SIZES } from '@/utils/paperConfig.js'
  38. import dynamicPaperConfig from '@/utils/paperConfigDynamic.js'
  39. export default {
  40. name: 'PaperSelector',
  41. props: {
  42. selectedPaper: {
  43. type: [String, Number], // 支持字符串(旧格式)和数字(新的纸张ID)
  44. default: null
  45. },
  46. orientation: {
  47. type: String,
  48. default: 'portrait'
  49. },
  50. customSize: {
  51. type: Object,
  52. default: () => ({ width: 600, height: 400 })
  53. },
  54. horizontalMode: {
  55. type: Boolean,
  56. default: false
  57. }
  58. },
  59. emits: ['paper-change', 'custom-size-change'],
  60. data() {
  61. return {
  62. dynamicPapers: [], // 动态纸张列表
  63. loading: false,
  64. defaultPaperId: null // 默认纸张ID
  65. }
  66. },
  67. async created() {
  68. await this.loadPapers()
  69. },
  70. watch: {
  71. orientation: {
  72. handler(newVal, oldVal) {
  73. if (newVal !== oldVal) {
  74. // 方向改变时,给用户一个视觉反馈
  75. this.$nextTick(() => {
  76. const orientationText = newVal === 'portrait' ? '纵向' : '横向'
  77. console.log(`打印方向已切换为: ${orientationText}`, {
  78. orientation: newVal,
  79. currentSize: this.currentSize
  80. })
  81. })
  82. }
  83. },
  84. immediate: false
  85. }
  86. },
  87. computed: {
  88. paperOptions() {
  89. return this.dynamicPapers.map(paper => ({
  90. value: paper.id,
  91. label: paper.name,
  92. description: `${paper.widthMm}×${paper.heightMm}mm`,
  93. paper: paper
  94. }))
  95. },
  96. // 确保选中的纸张ID是正确的类型
  97. normalizedSelectedPaper() {
  98. if (this.selectedPaper === null || this.selectedPaper === undefined) {
  99. return null
  100. }
  101. // 如果是字符串类型的数字,转换为数字
  102. if (typeof this.selectedPaper === 'string' && /^\d+$/.test(this.selectedPaper)) {
  103. return parseInt(this.selectedPaper, 10)
  104. }
  105. return this.selectedPaper
  106. },
  107. orientationText() {
  108. return this.orientation === 'portrait' ? '纵向' : '横向'
  109. },
  110. quickSizes() {
  111. // 从动态纸张中选择常用尺寸
  112. return this.dynamicPapers.slice(0, 8).map(paper => ({
  113. value: paper.id,
  114. label: paper.name.replace('英寸', '').replace('×', '×')
  115. }))
  116. },
  117. // 方向图标
  118. orientationIcon() {
  119. return this.orientation === 'portrait' ? 'el-icon-mobile-phone' : 'el-icon-monitor'
  120. },
  121. },
  122. methods: {
  123. // 加载纸张数据
  124. async loadPapers() {
  125. try {
  126. this.loading = true
  127. await dynamicPaperConfig.loadPapers()
  128. this.dynamicPapers = dynamicPaperConfig.getActivePapers()
  129. // 设置默认纸张ID
  130. if (this.dynamicPapers.length > 0 && !this.defaultPaperId) {
  131. // 优先选择4×2英寸作为默认纸张
  132. const defaultPaper = this.dynamicPapers.find(p => p.name.includes('4×2')) || this.dynamicPapers[0]
  133. this.defaultPaperId = defaultPaper.id
  134. }
  135. console.log('纸张选择器加载完成:', this.dynamicPapers.length, '个纸张')
  136. } catch (error) {
  137. console.error('加载纸张数据失败:', error)
  138. this.$message.error('加载纸张数据失败')
  139. } finally {
  140. this.loading = false
  141. }
  142. },
  143. handlePaperChange(paperId) {
  144. localStorage.setItem('paperId',paperId);
  145. this.$emit('paper-change', paperId)
  146. },
  147. handleOrientationChange(orientation) {
  148. // 通过父组件处理方向变化
  149. this.$emit('orientation-change', orientation)
  150. },
  151. // 刷新纸张数据
  152. async refreshPapers() {
  153. await this.loadPapers()
  154. },
  155. // 获取当前选择的纸张对象
  156. getCurrentPaper() {
  157. const paperId = this.normalizedSelectedPaper
  158. if (typeof paperId === 'number') {
  159. return this.dynamicPapers.find(p => p.id === paperId)
  160. }
  161. return null
  162. }
  163. }
  164. }
  165. </script>
  166. <style scoped>
  167. .paper-selector {
  168. padding: 12px;
  169. background: white;
  170. border-radius: 4px;
  171. border: 1px solid #e8e8e8;
  172. margin-bottom: 12px;
  173. }
  174. .selector-header {
  175. display: flex;
  176. align-items: center;
  177. justify-content: space-between;
  178. margin-bottom: 8px;
  179. }
  180. .selector-header h4 {
  181. margin: 0;
  182. font-size: 13px;
  183. font-weight: 600;
  184. color: #333;
  185. }
  186. .selector-header i {
  187. color: #909399;
  188. cursor: help;
  189. font-size: 12px;
  190. }
  191. .paper-type-select {
  192. margin-bottom: 10px;
  193. }
  194. .custom-size {
  195. margin-bottom: 10px;
  196. padding: 8px;
  197. background: #f8f9fa;
  198. border-radius: 3px;
  199. }
  200. .size-inputs {
  201. display: flex;
  202. gap: 8px;
  203. }
  204. .input-group {
  205. flex: 1;
  206. display: flex;
  207. flex-direction: column;
  208. gap: 3px;
  209. }
  210. .input-group label {
  211. font-size: 11px;
  212. color: #666;
  213. font-weight: 500;
  214. }
  215. .canvas-info {
  216. margin-bottom: 10px;
  217. padding: 8px;
  218. background: #f0f9ff;
  219. border-radius: 3px;
  220. border-left: 2px solid #409eff;
  221. }
  222. .info-item {
  223. display: flex;
  224. justify-content: space-between;
  225. margin-bottom: 3px;
  226. font-size: 11px;
  227. }
  228. .info-item:last-child {
  229. margin-bottom: 0;
  230. }
  231. .info-item .label {
  232. color: #666;
  233. font-weight: 500;
  234. }
  235. .info-item .value {
  236. color: #333;
  237. font-weight: 600;
  238. }
  239. .info-item.description .value {
  240. color: #909399;
  241. font-weight: normal;
  242. font-style: italic;
  243. }
  244. .quick-sizes {
  245. border-top: 1px solid #e8e8e8;
  246. padding-top: 8px;
  247. }
  248. .quick-title {
  249. font-size: 11px;
  250. color: #666;
  251. margin-bottom: 6px;
  252. font-weight: 500;
  253. }
  254. .quick-buttons {
  255. display: flex;
  256. flex-wrap: wrap;
  257. }
  258. .quick-buttons .el-button {
  259. flex: 1;
  260. min-width: 0;
  261. font-size: 8px;
  262. padding: 4px 1px;
  263. height: 24px;
  264. line-height: 1;
  265. border-radius: 3px;
  266. transition: all 0.2s ease;
  267. }
  268. .quick-buttons .el-button--mini {
  269. height: 24px;
  270. padding: 4px 1px;
  271. }
  272. .paper-preview {
  273. margin-bottom: 10px;
  274. padding: 8px;
  275. background: #f8f9fa;
  276. border-radius: 3px;
  277. text-align: center;
  278. }
  279. .preview-container {
  280. display: flex;
  281. justify-content: center;
  282. align-items: center;
  283. min-height: 60px;
  284. }
  285. .preview-paper {
  286. border: 2px solid #409eff;
  287. border-radius: 2px;
  288. display: flex;
  289. align-items: center;
  290. justify-content: center;
  291. position: relative;
  292. transition: all 0.3s ease;
  293. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  294. }
  295. .preview-paper.landscape {
  296. border-color: #67c23a;
  297. }
  298. .preview-label {
  299. font-size: 9px;
  300. color: #333;
  301. font-weight: 600;
  302. text-align: center;
  303. line-height: 1.2;
  304. padding: 2px;
  305. background: rgba(255, 255, 255, 0.8);
  306. border-radius: 2px;
  307. }
  308. /* 水平模式样式 */
  309. .paper-selector.horizontal-mode {
  310. display: flex;
  311. align-items: center;
  312. gap: 15px;
  313. padding: 0;
  314. background: transparent;
  315. border: none;
  316. margin-bottom: 0;
  317. }
  318. .horizontal-mode .paper-type-select {
  319. margin-bottom: 0;
  320. }
  321. .horizontal-mode .orientation-select.horizontal-inline {
  322. margin-bottom: 0;
  323. }
  324. .horizontal-mode .custom-size,
  325. .horizontal-mode .canvas-info,
  326. .horizontal-mode .quick-sizes,
  327. .horizontal-mode .paper-preview {
  328. display: none; /* 水平模式下隐藏这些详细信息 */
  329. }
  330. </style>