更新:登录功能

This commit is contained in:
2025-11-04 12:37:04 +08:00
commit a21fb92916
897 changed files with 51500 additions and 0 deletions

View File

@@ -0,0 +1,495 @@
<!--
* @Author: weisheng
* @Date: 2023-04-05 21:32:56
* @LastEditTime: 2025-04-28 19:41:17
* @LastEditors: weisheng
* @Description: 水印组件
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-watermark/wd-watermark.vue
* 记得注释
-->
<template>
<view :class="rootClass" :style="rootStyle">
<canvas
v-if="!canvasOffScreenable && showCanvas"
type="2d"
:style="{ height: canvasHeight + 'px', width: canvasWidth + 'px', visibility: 'hidden' }"
:canvas-id="canvasId"
:id="canvasId"
/>
</view>
</template>
<script lang="ts">
export default {
name: 'wd-watermark',
options: {
addGlobalClass: true,
virtualHost: true,
styleIsolation: 'shared'
}
}
</script>
<script lang="ts" setup>
import { computed, onMounted, ref, watch, nextTick, type CSSProperties } from 'vue'
import { addUnit, buildUrlWithParams, isBase64Image, objToStyle, uuid } from '../common/util'
import { watermarkProps } from './types'
const props = defineProps(watermarkProps)
watch(
() => props,
() => {
doReset()
},
{ deep: true }
)
const canvasId = ref<string>(`water${uuid()}`) // canvas 组件的唯一标识符
const waterMarkUrl = ref<string>('') // canvas生成base64水印
const canvasOffScreenable = ref<boolean>(uni.canIUse('createOffscreenCanvas') && Boolean(uni.createOffscreenCanvas)) // 是否可以使用离屏canvas
const pixelRatio = ref<number>(uni.getSystemInfoSync().pixelRatio) // 像素比
const canvasHeight = ref<number>((props.height + props.gutterY) * pixelRatio.value) // canvas画布高度
const canvasWidth = ref<number>((props.width + props.gutterX) * pixelRatio.value) // canvas画布宽度
const showCanvas = ref<boolean>(true) // 是否展示canvas
/**
* 水印css类
*/
const rootClass = computed(() => {
let classess: string = 'wd-watermark'
if (props.fullScreen) {
classess = `${classess} is-fullscreen`
}
return `${classess} ${props.customClass}`
})
/**
* 水印样式
*/
const rootStyle = computed(() => {
const style: CSSProperties = {
opacity: props.opacity,
backgroundSize: addUnit(props.width + props.gutterX)
}
if (waterMarkUrl.value) {
style['backgroundImage'] = `url('${waterMarkUrl.value}')`
}
return `${objToStyle(style)}${props.customStyle}`
})
onMounted(() => {
doInit()
})
function doReset() {
showCanvas.value = true
canvasHeight.value = (props.height + props.gutterY) * pixelRatio.value
canvasWidth.value = (props.width + props.gutterX) * pixelRatio.value
nextTick(() => {
doInit()
})
}
function doInit() {
// #ifdef H5
// h5使用document.createElement创建canvas不用展示canvas标签
showCanvas.value = false
// #endif
const { width, height, color, size, fontStyle, fontWeight, fontFamily, content, rotate, gutterX, gutterY, image, imageHeight, imageWidth } = props
// 创建水印
createWaterMark(width, height, color, size, fontStyle, fontWeight, fontFamily, content, rotate, gutterX, gutterY, image, imageHeight, imageWidth)
}
/**
* 创建水印图片
* @param width canvas宽度
* @param height canvas高度
* @param color canvas字体颜色
* @param size canvas字体大小
* @param fontStyle canvas字体样式
* @param fontWeight canvas字体字重
* @param fontFamily canvas字体系列
* @param content canvas内容
* @param rotate 倾斜角度
* @param gutterX X轴间距
* @param gutterY Y轴间距
* @param image canvas图片
* @param imageHeight canvas图片高度
* @param imageWidth canvas图片宽度
*/
function createWaterMark(
width: number,
height: number,
color: string,
size: number,
fontStyle: string,
fontWeight: number | string,
fontFamily: string,
content: string,
rotate: number,
gutterX: number,
gutterY: number,
image: string,
imageHeight: number,
imageWidth: number
) {
const canvasHeight = (height + gutterY) * pixelRatio.value
const canvasWidth = (width + gutterX) * pixelRatio.value
const contentWidth = width * pixelRatio.value
const contentHeight = height * pixelRatio.value
const fontSize = size * pixelRatio.value
// #ifndef H5
if (canvasOffScreenable.value) {
createOffscreenCanvas(
canvasHeight,
canvasWidth,
contentWidth,
contentHeight,
rotate,
fontSize,
fontFamily,
fontStyle,
fontWeight,
color,
content,
image,
imageHeight,
imageWidth
)
} else {
createCanvas(canvasHeight, contentWidth, rotate, fontSize, color, content, image, imageHeight, imageWidth)
}
// #endif
// #ifdef H5
createH5Canvas(
canvasHeight,
canvasWidth,
contentWidth,
contentHeight,
rotate,
fontSize,
fontFamily,
fontStyle,
fontWeight,
color,
content,
image,
imageHeight,
imageWidth
)
// #endif
}
/**
* 创建离屏canvas
* @param canvasHeight canvas高度
* @param canvasWidth canvas宽度
* @param contentWidth 内容宽度
* @param contentHeight 内容高度
* @param rotate 内容倾斜角度
* @param fontSize 字体大小
* @param fontFamily 字体系列
* @param fontStyle 字体样式
* @param fontWeight 字体字重
* @param color 字体颜色
* @param content 内容
* @param image canvas图片
* @param imageHeight canvas图片高度
* @param imageWidth canvas图片宽度
*/
function createOffscreenCanvas(
canvasHeight: number,
canvasWidth: number,
contentWidth: number,
contentHeight: number,
rotate: number,
fontSize: number,
fontFamily: string,
fontStyle: string,
fontWeight: string | number,
color: string,
content: string,
image: string,
imageHeight: number,
imageWidth: number
) {
// 创建离屏canvas
const canvas: any = uni.createOffscreenCanvas({ height: canvasHeight, width: canvasWidth, type: '2d' })
const ctx: any = canvas.getContext('2d')
if (ctx) {
if (image) {
const img = canvas.createImage() as HTMLImageElement
drawImageOffScreen(ctx, img, image, imageHeight, imageWidth, rotate, contentWidth, contentHeight, canvas)
} else {
drawTextOffScreen(ctx, content, contentWidth, contentHeight, rotate, fontSize, fontFamily, fontStyle, fontWeight, color, canvas)
}
} else {
console.error('无法获取canvas上下文请确认当前环境是否支持canvas')
}
}
/**
* 非H5创建canvas
* 不支持创建离屏canvas时调用
* @param contentHeight 内容高度
* @param contentWidth 内容宽度
* @param rotate 内容倾斜角度
* @param fontSize 字体大小
* @param color 字体颜色
* @param content 内容
* @param image canvas图片
* @param imageHeight canvas图片高度
* @param imageWidth canvas图片宽度
*/
function createCanvas(
contentHeight: number,
contentWidth: number,
rotate: number,
fontSize: number,
color: string,
content: string,
image: string,
imageHeight: number,
imageWidth: number
) {
const ctx = uni.createCanvasContext(canvasId.value)
if (ctx) {
if (image) {
drawImageOnScreen(ctx, image, imageHeight, imageWidth, rotate, contentWidth, contentHeight)
} else {
drawTextOnScreen(ctx, content, contentWidth, rotate, fontSize, color)
}
} else {
console.error('无法获取canvas上下文请确认当前环境是否支持canvas')
}
}
/**
* h5创建canvas
* @param canvasHeight canvas高度
* @param canvasWidth canvas宽度
* @param contentWidth 水印内容宽度
* @param contentHeight 水印内容高度
* @param rotate 水印内容倾斜角度
* @param fontSize 水印字体大小
* @param fontFamily 水印字体系列
* @param fontStyle 水印字体样式
* @param fontWeight 水印字体字重
* @param color 水印字体颜色
* @param content 水印内容
*/
function createH5Canvas(
canvasHeight: number,
canvasWidth: number,
contentWidth: number,
contentHeight: number,
rotate: number,
fontSize: number,
fontFamily: string,
fontStyle: string,
fontWeight: string | number,
color: string,
content: string,
image: string,
imageHeight: number,
imageWidth: number
) {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.setAttribute('width', `${canvasWidth}px`)
canvas.setAttribute('height', `${canvasHeight}px`)
if (ctx) {
if (image) {
const img = new Image()
drawImageOffScreen(ctx, img, image, imageHeight, imageWidth, rotate, contentWidth, contentHeight, canvas)
} else {
drawTextOffScreen(ctx, content, contentWidth, contentHeight, rotate, fontSize, fontFamily, fontStyle, fontWeight, color, canvas)
}
} else {
console.error('无法获取canvas上下文请确认当前环境是否支持canvas')
}
}
/**
* 绘制离屏文字canvas
* @param ctx canvas上下文
* @param content 水印内容
* @param contentWidth 水印宽度
* @param contentHeight 水印高度
* @param rotate 水印内容倾斜角度
* @param fontSize 水印字体大小
* @param fontFamily 水印字体系列
* @param fontStyle 水印字体样式
* @param fontWeight 水印字体字重
* @param color 水印字体颜色
* @param canvas canvas实例
*/
function drawTextOffScreen(
ctx: CanvasRenderingContext2D,
content: string,
contentWidth: number,
contentHeight: number,
rotate: number,
fontSize: number,
fontFamily: string,
fontStyle: string,
fontWeight: string | number,
color: string,
canvas: HTMLCanvasElement
) {
ctx.textBaseline = 'middle'
ctx.textAlign = 'center'
ctx.translate(contentWidth / 2, contentWidth / 2)
ctx.rotate((Math.PI / 180) * rotate)
ctx.font = `${fontStyle} normal ${fontWeight} ${fontSize}px/${contentHeight}px ${fontFamily}`
ctx.fillStyle = color
ctx.fillText(content, 0, 0)
ctx.restore()
waterMarkUrl.value = canvas.toDataURL()
}
/**
* 绘制在屏文字canvas
* @param ctx canvas上下文
* @param content 水印内容
* @param contentWidth 水印宽度
* @param rotate 水印内容倾斜角度
* @param fontSize 水印字体大小
* @param color 水印字体颜色
*/
function drawTextOnScreen(ctx: UniApp.CanvasContext, content: string, contentWidth: number, rotate: number, fontSize: number, color: string) {
ctx.setTextBaseline('middle')
ctx.setTextAlign('center')
ctx.translate(contentWidth / 2, contentWidth / 2)
ctx.rotate((Math.PI / 180) * rotate)
ctx.setFillStyle(color)
ctx.setFontSize(fontSize)
ctx.fillText(content, 0, 0)
ctx.restore()
ctx.draw()
// #ifdef MP-DINGTALK
// 钉钉小程序的canvasToTempFilePath接口与其他平台不一样
;(ctx as any).toTempFilePath({
success(res: any) {
showCanvas.value = false
waterMarkUrl.value = res.filePath
}
})
// #endif
// #ifndef MP-DINGTALK
uni.canvasToTempFilePath({
canvasId: canvasId.value,
success: (res) => {
showCanvas.value = false
waterMarkUrl.value = res.tempFilePath
}
})
// #endif
}
/**
* 绘制离屏图片canvas
* @param ctx canvas上下文
* @param img 水印图片对象
* @param image 水印图片地址
* @param imageHeight 水印图片高度
* @param imageWidth 水印图片宽度
* @param rotate 水印内容倾斜角度
* @param contentWidth 水印宽度
* @param contentHeight 水印高度
* @param canvas canvas实例
*/
async function drawImageOffScreen(
ctx: CanvasRenderingContext2D,
img: HTMLImageElement,
image: string,
imageHeight: number,
imageWidth: number,
rotate: number,
contentWidth: number,
contentHeight: number,
canvas: HTMLCanvasElement
) {
ctx.translate(contentWidth / 2, contentHeight / 2)
ctx.rotate((Math.PI / 180) * Number(rotate))
img.crossOrigin = 'anonymous'
img.referrerPolicy = 'no-referrer'
if (isBase64Image(image)) {
img.src = image
} else {
img.src = buildUrlWithParams(image, {
timestamp: `${new Date().getTime()}`
})
}
img.onload = () => {
ctx.drawImage(
img,
(-imageWidth * pixelRatio.value) / 2,
(-imageHeight * pixelRatio.value) / 2,
imageWidth * pixelRatio.value,
imageHeight * pixelRatio.value
)
ctx.restore()
waterMarkUrl.value = canvas.toDataURL()
}
}
/**
* 绘制在屏图片canvas
* @param ctx canvas上下文
* @param image 水印图片地址
* @param imageHeight 水印图片高度
* @param imageWidth 水印图片宽度
* @param rotate 水印内容倾斜角度
* @param contentWidth 水印宽度
* @param contentHeight 水印高度
*/
function drawImageOnScreen(
ctx: UniApp.CanvasContext,
image: string,
imageHeight: number,
imageWidth: number,
rotate: number,
contentWidth: number,
contentHeight: number
) {
ctx.translate(contentWidth / 2, contentHeight / 2)
ctx.rotate((Math.PI / 180) * Number(rotate))
ctx.drawImage(
image,
(-imageWidth * pixelRatio.value) / 2,
(-imageHeight * pixelRatio.value) / 2,
imageWidth * pixelRatio.value,
imageHeight * pixelRatio.value
)
ctx.restore()
ctx.draw(false, () => {
// #ifdef MP-DINGTALK
// 钉钉小程序的canvasToTempFilePath接口与其他平台不一样
;(ctx as any).toTempFilePath({
success(res: any) {
showCanvas.value = false
waterMarkUrl.value = res.filePath
}
})
// #endif
// #ifndef MP-DINGTALK
uni.canvasToTempFilePath({
canvasId: canvasId.value,
success: (res) => {
showCanvas.value = false
waterMarkUrl.value = res.tempFilePath
}
})
// #endif
})
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>