+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 | + + | import CwAntdCalendar from "./index.vue" + +export default CwAntdCalendar |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | <template> + <div class="cw-ant-calendar" style="--calendar-primary-background: #1890ff;--calendar-value-border-radius:2px"> + <a-calendar v-model="currentValue" ref="calendar" :header-render="headerRender" :locale="locale" valueFormat="YYYY-MM-DD" :fullscreen="false" @panelChange="handlePanelChange" @select="handleSelect" :getPopupContainer="getPopupContainer"> + <template slot="dateCellRender" slot-scope="value"> + <slot name="dateCell" :item="value" :current="value" :value="value" :isSelected="isDateSelected(value)" :isDisabled="false" v-if="slotDateCell"></slot> + <ul v-else class="events"> + <span v-for="item in getListData(value)" :key="item.content" class="cicle"></span> + </ul> + </template> + </a-calendar> + </div> +</template> + +<script> +import TimePickerLocale from "ant-design-vue/lib/date-picker/locale/zh_CN"; +import Vue from "vue" +import moment from "moment" +import 'moment/locale/zh-cn'; +moment.locale('zh-cn'); +import Calendar from "ant-design-vue/es/calendar"; +Vue.use(Calendar); +import "ant-design-vue/es/calendar/style/css"; +import supportDatasource from "@/mixins/support.datasource"; +Iimport get from "lodash/get"; +export default { + name: "cw-antd-calendar", + props: { + value: { + type: String, + }, + valueField: { + type: String, + }, + dataSource: { + type: Array, + default: () => [] + }, + slotDateCell: { + type: Boolean, + default: false + } + }, + mixins: [supportDatasource], + data() { + return { + currentValue: null, + locale: TimePickerLocale, + } + }, + watch: { + value: { + handler(val) { + this.currentValue = val + } + }, + }, + async mounted() { + const el = this.$refs["calendar"].$el + .querySelector(".ant-radio-group") + el.remove() + await this.load() + }, + methods: { + getPopupContainer() { + return document.querySelector(".cw-antd-library") + }, + getListData(value) { + let arr=[] + const listData = this.currentDataSource.data.filter(item => { + if (typeof item === "object") { + const isExist = get(item, this.valueField) === value.format('YYYY-MM-DD'); + if (isExist&& !arr.includes(value.format('YYYY-MM-DD'))) { + arr.push(value.format('YYYY-MM-DD')) + return true + } else { + return false + } + } else if (typeof item === "string") { + const isExist = item === value.format('YYYY-MM-DD'); + if (isExist && !arr.includes(value.format('YYYY-MM-DD'))) { + arr.push(value.format('YYYY-MM-DD')) + return true + } else { + return false + } + } else { + throw new Error("数据源格式不正确,只能是对象或者是字符串") + } + }); + + return listData || []; + }, + handleSelect(e) { + this.$emit('update:value', e) + this.$emit('onSelect', e); + }, + handlePanelChange(e, mode) { + this.$emit('update:value', e) + this.$emit('onPanelChange',e); + }, + isDateSelected(value) { + if (!this.currentValue || !value) return false; + return value.format('YYYY-MM-DD') === this.currentValue; + } + } +} +</script> + +<style> + +.cw-ant-calendar .cicle{ + background:var(--calendar-primary-background); + width: 4px; + height: 4px; + border-radius: 2px; + text-align: center; + display: inline-block; + margin-top: 0px; +} +.cw-ant-calendar .ant-fullcalendar-value{ + border-radius: var(--calendar-value-border-radius); +} +.cw-ant-calendar .ant-fullcalendar-selected-day .ant-fullcalendar-value{ + background: var(--calendar-primary-background) ; +} +.cw-ant-calendar .ant-fullcalendar-today .ant-fullcalendar-value{ + box-shadow: inset 0 0 0 1px var(--calendar-primary-background); +} + +.cw-ant-calendar .ant-fullcalendar-selected-day .cicle{ + background: #fff; +} +</style> |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 | + + | import CwAntdUpload from "./index.vue" + +export default CwAntdUpload |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | <template> + <div> + <div class="file-room" vusion-slot-name="default" style="min-height:30px;"> + <input ref="input" v-if="!$env.VUE_APP_DESIGNER" type="file" :accept="accept" :capture="capture" @change="handleFileChange" /> + <div v-if="$env.VUE_APP_DESIGNER && !$slots.default">+</div> + <slot></slot> + </div> + <div class="cropper-view" v-if="isShow"> + <vue-cropper + :high="false" + :centerBox="true" + :outputSize="outputSize" + :autoCropWidth="autoCropWidth" + :autoCropHeight="autoCropHeight" + :fixedNumber="fixedNumber" + outputType="jpeg" + :fixedBox="fixedBox" + :info="info" + :canMoveBox="canMoveBox" + autoCrop ref="cropper" :img="image" ></vue-cropper> + <div class="cropper-view-submit" @click="handleClick">确定</div> + <div class="cropper-view-reset" @click="handleResetClick">重置</div> + <div class="cropper-view-back" @click="handleCloseClick"><a-icon style="font-size: 20px;" type="left-circle" theme="filled" /></div> + </div> + </div> +</template> + +<script> +import VueCropper from "vue-cropper" +import Vue from "vue" +import axios from "axios" +Iimport Icon from "ant-design-vue/es/icon"; +Vue.use(VueCropper) +Vue.use(Icon) +export default { + name:"cw-antd-upload", + props:{ + outputSize:{ + type:String, + }, + autoCropHeight: { + type: String, + default: "200" + }, + autoCropWidth: { + type: String, + default: "200" + }, + fixedNumber: { + type: Array, + }, + value:{ + type: String, + }, + uploadUrl:{ + type: String, + }, + fixedBox: { + type: Boolean, + default: false + }, + canMoveBox: { + type: Boolean, + default: false + }, + accept: { + type: String, + default: "image/*" + }, + capture: { + type: String, + // default: "camera" + }, + info: { + type: Boolean, + default: true + }, + zoom: { + type: String, + default: "1" + }, + }, + data() { + return { + image: '', + croppedImage: '', + isShow: false, + filename: null + } + }, + mounted() { + + + }, + methods: { + async handleFileChange(e) { + const file = e.target.files[0] + this.filename = file.name + this.image = URL.createObjectURL(file) + this.isShow = true + await this.$nextTick() + var viewportHeight = window.innerHeight; + document.querySelector('.cropper-view').style.height = viewportHeight + 'px'; + }, + handleCloseClick() { + this.isShow = false + }, + handleResetClick() { + this.$refs.cropper.clearCrop() + this.$refs.cropper.goAutoCrop() + }, + async loadImg(url) { + var image = new Image(); + image.crossOrigin = 'anonymous'; + image.src = url + return new Promise((resolve,reject) => { + image.onload = function () { + resolve(image) + } + image.onerror = function () { + reject(new Error('Could not load image at ' + url)); + } + }) + }, + + async canvasToFile(canvas) { + return new Promise((resolve => { + canvas.toBlob(file => { + resolve(file) + }) + })) + }, + async handleClick(e) { + this.$refs.cropper.getCropBlob(async data => { + let result = null + try { + if (this.zoom !== "1") { + const url = window.URL.createObjectURL(data) + const image = await this.loadImg(url) + const canvas = document.createElement('canvas') + canvas.width = parseInt(image.width * Number(this.zoom)) + canvas.height = parseInt(image.height * Number(this.zoom)) + var context = canvas.getContext('2d'); + context.drawImage(image, 0, 0, canvas.width, canvas.height); + result = await this.canvasToFile(canvas) + console.log(URL.createObjectURL(result)); + } else { + result = data + } + const formData = new FormData() + formData.append('file', new File([result],this.filename, { type: data.type })) + const authorization = this.getCookie('authorization'); + const headers = authorization ? { Authorization: authorization } : {}; + const r = await axios.post(this.uploadUrl?this.uploadUrl:'/gateway/lowcode/api/v1/app/upload', formData,headers) + if (r.data.code === 200) { + this.$emit('update:value', r.data.result) + this.$emit("onSuccess",r.data.result) + }else{ + this.$emit("onError",r.data.message) + } + } catch (error) { + } finally { + this.$refs.input.value = '' + this.isShow = false + } + }) + }, + getCookie(cname) { + const name = `${cname}=`; + const ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + const c = ca[i].trim(); + if (c.indexOf(name) === 0) + return c.substring(name.length, c.length); + } + return ''; + }, + + } +} +</script> + +<style scoped> +.cropper-view{ + width: 100vw; + position: fixed; + left: 0; + top: 0; + z-index: 9999; +} +.cropper-view-back{ + left: 10px; + top: 10px; + position: absolute; + z-index: 9999; +} + +.cropper-view-submit{ + bottom: 10px; + right: 10px; + width: 100px; + height: 30px; + line-height: 30px; + text-align: center; + position: absolute; + background:#ffffff; + border: 1px #e5e5e5 solid; + z-index: 9999; + color: #333333; +} + +.cropper-view-reset{ + bottom: 10px; + right: 130px; + width: 100px; + height: 30px; + line-height: 30px; + text-align: center; + position: absolute; + background:#ffffff; + border: 1px #e5e5e5 solid; + z-index: 9999; + color: #333333; +} + +.file-room{ + position: relative; + width: 100%; +} +.file-room input{ + background: red; + position: absolute; + top: 0px; + left:0px; + width: 100%; + height: 100%; + opacity: 0; + z-index:1000; +} + +</style> |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 | + + | import CwAutoComplete from "./index.vue" + +export default CwAutoComplete |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | <template> + <div class="global-search-wrapper" style="width: 300px"> + <a-auto-complete + class="global-search" + size="large" + style="width: 100%" + :placeholder="placeholder" + option-label-prop="title" + @select="onSelect" + @search="handleSearch" + v-model="currentValue" + allowClear + :getPopupContainer="getPopupContainer" + > + <template slot="dataSource"> + <template v-if="valueField"> + <a-select-option v-for="item in listSource" :key="get(item,valueField)" :title="get(item,valueField)" > + {{ get(item,valueField) }} + </a-select-option> + </template> + <template v-else> + <a-select-option v-for="item in listSource" :key="item" :title="item"> + {{ item }} + </a-select-option> + </template> + </template> + </a-auto-complete> + </div> +</template> + +<script> +import { MField } from '../../widgets/m-field'; +import supportDatasource from "@/mixins/support.datasource"; +import AutoComplete from 'ant-design-vue/es/auto-complete'; +import Input from 'ant-design-vue/es/input'; +import Select from "ant-design-vue/es/select" +import Vue from "vue" +Iimport get from "lodash/get" +Vue.use(AutoComplete) +Vue.use(Input) +Vue.use(Select) +export default { + name:"cw-auto-complete", + props:{ + value:{ + type:String, + }, + placeholder:{ + type: String, + default: "请输入" + }, + valueField: { + type: String, + } + }, + mixins: [supportDatasource, + MField + ], + data() { + return { + listSource: [], + currentValue:"" + }; + }, + async mounted() { + await this.load() + }, + watch:{ + value:{ + handler(val){ + this.currentValue = val + } + } + }, + methods: { + getPopupContainer() { + return document.querySelector(".cw_ant_design_vue_library") + }, + get, + onSelect(value) { + this.$emit('update:value', value) + this.$emit('onChange',value) + this.$emit('update', value) + }, + async handleSearch(value) { + this.listSource = [] + this.listSource = value ? await this.searchResult(value) : []; + this.$emit('update:value', value) + this.$emit('update', value) + this.$emit('onChange',value) + }, + async searchResult(query) { + await this.load() + // console.log(this.currentDataSource.data); + const result = this.currentDataSource.data.filter(item => { + if (typeof item === "object") { + return get(item,this.valueField).toString().indexOf(query) !== -1 + }else if(typeof item === "string"){ + return item.indexOf(query) !== -1 + } else { + throw new Error("数据源格式不正确,只能是对象或者是字符串") + } + }); + return result + }, + } +} +</script> + +<style> +.ant-select-dropdown{ + z-index: 6000; +} +</style> |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| cw-antd-calendar | +
+
+ |
+ 0% | +0/12 | +0% | +0/23 | +0% | +0/2 | +0% | +0/11 | +
| cw-antd-upload | +
+
+ |
+ 0% | +0/8 | +0% | +0/23 | +0% | +0/2 | +0% | +0/7 | +
| cw-auto-complete | +
+
+ |
+ 0% | +0/12 | +0% | +0/23 | +0% | +0/2 | +0% | +0/11 | +