index.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <template>
  2. <div class="go-canvas-setting">
  3. <n-form inline :label-width="45" size="small" label-placement="left">
  4. <n-form-item label="宽度">
  5. <!-- 尺寸选择 -->
  6. <n-input-number
  7. size="small"
  8. v-model:value="canvasConfig.width"
  9. :disabled="editCanvas.lockScale"
  10. :validator="validator"
  11. @update:value="changeSizeHandle"
  12. ></n-input-number>
  13. </n-form-item>
  14. <n-form-item label="高度">
  15. <n-input-number
  16. size="small"
  17. v-model:value="canvasConfig.height"
  18. :disabled="editCanvas.lockScale"
  19. :validator="validator"
  20. @update:value="changeSizeHandle"
  21. ></n-input-number>
  22. </n-form-item>
  23. </n-form>
  24. <n-card class="upload-box">
  25. <n-upload
  26. v-model:file-list="uploadFileListRef"
  27. :show-file-list="false"
  28. :customRequest="customRequest"
  29. :onBeforeUpload="beforeUploadHandle"
  30. >
  31. <n-upload-dragger>
  32. <img v-if="canvasConfig.backgroundImage" class="upload-show" :src="canvasConfig.backgroundImage" alt="背景" />
  33. <div class="upload-img" v-show="!canvasConfig.backgroundImage">
  34. <img src="@/assets/images/canvas/noImage.png" />
  35. <n-text class="upload-desc" depth="3">
  36. 背景图需小于 {{ backgroundImageSize }}M ,格式为 png/jpg/gif 的文件
  37. </n-text>
  38. </div>
  39. </n-upload-dragger>
  40. </n-upload>
  41. </n-card>
  42. <n-space vertical :size="12">
  43. <n-space>
  44. <n-text>背景颜色</n-text>
  45. <div class="picker-height">
  46. <n-color-picker
  47. v-if="!switchSelectColorLoading"
  48. size="small"
  49. style="width: 250px"
  50. v-model:value="canvasConfig.background"
  51. :showPreview="true"
  52. :swatches="swatchesColors"
  53. ></n-color-picker>
  54. </div>
  55. </n-space>
  56. <n-space>
  57. <n-text>应用类型</n-text>
  58. <n-select
  59. size="small"
  60. style="width: 250px"
  61. v-model:value="selectColorValue"
  62. :disabled="!canvasConfig.backgroundImage"
  63. :options="selectColorOptions"
  64. @update:value="selectColorValueHandle"
  65. />
  66. </n-space>
  67. <n-space>
  68. <n-text>背景控制</n-text>
  69. <n-button class="clear-btn" size="small" :disabled="!canvasConfig.backgroundImage" @click="clearImage">
  70. 清除背景
  71. </n-button>
  72. <n-button class="clear-btn" size="small" :disabled="!canvasConfig.background" @click="clearColor">
  73. 清除颜色
  74. </n-button>
  75. </n-space>
  76. <n-space>
  77. <n-text>预览方式</n-text>
  78. <n-button-group>
  79. <n-button
  80. v-for="item in previewTypeList"
  81. :key="item.key"
  82. :type="canvasConfig.previewScaleType === item.key ? 'primary' : 'tertiary'"
  83. ghost
  84. size="small"
  85. @click="selectPreviewType(item.key)"
  86. >
  87. <n-tooltip :show-arrow="false" trigger="hover">
  88. <template #trigger>
  89. <n-icon class="select-preview-icon" size="18">
  90. <component :is="item.icon"></component>
  91. </n-icon>
  92. </template>
  93. {{ item.desc }}
  94. </n-tooltip>
  95. </n-button>
  96. </n-button-group>
  97. </n-space>
  98. </n-space>
  99. <!-- 滤镜 -->
  100. <styles-setting :isCanvas="true" :chartStyles="canvasConfig"></styles-setting>
  101. <n-divider style="margin: 10px 0"></n-divider>
  102. <!-- 主题选择和全局配置 -->
  103. <n-tabs class="tabs-box" size="small" type="segment">
  104. <n-tab-pane
  105. v-for="item in globalTabList"
  106. :key="item.key"
  107. :name="item.key"
  108. size="small"
  109. display-directive="show:lazy"
  110. >
  111. <template #tab>
  112. <n-space>
  113. <span>{{ item.title }}</span>
  114. <n-icon size="16" class="icon-position">
  115. <component :is="item.icon"></component>
  116. </n-icon>
  117. </n-space>
  118. </template>
  119. <component :is="item.render"></component>
  120. </n-tab-pane>
  121. </n-tabs>
  122. </div>
  123. </template>
  124. <script setup lang="ts">
  125. import { ref, nextTick, watch } from 'vue'
  126. import { backgroundImageSize } from '@/settings/designSetting'
  127. import { FileTypeEnum } from '@/enums/fileTypeEnum'
  128. import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  129. import { EditCanvasConfigEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
  130. import { StylesSetting } from '@/components/Pages/ChartItemSetting'
  131. import { UploadCustomRequestOptions } from 'naive-ui'
  132. import { fileToUrl, loadAsyncComponent } from '@/utils'
  133. import { PreviewScaleEnum } from '@/enums/styleEnum'
  134. import { icon } from '@/plugins'
  135. const { ColorPaletteIcon } = icon.ionicons5
  136. const { ScaleIcon, FitToScreenIcon, FitToHeightIcon, FitToWidthIcon } = icon.carbon
  137. const chartEditStore = useChartEditStore()
  138. const canvasConfig = chartEditStore.getEditCanvasConfig
  139. const editCanvas = chartEditStore.getEditCanvas
  140. const uploadFileListRef = ref()
  141. const switchSelectColorLoading = ref(false)
  142. const selectColorValue = ref(0)
  143. const ChartThemeColor = loadAsyncComponent(() => import('./components/ChartThemeColor/index.vue'))
  144. // 默认应用类型
  145. const selectColorOptions = [
  146. {
  147. label: '应用颜色',
  148. value: 0
  149. },
  150. {
  151. label: '应用背景',
  152. value: 1
  153. }
  154. ]
  155. // 默认展示颜色列表
  156. const swatchesColors = ['#232324', '#2a2a2b', '#313132', '#373739', '#757575', '#e0e0e0', '#eeeeee', '#fafafa']
  157. const globalTabList = [
  158. {
  159. key: 'ChartTheme',
  160. title: '主题颜色',
  161. icon: ColorPaletteIcon,
  162. render: ChartThemeColor
  163. }
  164. ]
  165. const previewTypeList = [
  166. {
  167. key: PreviewScaleEnum.FIT,
  168. title: '自适应',
  169. icon: ScaleIcon,
  170. desc: '自适应比例展示,页面会有留白'
  171. },
  172. {
  173. key: PreviewScaleEnum.SCROLL_Y,
  174. title: 'Y轴滚动',
  175. icon: FitToWidthIcon,
  176. desc: 'X轴铺满,Y轴自适应滚动'
  177. },
  178. {
  179. key: PreviewScaleEnum.SCROLL_X,
  180. title: 'X轴滚动',
  181. icon: FitToHeightIcon,
  182. desc: 'Y轴铺满,X轴自适应滚动'
  183. },
  184. {
  185. key: PreviewScaleEnum.FULL,
  186. title: '铺满',
  187. icon: FitToScreenIcon,
  188. desc: '强行拉伸画面,填充所有视图'
  189. }
  190. ]
  191. watch(
  192. () => canvasConfig.selectColor,
  193. newValue => {
  194. selectColorValue.value = newValue ? 0 : 1
  195. },
  196. {
  197. immediate: true
  198. }
  199. )
  200. // 画布尺寸规则
  201. const validator = (x: number) => x > 50
  202. // 修改尺寸
  203. const changeSizeHandle = () => {
  204. chartEditStore.computedScale()
  205. }
  206. // 上传图片前置处理
  207. //@ts-ignore
  208. const beforeUploadHandle = async ({ file }) => {
  209. uploadFileListRef.value = []
  210. const type = file.file.type
  211. const size = file.file.size
  212. if (size > 1024 * 1024 * backgroundImageSize) {
  213. window['$message'].warning(`图片超出 ${backgroundImageSize}M 限制,请重新上传!`)
  214. return false
  215. }
  216. if (type !== FileTypeEnum.PNG && type !== FileTypeEnum.JPEG && type !== FileTypeEnum.GIF) {
  217. window['$message'].warning('文件格式不符合,请重新上传!')
  218. return false
  219. }
  220. return true
  221. }
  222. // 应用颜色
  223. const selectColorValueHandle = (value: number) => {
  224. canvasConfig.selectColor = value == 0
  225. }
  226. // 清除背景
  227. const clearImage = () => {
  228. chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.BACKGROUND_IMAGE, undefined)
  229. chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.SELECT_COLOR, true)
  230. }
  231. // 启用/关闭 颜色(强制更新)
  232. const switchSelectColorHandle = () => {
  233. switchSelectColorLoading.value = true
  234. setTimeout(() => {
  235. switchSelectColorLoading.value = false
  236. })
  237. }
  238. // 清除颜色
  239. const clearColor = () => {
  240. chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.BACKGROUND, undefined)
  241. if (canvasConfig.backgroundImage) {
  242. chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.SELECT_COLOR, false)
  243. }
  244. switchSelectColorHandle()
  245. }
  246. // 自定义上传操作
  247. const customRequest = (options: UploadCustomRequestOptions) => {
  248. const { file } = options
  249. nextTick(() => {
  250. if (file.file) {
  251. const ImageUrl = fileToUrl(file.file)
  252. chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.BACKGROUND_IMAGE, ImageUrl)
  253. chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.SELECT_COLOR, false)
  254. } else {
  255. window['$message'].error('添加图片失败,请稍后重试!')
  256. }
  257. })
  258. }
  259. // 选择预览方式
  260. const selectPreviewType = (key: PreviewScaleEnum) => {
  261. chartEditStore.setEditCanvasConfig(EditCanvasConfigEnum.PREVIEW_SCALE_TYPE, key)
  262. }
  263. </script>
  264. <style lang="scss" scoped>
  265. $uploadWidth: 326px;
  266. $uploadHeight: 193px;
  267. @include go(canvas-setting) {
  268. padding-top: 20px;
  269. .upload-box {
  270. cursor: pointer;
  271. margin-bottom: 20px;
  272. @include deep() {
  273. .n-card__content {
  274. padding: 0;
  275. overflow: hidden;
  276. }
  277. .n-upload-dragger {
  278. padding: 5px;
  279. width: $uploadWidth;
  280. }
  281. }
  282. .upload-show {
  283. width: -webkit-fill-available;
  284. height: $uploadHeight;
  285. border-radius: 5px;
  286. }
  287. .upload-img {
  288. display: flex;
  289. flex-direction: column;
  290. align-items: center;
  291. img {
  292. height: 150px;
  293. }
  294. .upload-desc {
  295. padding: 10px 0;
  296. }
  297. }
  298. }
  299. .icon-position {
  300. padding-top: 2px;
  301. }
  302. .picker-height {
  303. min-height: 35px;
  304. }
  305. .clear-btn {
  306. padding-left: 2.25em;
  307. padding-right: 2.25em;
  308. }
  309. .select-preview-icon {
  310. padding-right: .68em;
  311. padding-left: .68em;
  312. }
  313. .tabs-box {
  314. margin-top: 20px;
  315. }
  316. }
  317. </style>