@qxs-bns/components 0.0.29 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/package.json.mjs +1 -1
- package/es/src/data-chart/src/components/area.vue2.mjs +1 -1
- package/es/src/data-chart/src/components/area.vue2.mjs.map +1 -1
- package/es/src/data-chart/src/components/bar.vue.mjs +1 -1
- package/es/src/data-chart/src/components/bar.vue.mjs.map +1 -1
- package/es/src/data-chart/src/components/funnel.vue.mjs +1 -1
- package/es/src/data-chart/src/components/funnel.vue.mjs.map +1 -1
- package/es/src/data-chart/src/components/line.vue2.mjs +1 -1
- package/es/src/data-chart/src/components/line.vue2.mjs.map +1 -1
- package/es/src/data-chart/src/components/pie.vue.mjs +1 -1
- package/es/src/data-chart/src/components/pie.vue.mjs.map +1 -1
- package/es/src/data-chart/src/components/radar.vue.mjs +1 -1
- package/es/src/data-chart/src/components/radar.vue.mjs.map +1 -1
- package/es/src/data-chart/src/components/scatter-simple.vue.mjs +1 -1
- package/es/src/data-chart/src/components/scatter-simple.vue.mjs.map +1 -1
- package/es/src/data-chart/src/components/scatter.vue.mjs +1 -1
- package/es/src/data-chart/src/components/scatter.vue.mjs.map +1 -1
- package/es/src/data-chart/src/components/table.vue.mjs +1 -1
- package/es/src/data-chart/src/components/table.vue.mjs.map +1 -1
- package/es/src/data-chart/src/data-chart.vue.mjs +1 -1
- package/es/src/data-chart/src/data-chart.vue.mjs.map +1 -1
- package/es/src/data-chart/src/utils/useCharts.mjs +1 -1
- package/es/src/data-chart/src/utils/useCharts.mjs.map +1 -1
- package/es/src/file-upload/src/file-upload.vue.mjs +1 -1
- package/es/src/file-upload/src/file-upload.vue.mjs.map +1 -1
- package/es/src/fixed-action-bar/src/fixed-action-bar.vue.mjs +1 -1
- package/es/src/fixed-action-bar/src/fixed-action-bar.vue.mjs.map +1 -1
- package/es/src/image-upload/src/image-upload.vue.mjs +1 -1
- package/es/src/image-upload/src/image-upload.vue.mjs.map +1 -1
- package/es/src/photo-crop-tool/src/composables.mjs +1 -1
- package/es/src/photo-crop-tool/src/composables.mjs.map +1 -1
- package/es/src/photo-crop-tool/src/photo-crop-tool.vue.mjs +1 -1
- package/es/src/photo-crop-tool/src/photo-crop-tool.vue.mjs.map +1 -1
- package/es/src/subject-action/src/subject-action.vue.mjs +1 -1
- package/es/src/subject-action/src/subject-action.vue.mjs.map +1 -1
- package/es/src/subject-list/src/components/SubjectPageEnd.vue.mjs +1 -1
- package/es/src/subject-list/src/components/SubjectPageEnd.vue.mjs.map +1 -1
- package/es/src/subject-list/src/components/SubjectRichText.vue.mjs +1 -1
- package/es/src/subject-list/src/components/SubjectRichText.vue.mjs.map +1 -1
- package/es/src/subject-list/src/components/subject-blank-fill.vue.mjs +1 -1
- package/es/src/subject-list/src/components/subject-blank-fill.vue.mjs.map +1 -1
- package/es/src/subject-list/src/components/subject-scale.vue.mjs +1 -1
- package/es/src/subject-list/src/components/subject-scale.vue.mjs.map +1 -1
- package/es/src/subject-list/src/components/subject-single.vue.mjs +1 -1
- package/es/src/subject-list/src/components/subject-single.vue.mjs.map +1 -1
- package/es/src/subject-list/src/components/subject-text-fill.vue.mjs +1 -1
- package/es/src/subject-list/src/components/subject-text-fill.vue.mjs.map +1 -1
- package/es/src/subject-list/src/subject-list.vue.mjs +1 -1
- package/es/src/subject-list/src/subject-list.vue.mjs.map +1 -1
- package/es/src/subject-type/src/subject-type.vue.mjs +1 -1
- package/es/src/subject-type/src/subject-type.vue.mjs.map +1 -1
- package/es/src/tiny-mce-editor/src/tiny-mce-editor.vue.mjs +1 -1
- package/es/src/tiny-mce-editor/src/tiny-mce-editor.vue.mjs.map +1 -1
- package/lib/package.json.cjs +1 -1
- package/lib/src/data-chart/src/components/area.vue2.cjs +1 -1
- package/lib/src/data-chart/src/components/area.vue2.cjs.map +1 -1
- package/lib/src/data-chart/src/components/bar.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/bar.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/components/funnel.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/funnel.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/components/line.vue2.cjs +1 -1
- package/lib/src/data-chart/src/components/line.vue2.cjs.map +1 -1
- package/lib/src/data-chart/src/components/pie.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/pie.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/components/radar.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/radar.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/components/scatter-simple.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/scatter-simple.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/components/scatter.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/scatter.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/components/table.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/table.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/data-chart.vue.cjs +1 -1
- package/lib/src/data-chart/src/data-chart.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/utils/useCharts.cjs +1 -1
- package/lib/src/data-chart/src/utils/useCharts.cjs.map +1 -1
- package/lib/src/file-upload/src/file-upload.vue.cjs +1 -1
- package/lib/src/file-upload/src/file-upload.vue.cjs.map +1 -1
- package/lib/src/fixed-action-bar/src/fixed-action-bar.vue.cjs +1 -1
- package/lib/src/fixed-action-bar/src/fixed-action-bar.vue.cjs.map +1 -1
- package/lib/src/image-upload/src/image-upload.vue.cjs +1 -1
- package/lib/src/image-upload/src/image-upload.vue.cjs.map +1 -1
- package/lib/src/photo-crop-tool/src/composables.cjs +1 -1
- package/lib/src/photo-crop-tool/src/composables.cjs.map +1 -1
- package/lib/src/photo-crop-tool/src/photo-crop-tool.vue.cjs +1 -1
- package/lib/src/photo-crop-tool/src/photo-crop-tool.vue.cjs.map +1 -1
- package/lib/src/subject-action/src/subject-action.vue.cjs +1 -1
- package/lib/src/subject-action/src/subject-action.vue.cjs.map +1 -1
- package/lib/src/subject-list/src/components/SubjectPageEnd.vue.cjs +1 -1
- package/lib/src/subject-list/src/components/SubjectPageEnd.vue.cjs.map +1 -1
- package/lib/src/subject-list/src/components/SubjectRichText.vue.cjs +1 -1
- package/lib/src/subject-list/src/components/SubjectRichText.vue.cjs.map +1 -1
- package/lib/src/subject-list/src/components/subject-blank-fill.vue.cjs +1 -1
- package/lib/src/subject-list/src/components/subject-blank-fill.vue.cjs.map +1 -1
- package/lib/src/subject-list/src/components/subject-scale.vue.cjs +1 -1
- package/lib/src/subject-list/src/components/subject-scale.vue.cjs.map +1 -1
- package/lib/src/subject-list/src/components/subject-single.vue.cjs +1 -1
- package/lib/src/subject-list/src/components/subject-single.vue.cjs.map +1 -1
- package/lib/src/subject-list/src/components/subject-text-fill.vue.cjs +1 -1
- package/lib/src/subject-list/src/components/subject-text-fill.vue.cjs.map +1 -1
- package/lib/src/subject-list/src/subject-list.vue.cjs +1 -1
- package/lib/src/subject-list/src/subject-list.vue.cjs.map +1 -1
- package/lib/src/subject-type/src/subject-type.vue.cjs +1 -1
- package/lib/src/subject-type/src/subject-type.vue.cjs.map +1 -1
- package/lib/src/tiny-mce-editor/src/tiny-mce-editor.vue.cjs +1 -1
- package/lib/src/tiny-mce-editor/src/tiny-mce-editor.vue.cjs.map +1 -1
- package/package.json +8 -6
- package/types/index.d.ts +0 -6
- package/types/index.d.ts.map +0 -1
- package/types/src/base/style/css.d.ts +0 -2
- package/types/src/base/style/css.d.ts.map +0 -1
- package/types/src/base/style/index.d.ts +0 -2
- package/types/src/base/style/index.d.ts.map +0 -1
- package/types/src/components.d.ts +0 -11
- package/types/src/components.d.ts.map +0 -1
- package/types/src/data-chart/index.d.ts +0 -4
- package/types/src/data-chart/index.d.ts.map +0 -1
- package/types/src/data-chart/src/analyze.d.ts +0 -23
- package/types/src/data-chart/src/analyze.d.ts.map +0 -1
- package/types/src/data-chart/src/utils/config.d.ts +0 -41
- package/types/src/data-chart/src/utils/config.d.ts.map +0 -1
- package/types/src/data-chart/src/utils/injectionKeys.d.ts +0 -3
- package/types/src/data-chart/src/utils/injectionKeys.d.ts.map +0 -1
- package/types/src/data-chart/src/utils/useCharts.d.ts +0 -16
- package/types/src/data-chart/src/utils/useCharts.d.ts.map +0 -1
- package/types/src/data-chart/style/index.d.ts +0 -3
- package/types/src/data-chart/style/index.d.ts.map +0 -1
- package/types/src/defaults.d.ts +0 -6
- package/types/src/defaults.d.ts.map +0 -1
- package/types/src/file-upload/index.d.ts +0 -4
- package/types/src/file-upload/index.d.ts.map +0 -1
- package/types/src/file-upload/style/index.d.ts +0 -3
- package/types/src/file-upload/style/index.d.ts.map +0 -1
- package/types/src/fixed-action-bar/index.d.ts +0 -4
- package/types/src/fixed-action-bar/index.d.ts.map +0 -1
- package/types/src/fixed-action-bar/style/index.d.ts +0 -3
- package/types/src/fixed-action-bar/style/index.d.ts.map +0 -1
- package/types/src/image-upload/index.d.ts +0 -4
- package/types/src/image-upload/index.d.ts.map +0 -1
- package/types/src/image-upload/style/index.d.ts +0 -3
- package/types/src/image-upload/style/index.d.ts.map +0 -1
- package/types/src/make-installer.d.ts +0 -9
- package/types/src/make-installer.d.ts.map +0 -1
- package/types/src/photo-crop-tool/index.d.ts +0 -4
- package/types/src/photo-crop-tool/index.d.ts.map +0 -1
- package/types/src/photo-crop-tool/src/composables.d.ts +0 -7
- package/types/src/photo-crop-tool/src/composables.d.ts.map +0 -1
- package/types/src/photo-crop-tool/style/index.d.ts +0 -3
- package/types/src/photo-crop-tool/style/index.d.ts.map +0 -1
- package/types/src/subject-action/index.d.ts +0 -4
- package/types/src/subject-action/index.d.ts.map +0 -1
- package/types/src/subject-action/style/index.d.ts +0 -3
- package/types/src/subject-action/style/index.d.ts.map +0 -1
- package/types/src/subject-layout/index.d.ts +0 -4
- package/types/src/subject-layout/index.d.ts.map +0 -1
- package/types/src/subject-layout/style/index.d.ts +0 -3
- package/types/src/subject-layout/style/index.d.ts.map +0 -1
- package/types/src/subject-list/index.d.ts +0 -4
- package/types/src/subject-list/index.d.ts.map +0 -1
- package/types/src/subject-list/style/index.d.ts +0 -3
- package/types/src/subject-list/style/index.d.ts.map +0 -1
- package/types/src/subject-type/index.d.ts +0 -4
- package/types/src/subject-type/index.d.ts.map +0 -1
- package/types/src/subject-type/style/index.d.ts +0 -3
- package/types/src/subject-type/style/index.d.ts.map +0 -1
- package/types/src/tiny-mce-editor/index.d.ts +0 -4
- package/types/src/tiny-mce-editor/index.d.ts.map +0 -1
- package/types/src/tiny-mce-editor/style/index.d.ts +0 -3
- package/types/src/tiny-mce-editor/style/index.d.ts.map +0 -1
- package/types/src/withInstall.d.ts +0 -4
- package/types/src/withInstall.d.ts.map +0 -1
- package/types/tsconfig.tsbuildinfo +0 -1
@@ -1,2 +1,2 @@
|
|
1
|
-
import{ElUpload as e,ElIcon as t,ElAlert as i,ElMessage as l}from"element-plus/es";import{defineComponent as a,
|
1
|
+
import{ElUpload as e,ElIcon as t,ElAlert as i,ElMessage as l}from"element-plus/es";import{defineComponent as a,computed as r,createBlock as s,openBlock as o,normalizeClass as n,unref as u,withCtx as d,createElementVNode as p,createVNode as c,createTextVNode as m,createElementBlock as f,createCommentVNode as y}from"vue";import{UploadFilled as q}from"@element-plus/icons-vue";import{useNamespace as v}from"@qxs-bns/hooks";const x={class:"slot"},_={key:0,class:"el-upload__tip"},b={style:{display:"inline-block"}};var h=a({name:"QxsFileUpload",__name:"file-upload",props:{action:{type:String,required:!0},headers:{type:null,required:!1},data:{type:null,required:!1},name:{type:String,required:!1,default:"file"},size:{type:Number,required:!1,default:20},max:{type:Number,required:!1,default:3},accept:{type:String,required:!1,default:"zip,rar"},files:{type:Array,required:!1,default:()=>[]},notip:{type:Boolean,required:!1,default:!1},ext:{type:Array,required:!1}},emits:["onSuccess"],setup(a,{emit:h}){const z=h,g=v("file-upload"),S=r((()=>a.accept.split(","))),$=e=>{const t=e.name.split(".").at(-1)??"",i=S.value.includes(t),r=e.size/1024/1024<a.size;return i||l.error(`上传文件只支持 ${S.value.join(" / ")} 格式!`),r||l.error(`上传文件大小不能超过 ${a.size}MB!`),i&&r},k=()=>{l.warning("文件上传超过限制")},B=(e,t,i)=>{z("onSuccess",e,t,i)};return(l,a)=>{const r=t,v=i,h=e;return o(),s(h,{headers:l.headers,action:l.action,data:l.data,name:l.name,"before-upload":$,"on-exceed":k,"on-success":B,"file-list":l.files,limit:l.max,drag:"",class:n(u(g).e("control"))},{tip:d((()=>[l.notip?y("v-if",!0):(o(),f("div",_,[p("div",b,[c(v,{title:`上传文件支持 ${u(S).join(" / ")} 格式,单个文件大小不超过 ${l.size}MB,且文件数量不超过 ${l.max} 个`,type:"info","show-icon":"",closable:!1},null,8,["title"])])]))])),default:d((()=>[p("div",x,[c(r,{class:"el-icon--upload"},{default:d((()=>[c(u(q))])),_:1}),a[0]||(a[0]=p("div",{class:"el-upload__text"},[m("将文件拖到此处,或"),p("em",null,"点击上传")],-1))])])),_:1},8,["headers","action","data","name","file-list","limit","class"])}}});export{h as default};
|
2
2
|
//# sourceMappingURL=file-upload.vue.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"file-upload.vue.mjs","sources":["../../../../../../packages/components/src/file-upload/src/file-upload.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { UploadProps, UploadUserFile } from
|
1
|
+
{"version":3,"file":"file-upload.vue.mjs","sources":["../../../../../../packages/components/src/file-upload/src/file-upload.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { UploadProps, UploadUserFile } from \"element-plus\";\nimport { UploadFilled } from \"@element-plus/icons-vue\";\nimport { useNamespace } from \"@qxs-bns/hooks\";\n\ndefineOptions({\n name: \"QxsFileUpload\",\n});\n\nconst {\n name = \"file\",\n size = 20,\n max = 3,\n files = [],\n notip = false,\n accept = \"zip,rar\",\n} = defineProps<{\n action: UploadProps[\"action\"];\n headers?: UploadProps[\"headers\"];\n data?: UploadProps[\"data\"];\n name?: UploadProps[\"name\"];\n size?: number;\n max?: number;\n accept?: string;\n files?: UploadUserFile[];\n notip?: boolean;\n ext?: string[];\n}>();\n\nconst emit = defineEmits([\"onSuccess\"]);\n\nconst ns = useNamespace(\"file-upload\");\n\nconst exts = computed(() => {\n return accept.split(\",\")\n});\nconst beforeUpload: UploadProps[\"beforeUpload\"] = (file) => {\n const fileName = file.name.split(\".\");\n const fileExt = fileName.at(-1) ?? \"\";\n const isTypeOk = exts.value.includes(fileExt);\n const isSizeOk = file.size / 1024 / 1024 < size;\n if (!isTypeOk) {\n ElMessage.error(`上传文件只支持 ${exts.value.join(\" / \")} 格式!`);\n }\n if (!isSizeOk) {\n ElMessage.error(`上传文件大小不能超过 ${size}MB!`);\n }\n return isTypeOk && isSizeOk;\n};\n\nconst onExceed: UploadProps[\"onExceed\"] = () => {\n ElMessage.warning(\"文件上传超过限制\");\n};\n\nconst onSuccess: UploadProps[\"onSuccess\"] = (res, file, fileList) => {\n emit(\"onSuccess\", res, file, fileList);\n};\n</script>\n\n<template>\n <el-upload\n :headers=\"headers\"\n :action=\"action\"\n :data=\"data\"\n :name=\"name\"\n :before-upload=\"beforeUpload\"\n :on-exceed=\"onExceed\"\n :on-success=\"onSuccess\"\n :file-list=\"files\"\n :limit=\"max\"\n drag\n :class=\"ns.e('control')\"\n >\n <div class=\"slot\">\n <el-icon class=\"el-icon--upload\">\n <UploadFilled />\n </el-icon>\n <div class=\"el-upload__text\">将文件拖到此处,或<em>点击上传</em></div>\n </div>\n <template #tip>\n <div v-if=\"!notip\" class=\"el-upload__tip\">\n <div style=\"display: inline-block\">\n <el-alert\n :title=\"`上传文件支持 ${exts.join(\n ' / '\n )} 格式,单个文件大小不超过 ${size}MB,且文件数量不超过 ${max} 个`\"\n type=\"info\"\n show-icon\n :closable=\"false\"\n />\n </div>\n </div>\n </template>\n </el-upload>\n</template>\n"],"names":["emit","__emit","ns","useNamespace","exts","computed","__props","accept","split","beforeUpload","file","fileExt","name","at","isTypeOk","value","includes","isSizeOk","size","ElMessage","error","join","onExceed","warning","onSuccess","res","fileList"],"mappings":"0+BA6BA,MAAMA,EAAOC,EAEPC,EAAKC,EAAa,eAElBC,EAAOC,GAAS,IACbC,EAAAC,OAAOC,MAAM,OAEhBC,EAA6CC,IACjD,MACMC,EADWD,EAAKE,KAAKJ,MAAM,KACRK,IAAG,IAAO,GAC7BC,EAAWV,EAAKW,MAAMC,SAASL,GAC/BM,EAAWP,EAAKQ,KAAO,KAAO,KAAOZ,EAAIY,KAO/C,OANKJ,GACHK,EAAUC,MAAM,WAAWhB,EAAKW,MAAMM,KAAK,cAExCJ,GACHE,EAAUC,MAAM,cAAcd,EAAIY,WAE7BJ,GAAYG,CAAA,EAGfK,EAAoC,KACxCH,EAAUI,QAAQ,WAAU,EAGxBC,EAAsC,CAACC,EAAKf,EAAMgB,KACjD1B,EAAA,YAAayB,EAAKf,EAAMgB,EAAQ"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{defineComponent as e,
|
1
|
+
import{defineComponent as e,ref as t,computed as a,onMounted as n,onUnmounted as i,createElementBlock as o,openBlock as r,normalizeStyle as l,unref as d,createElementVNode as s,normalizeClass as c,renderSlot as p}from"vue";import{useNamespace as u}from"@qxs-bns/hooks";import{getDeviceType as h}from"@qxs-bns/utils";import{debounce as g}from"lodash-es";var m=e({name:"QxsFixedActionBar",props:{padding:{type:Number,default:8},className:{type:String,default:""}},setup(e){const m=e,v=u("fixed-action-bar"),f=t(!1),x=t(null),w=t(null),b=t({width:0,height:0}),y=t(0),F=t(0),R={resize:null,parent:null},$=(e,t,a)=>{const n=new ResizeObserver((e=>{e.forEach((e=>requestAnimationFrame((()=>t(e)))))}));return n.observe(e,a),n},E=()=>{if(!x.value||!w.value)return;R.resize=$(x.value,(e=>{const t=(e=>{const t=getComputedStyle(e);return{x:parseFloat(t.paddingLeft)+parseFloat(t.paddingRight),y:parseFloat(t.paddingTop)+parseFloat(t.paddingBottom)}})(e.target);b.value={width:e.contentRect.width+t.x,height:e.contentRect.height+t.y}}),{box:"border-box"});const e=w.value.parentElement;e&&(R.parent=$(e,(()=>{const t=e.getBoundingClientRect();y.value=t.width,F.value=t.left})))},k=g((()=>{const{scrollY:e}=window,{clientHeight:t,scrollHeight:a}=document.documentElement;f.value=Math.ceil(e+t)>=a}),100),z=a((()=>f.value?"":v.is("shadow"))),B=a((()=>"Android"===h()?Math.max(m.padding,20):m.padding)),q=a((()=>({width:`${y.value}px`,left:`${F.value}px`,...v.cssVarBlock({"actionbar-padding":`${m.padding}px`,"actionbar-padding-bottom":`${B.value}px`})})));return n((()=>{E(),window.addEventListener("scroll",k,{passive:!0})})),i((()=>{R.resize?.disconnect(),R.parent?.disconnect(),window.removeEventListener("scroll",k)})),(t,a)=>(r(),o("div",{ref_key:"placeholderRef",ref:w,style:l({width:"100%",height:`${d(b).height}px`})},[s("div",{ref_key:"actionbar",ref:x,style:l(d(q)),class:c([d(v).e("actionbar"),d(z),e.className]),"data-fixed-calc-width":""},[p(t.$slots,"default")],6)],4))}});export{m as default};
|
2
2
|
//# sourceMappingURL=fixed-action-bar.vue.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"fixed-action-bar.vue.mjs","sources":["../../../../../../packages/components/src/fixed-action-bar/src/fixed-action-bar.vue"],"sourcesContent":["<script lang=\"ts\">\nexport default {\n name: \"QxsFixedActionBar\",\n};\n</script>\n<script setup lang=\"ts\">\nimport { useNamespace } from \"@qxs-bns/hooks\";\nimport { getDeviceType } from \"@qxs-bns/utils\";\nimport {
|
1
|
+
{"version":3,"file":"fixed-action-bar.vue.mjs","sources":["../../../../../../packages/components/src/fixed-action-bar/src/fixed-action-bar.vue"],"sourcesContent":["<script lang=\"ts\">\nexport default {\n name: \"QxsFixedActionBar\",\n};\n</script>\n<script setup lang=\"ts\">\nimport { useNamespace } from \"@qxs-bns/hooks\";\nimport { getDeviceType } from \"@qxs-bns/utils\";\nimport { debounce } from \"lodash-es\";\n\ntype ElementSize = { width: number; height: number };\n\nconst props = defineProps({\n padding: {\n type: Number,\n default: 8,\n },\n className: {\n type: String,\n default: \"\",\n },\n});\n\nconst ns = useNamespace(\"fixed-action-bar\");\nconst isBottom = ref(false);\nconst actionbar = ref<HTMLElement | null>(null);\nconst placeholderRef = ref<HTMLElement | null>(null);\n\nconst elementSize = ref<ElementSize>({ width: 0, height: 0 });\nconst parentWidth = ref(0);\nconst elementLeft = ref(0);\n\nconst observers = {\n resize: null as ResizeObserver | null,\n parent: null as ResizeObserver | null,\n};\n\nconst getTotalPadding = (el: HTMLElement) => {\n const style = getComputedStyle(el);\n return {\n x: parseFloat(style.paddingLeft) + parseFloat(style.paddingRight),\n y: parseFloat(style.paddingTop) + parseFloat(style.paddingBottom),\n };\n};\n\nconst createResizeObserver = (\n el: HTMLElement,\n callback: (entry: ResizeObserverEntry) => void,\n options?: ResizeObserverOptions\n) => {\n const observer = new ResizeObserver((entries) => {\n entries.forEach((entry) => requestAnimationFrame(() => callback(entry)));\n });\n observer.observe(el, options);\n return observer;\n};\n\nconst initObservers = () => {\n if (!actionbar.value || !placeholderRef.value) return;\n\n // 主元素尺寸观察\n observers.resize = createResizeObserver(\n actionbar.value,\n (entry) => {\n const padding = getTotalPadding(entry.target as HTMLElement);\n elementSize.value = {\n width: entry.contentRect.width + padding.x,\n height: entry.contentRect.height + padding.y,\n };\n },\n { box: \"border-box\" }\n );\n\n // 父元素观察\n const parent = placeholderRef.value.parentElement;\n if (parent) {\n observers.parent = createResizeObserver(parent, () => {\n const rect = parent.getBoundingClientRect();\n parentWidth.value = rect.width;\n elementLeft.value = rect.left;\n });\n }\n};\n\nconst calculateScrollDetails = debounce(() => {\n const { scrollY } = window;\n const { clientHeight, scrollHeight } = document.documentElement;\n isBottom.value = Math.ceil(scrollY + clientHeight) >= scrollHeight;\n}, 100);\n\nconst shadowClass = computed(() => (!isBottom.value ? ns.is(\"shadow\") : \"\"));\n\nconst paddingBottom = computed(() =>\n getDeviceType() === \"Android\" ? Math.max(props.padding, 20) : props.padding\n);\n\nconst actionbarStyle = computed(() => ({\n width: `${parentWidth.value}px`,\n left: `${elementLeft.value}px`,\n ...ns.cssVarBlock({\n \"actionbar-padding\": `${props.padding}px`,\n \"actionbar-padding-bottom\": `${paddingBottom.value}px`,\n }),\n}));\n\nonMounted(() => {\n initObservers();\n window.addEventListener(\"scroll\", calculateScrollDetails, { passive: true });\n});\n\nonUnmounted(() => {\n observers.resize?.disconnect();\n observers.parent?.disconnect();\n window.removeEventListener(\"scroll\", calculateScrollDetails);\n});\n</script>\n\n<template>\n <div\n ref=\"placeholderRef\"\n :style=\"{ width: '100%', height: `${elementSize.height}px` }\"\n >\n <div\n ref=\"actionbar\"\n :style=\"actionbarStyle\"\n :class=\"[ns.e('actionbar'), shadowClass, className]\"\n data-fixed-calc-width\n >\n <slot />\n </div>\n </div>\n</template>\n"],"names":["name","props","__props","ns","useNamespace","isBottom","ref","actionbar","placeholderRef","elementSize","width","height","parentWidth","elementLeft","observers","resize","parent","createResizeObserver","el","callback","options","observer","ResizeObserver","entries","forEach","entry","requestAnimationFrame","observe","initObservers","value","padding","style","getComputedStyle","x","parseFloat","paddingLeft","paddingRight","y","paddingTop","paddingBottom","getTotalPadding","target","contentRect","box","parentElement","rect","getBoundingClientRect","left","calculateScrollDetails","debounce","scrollY","window","clientHeight","scrollHeight","document","documentElement","Math","ceil","shadowClass","computed","is","getDeviceType","max","actionbarStyle","cssVarBlock","onMounted","addEventListener","passive","onUnmounted","disconnect","removeEventListener"],"mappings":"0WAEEA,KAAM,wGAUR,MAAMC,EAAQC,EAWRC,EAAKC,EAAa,oBAClBC,EAAWC,GAAI,GACfC,EAAYD,EAAwB,MACpCE,EAAiBF,EAAwB,MAEzCG,EAAcH,EAAiB,CAAEI,MAAO,EAAGC,OAAQ,IACnDC,EAAcN,EAAI,GAClBO,EAAcP,EAAI,GAElBQ,EAAY,CAChBC,OAAQ,KACRC,OAAQ,MAWJC,EAAuB,CAC3BC,EACAC,EACAC,KAEA,MAAMC,EAAW,IAAIC,gBAAgBC,IAC3BA,EAAAC,SAASC,GAAUC,uBAAsB,IAAMP,EAASM,MAAO,IAGlE,OADEJ,EAAAM,QAAQT,EAAIE,GACdC,CAAA,EAGHO,EAAgB,KACpB,IAAKrB,EAAUsB,QAAUrB,EAAeqB,MAAO,OAG/Cf,EAAUC,OAASE,EACjBV,EAAUsB,OACTJ,IACO,MAAAK,EA3BY,CAACZ,IACjB,MAAAa,EAAQC,iBAAiBd,GACxB,MAAA,CACLe,EAAGC,WAAWH,EAAMI,aAAeD,WAAWH,EAAMK,cACpDC,EAAGH,WAAWH,EAAMO,YAAcJ,WAAWH,EAAMQ,eACrD,EAsBoBC,CAAgBf,EAAMgB,QACtChC,EAAYoB,MAAQ,CAClBnB,MAAOe,EAAMiB,YAAYhC,MAAQoB,EAAQG,EACzCtB,OAAQc,EAAMiB,YAAY/B,OAASmB,EAAQO,EAC7C,GAEF,CAAEM,IAAK,eAIH,MAAA3B,EAASR,EAAeqB,MAAMe,cAChC5B,IACQF,EAAAE,OAASC,EAAqBD,GAAQ,KACxC,MAAA6B,EAAO7B,EAAO8B,wBACpBlC,EAAYiB,MAAQgB,EAAKnC,MACzBG,EAAYgB,MAAQgB,EAAKE,IAAA,IAC1B,EAICC,EAAyBC,GAAS,KAChC,MAAAC,QAAEA,GAAYC,QACdC,aAAEA,EAAAC,aAAcA,GAAiBC,SAASC,gBAChDlD,EAASwB,MAAQ2B,KAAKC,KAAKP,EAAUE,IAAiBC,CAAA,GACrD,KAEGK,EAAcC,GAAS,IAAQtD,EAASwB,MAA0B,GAAlB1B,EAAGyD,GAAG,YAEtDrB,EAAgBoB,GAAS,IACT,YAApBE,IAAgCL,KAAKM,IAAI7D,EAAM6B,QAAS,IAAM7B,EAAM6B,UAGhEiC,EAAiBJ,GAAS,KAAO,CACrCjD,MAAO,GAAGE,EAAYiB,UACtBkB,KAAM,GAAGlC,EAAYgB,aAClB1B,EAAG6D,YAAY,CAChB,oBAAqB,GAAG/D,EAAM6B,YAC9B,2BAA4B,GAAGS,EAAcV,uBAIjDoC,GAAU,KACMrC,IACduB,OAAOe,iBAAiB,SAAUlB,EAAwB,CAAEmB,SAAS,GAAM,IAG7EC,GAAY,KACVtD,EAAUC,QAAQsD,aAClBvD,EAAUE,QAAQqD,aACXlB,OAAAmB,oBAAoB,SAAUtB,EAAsB"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{ElUpload as e,ElImage as t,ElIcon as i,ElProgress as r,ElImageViewer as l,ElMessage as s}from"element-plus/es";import{defineComponent as a,
|
1
|
+
import{ElUpload as e,ElImage as t,ElIcon as i,ElProgress as r,ElImageViewer as l,ElMessage as s}from"element-plus/es";import{defineComponent as a,ref as p,computed as u,createElementBlock as o,openBlock as d,normalizeClass as n,unref as c,createVNode as h,createCommentVNode as g,createBlock as m,withCtx as f,withDirectives as y,normalizeStyle as v,createElementVNode as w,toDisplayString as x,withModifiers as $,vShow as b}from"vue";import{Plus as q,ZoomIn as k,Delete as _}from"@element-plus/icons-vue";import{useNamespace as S}from"@qxs-bns/hooks";const V={key:1,class:"image"},U={class:"mask"},j={class:"actions"},z={key:0,class:"el-upload__tip-text"},B={style:{display:"inline-block"}};var C=a({name:"QxsImageUpload",__name:"image-upload",props:{action:{type:String,required:!0},headers:{type:null,required:!1},data:{type:null,required:!1},name:{type:String,required:!1,default:"file"},url:{type:String,required:!1,default:""},size:{type:Number,required:!1,default:20},width:{type:Number,required:!1,default:160},accept:{type:String,required:!1,default:"image/jpeg,image/jpg,image/png,image/gif"},height:{type:Number,required:!1,default:90},placeholder:{type:String,required:!1,default:"点击上传图片"},notip:{type:Boolean,required:!1,default:!1},tipText:{type:String,required:!1},beforeUpload:{type:null,required:!1}},emits:["update:url","onSuccess"],setup(a,{emit:C}){const M=a,N=C,L=S("image-upload"),R=p({imageViewerVisible:!1,progress:{preview:"",percent:0}}),T=u((()=>M.accept.split(",").map((e=>e.split("/").pop()))));function I(){R.value.imageViewerVisible=!0}function O(){R.value.imageViewerVisible=!1}function Q(){N("update:url","")}const A=e=>{const t=e.name.split(".").at(-1)??"",i=T.value.includes(t),r=e.size/1024/1024<M.size;return i?r?R.value.progress.preview=URL.createObjectURL(e):s.error(`上传图片大小不能超过 ${M.size}MB!`):s.error(`上传图片只支持${T.value.join(" / ")}格式!`),i&&r&&(!M.beforeUpload||M.beforeUpload(e))},D=e=>{R.value.progress.percent=~~e.percent},E=(...e)=>{R.value.progress.preview="",R.value.progress.percent=0,N("onSuccess",...e)};return(s,a)=>{const p=i,u=t,S=r,C=e,M=l;return d(),o("div",{class:n(c(L).e("upload-container"))},[h(C,{"show-file-list":!1,headers:s.headers,action:s.action,data:s.data,name:s.name,"before-upload":A,"on-progress":D,"on-success":E,drag:"",accept:s.accept,class:n(c(L).e("image-upload"))},{default:f((()=>[""===s.url?(d(),m(u,{key:0,src:""===s.url?s.placeholder:s.url,style:v(`width:${s.width}px;height:${s.height}px;`),fit:"fill"},{error:f((()=>[w("div",{class:"image-slot",style:v(`width:${s.width}px;height:${s.height}px;`)},[h(p,null,{default:f((()=>[h(c(q))])),_:1}),w("p",null,x(s.placeholder),1)],4)])),_:1},8,["src","style"])):(d(),o("div",V,[h(u,{src:s.url,style:v(`width:${s.width}px;height:${s.height}px;`),fit:"fill"},null,8,["src","style"]),w("div",U,[w("div",j,[w("span",{title:"预览",onClick:$(I,["stop"])},[h(p,null,{default:f((()=>[h(c(k))])),_:1})]),w("span",{title:"移除",onClick:$(Q,["stop"])},[h(p,null,{default:f((()=>[h(c(_))])),_:1})])])])])),y(w("div",{class:"progress",style:v(`width:${s.width}px;height:${s.height}px;`)},[h(u,{src:c(R).progress.preview,style:v(`width:${s.width}px;height:${s.height}px;`),fit:"fill"},null,8,["src","style"]),h(S,{type:"circle",width:.8*Math.min(s.width,s.height),percentage:c(R).progress.percent},null,8,["width","percentage"])],4),[[b,""===s.url&&c(R).progress.percent]])])),_:1},8,["headers","action","data","name","accept","class"]),s.notip?g("v-if",!0):(d(),o("div",z,[w("div",B,x(s.tipText||`上传图片支持 ${c(T).join(" / ")} 格式,且图片大小不超过 ${s.size}MB,建议图片尺寸为 ${s.width}*${s.height}`),1)])),c(R).imageViewerVisible?(d(),m(M,{key:1,"url-list":[s.url],teleported:"",onClose:O},null,8,["url-list"])):g("v-if",!0)],2)}}});export{C as default};
|
2
2
|
//# sourceMappingURL=image-upload.vue.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"image-upload.vue.mjs","sources":["../../../../../../packages/components/src/image-upload/src/image-upload.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { UploadFile, UploadFiles, UploadProps } from 'element-plus'\nimport { Delete, Plus, ZoomIn } from '@element-plus/icons-vue'\nimport { useNamespace } from '@qxs-bns/hooks'\n\ndefineOptions({\n name: 'QxsImageUpload',\n})\nconst props = withDefaults(\n defineProps<{\n action: UploadProps['action']\n headers?: UploadProps['headers']\n data?: UploadProps['data']\n name?: UploadProps['name']\n url?: string\n size?: number\n width?: number\n accept?: string\n height?: number\n placeholder?: string\n notip?: boolean\n tipText?: string\n beforeUpload?: UploadProps['beforeUpload']\n }>(),\n {\n name: 'file',\n url: '',\n size: 20,\n width: 160,\n height: 90,\n placeholder: '点击上传图片',\n notip: false,\n accept: 'image/jpeg,image/jpg,image/png,image/gif',\n },\n)\nconst emits = defineEmits<{\n 'update:url': [\n url: string,\n ]\n 'onSuccess': [\n res: any,\n uploadFile: UploadFile,\n uploadFiles: UploadFiles,\n ]\n}>()\n\nconst ns = useNamespace('image-upload')\n\nconst uploadData = ref({\n imageViewerVisible: false,\n progress: {\n preview: '',\n percent: 0,\n },\n})\n\nconst exts = computed(() => {\n return props.accept.split(',').map(ext => ext.split('/').pop())\n})\n\n// 预览\nfunction preview() {\n uploadData.value.imageViewerVisible = true\n}\n// 关闭预览\nfunction previewClose() {\n uploadData.value.imageViewerVisible = false\n}\n// 移除\nfunction remove() {\n emits('update:url', '')\n}\nconst handleBeforeUpload: UploadProps['beforeUpload'] = (file) => {\n const fileName = file.name.split('.')\n const fileExt = fileName.at(-1) ?? ''\n const isTypeOk = exts.value.includes(fileExt)\n const isSizeOk = file.size / 1024 / 1024 < props.size\n\n if (!isTypeOk) {\n ElMessage.error(`上传图片只支持${exts.value.join(' / ')}格式!`)\n }\n\n else if (!isSizeOk) {\n ElMessage.error(`上传图片大小不能超过 ${props.size}MB!`)\n }\n else {\n uploadData.value.progress.preview = URL.createObjectURL(file)\n }\n\n return isTypeOk && isSizeOk && (!props.beforeUpload || props.beforeUpload(file))\n}\nconst onProgress: UploadProps['onProgress'] = (file) => {\n uploadData.value.progress.percent = ~~file.percent\n}\nconst onSuccess: UploadProps['onSuccess'] = (...res) => {\n uploadData.value.progress.preview = ''\n uploadData.value.progress.percent = 0\n emits('onSuccess', ...res)\n}\n</script>\n\n<template>\n <div :class=\"ns.e('upload-container')\">\n <el-upload\n :show-file-list=\"false\"\n :headers=\"headers\"\n :action=\"action\"\n :data=\"data\"\n :name=\"name\"\n :before-upload=\"handleBeforeUpload\"\n :on-progress=\"onProgress\"\n :on-success=\"onSuccess\"\n drag\n :accept=\"accept\"\n :class=\"ns.e('image-upload')\"\n >\n <el-image\n v-if=\"url === ''\"\n :src=\"url === '' ? placeholder : url\"\n :style=\"`width:${width}px;height:${height}px;`\"\n fit=\"fill\"\n >\n <template #error>\n <div class=\"image-slot\" :style=\"`width:${width}px;height:${height}px;`\">\n <el-icon>\n <Plus />\n </el-icon>\n <p>\n {{ placeholder }}\n </p>\n </div>\n </template>\n </el-image>\n <div v-else class=\"image\">\n <el-image\n :src=\"url\"\n :style=\"`width:${width}px;height:${height}px;`\"\n fit=\"fill\"\n />\n <div class=\"mask\">\n <div class=\"actions\">\n <span title=\"预览\" @click.stop=\"preview\">\n <el-icon><ZoomIn /></el-icon>\n </span>\n <span title=\"移除\" @click.stop=\"remove\">\n <el-icon>\n <Delete />\n </el-icon>\n </span>\n </div>\n </div>\n </div>\n <div\n v-show=\"url === '' && uploadData.progress.percent\"\n class=\"progress\"\n :style=\"`width:${width}px;height:${height}px;`\"\n >\n <el-image\n :src=\"uploadData.progress.preview\"\n :style=\"`width:${width}px;height:${height}px;`\"\n fit=\"fill\"\n />\n <el-progress\n type=\"circle\"\n :width=\"Math.min(width, height) * 0.8\"\n :percentage=\"uploadData.progress.percent\"\n />\n </div>\n </el-upload>\n <div v-if=\"!notip\" class=\"el-upload__tip-text\">\n <div style=\"display: inline-block;\">\n {{ tipText || `上传图片支持 ${exts.join(' / ')} 格式,且图片大小不超过 ${size}MB,建议图片尺寸为 ${width}*${height}` }}\n </div>\n </div>\n <el-image-viewer\n v-if=\"uploadData.imageViewerVisible\"\n :url-list=\"[url]\"\n teleported\n @close=\"previewClose\"\n />\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","ns","useNamespace","uploadData","ref","imageViewerVisible","progress","preview","percent","exts","computed","accept","split","map","ext","pop","value","previewClose","remove","handleBeforeUpload","file","fileExt","name","at","isTypeOk","includes","isSizeOk","size","URL","createObjectURL","ElMessage","error","join","beforeUpload","onProgress","onSuccess","res"],"mappings":"
|
1
|
+
{"version":3,"file":"image-upload.vue.mjs","sources":["../../../../../../packages/components/src/image-upload/src/image-upload.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { UploadFile, UploadFiles, UploadProps } from 'element-plus'\nimport { Delete, Plus, ZoomIn } from '@element-plus/icons-vue'\nimport { useNamespace } from '@qxs-bns/hooks'\n\ndefineOptions({\n name: 'QxsImageUpload',\n})\nconst props = withDefaults(\n defineProps<{\n action: UploadProps['action']\n headers?: UploadProps['headers']\n data?: UploadProps['data']\n name?: UploadProps['name']\n url?: string\n size?: number\n width?: number\n accept?: string\n height?: number\n placeholder?: string\n notip?: boolean\n tipText?: string\n beforeUpload?: UploadProps['beforeUpload']\n }>(),\n {\n name: 'file',\n url: '',\n size: 20,\n width: 160,\n height: 90,\n placeholder: '点击上传图片',\n notip: false,\n accept: 'image/jpeg,image/jpg,image/png,image/gif',\n },\n)\nconst emits = defineEmits<{\n 'update:url': [\n url: string,\n ]\n 'onSuccess': [\n res: any,\n uploadFile: UploadFile,\n uploadFiles: UploadFiles,\n ]\n}>()\n\nconst ns = useNamespace('image-upload')\n\nconst uploadData = ref({\n imageViewerVisible: false,\n progress: {\n preview: '',\n percent: 0,\n },\n})\n\nconst exts = computed(() => {\n return props.accept.split(',').map(ext => ext.split('/').pop())\n})\n\n// 预览\nfunction preview() {\n uploadData.value.imageViewerVisible = true\n}\n// 关闭预览\nfunction previewClose() {\n uploadData.value.imageViewerVisible = false\n}\n// 移除\nfunction remove() {\n emits('update:url', '')\n}\nconst handleBeforeUpload: UploadProps['beforeUpload'] = (file) => {\n const fileName = file.name.split('.')\n const fileExt = fileName.at(-1) ?? ''\n const isTypeOk = exts.value.includes(fileExt)\n const isSizeOk = file.size / 1024 / 1024 < props.size\n\n if (!isTypeOk) {\n ElMessage.error(`上传图片只支持${exts.value.join(' / ')}格式!`)\n }\n\n else if (!isSizeOk) {\n ElMessage.error(`上传图片大小不能超过 ${props.size}MB!`)\n }\n else {\n uploadData.value.progress.preview = URL.createObjectURL(file)\n }\n\n return isTypeOk && isSizeOk && (!props.beforeUpload || props.beforeUpload(file))\n}\nconst onProgress: UploadProps['onProgress'] = (file) => {\n uploadData.value.progress.percent = ~~file.percent\n}\nconst onSuccess: UploadProps['onSuccess'] = (...res) => {\n uploadData.value.progress.preview = ''\n uploadData.value.progress.percent = 0\n emits('onSuccess', ...res)\n}\n</script>\n\n<template>\n <div :class=\"ns.e('upload-container')\">\n <el-upload\n :show-file-list=\"false\"\n :headers=\"headers\"\n :action=\"action\"\n :data=\"data\"\n :name=\"name\"\n :before-upload=\"handleBeforeUpload\"\n :on-progress=\"onProgress\"\n :on-success=\"onSuccess\"\n drag\n :accept=\"accept\"\n :class=\"ns.e('image-upload')\"\n >\n <el-image\n v-if=\"url === ''\"\n :src=\"url === '' ? placeholder : url\"\n :style=\"`width:${width}px;height:${height}px;`\"\n fit=\"fill\"\n >\n <template #error>\n <div class=\"image-slot\" :style=\"`width:${width}px;height:${height}px;`\">\n <el-icon>\n <Plus />\n </el-icon>\n <p>\n {{ placeholder }}\n </p>\n </div>\n </template>\n </el-image>\n <div v-else class=\"image\">\n <el-image\n :src=\"url\"\n :style=\"`width:${width}px;height:${height}px;`\"\n fit=\"fill\"\n />\n <div class=\"mask\">\n <div class=\"actions\">\n <span title=\"预览\" @click.stop=\"preview\">\n <el-icon><ZoomIn /></el-icon>\n </span>\n <span title=\"移除\" @click.stop=\"remove\">\n <el-icon>\n <Delete />\n </el-icon>\n </span>\n </div>\n </div>\n </div>\n <div\n v-show=\"url === '' && uploadData.progress.percent\"\n class=\"progress\"\n :style=\"`width:${width}px;height:${height}px;`\"\n >\n <el-image\n :src=\"uploadData.progress.preview\"\n :style=\"`width:${width}px;height:${height}px;`\"\n fit=\"fill\"\n />\n <el-progress\n type=\"circle\"\n :width=\"Math.min(width, height) * 0.8\"\n :percentage=\"uploadData.progress.percent\"\n />\n </div>\n </el-upload>\n <div v-if=\"!notip\" class=\"el-upload__tip-text\">\n <div style=\"display: inline-block;\">\n {{ tipText || `上传图片支持 ${exts.join(' / ')} 格式,且图片大小不超过 ${size}MB,建议图片尺寸为 ${width}*${height}` }}\n </div>\n </div>\n <el-image-viewer\n v-if=\"uploadData.imageViewerVisible\"\n :url-list=\"[url]\"\n teleported\n @close=\"previewClose\"\n />\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","ns","useNamespace","uploadData","ref","imageViewerVisible","progress","preview","percent","exts","computed","accept","split","map","ext","pop","value","previewClose","remove","handleBeforeUpload","file","fileExt","name","at","isTypeOk","includes","isSizeOk","size","URL","createObjectURL","ElMessage","error","join","beforeUpload","onProgress","onSuccess","res"],"mappings":"y1CAQA,MAAMA,EAAQC,EA2BRC,EAAQC,EAWRC,EAAKC,EAAa,gBAElBC,EAAaC,EAAI,CACrBC,oBAAoB,EACpBC,SAAU,CACRC,QAAS,GACTC,QAAS,KAIPC,EAAOC,GAAS,IACbb,EAAMc,OAAOC,MAAM,KAAKC,KAAWC,GAAAA,EAAIF,MAAM,KAAKG,UAI3D,SAASR,IACPJ,EAAWa,MAAMX,oBAAqB,CAAA,CAGxC,SAASY,IACPd,EAAWa,MAAMX,oBAAqB,CAAA,CAGxC,SAASa,IACPnB,EAAM,aAAc,GAAE,CAElB,MAAAoB,EAAmDC,IACvD,MACMC,EADWD,EAAKE,KAAKV,MAAM,KACRW,IAAG,IAAO,GAC7BC,EAAWf,EAAKO,MAAMS,SAASJ,GAC/BK,EAAWN,EAAKO,KAAO,KAAO,KAAO9B,EAAM8B,KAajD,OAXKH,EAIKE,EAIRvB,EAAWa,MAAMV,SAASC,QAAUqB,IAAIC,gBAAgBT,GAHxDU,EAAUC,MAAM,cAAclC,EAAM8B,WAJpCG,EAAUC,MAAM,UAAUtB,EAAKO,MAAMgB,KAAK,aAUrCR,GAAYE,KAAc7B,EAAMoC,cAAgBpC,EAAMoC,aAAab,GAAI,EAE1Ec,EAAyCd,IAC7CjB,EAAWa,MAAMV,SAASE,UAAYY,EAAKZ,OAAA,EAEvC2B,EAAsC,IAAIC,KACnCjC,EAAAa,MAAMV,SAASC,QAAU,GACzBJ,EAAAa,MAAMV,SAASE,QAAU,EAC9BT,EAAA,eAAgBqC,EAAG"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{ref as e}from"vue
|
1
|
+
import{ref as e}from"vue";function l(l){const a=e(null);l&&(a.value=l.getContext("2d"));return{clearCanvas:()=>{a.value&&a.value.clearRect(0,0,l.width,l.height)},drawColor:(e,l,t,n,o)=>{a.value&&(a.value.fillStyle=o,a.value.fillRect(e,l,t,n))},drawImage:(e,l,t,n,o)=>{a.value.drawImage(e,l,t,n,o)},cropCanvas:(e,t,n,o)=>new Promise((r=>{if(a.value){const a=document.createElement("canvas");a.width=n,a.height=o;const u=a.getContext("2d");u?(u.drawImage(l,e,t,n,o,0,0,n,o),a.toBlob((e=>{if(e){const l=new File([e],"cropped_image.png",{type:"image/png"});r(l)}else r(null)}),"image/png")):r(null)}else r(null)}))}}export{l as useCanvas};
|
2
2
|
//# sourceMappingURL=composables.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"composables.mjs","sources":["../../../../../../packages/components/src/photo-crop-tool/src/composables.ts"],"sourcesContent":["// useCanvas.ts\nimport type { Ref } from 'vue-demi'\nimport { ref } from 'vue-demi'\n\nexport function useCanvas(canvasElement: HTMLCanvasElement) {\n const context: Ref<CanvasRenderingContext2D | null> = ref(null)\n\n if (canvasElement) {\n context.value = canvasElement.getContext('2d')\n }\n\n const clearCanvas = () => {\n if (context.value) {\n context.value.clearRect(0, 0, canvasElement.width, canvasElement.height)\n }\n }\n\n const drawColor = (x: number, y: number, width: number, height: number, color: string) => {\n if (context.value) {\n context.value.fillStyle = color\n context.value.fillRect(x, y, width, height)\n }\n }\n\n const drawImage = (image: HTMLImageElement, x: number, y: number, width: number, height: number) => {\n context.value!.drawImage(image, x, y, width, height)\n }\n\n const cropCanvas = (x: number, y: number, width: number, height: number): Promise<File | null> => {\n return new Promise((resolve) => {\n if (context.value) {\n const croppedCanvas = document.createElement('canvas')\n croppedCanvas.width = width\n croppedCanvas.height = height\n const croppedContext = croppedCanvas.getContext('2d')\n if (croppedContext) {\n croppedContext.drawImage(canvasElement, x, y, width, height, 0, 0, width, height)\n croppedCanvas.toBlob((blob) => {\n if (blob) {\n const file = new File([blob], 'cropped_image.png', { type: 'image/png' })\n resolve(file)\n }\n else {\n resolve(null)\n }\n }, 'image/png')\n }\n else {\n resolve(null)\n }\n }\n else {\n resolve(null)\n }\n })\n }\n\n return {\n clearCanvas,\n drawColor,\n drawImage,\n cropCanvas,\n }\n}\n"],"names":["useCanvas","canvasElement","context","ref","value","getContext","clearCanvas","clearRect","width","height","drawColor","x","y","color","fillStyle","fillRect","drawImage","image","cropCanvas","Promise","resolve","croppedCanvas","document","createElement","croppedContext","toBlob","blob","file","File","type"],"mappings":"
|
1
|
+
{"version":3,"file":"composables.mjs","sources":["../../../../../../packages/components/src/photo-crop-tool/src/composables.ts"],"sourcesContent":["// useCanvas.ts\nimport type { Ref } from 'vue-demi'\nimport { ref } from 'vue-demi'\n\nexport function useCanvas(canvasElement: HTMLCanvasElement) {\n const context: Ref<CanvasRenderingContext2D | null> = ref(null)\n\n if (canvasElement) {\n context.value = canvasElement.getContext('2d')\n }\n\n const clearCanvas = () => {\n if (context.value) {\n context.value.clearRect(0, 0, canvasElement.width, canvasElement.height)\n }\n }\n\n const drawColor = (x: number, y: number, width: number, height: number, color: string) => {\n if (context.value) {\n context.value.fillStyle = color\n context.value.fillRect(x, y, width, height)\n }\n }\n\n const drawImage = (image: HTMLImageElement, x: number, y: number, width: number, height: number) => {\n context.value!.drawImage(image, x, y, width, height)\n }\n\n const cropCanvas = (x: number, y: number, width: number, height: number): Promise<File | null> => {\n return new Promise((resolve) => {\n if (context.value) {\n const croppedCanvas = document.createElement('canvas')\n croppedCanvas.width = width\n croppedCanvas.height = height\n const croppedContext = croppedCanvas.getContext('2d')\n if (croppedContext) {\n croppedContext.drawImage(canvasElement, x, y, width, height, 0, 0, width, height)\n croppedCanvas.toBlob((blob) => {\n if (blob) {\n const file = new File([blob], 'cropped_image.png', { type: 'image/png' })\n resolve(file)\n }\n else {\n resolve(null)\n }\n }, 'image/png')\n }\n else {\n resolve(null)\n }\n }\n else {\n resolve(null)\n }\n })\n }\n\n return {\n clearCanvas,\n drawColor,\n drawImage,\n cropCanvas,\n }\n}\n"],"names":["useCanvas","canvasElement","context","ref","value","getContext","clearCanvas","clearRect","width","height","drawColor","x","y","color","fillStyle","fillRect","drawImage","image","cropCanvas","Promise","resolve","croppedCanvas","document","createElement","croppedContext","toBlob","blob","file","File","type"],"mappings":"0BAIO,SAASA,EAAUC,GAClB,MAAAC,EAAgDC,EAAI,MAEtDF,IACMC,EAAAE,MAAQH,EAAcI,WAAW,OAiDpC,MAAA,CACLC,YA/CkBA,KACdJ,EAAQE,OACVF,EAAQE,MAAMG,UAAU,EAAG,EAAGN,EAAcO,MAAOP,EAAcQ,OACnE,EA6CAC,UA1CgBA,CAACC,EAAWC,EAAWJ,EAAeC,EAAgBI,KAClEX,EAAQE,QACVF,EAAQE,MAAMU,UAAYD,EAC1BX,EAAQE,MAAMW,SAASJ,EAAGC,EAAGJ,EAAOC,GACtC,EAuCAO,UApCgBA,CAACC,EAAyBN,EAAWC,EAAWJ,EAAeC,KAC/EP,EAAQE,MAAOY,UAAUC,EAAON,EAAGC,EAAGJ,EAAOC,EAAM,EAoCnDS,WAjCiBA,CAACP,EAAWC,EAAWJ,EAAeC,IAChD,IAAIU,SAASC,IAClB,GAAIlB,EAAQE,MAAO,CACX,MAAAiB,EAAgBC,SAASC,cAAc,UAC7CF,EAAcb,MAAQA,EACtBa,EAAcZ,OAASA,EACjB,MAAAe,EAAiBH,EAAchB,WAAW,MAC5CmB,GACaA,EAAAR,UAAUf,EAAeU,EAAGC,EAAGJ,EAAOC,EAAQ,EAAG,EAAGD,EAAOC,GAC5DY,EAAAI,QAAQC,IACpB,GAAIA,EAAM,CACF,MAAAC,EAAO,IAAIC,KAAK,CAACF,GAAO,oBAAqB,CAAEG,KAAM,cAC3DT,EAAQO,EACV,MAEEP,EAAQ,KACV,GACC,cAGHA,EAAQ,KAEZ,MAEEA,EAAQ,KACV,IAUN"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{defineComponent as e,
|
1
|
+
import{defineComponent as e,ref as t,computed as l,watch as a,onMounted as o,nextTick as i,onUnmounted as u,createElementBlock as v,openBlock as h,normalizeClass as s,unref as n,toDisplayString as r,Fragment as p,createElementVNode as c,normalizeStyle as f}from"vue";import{useNamespace as d}from"@qxs-bns/hooks";import{useElementSize as m,useDraggable as g}from"@vueuse/core";import{useCanvas as y}from"./composables.mjs";const w=["src"];var x=e({name:"QxsPhotoCropTool",__name:"photo-crop-tool",props:{imgFile:{type:Object,default:()=>null},aspectRatio:{type:String,default:()=>"16 / 9"},defaultWidth:{type:Number,default:()=>320},defaultHeight:{type:Number,default:()=>180},zoomType:{type:String,default:()=>"fixed"}},setup(e,{expose:x}){const b=e;let R=0,H=0,T=0,z=0;const F=d("photo-crop-tool"),N=t(null),W=t(null),k=t(null),L=t(""),M=t(""),E=t({x:0,y:0}),$=t({width:b.defaultWidth,height:b.defaultHeight,x:0,y:0}),{width:C,height:_}=m(N),{width:j}=m(k),{x:U,y:B,style:O}=g(N,{containerElement:W,draggingElement:N,disabled:l((()=>!!M.value)),exact:!0,initialValue:E}),S=l((()=>b.imgFile?URL.createObjectURL(b.imgFile):""));a((()=>b.imgFile),(e=>{e&&!e.type.startsWith("image/")?L.value="文件类型错误":L.value=""}));const P=l((()=>(k.value?.naturalWidth||0)/j.value)),V=l((()=>{const e={left:0,top:0};return"bottom-right"===M.value?(e.left=$.value.x,e.top=$.value.y):"top-left"===M.value?(e.left=$.value.x-C.value,e.top=$.value.y-_.value):"top-right"===M.value?(e.top=$.value.y-_.value,e.left=$.value.x):"bottom-left"===M.value&&(e.left=$.value.x-C.value,e.top=$.value.y),e})),X=l((()=>{const{aspectRatio:e}=b,t={width:`${$.value.width||b.defaultWidth}`,height:`${$.value.height||b.defaultHeight}`,"aspect-ratio":e,top:`${V.value.top}px`,left:`${V.value.left}px`};return"free"===b.zoomType?delete t["aspect-ratio"]:"fixed"===b.zoomType&&delete t.height,F.cssVarBlock(t)}));function Y(e){return e*P.value}function q(e,t){const l=W.value?.clientWidth||1/0,a=W.value?.clientHeight||1/0;return{width:Math.min(Math.max(e,0),l),height:Math.min(Math.max(t,0),a)}}function D(e){const t=e.clientX-R,l=e.clientY-H;if("bottom-right"===M.value){if("free"===b.zoomType){const{width:e,height:a}=q(T+t,z+l);$.value.width=e,$.value.height=a}else if("fixed"===b.zoomType){const e=Number.parseFloat(b.aspectRatio.split(" / ")[0])/Number.parseFloat(b.aspectRatio.split(" / ")[1]);let l=T+t,a=l/e;const{width:o,height:i}=q(l,a);i>(W.value?.clientHeight||1/0)&&(a=W.value?.clientHeight||1/0,l=a*e),$.value.width=o,$.value.height=i}}else if("top-left"===M.value){if("free"===b.zoomType){const{width:e,height:a}=q(T-t,z-l);$.value.width=e,$.value.height=a}else if("fixed"===b.zoomType){const e=Number.parseFloat(b.aspectRatio.split(" / ")[0])/Number.parseFloat(b.aspectRatio.split(" / ")[1]);let l=T-t,a=l/e;const{width:o,height:i}=q(l,a);i>(W.value?.clientHeight||1/0)&&(a=W.value?.clientHeight||1/0,l=a*e),$.value.width=o,$.value.height=i}U.value=V.value.left,B.value=V.value.top}else if("top-right"===M.value){if("free"===b.zoomType){const{width:e,height:a}=q(T+t,z-l);$.value.width=e,$.value.height=a}else if("fixed"===b.zoomType){const e=Number.parseFloat(b.aspectRatio.split(" / ")[0])/Number.parseFloat(b.aspectRatio.split(" / ")[1]);let l=T+t,a=l/e;const{width:o,height:i}=q(l,a);i>(W.value?.clientHeight||1/0)&&(a=W.value?.clientHeight||1/0,l=a*e),$.value.width=o,$.value.height=i}U.value=V.value.left,B.value=V.value.top}else if("bottom-left"===M.value){if("free"===b.zoomType){const{width:e,height:a}=q(T-t,z+l);$.value.width=e,$.value.height=a}else if("fixed"===b.zoomType){const e=Number.parseFloat(b.aspectRatio.split(" / ")[0])/Number.parseFloat(b.aspectRatio.split(" / ")[1]);let l=T-t,a=l/e;const{width:o,height:i}=q(l,a);i>(W.value?.clientHeight||1/0)&&(a=W.value?.clientHeight||1/0,l=a*e),$.value.width=o,$.value.height=i}U.value=V.value.left,B.value=V.value.top}e.preventDefault(),e.stopPropagation()}function I(e,t){M.value=t,R=e.clientX,H=e.clientY,T=$.value.width,z=$.value.height,"bottom-right"===t?($.value.x=U.value,$.value.y=B.value):"top-left"===t?($.value.x=U.value+C.value,$.value.y=B.value+_.value):"top-right"===t?($.value.x=U.value,$.value.y=B.value+_.value):"bottom-left"===t&&($.value.x=U.value+C.value,$.value.y=B.value)}function Q(){M.value=""}return document.addEventListener("mouseup",Q),document.addEventListener("mousemove",D),o((()=>{i((()=>{E.value.x=(W.value?.offsetWidth||0)/2-$.value.width/2,E.value.y=(W.value?.offsetHeight||0)/2-$.value.height/2}))})),u((()=>{S.value&&URL.revokeObjectURL(S.value),document.removeEventListener("mouseup",Q),document.removeEventListener("mousemove",D)})),x({crop:async function(e=k.value){let t="transparent";W.value&&(t=window.getComputedStyle(W.value).backgroundColor);const l=document.createElement("canvas");l.width=Y(W.value?.clientWidth||0),l.height=Y(W.value?.clientHeight||0);const{drawImage:a,cropCanvas:o,drawColor:i}=y(l);return i(0,0,l.width,l.height,t),a(e,Y(e.offsetLeft),Y(e.offsetTop),e.naturalWidth,e.naturalHeight),await o(Y(U.value),Y(B.value),Y(C.value),Y(_.value))},resize:function(){$.value.width=b.defaultWidth,$.value.height=b.defaultHeight,U.value=0,B.value=0}}),(e,t)=>(h(),v("div",{ref_key:"containerBoxRef",ref:W,class:s([n(F).e("img-box")])},[n(L)?(h(),v("div",{key:0,class:s([n(F).e("error-message")])},r(n(L)),3)):(h(),v(p,{key:1},[c("img",{ref_key:"imgRef",ref:k,class:s([n(F).e("image")]),src:n(S)},null,10,w),c("div",{ref_key:"cropBoxRef",ref:N,class:s([n(F).e("crop-tool-box")]),style:f([n(X),n(M)?`left: ${n(V).left}px;top: ${n(V).top}px`:n(O)])},[c("div",{class:s([n(F).e("top-left")]),onMousedown:t[0]||(t[0]=e=>I(e,"top-left"))},null,34),c("div",{class:s([n(F).e("top-right")]),onMousedown:t[1]||(t[1]=e=>I(e,"top-right"))},null,34),c("div",{class:s([n(F).e("bottom-right")]),onMousedown:t[2]||(t[2]=e=>I(e,"bottom-right"))},null,34),c("div",{class:s([n(F).e("bottom-left")]),onMousedown:t[3]||(t[3]=e=>I(e,"bottom-left"))},null,34)],6)],64))],2))}});export{x as default};
|
2
2
|
//# sourceMappingURL=photo-crop-tool.vue.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"photo-crop-tool.vue.mjs","sources":["../../../../../../packages/components/src/photo-crop-tool/src/photo-crop-tool.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PropType } from 'vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport { useDraggable, useElementSize } from '@vueuse/core'\nimport { useCanvas } from './composables'\n\ndefineOptions({\n name: 'QxsPhotoCropTool',\n})\n\nconst props = defineProps({\n imgFile: {\n type: Object as PropType<File>,\n default: () => null,\n },\n aspectRatio: {\n type: String,\n default: () => '16 / 9',\n },\n defaultWidth: {\n type: Number,\n default: () => 320,\n },\n defaultHeight: {\n type: Number,\n default: () => 180,\n },\n /**\n * free 自由缩放\n * fixed 固定比例缩放\n */\n zoomType: {\n type: String,\n default: () => 'fixed',\n },\n})\nlet startX = 0\nlet startY = 0\nlet startWidth = 0\nlet startHeight = 0\n\nconst ns = useNamespace('photo-crop-tool')\n\nconst cropBoxRef = ref<HTMLElement | null>(null)\nconst containerBoxRef = ref<HTMLElement | null>(null)\nconst imgRef = ref<HTMLImageElement | null>(null)\nconst errorMessage = ref('')\nconst dargPoint = ref('')\nconst initialValue = ref({\n x: 0,\n y: 0,\n})\nconst cropInfo = ref({\n width: props.defaultWidth,\n height: props.defaultHeight,\n x: 0,\n y: 0,\n})\n\nconst { width, height } = useElementSize(cropBoxRef)\nconst { width: imgWidth } = useElementSize(imgRef)\n\nconst { x, y, style } = useDraggable(cropBoxRef, {\n containerElement: containerBoxRef,\n draggingElement: cropBoxRef,\n disabled: computed(() => !!dargPoint.value),\n exact: true,\n initialValue,\n})\n\nconst imageUrl = computed(() => {\n if (!props.imgFile) {\n return ''\n }\n return URL.createObjectURL(props.imgFile)\n})\n\nwatch(\n () => props.imgFile,\n (newFile: File | null) => {\n if (newFile && !newFile.type.startsWith('image/')) {\n errorMessage.value = '文件类型错误'\n }\n else {\n errorMessage.value = ''\n }\n },\n)\n\nconst ratio = computed(() => {\n return (imgRef.value?.naturalWidth || 0) / imgWidth.value\n})\n\nconst customStyle = computed(() => {\n const position = {\n left: 0,\n top: 0,\n }\n if (dargPoint.value === 'bottom-right') {\n position.left = cropInfo.value.x\n position.top = cropInfo.value.y\n }\n else if (dargPoint.value === 'top-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y - height.value\n }\n else if (dargPoint.value === 'top-right') {\n position.top = cropInfo.value.y - height.value\n position.left = cropInfo.value.x\n }\n else if (dargPoint.value === 'bottom-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y\n }\n return position\n})\n\nconst sizeStyle = computed(() => {\n const { aspectRatio } = props\n\n const style: {\n 'height'?: string\n 'width': string\n 'aspect-ratio'?: string\n 'top': string\n 'left': string\n } = {\n 'width': `${cropInfo.value.width || props.defaultWidth}`,\n 'height': `${cropInfo.value.height || props.defaultHeight}`,\n 'aspect-ratio': aspectRatio,\n 'top': `${customStyle.value.top}px`,\n 'left': `${customStyle.value.left}px`,\n }\n if (props.zoomType === 'free') {\n delete style['aspect-ratio']\n }\n else if (props.zoomType === 'fixed') {\n delete style.height\n }\n return ns.cssVarBlock(style)\n})\n\nfunction zoom(pixel: number) {\n return pixel * ratio.value\n}\nasync function crop(img: HTMLImageElement = imgRef.value!) {\n let backgroundColor = 'transparent'\n if (containerBoxRef.value) {\n backgroundColor = window.getComputedStyle(\n containerBoxRef.value,\n ).backgroundColor\n }\n const canvas = document.createElement('canvas')\n canvas.width = zoom(containerBoxRef.value?.clientWidth || 0)\n canvas.height = zoom(containerBoxRef.value?.clientHeight || 0)\n const { drawImage, cropCanvas, drawColor } = useCanvas(canvas)\n drawColor(0, 0, canvas.width, canvas.height, backgroundColor)\n drawImage(\n img,\n zoom(img.offsetLeft),\n zoom(img.offsetTop),\n img.naturalWidth,\n img.naturalHeight,\n )\n return await cropCanvas(\n zoom(x.value),\n zoom(y.value),\n zoom(width.value),\n zoom(height.value),\n )\n}\n\nfunction checkBoundaries(\n newWidth: number,\n newHeight: number,\n): { width: number, height: number } {\n const maxWidth = containerBoxRef.value?.clientWidth || Infinity\n const maxHeight = containerBoxRef.value?.clientHeight || Infinity\n\n return {\n width: Math.min(Math.max(newWidth, 0), maxWidth),\n height: Math.min(Math.max(newHeight, 0), maxHeight),\n }\n}\n\nfunction mousemove(e: MouseEvent) {\n const deltaX = e.clientX - startX\n const deltaY = e.clientY - startY\n\n if (dargPoint.value === 'bottom-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n }\n else if (dargPoint.value === 'top-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'top-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'bottom-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n e.preventDefault()\n e.stopPropagation()\n}\n\nfunction mousedown(e: MouseEvent, point: string) {\n dargPoint.value = point\n startX = e.clientX\n startY = e.clientY\n startWidth = cropInfo.value.width\n startHeight = cropInfo.value.height\n\n if (point === 'bottom-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value\n }\n else if (point === 'top-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'top-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'bottom-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value\n }\n}\n\nfunction mouseup() {\n dargPoint.value = ''\n}\n\nfunction resize() {\n cropInfo.value.width = props.defaultWidth\n cropInfo.value.height = props.defaultHeight\n x.value = 0\n y.value = 0\n}\n\ndocument.addEventListener('mouseup', mouseup)\ndocument.addEventListener('mousemove', mousemove)\n\nonMounted(() => {\n nextTick(() => {\n // 初始化位置\n initialValue.value.x\n = (containerBoxRef.value?.offsetWidth || 0) / 2 - cropInfo.value.width / 2\n initialValue.value.y\n = (containerBoxRef.value?.offsetHeight || 0) / 2\n - cropInfo.value.height / 2\n })\n})\n\nonUnmounted(() => {\n if (imageUrl.value) {\n URL.revokeObjectURL(imageUrl.value)\n }\n document.removeEventListener('mouseup', mouseup)\n document.removeEventListener('mousemove', mousemove)\n})\n\ndefineExpose({\n crop,\n resize,\n})\n</script>\n\n<template>\n <div ref=\"containerBoxRef\" :class=\"[ns.e('img-box')]\">\n <div v-if=\"errorMessage\" :class=\"[ns.e('error-message')]\">\n {{ errorMessage }}\n </div>\n <template v-else>\n <img\n ref=\"imgRef\"\n :class=\"[ns.e('image')]\"\n :src=\"imageUrl\"\n >\n <div\n ref=\"cropBoxRef\"\n :class=\"[ns.e('crop-tool-box')]\"\n :style=\"[\n sizeStyle,\n dargPoint\n ? `left: ${customStyle.left}px;top: ${customStyle.top}px`\n : style,\n ]\"\n >\n <div\n :class=\"[ns.e('top-left')]\"\n @mousedown=\"mousedown($event, 'top-left')\"\n />\n <div\n :class=\"[ns.e('top-right')]\"\n @mousedown=\"mousedown($event, 'top-right')\"\n />\n <div\n :class=\"[ns.e('bottom-right')]\"\n @mousedown=\"mousedown($event, 'bottom-right')\"\n />\n <div\n :class=\"[ns.e('bottom-left')]\"\n @mousedown=\"mousedown($event, 'bottom-left')\"\n />\n </div>\n </template>\n </div>\n</template>\n"],"names":["props","__props","startX","startY","startWidth","startHeight","ns","useNamespace","cropBoxRef","ref","containerBoxRef","imgRef","errorMessage","dargPoint","initialValue","x","y","cropInfo","width","defaultWidth","height","defaultHeight","useElementSize","imgWidth","style","useDraggable","containerElement","draggingElement","disabled","computed","value","exact","imageUrl","imgFile","URL","createObjectURL","watch","newFile","type","startsWith","ratio","naturalWidth","customStyle","position","left","top","sizeStyle","aspectRatio","zoomType","cssVarBlock","zoom","pixel","checkBoundaries","newWidth","newHeight","maxWidth","clientWidth","Infinity","maxHeight","clientHeight","Math","min","max","mousemove","e","deltaX","clientX","deltaY","clientY","Number","parseFloat","split","preventDefault","stopPropagation","mousedown","point","mouseup","document","addEventListener","onMounted","nextTick","offsetWidth","offsetHeight","onUnmounted","revokeObjectURL","removeEventListener","__expose","crop","async","img","backgroundColor","window","getComputedStyle","canvas","createElement","drawImage","cropCanvas","drawColor","useCanvas","offsetLeft","offsetTop","naturalHeight","resize"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"photo-crop-tool.vue.mjs","sources":["../../../../../../packages/components/src/photo-crop-tool/src/photo-crop-tool.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PropType } from 'vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport { useDraggable, useElementSize } from '@vueuse/core'\nimport { useCanvas } from './composables'\n\ndefineOptions({\n name: 'QxsPhotoCropTool',\n})\n\nconst props = defineProps({\n imgFile: {\n type: Object as PropType<File>,\n default: () => null,\n },\n aspectRatio: {\n type: String,\n default: () => '16 / 9',\n },\n defaultWidth: {\n type: Number,\n default: () => 320,\n },\n defaultHeight: {\n type: Number,\n default: () => 180,\n },\n /**\n * free 自由缩放\n * fixed 固定比例缩放\n */\n zoomType: {\n type: String,\n default: () => 'fixed',\n },\n})\nlet startX = 0\nlet startY = 0\nlet startWidth = 0\nlet startHeight = 0\n\nconst ns = useNamespace('photo-crop-tool')\n\nconst cropBoxRef = ref<HTMLElement | null>(null)\nconst containerBoxRef = ref<HTMLElement | null>(null)\nconst imgRef = ref<HTMLImageElement | null>(null)\nconst errorMessage = ref('')\nconst dargPoint = ref('')\nconst initialValue = ref({\n x: 0,\n y: 0,\n})\nconst cropInfo = ref({\n width: props.defaultWidth,\n height: props.defaultHeight,\n x: 0,\n y: 0,\n})\n\nconst { width, height } = useElementSize(cropBoxRef)\nconst { width: imgWidth } = useElementSize(imgRef)\n\nconst { x, y, style } = useDraggable(cropBoxRef, {\n containerElement: containerBoxRef,\n draggingElement: cropBoxRef,\n disabled: computed(() => !!dargPoint.value),\n exact: true,\n initialValue,\n})\n\nconst imageUrl = computed(() => {\n if (!props.imgFile) {\n return ''\n }\n return URL.createObjectURL(props.imgFile)\n})\n\nwatch(\n () => props.imgFile,\n (newFile: File | null) => {\n if (newFile && !newFile.type.startsWith('image/')) {\n errorMessage.value = '文件类型错误'\n }\n else {\n errorMessage.value = ''\n }\n },\n)\n\nconst ratio = computed(() => {\n return (imgRef.value?.naturalWidth || 0) / imgWidth.value\n})\n\nconst customStyle = computed(() => {\n const position = {\n left: 0,\n top: 0,\n }\n if (dargPoint.value === 'bottom-right') {\n position.left = cropInfo.value.x\n position.top = cropInfo.value.y\n }\n else if (dargPoint.value === 'top-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y - height.value\n }\n else if (dargPoint.value === 'top-right') {\n position.top = cropInfo.value.y - height.value\n position.left = cropInfo.value.x\n }\n else if (dargPoint.value === 'bottom-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y\n }\n return position\n})\n\nconst sizeStyle = computed(() => {\n const { aspectRatio } = props\n\n const style: {\n 'height'?: string\n 'width': string\n 'aspect-ratio'?: string\n 'top': string\n 'left': string\n } = {\n 'width': `${cropInfo.value.width || props.defaultWidth}`,\n 'height': `${cropInfo.value.height || props.defaultHeight}`,\n 'aspect-ratio': aspectRatio,\n 'top': `${customStyle.value.top}px`,\n 'left': `${customStyle.value.left}px`,\n }\n if (props.zoomType === 'free') {\n delete style['aspect-ratio']\n }\n else if (props.zoomType === 'fixed') {\n delete style.height\n }\n return ns.cssVarBlock(style)\n})\n\nfunction zoom(pixel: number) {\n return pixel * ratio.value\n}\nasync function crop(img: HTMLImageElement = imgRef.value!) {\n let backgroundColor = 'transparent'\n if (containerBoxRef.value) {\n backgroundColor = window.getComputedStyle(\n containerBoxRef.value,\n ).backgroundColor\n }\n const canvas = document.createElement('canvas')\n canvas.width = zoom(containerBoxRef.value?.clientWidth || 0)\n canvas.height = zoom(containerBoxRef.value?.clientHeight || 0)\n const { drawImage, cropCanvas, drawColor } = useCanvas(canvas)\n drawColor(0, 0, canvas.width, canvas.height, backgroundColor)\n drawImage(\n img,\n zoom(img.offsetLeft),\n zoom(img.offsetTop),\n img.naturalWidth,\n img.naturalHeight,\n )\n return await cropCanvas(\n zoom(x.value),\n zoom(y.value),\n zoom(width.value),\n zoom(height.value),\n )\n}\n\nfunction checkBoundaries(\n newWidth: number,\n newHeight: number,\n): { width: number, height: number } {\n const maxWidth = containerBoxRef.value?.clientWidth || Infinity\n const maxHeight = containerBoxRef.value?.clientHeight || Infinity\n\n return {\n width: Math.min(Math.max(newWidth, 0), maxWidth),\n height: Math.min(Math.max(newHeight, 0), maxHeight),\n }\n}\n\nfunction mousemove(e: MouseEvent) {\n const deltaX = e.clientX - startX\n const deltaY = e.clientY - startY\n\n if (dargPoint.value === 'bottom-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n }\n else if (dargPoint.value === 'top-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'top-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'bottom-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n e.preventDefault()\n e.stopPropagation()\n}\n\nfunction mousedown(e: MouseEvent, point: string) {\n dargPoint.value = point\n startX = e.clientX\n startY = e.clientY\n startWidth = cropInfo.value.width\n startHeight = cropInfo.value.height\n\n if (point === 'bottom-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value\n }\n else if (point === 'top-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'top-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'bottom-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value\n }\n}\n\nfunction mouseup() {\n dargPoint.value = ''\n}\n\nfunction resize() {\n cropInfo.value.width = props.defaultWidth\n cropInfo.value.height = props.defaultHeight\n x.value = 0\n y.value = 0\n}\n\ndocument.addEventListener('mouseup', mouseup)\ndocument.addEventListener('mousemove', mousemove)\n\nonMounted(() => {\n nextTick(() => {\n // 初始化位置\n initialValue.value.x\n = (containerBoxRef.value?.offsetWidth || 0) / 2 - cropInfo.value.width / 2\n initialValue.value.y\n = (containerBoxRef.value?.offsetHeight || 0) / 2\n - cropInfo.value.height / 2\n })\n})\n\nonUnmounted(() => {\n if (imageUrl.value) {\n URL.revokeObjectURL(imageUrl.value)\n }\n document.removeEventListener('mouseup', mouseup)\n document.removeEventListener('mousemove', mousemove)\n})\n\ndefineExpose({\n crop,\n resize,\n})\n</script>\n\n<template>\n <div ref=\"containerBoxRef\" :class=\"[ns.e('img-box')]\">\n <div v-if=\"errorMessage\" :class=\"[ns.e('error-message')]\">\n {{ errorMessage }}\n </div>\n <template v-else>\n <img\n ref=\"imgRef\"\n :class=\"[ns.e('image')]\"\n :src=\"imageUrl\"\n >\n <div\n ref=\"cropBoxRef\"\n :class=\"[ns.e('crop-tool-box')]\"\n :style=\"[\n sizeStyle,\n dargPoint\n ? `left: ${customStyle.left}px;top: ${customStyle.top}px`\n : style,\n ]\"\n >\n <div\n :class=\"[ns.e('top-left')]\"\n @mousedown=\"mousedown($event, 'top-left')\"\n />\n <div\n :class=\"[ns.e('top-right')]\"\n @mousedown=\"mousedown($event, 'top-right')\"\n />\n <div\n :class=\"[ns.e('bottom-right')]\"\n @mousedown=\"mousedown($event, 'bottom-right')\"\n />\n <div\n :class=\"[ns.e('bottom-left')]\"\n @mousedown=\"mousedown($event, 'bottom-left')\"\n />\n </div>\n </template>\n </div>\n</template>\n"],"names":["props","__props","startX","startY","startWidth","startHeight","ns","useNamespace","cropBoxRef","ref","containerBoxRef","imgRef","errorMessage","dargPoint","initialValue","x","y","cropInfo","width","defaultWidth","height","defaultHeight","useElementSize","imgWidth","style","useDraggable","containerElement","draggingElement","disabled","computed","value","exact","imageUrl","imgFile","URL","createObjectURL","watch","newFile","type","startsWith","ratio","naturalWidth","customStyle","position","left","top","sizeStyle","aspectRatio","zoomType","cssVarBlock","zoom","pixel","checkBoundaries","newWidth","newHeight","maxWidth","clientWidth","Infinity","maxHeight","clientHeight","Math","min","max","mousemove","e","deltaX","clientX","deltaY","clientY","Number","parseFloat","split","preventDefault","stopPropagation","mousedown","point","mouseup","document","addEventListener","onMounted","nextTick","offsetWidth","offsetHeight","onUnmounted","revokeObjectURL","removeEventListener","__expose","crop","async","img","backgroundColor","window","getComputedStyle","canvas","createElement","drawImage","cropCanvas","drawColor","useCanvas","offsetLeft","offsetTop","naturalHeight","resize"],"mappings":"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"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{ElPopover as e,ElLink as l,ElCheckbox as a,ElButton as t,ElIcon as n,ElDialog as o,ElRadioGroup as i,ElRadio as u}from"element-plus/es";import{defineComponent as s,
|
1
|
+
import{ElPopover as e,ElLink as l,ElCheckbox as a,ElButton as t,ElIcon as n,ElDialog as o,ElRadioGroup as i,ElRadio as u}from"element-plus/es";import{defineComponent as s,ref as d,computed as c,createElementBlock as r,openBlock as m,normalizeClass as p,unref as f,createElementVNode as y,createCommentVNode as v,createVNode as b,createBlock as k,withCtx as _,createTextVNode as h,isRef as g,Fragment as w,renderList as C,toDisplayString as x}from"vue";import{Edit as V,Delete as j,Top as O,Bottom as S}from"@element-plus/icons-vue";import{useNamespace as E}from"@qxs-bns/hooks";import T from"../../subject-type/src/subject-type.vue.mjs";const U={key:0,class:"flex-justify-between"},A={key:0,class:"has-set"},B={key:1,class:"flex flex-justify-end",style:{width:"100%"}};var K=s({name:"QxsSubjectAction",__name:"subject-action",props:{isEdit:{type:Boolean},isSet:{type:Boolean,default:!1},isKey:{type:Boolean,default:!1},answerCheckType:{type:Number,default:1},showOtherOption:{type:Boolean,default:!0},examAnswerRelationType:{type:Number,default:null},pageEnd:{type:Boolean,default:!1}},emits:["moveUp","moveDown","delete","save","edit","add","onShowRichText","setKey","setAnswerSetting"],setup(s,{emit:K}){const R=s,z=d(R.isKey),D=d(!1),N=K,q=d(R.answerCheckType),Q=E("subject-action"),F=[{value:2,label:"必须全部都是支持选项,方可下一步"},{value:1,label:"无需判断是否是支持选项"},{value:3,label:"包含全部支持选项,即可下一步"}],G=c((()=>F.find((e=>e.value===q.value))?.label));function H(){D.value=!1,N("setAnswerSetting",q.value)}function I(e,l){N("add",e,l?R.examAnswerRelationType:null)}return(d,c)=>{const E=l,K=e,R=a,J=n,L=t,M=u,P=i,W=o;return m(),r("div",{class:p(f(Q).e("action-exam"))},[y("div",{class:p(["action flex",[{active:s.isEdit}]])},[s.isEdit?(m(),r("div",U,[b(K,{trigger:"click"},{reference:_((()=>[b(E,{type:"primary",class:"btn-margin"},{default:_((()=>c[14]||(c[14]=[h(" +在此题后加入新题 ")]))),_:1})])),default:_((()=>[b(T,{onSelect:I})])),_:1}),s.showOtherOption?(m(),k(E,{key:0,type:"primary",onClick:c[0]||(c[0]=e=>N("onShowRichText")),class:"btn-margin"},{default:_((()=>c[15]||(c[15]=[h(" +添加题目描述(图文) ")]))),_:1})):v("v-if",!0),s.showOtherOption?(m(),k(E,{key:1,type:"primary",onClick:c[1]||(c[1]=e=>D.value=!0),class:"btn-margin"},{default:_((()=>c[16]||(c[16]=[h(" 答题设置 ")]))),_:1})):v("v-if",!0),s.showOtherOption?(m(),k(R,{key:2,modelValue:f(z),"onUpdate:modelValue":c[2]||(c[2]=e=>g(z)?z.value=e:null),label:"核心题",onChange:c[3]||(c[3]=e=>N("setKey",f(z)))},null,8,["modelValue"])):v("v-if",!0)])):v("v-if",!0),y("div",null,[s.isSet?(m(),r("div",A," *此题设置了跳题逻辑 ")):(m(),r("div",B,[s.isEdit?(m(),r(w,{key:1},[b(L,{class:"btn-margin",onClick:c[9]||(c[9]=e=>N("delete"))},{default:_((()=>c[21]||(c[21]=[h(" 删除 ")]))),_:1}),b(L,{type:"primary",onClick:c[10]||(c[10]=e=>N("save"))},{default:_((()=>c[22]||(c[22]=[h(" 完成编辑 ")]))),_:1})],64)):(m(),r(w,{key:0},[b(R,{modelValue:f(z),"onUpdate:modelValue":c[4]||(c[4]=e=>g(z)?z.value=e:null),label:"核心题",disabled:""},null,8,["modelValue"]),b(R,{"v-model":!0,label:f(G),disabled:""},null,8,["label"]),s.pageEnd?v("v-if",!0):(m(),k(L,{key:0,class:"btn-margin",onClick:c[5]||(c[5]=e=>N("edit"))},{icon:_((()=>[b(J,null,{default:_((()=>[b(f(V))])),_:1})])),default:_((()=>[c[17]||(c[17]=h(" 编辑 "))])),_:1})),b(L,{class:"btn-margin",onClick:c[6]||(c[6]=e=>N("delete"))},{icon:_((()=>[b(J,null,{default:_((()=>[b(f(j))])),_:1})])),default:_((()=>[c[18]||(c[18]=h(" 删除 "))])),_:1}),b(L,{class:"btn-margin",onClick:c[7]||(c[7]=e=>N("moveUp"))},{icon:_((()=>[b(J,null,{default:_((()=>[b(f(O))])),_:1})])),default:_((()=>[c[19]||(c[19]=h(" 上移 "))])),_:1}),b(L,{class:"btn-margin",onClick:c[8]||(c[8]=e=>N("moveDown"))},{icon:_((()=>[b(J,null,{default:_((()=>[b(f(S))])),_:1})])),default:_((()=>[c[20]||(c[20]=h(" 下移 "))])),_:1})],64))]))]),b(W,{modelValue:f(D),"onUpdate:modelValue":c[13]||(c[13]=e=>g(D)?D.value=e:null),title:"答题设置",class:"customize-dialog"},{footer:_((()=>[b(L,{class:"customize-button",type:"primary",plain:"",onClick:c[12]||(c[12]=e=>D.value=!1)},{default:_((()=>c[23]||(c[23]=[h(" 取消 ")]))),_:1}),b(L,{class:"customize-button",type:"primary",plain:"",onClick:H},{default:_((()=>c[24]||(c[24]=[h(" 保存 ")]))),_:1})])),default:_((()=>[(m(),r(w,null,C(F,(e=>b(P,{modelValue:f(q),"onUpdate:modelValue":c[11]||(c[11]=e=>g(q)?q.value=e:null),class:"vertical-radio-group"},{default:_((()=>[b(M,{value:e.value},{default:_((()=>[h(x(e.label),1)])),_:2},1032,["value"])])),_:2},1032,["modelValue"]))),64))])),_:1},8,["modelValue"])],2)],2)}}});export{K as default};
|
2
2
|
//# sourceMappingURL=subject-action.vue.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"subject-action.vue.mjs","sources":["../../../../../../packages/components/src/subject-action/src/subject-action.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { Bottom, Delete, Edit, Top } from '@element-plus/icons-vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport SubjectType from '../../subject-type/src/subject-type.vue'\n\ndefineOptions({\n name: 'QxsSubjectAction',\n})\nconst props = defineProps({\n isEdit: {\n type: Boolean,\n },\n isSet: {\n type: Boolean,\n default: false,\n },\n isKey: {\n type: Boolean,\n default: false,\n },\n answerCheckType: {\n type: Number,\n default: 1\n },\n showOtherOption: {\n type: Boolean,\n default: true,\n },\n examAnswerRelationType: {\n type: Number,\n default: null\n },\n pageEnd: {\n type: Boolean,\n default: false\n }\n})\nconst isKey = ref(props.isKey)\nconst showAnswerSetting = ref(false)\nconst emits = defineEmits(['moveUp', 'moveDown', 'delete', 'save', 'edit', 'add', 'onShowRichText', 'setKey', 'setAnswerSetting'])\nconst answerType = ref(props.answerCheckType)\nconst ns = useNamespace('subject-action')\nconst answerTextList = [\n {\n value: 2,\n label: '必须全部都是支持选项,方可下一步'\n },\n {\n value: 1,\n label: '无需判断是否是支持选项'\n },\n {\n value: 3,\n label: '包含全部支持选项,即可下一步'\n }\n]\nconst answerText = computed(() => {\n return answerTextList.find(item => item.value === answerType.value)?.label\n})\nfunction onSaveSetting() {\n showAnswerSetting.value = false\n emits('setAnswerSetting', answerType.value)\n}\n\nfunction selectExam(type:string, canSet: boolean) {\n emits('add', type, canSet? props.examAnswerRelationType: null)\n}\n</script>\n\n<template>\n <div :class=\"ns.e('action-exam')\">\n <div class=\"action flex\" :class=\"[{ active: isEdit }]\">\n <div v-if=\"isEdit\" class=\"flex-justify-between\">\n <el-popover trigger=\"click\">\n <template #reference>\n <el-link type=\"primary\" class=\"btn-margin\">\n +在此题后加入新题\n </el-link>\n </template>\n <SubjectType @select=\"selectExam\" />\n </el-popover>\n <el-link type=\"primary\" @click=\"emits('onShowRichText')\" v-if=\"showOtherOption\" class=\"btn-margin\">\n +添加题目描述(图文)\n </el-link>\n <el-link type=\"primary\" @click=\"showAnswerSetting = true\" v-if=\"showOtherOption\" class=\"btn-margin\">\n 答题设置\n </el-link>\n <el-checkbox v-model=\"isKey\" label=\"核心题\" @change=\"emits('setKey', isKey)\" v-if=\"showOtherOption\" />\n </div>\n <div>\n <div v-if=\"isSet\" class=\"has-set\">\n *此题设置了跳题逻辑\n </div>\n <div v-else class=\"flex flex-justify-end\" style=\"width: 100%;\">\n <template v-if=\"!isEdit\">\n <el-checkbox v-model=\"isKey\" label=\"核心题\" disabled />\n <el-checkbox :v-model=\"true\" :label=\"answerText\" disabled />\n <el-button class=\"btn-margin\" @click=\"emits('edit')\" v-if=\"!pageEnd\">\n <template #icon>\n <el-icon>\n <Edit />\n </el-icon>\n </template>\n 编辑\n </el-button>\n <el-button class=\"btn-margin\" @click=\"emits('delete')\">\n <template #icon>\n <el-icon>\n <Delete />\n </el-icon>\n </template>\n 删除\n </el-button>\n <el-button class=\"btn-margin\" @click=\"emits('moveUp')\">\n <template #icon>\n <el-icon>\n <Top />\n </el-icon>\n </template>\n 上移\n </el-button>\n <el-button class=\"btn-margin\" @click=\"emits('moveDown')\">\n <template #icon>\n <el-icon>\n <Bottom />\n </el-icon>\n </template>\n 下移\n </el-button>\n </template>\n <template v-else>\n <el-button class=\"btn-margin\" @click=\"emits('delete')\">\n 删除\n </el-button>\n <el-button type=\"primary\" @click=\"emits('save')\">\n 完成编辑\n </el-button>\n </template>\n </div>\n </div>\n <el-dialog\n v-model=\"showAnswerSetting\"\n title=\"答题设置\"\n class=\"customize-dialog\"\n >\n <el-radio-group v-model=\"answerType\" class=\"vertical-radio-group\" v-for=\"item in answerTextList\">\n <el-radio :value=\"item.value\">{{ item.label }}</el-radio>\n </el-radio-group>\n <template #footer>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"showAnswerSetting = false\"\n >\n 取消\n </el-button>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"onSaveSetting\"\n >\n 保存\n </el-button>\n </template>\n </el-dialog>\n </div>\n </div>\n</template>\n"],"names":["props","__props","isKey","ref","showAnswerSetting","emits","__emit","answerType","answerCheckType","ns","useNamespace","answerTextList","value","label","answerText","computed","find","item","onSaveSetting","selectExam","type","canSet","examAnswerRelationType"],"mappings":"
|
1
|
+
{"version":3,"file":"subject-action.vue.mjs","sources":["../../../../../../packages/components/src/subject-action/src/subject-action.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { Bottom, Delete, Edit, Top } from '@element-plus/icons-vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport SubjectType from '../../subject-type/src/subject-type.vue'\n\ndefineOptions({\n name: 'QxsSubjectAction',\n})\nconst props = defineProps({\n isEdit: {\n type: Boolean,\n },\n isSet: {\n type: Boolean,\n default: false,\n },\n isKey: {\n type: Boolean,\n default: false,\n },\n answerCheckType: {\n type: Number,\n default: 1\n },\n showOtherOption: {\n type: Boolean,\n default: true,\n },\n examAnswerRelationType: {\n type: Number,\n default: null\n },\n pageEnd: {\n type: Boolean,\n default: false\n }\n})\nconst isKey = ref(props.isKey)\nconst showAnswerSetting = ref(false)\nconst emits = defineEmits(['moveUp', 'moveDown', 'delete', 'save', 'edit', 'add', 'onShowRichText', 'setKey', 'setAnswerSetting'])\nconst answerType = ref(props.answerCheckType)\nconst ns = useNamespace('subject-action')\nconst answerTextList = [\n {\n value: 2,\n label: '必须全部都是支持选项,方可下一步'\n },\n {\n value: 1,\n label: '无需判断是否是支持选项'\n },\n {\n value: 3,\n label: '包含全部支持选项,即可下一步'\n }\n]\nconst answerText = computed(() => {\n return answerTextList.find(item => item.value === answerType.value)?.label\n})\nfunction onSaveSetting() {\n showAnswerSetting.value = false\n emits('setAnswerSetting', answerType.value)\n}\n\nfunction selectExam(type:string, canSet: boolean) {\n emits('add', type, canSet? props.examAnswerRelationType: null)\n}\n</script>\n\n<template>\n <div :class=\"ns.e('action-exam')\">\n <div class=\"action flex\" :class=\"[{ active: isEdit }]\">\n <div v-if=\"isEdit\" class=\"flex-justify-between\">\n <el-popover trigger=\"click\">\n <template #reference>\n <el-link type=\"primary\" class=\"btn-margin\">\n +在此题后加入新题\n </el-link>\n </template>\n <SubjectType @select=\"selectExam\" />\n </el-popover>\n <el-link type=\"primary\" @click=\"emits('onShowRichText')\" v-if=\"showOtherOption\" class=\"btn-margin\">\n +添加题目描述(图文)\n </el-link>\n <el-link type=\"primary\" @click=\"showAnswerSetting = true\" v-if=\"showOtherOption\" class=\"btn-margin\">\n 答题设置\n </el-link>\n <el-checkbox v-model=\"isKey\" label=\"核心题\" @change=\"emits('setKey', isKey)\" v-if=\"showOtherOption\" />\n </div>\n <div>\n <div v-if=\"isSet\" class=\"has-set\">\n *此题设置了跳题逻辑\n </div>\n <div v-else class=\"flex flex-justify-end\" style=\"width: 100%;\">\n <template v-if=\"!isEdit\">\n <el-checkbox v-model=\"isKey\" label=\"核心题\" disabled />\n <el-checkbox :v-model=\"true\" :label=\"answerText\" disabled />\n <el-button class=\"btn-margin\" @click=\"emits('edit')\" v-if=\"!pageEnd\">\n <template #icon>\n <el-icon>\n <Edit />\n </el-icon>\n </template>\n 编辑\n </el-button>\n <el-button class=\"btn-margin\" @click=\"emits('delete')\">\n <template #icon>\n <el-icon>\n <Delete />\n </el-icon>\n </template>\n 删除\n </el-button>\n <el-button class=\"btn-margin\" @click=\"emits('moveUp')\">\n <template #icon>\n <el-icon>\n <Top />\n </el-icon>\n </template>\n 上移\n </el-button>\n <el-button class=\"btn-margin\" @click=\"emits('moveDown')\">\n <template #icon>\n <el-icon>\n <Bottom />\n </el-icon>\n </template>\n 下移\n </el-button>\n </template>\n <template v-else>\n <el-button class=\"btn-margin\" @click=\"emits('delete')\">\n 删除\n </el-button>\n <el-button type=\"primary\" @click=\"emits('save')\">\n 完成编辑\n </el-button>\n </template>\n </div>\n </div>\n <el-dialog\n v-model=\"showAnswerSetting\"\n title=\"答题设置\"\n class=\"customize-dialog\"\n >\n <el-radio-group v-model=\"answerType\" class=\"vertical-radio-group\" v-for=\"item in answerTextList\">\n <el-radio :value=\"item.value\">{{ item.label }}</el-radio>\n </el-radio-group>\n <template #footer>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"showAnswerSetting = false\"\n >\n 取消\n </el-button>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"onSaveSetting\"\n >\n 保存\n </el-button>\n </template>\n </el-dialog>\n </div>\n </div>\n</template>\n"],"names":["props","__props","isKey","ref","showAnswerSetting","emits","__emit","answerType","answerCheckType","ns","useNamespace","answerTextList","value","label","answerText","computed","find","item","onSaveSetting","selectExam","type","canSet","examAnswerRelationType"],"mappings":"srCAQA,MAAMA,EAAQC,EA6BRC,EAAQC,EAAIH,EAAME,OAClBE,EAAoBD,GAAI,GACxBE,EAAQC,EACRC,EAAaJ,EAAIH,EAAMQ,iBACvBC,EAAKC,EAAa,kBAClBC,EAAiB,CACrB,CACEC,MAAO,EACPC,MAAO,oBAET,CACED,MAAO,EACPC,MAAO,eAET,CACED,MAAO,EACPC,MAAO,mBAGLC,EAAaC,GAAS,IACnBJ,EAAeK,MAAKC,GAAQA,EAAKL,QAAUL,EAAWK,SAAQC,QAEvE,SAASK,IACPd,EAAkBQ,OAAQ,EACpBP,EAAA,mBAAoBE,EAAWK,MAAK,CAGnC,SAAAO,EAAWC,EAAaC,GAChChB,EAAM,MAAOe,EAAMC,EAAQrB,EAAMsB,uBAAwB,KAAI"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{ElRow as e}from"element-plus/es";import{defineComponent as t,
|
1
|
+
import{ElRow as e}from"element-plus/es";import{defineComponent as t,onMounted as n,createElementBlock as o,openBlock as a,normalizeClass as s,unref as r,createVNode as i,withCtx as l,createElementVNode as u,toDisplayString as d}from"vue";import{useNamespace as p}from"@qxs-bns/hooks";import m from"../../../subject-action/src/subject-action.vue.mjs";var c=t({name:"QxsSubjectScale",__name:"SubjectPageEnd",props:{currentPageIndex:{type:Number,required:!0},totalPage:{type:Number,required:!0},isSave:{type:Boolean,required:!0},showAction:{type:Boolean,required:!1},isEdit:{type:Boolean,required:!0},isSet:{type:Boolean,required:!0},examAnswerRelationType:{type:Number,required:!1}},emits:["move","save","delete","edit","add"],setup(t,{emit:c}){const y=t,v=c;n((function(){}));const x=p("subject-end");return(t,n)=>{const p=e;return a(),o("div",{class:s(r(x).e("end-exam"))},[i(p,{type:"flex",align:"middle"},{default:l((()=>[n[5]||(n[5]=u("span",{class:"auto-line"},null,-1)),u("span",null,"第"+d(y.currentPageIndex)+" / "+d(t.totalPage)+"页",1),n[6]||(n[6]=u("span",{class:"auto-line"},null,-1))])),_:1}),i(m,{"is-edit":!1,"is-set":t.isSet,pageEnd:!0,examAnswerRelationType:y.examAnswerRelationType,showOtherOption:!1,onMoveUp:n[0]||(n[0]=e=>v("move","up")),onMoveDown:n[1]||(n[1]=e=>v("move","down")),onDelete:n[2]||(n[2]=e=>v("delete")),onEdit:n[3]||(n[3]=e=>v("edit")),onAdd:n[4]||(n[4]=e=>v("add",e))},null,8,["is-set","examAnswerRelationType"])],2)}}});export{c as default};
|
2
2
|
//# sourceMappingURL=SubjectPageEnd.vue.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"SubjectPageEnd.vue.mjs","sources":["../../../../../../../packages/components/src/subject-list/src/components/SubjectPageEnd.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useNamespace } from '@qxs-bns/hooks'\nimport SubjectAction from '../../../subject-action/src/subject-action.vue'\n\ndefineOptions({\n name: 'QxsSubjectScale',\n})\nconst props = defineProps<{\n currentPageIndex: number\n totalPage: number\n isSave: boolean\n showAction?: boolean\n isEdit: boolean\n isSet: boolean\n examAnswerRelationType?: number\n}>()\nconst emits = defineEmits(['move', 'save', 'delete', 'edit', 'add'])\n\nfunction init() {\n\n}\n\nonMounted(init)\nconst ns = useNamespace('subject-end')\n</script>\n\n<template>\n <div :class=\"ns.e('end-exam')\">\n <el-row type=\"flex\" align=\"middle\">\n <span class=\"auto-line\" />\n <span>第{{ props.currentPageIndex }} / {{ totalPage }}页</span>\n <span class=\"auto-line\" />\n </el-row>\n <SubjectAction\n :is-edit=\"false\"\n :is-set=\"isSet\"\n :pageEnd=\"true\"\n :examAnswerRelationType=\"props.examAnswerRelationType\"\n :showOtherOption=\"false\"\n @move-up=\"emits('move', 'up')\"\n @move-down=\"emits('move', 'down')\"\n @delete=\"emits('delete')\"\n @edit=\"emits('edit')\"\n @add=\"type => emits('add', type)\"\n />\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","onMounted","ns","useNamespace"],"mappings":"
|
1
|
+
{"version":3,"file":"SubjectPageEnd.vue.mjs","sources":["../../../../../../../packages/components/src/subject-list/src/components/SubjectPageEnd.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useNamespace } from '@qxs-bns/hooks'\nimport SubjectAction from '../../../subject-action/src/subject-action.vue'\n\ndefineOptions({\n name: 'QxsSubjectScale',\n})\nconst props = defineProps<{\n currentPageIndex: number\n totalPage: number\n isSave: boolean\n showAction?: boolean\n isEdit: boolean\n isSet: boolean\n examAnswerRelationType?: number\n}>()\nconst emits = defineEmits(['move', 'save', 'delete', 'edit', 'add'])\n\nfunction init() {\n\n}\n\nonMounted(init)\nconst ns = useNamespace('subject-end')\n</script>\n\n<template>\n <div :class=\"ns.e('end-exam')\">\n <el-row type=\"flex\" align=\"middle\">\n <span class=\"auto-line\" />\n <span>第{{ props.currentPageIndex }} / {{ totalPage }}页</span>\n <span class=\"auto-line\" />\n </el-row>\n <SubjectAction\n :is-edit=\"false\"\n :is-set=\"isSet\"\n :pageEnd=\"true\"\n :examAnswerRelationType=\"props.examAnswerRelationType\"\n :showOtherOption=\"false\"\n @move-up=\"emits('move', 'up')\"\n @move-down=\"emits('move', 'down')\"\n @delete=\"emits('delete')\"\n @edit=\"emits('edit')\"\n @add=\"type => emits('add', type)\"\n />\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","onMounted","ns","useNamespace"],"mappings":"uuBAOA,MAAMA,EAAQC,EASRC,EAAQC,EAMdC,GAJA,WAAgB,IAKV,MAAAC,EAAKC,EAAa"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{defineComponent as e,
|
1
|
+
import{defineComponent as e,useAttrs as t,ref as o,onMounted as i,createElementBlock as r,openBlock as n,normalizeClass as s,unref as d,createVNode as a,withCtx as l,createBlock as u,createCommentVNode as m,mergeProps as c,isRef as p,createElementVNode as v,createTextVNode as y,toDisplayString as x}from"vue";import{useNamespace as w}from"@qxs-bns/hooks";import{ElMessage as h}from"element-plus";import f from"../../../subject-action/src/subject-action.vue.mjs";import T from"../../../subject-layout/src/subject-layout.vue.mjs";import b from"../../../tiny-mce-editor/src/tiny-mce-editor.vue.mjs";const j={class:"preview"},q=["innerHTML"];var S=e({name:"QxsSubjectScale",__name:"SubjectRichText",props:{orderIndex:{type:Number,required:!0},richTextContent:{type:String,required:!0},title:{type:String,required:!1},isSave:{type:Boolean,required:!0},showAction:{type:Boolean,required:!1},isEdit:{type:Boolean,required:!0},isSet:{type:Boolean,required:!0},examAnswerRelationType:{type:Number,required:!1}},emits:["move","save","delete","edit","add"],setup(e,{emit:S}){const A=e,R=S,B=t(),C=o("");function E(){C.value?R("save",{richTextContent:C.value||""}):h.error("富文本内容不能为空!")}i((function(){A.richTextContent&&(C.value=A.richTextContent)}));const M=w("subject-scale");return(e,t)=>(n(),r("div",{class:s(d(M).e("scale-exam"))},[a(T,{"show-edit":e.isEdit},{preview:l((()=>[v("div",j,[y(x(e.orderIndex+1)+".",1),v("div",{innerHTML:d(C)},null,8,q)])])),edit:l((()=>[a(b,c({"model-value":d(C),"onUpdate:modelValue":t[0]||(t[0]=e=>p(C)?C.value=e:null)},d(B),{style:{width:"100%"}}),null,16,["model-value"])])),default:l((()=>[e.showAction?(n(),u(f,{key:0,"is-edit":e.isEdit,"is-set":e.isSet,examAnswerRelationType:A.examAnswerRelationType,showOtherOption:!1,onMoveUp:t[1]||(t[1]=e=>R("move","up")),onMoveDown:t[2]||(t[2]=e=>R("move","down")),onDelete:t[3]||(t[3]=e=>R("delete")),onSave:E,onEdit:t[4]||(t[4]=e=>R("edit")),onAdd:t[5]||(t[5]=e=>R("add",e))},null,8,["is-edit","is-set","examAnswerRelationType"])):m("v-if",!0)])),_:1},8,["show-edit"])],2))}});export{S as default};
|
2
2
|
//# sourceMappingURL=SubjectRichText.vue.mjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"SubjectRichText.vue.mjs","sources":["../../../../../../../packages/components/src/subject-list/src/components/SubjectRichText.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useNamespace } from '@qxs-bns/hooks'\nimport { ElMessage } from 'element-plus'\nimport SubjectAction from '../../../subject-action/src/subject-action.vue'\nimport SubjectLayout from '../../../subject-layout/src/subject-layout.vue'\nimport TinyMceEditor from '../../../tiny-mce-editor/src/tiny-mce-editor.vue'\n\ndefineOptions({\n name: 'QxsSubjectScale',\n})\nconst props = defineProps<{\n orderIndex: number\n richTextContent: string\n title?: string\n isSave: boolean\n showAction?: boolean\n isEdit: boolean\n isSet: boolean\n examAnswerRelationType?: number\n}>()\nconst emits = defineEmits(['move', 'save', 'delete', 'edit', 'add'])\n\nconst attrs = useAttrs()\n\nconst richContent = ref('')\n\nfunction save() {\n if (!richContent.value) {\n ElMessage.error('富文本内容不能为空!')\n return\n }\n\n\n emits('save', {\n richTextContent: richContent.value ||'',\n })\n}\n\nfunction init() {\n if (props.richTextContent) {\n richContent.value = props.richTextContent\n }\n}\n\nonMounted(init)\nconst ns = useNamespace('subject-scale')\n</script>\n\n<template>\n <div :class=\"ns.e('scale-exam')\">\n <SubjectLayout :show-edit=\"isEdit\">\n <template #preview>\n <div class=\"preview\">\n {{ orderIndex + 1 }}.<div v-html=\"richContent\" />\n </div>\n </template>\n <template #edit>\n <TinyMceEditor v-model:model-value=\"richContent\" v-bind=\"attrs\" style=\"width: 100%;\" />\n </template>\n <SubjectAction\n v-if=\"showAction\"\n :is-edit=\"isEdit\"\n :is-set=\"isSet\"\n :examAnswerRelationType=\"props.examAnswerRelationType\"\n :showOtherOption=\"false\"\n @move-up=\"emits('move', 'up')\"\n @move-down=\"emits('move', 'down')\"\n @delete=\"emits('delete')\"\n @save=\"save\"\n @edit=\"emits('edit')\"\n @add=\"type => emits('add', type)\"\n />\n </SubjectLayout>\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","attrs","useAttrs","richContent","ref","save","value","richTextContent","ElMessage","error","onMounted","ns","useNamespace"],"mappings":"
|
1
|
+
{"version":3,"file":"SubjectRichText.vue.mjs","sources":["../../../../../../../packages/components/src/subject-list/src/components/SubjectRichText.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useNamespace } from '@qxs-bns/hooks'\nimport { ElMessage } from 'element-plus'\nimport SubjectAction from '../../../subject-action/src/subject-action.vue'\nimport SubjectLayout from '../../../subject-layout/src/subject-layout.vue'\nimport TinyMceEditor from '../../../tiny-mce-editor/src/tiny-mce-editor.vue'\n\ndefineOptions({\n name: 'QxsSubjectScale',\n})\nconst props = defineProps<{\n orderIndex: number\n richTextContent: string\n title?: string\n isSave: boolean\n showAction?: boolean\n isEdit: boolean\n isSet: boolean\n examAnswerRelationType?: number\n}>()\nconst emits = defineEmits(['move', 'save', 'delete', 'edit', 'add'])\n\nconst attrs = useAttrs()\n\nconst richContent = ref('')\n\nfunction save() {\n if (!richContent.value) {\n ElMessage.error('富文本内容不能为空!')\n return\n }\n\n\n emits('save', {\n richTextContent: richContent.value ||'',\n })\n}\n\nfunction init() {\n if (props.richTextContent) {\n richContent.value = props.richTextContent\n }\n}\n\nonMounted(init)\nconst ns = useNamespace('subject-scale')\n</script>\n\n<template>\n <div :class=\"ns.e('scale-exam')\">\n <SubjectLayout :show-edit=\"isEdit\">\n <template #preview>\n <div class=\"preview\">\n {{ orderIndex + 1 }}.<div v-html=\"richContent\" />\n </div>\n </template>\n <template #edit>\n <TinyMceEditor v-model:model-value=\"richContent\" v-bind=\"attrs\" style=\"width: 100%;\" />\n </template>\n <SubjectAction\n v-if=\"showAction\"\n :is-edit=\"isEdit\"\n :is-set=\"isSet\"\n :examAnswerRelationType=\"props.examAnswerRelationType\"\n :showOtherOption=\"false\"\n @move-up=\"emits('move', 'up')\"\n @move-down=\"emits('move', 'down')\"\n @delete=\"emits('delete')\"\n @save=\"save\"\n @edit=\"emits('edit')\"\n @add=\"type => emits('add', type)\"\n />\n </SubjectLayout>\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","attrs","useAttrs","richContent","ref","save","value","richTextContent","ElMessage","error","onMounted","ns","useNamespace"],"mappings":"yiCAUA,MAAMA,EAAQC,EAURC,EAAQC,EAERC,EAAQC,IAERC,EAAcC,EAAI,IAExB,SAASC,IACFF,EAAYG,MAMjBP,EAAM,OAAQ,CACZQ,gBAAiBJ,EAAYG,OAAQ,KANrCE,EAAUC,MAAM,aAOjB,CASHC,GANA,WACMb,EAAMU,kBACRJ,EAAYG,MAAQT,EAAMU,gBAC5B,IAII,MAAAI,EAAKC,EAAa"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{ElInput as e,ElLink as l,ElCheckboxGroup as t,ElCheckbox as i,ElTag as a,ElButton as s,ElIcon as n}from"element-plus/es";import{defineComponent as o,
|
1
|
+
import{ElInput as e,ElLink as l,ElCheckboxGroup as t,ElCheckbox as i,ElTag as a,ElButton as s,ElIcon as n}from"element-plus/es";import{defineComponent as o,useAttrs as r,ref as u,watch as d,onMounted as v,createElementBlock as m,openBlock as c,normalizeClass as f,unref as p,createVNode as x,withCtx as y,createBlock as w,createCommentVNode as g,createElementVNode as h,isRef as _,createTextVNode as b,Fragment as k,renderList as j,toDisplayString as A,mergeProps as C}from"vue";import{Plus as I}from"@element-plus/icons-vue";import{useNamespace as V}from"@qxs-bns/hooks";import{ElMessage as S}from"element-plus";import O from"../../../subject-action/src/subject-action.vue.mjs";import q from"../../../subject-layout/src/subject-layout.vue.mjs";import T from"../../../tiny-mce-editor/src/tiny-mce-editor.vue.mjs";const R={class:"preview"},B={class:"content"},U={class:"title"},L={key:0},E=["innerHTML"],M={key:1,class:"flex flex-wrap",style:{"margin-top":"10px",color:"#a8abb2"}},D={class:"flex"},H={style:{flex:"1"}},N={class:"flex flex-justify-end"},z={class:"margin-bottom flex flex-items-center"},F={class:"margin-bottom answer-list"},G={class:"label flex flex-justify-end"},J={class:"answer-tags"},K={key:0,class:"margin-bottom flex"},P={style:{flex:"1"}},Q={key:1,class:"margin-bottom flex"},W={style:{flex:"1"}},X={class:"flex flex-justify-end"};var Y=o({__name:"subject-blank-fill",props:{orderIndex:{type:Number,required:!0},title:{type:String,required:!1},isSave:{type:Boolean,required:!0},showAction:{type:Boolean,required:!1},answerList:{type:null,required:!1},analysis:{type:String,required:!1},isEdit:{type:Boolean,required:!0},isSet:{type:Boolean,required:!0},examAnswerSettingVO:{type:Object,required:!1},examRichTextContent:{type:String,required:!1},showAnalysis:{type:Boolean,required:!1},examAnswerRelationType:{type:Number,required:!1}},emits:["move","save","delete","edit","add"],setup(o,{emit:Y}){const Z=o,$=Y,ee=r(),le=u([]),te=u(""),ie=u(""),ae=u(!1),se=u(""),ne=[{label:"答案不分顺序",value:"isInOrder"},{label:"忽略大小写",value:"isIgnoreCase"}],oe=u(["isIgnoreCase"]);function re(){te.value+=" ______",le.value.push({title:"",tag:"",showInput:!1})}function ue(){ae.value=!1,se.value=""}function de(){te.value?le.value.length<1?S.error("至少添加一个填空符!"):$("save",{title:te.value.replaceAll(/ ______/g,"<filter></filter>"),answers:le.value.map((e=>({title:e.title,isCorrect:!0}))),analysis:ie.value,isSetCorrectAnswer:!0,examAnswerSettingBO:{isIgnoreCase:oe.value?.includes("isIgnoreCase"),isInOrder:oe.value?.includes("isInOrder")},examRichTextContent:ae.value?se.value:""}):S.error("题目标题不能为空!")}d((()=>te.value),(()=>{const[...e]=te.value.matchAll(/ ______/g);if(e.length!==le.value.length){const l=le.value.length-e.length;le.value.splice(le.value.length-l,l)}})),v((function(){Z.title&&(te.value=Z.title.replaceAll(/<filter><\/filter>/g," ______")),Z.answerList&&Z.answerList.length&&(le.value=Z.answerList),Z.examAnswerSettingVO&&(oe.value=oe.value.filter((e=>"isIgnoreCase"===e&&Z.examAnswerSettingVO?.isIgnoreCase||"isInOrder"===e&&Z.examAnswerSettingVO?.isInOrder))),Z.analysis&&(ie.value=Z.analysis),Z.examRichTextContent&&(se.value=Z.examRichTextContent,ae.value=!0)}));const ve=V("subject-blank-fill");return(o,r)=>{const u=e,d=l,v=i,V=t,S=a,Y=n,me=s;return c(),m("div",{class:f(p(ve).e("blank-fill-exam"))},[x(q,{"show-edit":o.isEdit},{preview:y((()=>[h("div",R,[h("div",B,[h("span",U,A(o.orderIndex+1)+"."+A(p(te))+"(填空题)",1),p(ae)?(c(),m("div",L,[h("div",{innerHTML:p(se)},null,8,E)])):g("v-if",!0),p(le).some((e=>e.title))?(c(),m("div",M,[r[10]||(r[10]=h("span",{class:"title"},"正确答案:",-1)),(c(!0),m(k,null,j(p(le),((e,l)=>(c(),m("div",{key:l,class:"flex flex-wrap flex-items-center",style:{"margin-right":"10px"}},[h("span",null,"填空"+A(l+1)+":",1),h("span",null,A(e.title),1)])))),128))])):g("v-if",!0)])])])),edit:y((()=>[h("div",D,[r[11]||(r[11]=h("div",{class:"label flex flex-justify-end"},[h("span",null,"题目:")],-1)),h("div",H,[x(u,{modelValue:p(te),"onUpdate:modelValue":r[0]||(r[0]=e=>_(te)?te.value=e:null),type:"textarea",rows:7,"show-word-limit":"",maxlength:"400",placeholder:"【填空题】请输入问题",disabled:o.isSave},null,8,["modelValue","disabled"])])]),h("div",N,[g(' <el-link\n v-if="!showRichText"\n type="primary"\n @click="showRichText = true"\n >\n 添加富文本\n </el-link> '),x(d,{class:"margin-left-10",type:"primary",disabled:o.isSave,onClick:re},{default:y((()=>r[12]||(r[12]=[b(" 插入填空符 ")]))),_:1},8,["disabled"])]),h("div",z,[r[13]||(r[13]=h("div",{class:"label flex flex-justify-end"},[h("span",null,"答题设置:")],-1)),(c(),m(k,null,j(ne,(e=>x(V,{key:e.value,modelValue:p(oe),"onUpdate:modelValue":r[1]||(r[1]=e=>_(oe)?oe.value=e:null)},{default:y((()=>[x(v,{value:e.value,class:"margin-left-10"},{default:y((()=>[b(A(e.label),1)])),_:2},1032,["value"])])),_:2},1032,["modelValue"]))),64))]),h("div",F,[(c(!0),m(k,null,j(p(le),((e,l)=>(c(),m("div",{key:l,class:"answer-item flex flex-items-center"},[h("div",G,[h("span",null,"第"+A(l+1)+"空答案:",1)]),h("div",J,[(c(!0),m(k,null,j(e.title.split(","),(l=>(c(),m(k,{key:l},[l?(c(),w(S,{key:0,closable:"",onClose:t=>function(e,l){if(e){const t=l.title.split(","),i=t.findIndex((l=>l===e));i>-1&&(t.splice(i,1),l.title=t.join(","))}}(l,e)},{default:y((()=>[b(A(l),1)])),_:2},1032,["onClose"])):g("v-if",!0)],64)))),128)),o.isSave?g("v-if",!0):(c(),m(k,{key:0},[e.showInput?(c(),w(u,{key:0,modelValue:e.tag,"onUpdate:modelValue":l=>e.tag=l,style:{width:"80px"},onBlur:()=>function(e){e.showInput=!1,e.tag&&(e.title=e.title?[e.title,e.tag].join(","):e.tag,e.tag="")}(e)},null,8,["modelValue","onUpdate:modelValue","onBlur"])):(c(),w(me,{key:1,size:"small",onClick:l=>e.showInput=!0},{default:y((()=>[x(Y,null,{default:y((()=>[x(p(I))])),_:1}),h("span",null,A(e.title?"添加同义词":"添加答案"),1)])),_:2},1032,["onClick"]))],64))])])))),128))]),o.showAnalysis?(c(),m("div",K,[r[14]||(r[14]=h("div",{class:"label flex flex-justify-end"},[h("span",null,"解析:")],-1)),h("div",P,[x(u,{modelValue:p(ie),"onUpdate:modelValue":r[2]||(r[2]=e=>_(ie)?ie.value=e:null),type:"textarea",rows:2,placeholder:"请输入题目解析"},null,8,["modelValue"])])])):g("v-if",!0),p(ae)?(c(),m("div",Q,[r[16]||(r[16]=h("div",{class:"label flex flex-justify-center"},[h("span",null,"富文本:")],-1)),h("div",W,[x(T,C({"model-value":p(se),"onUpdate:modelValue":r[3]||(r[3]=e=>_(se)?se.value=e:null)},p(ee),{style:{width:"100%"}}),null,16,["model-value"]),h("div",X,[x(d,{type:"danger",onClick:ue},{default:y((()=>r[15]||(r[15]=[b(" 删除富文本 ")]))),_:1})])])])):g("v-if",!0)])),default:y((()=>[o.showAction?(c(),w(O,{key:0,"is-edit":o.isEdit,"is-set":o.isSet,showOtherOption:!1,examAnswerRelationType:Z.examAnswerRelationType,onMoveUp:r[4]||(r[4]=e=>$("move","up")),onMoveDown:r[5]||(r[5]=e=>$("move","down")),onDelete:r[6]||(r[6]=e=>$("delete")),onSave:de,onEdit:r[7]||(r[7]=e=>$("edit")),onAdd:r[8]||(r[8]=e=>$("add",e)),onOnShowRichText:r[9]||(r[9]=e=>ae.value=!0)},null,8,["is-edit","is-set","examAnswerRelationType"])):g("v-if",!0)])),_:1},8,["show-edit"])],2)}}});export{Y as default};
|
2
2
|
//# sourceMappingURL=subject-blank-fill.vue.mjs.map
|