mGY#Xn$XV@+D3HBuUP_MKbp
z>^o}&_wvwDrisWAKK%rMF+ytadb@Mc!XJv)&Zt)O9loScN9{_YDJ)RS$vMGAwqPVF
z_SJVOu(|uVrE`Q)Xn;s~;EwLbv1@DJ=1_|#Qu-*EyTUi^heK>(?{(3+&N9VE=ETFE
zQz-{aut3v3S3z@qlwktQ**y9fy=!KF6IQ*x??`3YdC;8EA$C-;NTva
zvw2#Dyqg`YL(?BRIaEbRoi3Tf%7;$%2Kn(fzHF`m&D-`DaR}f~K~Qta*hm>&xONF-W_xyB7`MgRH~
zo*umx;NfM!P51eLa2p&zKfsnTK=4?UWCoAMRXTNib+1rwAxY0fZOd-K1ynW3MQ=m?
z8g4xCBhd*u|KvA6e~CrRw9E?g$ys_$R@l0zCC6X#39lPbY`Lq?_bPY3BFDW1;MAgZ
z@=C3GI@DC$B$Gi*v-yaA&8X=ZS)@EFT_487{Y@B*l)n=NZ~5wyz9u%JQrt2#z4_6*
zfk(pIBaBj3jBeWhG<3}EjCXGPVtW9er*2rmiAY|X9`gBz(k!81{yWB>vD{V+I$93g
Tk*#;_{|5z(C(ff88JYPnu8*-u
literal 0
HcmV?d00001
diff --git a/app/miniprogram_npm/lin-ui/image-clipper/images/rotate-inverse.png b/app/miniprogram_npm/lin-ui/image-clipper/images/rotate-inverse.png
new file mode 100644
index 0000000000000000000000000000000000000000..ec77b6b55b31ce92efac9fd60c3ee9bff3832f45
GIT binary patch
literal 1786
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
VXF {
+ // 计算图片尺寸
+ this.imgComputeSize(res.width, res.height);
+ if (this.properties.limitMove) {
+ // 限制移动,不留空白处理
+ this.imgMarginDetectionScale();
+ eventUtil.emit(this, 'linimageready', res);
+ }
+ },
+ fail: () => {
+ this.imgComputeSize();
+ if (this.properties.limitMove) {
+ this.imgMarginDetectionScale();
+ }
+ }
+ });
+ },
+ 'clipWidth, clipHeight'(widthVal, heightVal) {
+ let { minWidth, minHeight } = this.data;
+ minWidth = minWidth / 2;
+ minHeight = minHeight / 2;
+ if (widthVal < minWidth) {
+ dataUtil.setDiffData(this, { clipWidth: minWidth });
+ }
+ if (heightVal < minHeight) {
+ dataUtil.setDiffData(this, { clipHeight: minHeight });
+ }
+ this.computeCutSize();
+ },
+ 'rotateAngle'(val) {
+ dataUtil.setDiffData(this, { cutAnimation: true, angle: val });
+ },
+ 'angle'(val) {
+ this.moveStop();
+ const {
+ limitMove
+ } = this.properties;
+ if (limitMove && val % 90) {
+ dataUtil.setDiffData(this, { angle: Math.round(val / 90) * 90 });
+ }
+ this.imgMarginDetectionScale();
+ },
+ 'cutAnimation'(val) {
+ // 开启过渡260毫秒之后自动关闭
+ clearTimeout(this.data._cutAnimationTime);
+ if (val) {
+ let _cutAnimationTime = setTimeout(() => {
+ dataUtil.setDiffData(this, { cutAnimation: false });
+ }, 260);
+ dataUtil.setDiffData(this, { _cutAnimationTime });
+ }
+ },
+ 'limitMove'(val) {
+ if (val) {
+ if (this.data.angle % 90) {
+ dataUtil.setDiffData(this, { angle: Math.round(this.data.angle / 90) * 90 });
+ }
+ this.imgMarginDetectionScale();
+ }
+ },
+ 'cutY, cutX'() {
+ this.cutDetectionPosition();
+ },
+ 'width, height'(width, height) {
+ if(width !== this.width) {
+ dataUtil.setDiffData(this, {clipWidth: width / 2});
+ }
+ if(height !== this.height) {
+ dataUtil.setDiffData(this, {clipHeight: height / 2});
+ }
+ }
+ },
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ /**
+ * 设置裁剪框的一些信息
+ */
+ setCutInfo() {
+ const {
+ width,
+ height
+ } = this.properties;
+ const {
+ _SYS_INFO
+ } = this.data;
+ // 本组件动态style默认单位为px,需将用户传入值/2
+ const clipWidth = width / 2;
+ const clipHeight = height / 2;
+ const cutY = (_SYS_INFO.windowHeight - clipHeight) / 2;
+ const cutX = (_SYS_INFO.windowWidth - clipWidth) / 2;
+ const imageLeft = _SYS_INFO.windowWidth / 2;
+ const imageTop = _SYS_INFO.windowHeight / 2;
+ const _ctx = wx.createCanvasContext('image-clipper', this);
+ this.setData({
+ clipWidth,
+ clipHeight,
+ cutX,
+ cutY,
+ CANVAS_HEIGHT: clipHeight,
+ CANVAS_WIDTH: clipWidth,
+ _ctx,
+ imageLeft,
+ imageTop
+ });
+ },
+ /**
+ * 裁剪框居中
+ */
+ setCutCenter() {
+ const { sysInfo, clipHeight, clipWidth, imageTop, imageLeft } = this.data;
+ let sys = sysInfo || wx.getSystemInfoSync();
+ let cutY = (sys.windowHeight - clipHeight) * 0.5;
+ let cutX = (sys.windowWidth - clipWidth) * 0.5;
+ this.setData({
+ imageTop: imageTop - this.data.cutY + cutY,
+ imageLeft: imageLeft - this.data.cutX + cutX,
+ cutY,
+ cutX
+ });
+ },
+ /**
+ * 开始拖动裁剪框
+ * 需在此处查找到是否拖动的裁剪框四角
+ */
+ clipTouchStart(event) {
+ if (!this.properties.imageUrl) {
+ wx.showToast({
+ title: '请选择图片',
+ icon: 'none'
+ });
+ return;
+ }
+ const currentX = event.touches[0].clientX;
+ const currentY = event.touches[0].clientY;
+ const { cutX, cutY, clipWidth, clipHeight } = this.data;
+ const corner = determineDirection(cutX, cutY, clipWidth, clipHeight, currentX, currentY);
+ this.moveDuring();
+ const _CUT_START = {
+ width: clipWidth,
+ height: clipHeight,
+ x: currentX,
+ y: currentY,
+ cutY,
+ cutX,
+ corner
+ };
+ this.setData({ _flagCutTouch: true, _flagEndTouch: true, _CUT_START });
+ },
+ /**
+ * 拖动裁剪框
+ * 当拖动的裁剪框区域时处理数据
+ */
+ clipTouchMove(event) {
+ if (!this.properties.imageUrl) {
+ wx.showToast({
+ title: '请选择图片',
+ icon: 'none'
+ });
+ return;
+ }
+ // fix & optimize #1129
+ // 只针对单指点击做处理
+ if (event.touches.length !== 1) {
+ return;
+ }
+ const { _flagCutTouch, _MOVE_THROTTLE_FLAG } = this.data;
+ if (_flagCutTouch && _MOVE_THROTTLE_FLAG) {
+ const { lockRatio, lockHeight, lockWidth } = this.properties;
+ if (lockRatio && (lockWidth || lockHeight)) return;
+ dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: false });
+ this.moveThrottle();
+ const clipData = clipTouchMoveOfCalculate(this.data, event);
+ // fix #1129
+ // 原因:未做 clipTouchMoveOfCalculate 方法返回 undefined 值处理
+ if(clipData) {
+ const { width, height, cutX, cutY } = clipData;
+ if (!lockWidth && !lockHeight) {
+ dataUtil.setDiffData(this, { clipWidth: width, clipHeight: height, cutX, cutY });
+ } else if (!lockWidth) {
+ dataUtil.setDiffData(this, { clipWidth: width, cutX });
+ } else if (!lockHeight) {
+ dataUtil.setDiffData(this, { clipHeight: height, cutY });
+ }
+ this.imgMarginDetectionScale();
+ }
+ }
+ },
+ /**
+ * 拖动裁剪框结束
+ * 当拖动的裁剪框区域时处理数据
+ */
+ clipTouchEnd() {
+ this.moveStop();
+ this.setData({ _flagCutTouch: false });
+ },
+ /**
+ * 清空之前的自动居中延迟函数
+ */
+ moveDuring() {
+ clearTimeout(this.data._TIME_CUT_CENTER);
+ },
+ /**
+ * 停止移动时需要做的操作
+ * 清空之前的自动居中延迟函数并添加最新的
+ */
+ moveStop() {
+ clearTimeout(this.data._TIME_CUT_CENTER);
+ const _TIME_CUT_CENTER = setTimeout(() => {
+ //动画启动
+ if (!this.data.cutAnimation) {
+ dataUtil.setDiffData(this, { cutAnimation: true });
+ }
+ this.setCutCenter();
+ }, 800);
+ dataUtil.setDiffData(this, { _TIME_CUT_CENTER });
+ },
+ /**
+ * 重置延迟函数
+ */
+ moveThrottle() {
+ if (this.data._SYS_INFO.platform === 'android') {
+ clearTimeout(this.data._MOVE_THROTTLE);
+ const _MOVE_THROTTLE = setTimeout(() => {
+ dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: true });
+ }, 800 / 40);
+ dataUtil.setDiffData(this, { _MOVE_THROTTLE });
+ } else {
+ dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: true });
+ }
+ },
+ /**
+ * 图片初始化
+ */
+ imageReset() {
+ const sys = this.data._SYS_INFO || wx.getSystemInfoSync();
+ this.setData({ scale: 1, angle: 0, imageTop: sys.windowHeight / 2, imageLeft: sys.windowWidth / 2 });
+ },
+ /**
+ * 图片加载完成
+ */
+ imageLoad() {
+ this.imageReset();
+ wx.hideLoading();
+ eventUtil.emit(this, 'linimageload', detail);
+ },
+ /**
+ * 计算图片尺寸
+ */
+ imgComputeSize(width, height) {
+ const { imageWidth, imageHeight } = calcImageSize(width, height, this.data);
+ this.setData({ imageWidth, imageHeight });
+ },
+ /**
+ * 图片边缘检测-缩放
+ */
+ imgMarginDetectionScale(scale) {
+ if (!this.properties.limitMove) return;
+ const currentScale = calcImageScale(this.data, scale);
+ this.imgMarginDetectionPosition(currentScale);
+ },
+ /**
+ * 图片边缘检测-位置
+ */
+ imgMarginDetectionPosition(scale) {
+ if (!this.properties.limitMove) return;
+ const { scale: currentScale, left, top } = calcImageOffset(this.data, scale);
+ dataUtil.setDiffData(this, { imageLeft: left, imageTop: top, scale: currentScale });
+ },
+ /**
+ * 开始图片触摸
+ */
+ imageTouchStart(e) {
+ this.setData({ _flagEndTouch: false });
+ const { imageLeft, imageTop } = this.data;
+ // 双指左指坐标
+ const clientXForLeft = e.touches[0].clientX;
+ const clientYForLeft = e.touches[0].clientY;
+
+ let _touchRelative = [];
+ if (e.touches.length === 1) {
+ // 单指拖动
+ _touchRelative[0] = {
+ x: clientXForLeft - imageLeft,
+ y: clientYForLeft - imageTop
+ };
+ this.setData({ _touchRelative });
+ } else {
+ // 双指右指坐标
+ const clientXForRight = e.touches[1].clientX;
+ const clientYForRight = e.touches[1].clientY;
+ // 双指放大
+ let width = Math.abs(clientXForLeft - clientXForRight);
+ let height = Math.abs(clientYForLeft - clientYForRight);
+ // 勾股定理求出斜边长度
+ const _hypotenuseLength = calcPythagoreanTheorem(width, height);
+
+ _touchRelative = [{
+ x: clientXForLeft - imageLeft,
+ y: clientYForLeft - imageTop
+ },
+ {
+ x: clientXForRight - imageLeft,
+ y: clientYForRight - imageTop
+ }
+ ];
+ this.setData({_touchRelative, _hypotenuseLength});
+ }
+ },
+ /**
+ * 图片放大旋转等操作
+ */
+ imageTouchMove(e) {
+ const {
+ _flagEndTouch,
+ _MOVE_THROTTLE_FLAG
+ } = this.data;
+ if (_flagEndTouch || !_MOVE_THROTTLE_FLAG) return;
+ // 双指左指坐标
+ const clientXForLeft = e.touches[0].clientX;
+ const clientYForLeft = e.touches[0].clientY;
+
+ dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: false });
+ this.moveThrottle();
+ this.moveDuring();
+ if (e.touches.length === 1) {
+ //单指拖动
+ const { left, top } = imageTouchMoveOfCalcOffset(this.data, clientXForLeft, clientYForLeft);
+ dataUtil.setDiffData(this, { imageLeft: left, imageTop: top});
+ // 图像边缘检测,防止截取到空白
+ this.imgMarginDetectionPosition();
+ } else {
+ // 双指右指坐标
+ const clientXForRight = e.touches[1].clientX;
+ const clientYForRight = e.touches[1].clientY;
+ // 双指放大
+ let width = Math.abs(clientXForLeft - clientXForRight),
+ height = Math.abs(clientYForLeft - clientYForRight),
+ // 勾股定理求出斜边长度
+ hypotenuse = calcPythagoreanTheorem(width, height), // 斜边
+ scale = this.data.scale * (hypotenuse / this.data._hypotenuseLength);
+ // 计算出真实缩放倍率
+ // 如果禁止缩放则倍率一直为1
+ if (this.properties.disableScale) {
+ scale = 1;
+ } else {
+ scale = scale <= this.properties.minRatio ? this.properties.minRatio : scale;
+ scale = scale >= this.properties.maxRatio ? this.properties.maxRatio : scale;
+ eventUtil.emit(this, 'linsizechange', {
+ imageWidth: this.data.imageWidth * scale,
+ imageHeight: this.data.imageHeight * scale
+ });
+ }
+
+ this.imgMarginDetectionScale(scale);
+ dataUtil.setDiffData(this, {
+ _hypotenuseLength: Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),
+ scale
+ });
+ }
+ },
+ /**
+ * 图片手指触摸结束
+ */
+ imageTouchEnd() {
+ dataUtil.setDiffData(this, { _flagEndTouch: true });
+ this.moveStop();
+ },
+
+ /**
+ * 检测剪裁框位置是否在允许的范围内(屏幕内)
+ */
+ cutDetectionPosition() {
+ const { cutX, cutY, _SYS_INFO, clipHeight, clipWidth } = this.data;
+ let cutDetectionPositionTop = () => {
+ //检测上边距是否在范围内
+ if (cutY < 0) {
+ dataUtil.setDiffData(this, { cutY: 0 });
+ }
+ if (cutY > _SYS_INFO.windowHeight - clipHeight) {
+ dataUtil.setDiffData(this, { cutY: _SYS_INFO.windowHeight - clipHeight });
+ }
+ },
+ cutDetectionPositionLeft = () => {
+ //检测左边距是否在范围内
+ if (cutX < 0) {
+ dataUtil.setDiffData(this, { cutX: 0 });
+ }
+ if (cutX > _SYS_INFO.windowWidth - clipWidth) {
+ dataUtil.setDiffData(this, { cutX: _SYS_INFO.windowWidth - clipWidth });
+ }
+ };
+ //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中)
+ if (cutY === null && cutX === null) {
+ let newCutY = (_SYS_INFO.windowHeight - clipHeight) * 0.5;
+ let newCutX = (_SYS_INFO.windowWidth - clipWidth) * 0.5;
+ dataUtil.setDiffData(this, {
+ cutX: newCutX, // 截取的框上边距
+ cutY: newCutY // 截取的框左边距
+ });
+ } else if (cutY !== null && cutX !== null) {
+ cutDetectionPositionTop();
+ cutDetectionPositionLeft();
+ } else if (cutY !== null && cutX === null) {
+ cutDetectionPositionTop();
+ dataUtil.setDiffData(this, { cutX: (_SYS_INFO.windowWidth - clipWidth) / 2 });
+ } else if (cutY === null && cutX !== null) {
+ cutDetectionPositionLeft();
+ dataUtil.setDiffData(this, { cutY: (_SYS_INFO.windowHeight - clipHeight) / 2 });
+ }
+ },
+ /**
+ * 改变截取框大小
+ */
+ computeCutSize() {
+ const { clipHeight, clipWidth, _SYS_INFO, cutX, cutY } = this.data;
+ if (clipWidth > _SYS_INFO.windowWidth) {
+ // 设置裁剪框宽度
+ dataUtil.setDiffData(this, { clipWidth: _SYS_INFO.windowWidth });
+ } else if (clipWidth + cutX > _SYS_INFO.windowWidth) {
+ dataUtil.setDiffData(this, { cutX: _SYS_INFO.windowWidth - cutX });
+ }
+ if (clipHeight > _SYS_INFO.windowHeight) {
+ // 设置裁剪框高度
+ dataUtil.setDiffData(this, { clipHeight: _SYS_INFO.windowHeight });
+ } else if (clipHeight + cutY > _SYS_INFO.windowHeight) {
+ dataUtil.setDiffData(this, { cutY: _SYS_INFO.windowHeight - cutY });
+ }
+ },
+ /**
+ * 获取图片数据
+ */
+ getImageData() {
+ if (!this.properties.imageUrl) {
+ wx.showToast({
+ title: '请选择图片',
+ icon: 'none'
+ });
+ return;
+ }
+ wx.showLoading({
+ title: '加载中'
+ });
+
+ const { clipHeight, clipWidth, _ctx, scale, imageLeft, imageTop, cutX, cutY, angle } = this.data;
+ let { CANVAS_HEIGHT, CANVAS_WIDTH } = this.data;
+ const { scaleRatio, imageUrl, quality, type: imageType } = this.properties;
+ // 绘制函数
+ const draw = () => {
+ // 图片真实大小
+ const imageWidth = this.data.imageWidth * scale * scaleRatio;
+ const imageHeight = this.data.imageHeight * scale * scaleRatio;
+ // canvas和图片的相对距离
+ const xpos = imageLeft - cutX;
+ const ypos = imageTop - cutY;
+ // 旋转画布
+ _ctx.translate(xpos * scaleRatio, ypos * scaleRatio);
+ _ctx.rotate((angle * Math.PI) / 180);
+ _ctx.drawImage(imageUrl, -imageWidth / 2, -imageHeight / 2, imageWidth, imageHeight);
+ _ctx.draw(false, () => {
+ let params = {
+ width: clipWidth * scaleRatio,
+ height: Math.round(clipHeight * scaleRatio),
+ destWidth: clipWidth * scaleRatio,
+ destHeight: Math.round(clipHeight) * scaleRatio,
+ fileType: 'png',
+ quality
+ };
+
+ let data = {
+ url: '',
+ base64: '',
+ width: clipWidth * scaleRatio,
+ height: clipHeight * scaleRatio
+ };
+
+ if (IMAGE_TYPE.base64 === imageType) {
+ wx.canvasGetImageData({
+ canvasId: 'image-clipper',
+ x: 0,
+ y: 0,
+ width: clipWidth * scaleRatio,
+ height: Math.round(clipHeight * scaleRatio),
+ success: res => {
+ const arrayBuffer = new Uint8Array(res.data);
+ const base64 = wx.arrayBufferToBase64(arrayBuffer);
+ data.url = base64;
+ data.base64 = base64;
+ wx.hideLoading();
+ eventUtil.emit(this, 'linclip', data);
+ }
+ });
+ } else {
+ wx.canvasToTempFilePath({
+ ...params,
+ canvasId: 'image-clipper',
+ success: res => {
+ data.url = res.tempFilePath;
+ data.base64 = res.tempFilePath;
+ wx.hideLoading();
+ eventUtil.emit(this, 'linclip', data);
+ },
+ fail(res) {
+ throw res;
+ }
+ },
+ this
+ );
+ }
+ });
+ };
+
+ if (CANVAS_WIDTH !== clipWidth || CANVAS_HEIGHT !== clipHeight) {
+ CANVAS_WIDTH = clipWidth;
+ CANVAS_HEIGHT = clipHeight;
+ _ctx.draw();
+ setTimeout(() => {
+ draw();
+ }, 100);
+ } else {
+ draw();
+ }
+ },
+ /**
+ * 上传图片
+ */
+ uploadImage() {
+ wx.chooseImage({
+ count: 1,
+ sizeType: ['original', 'compressed'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const tempFilePaths = res.tempFilePaths;
+ this.setData({ imageUrl: tempFilePaths });
+ }
+ });
+ },
+ /**
+ * 工具栏旋转
+ */
+ rotate(event) {
+ if (this.properties.disableRotate) return;
+ if (!this.properties.imageUrl) {
+ wx.showToast({
+ title: '请选择图片',
+ icon: 'none'
+ });
+ return;
+ }
+ const { rotateAngle } = this.properties;
+ const originAngle = this.data.angle;
+ const type = event.currentTarget.dataset.type;
+ if (type === 'along') {
+ this.setData({ angle: originAngle + rotateAngle });
+ } else {
+ this.setData({ angle: originAngle - rotateAngle});
+ }
+ eventUtil.emit(this, 'linrotate', { currentDeg: this.data.angle });
+ },
+ /**
+ * 关闭
+ */
+ close() {
+ this.setData({ show: false });
+ },
+ /**
+ * 空方法,占位用
+ */
+ doNothing() {}
+ },
+
+ /**
+ * 组件的生命周期
+ */
+ lifetimes: {
+ ready() {
+ const _SYS_INFO = wx.getSystemInfoSync();
+ this.setData({ _SYS_INFO });
+ this.setCutInfo();
+ this.setCutCenter();
+ this.computeCutSize();
+ this.cutDetectionPosition();
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/image-clipper/index.json b/app/miniprogram_npm/lin-ui/image-clipper/index.json
new file mode 100644
index 000000000..e8cfaaf80
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/image-clipper/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/image-clipper/index.less b/app/miniprogram_npm/lin-ui/image-clipper/index.less
new file mode 100644
index 000000000..b32215ae9
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/image-clipper/index.less
@@ -0,0 +1,131 @@
+.container {
+ width: 100vw;
+ height: 100vh;
+ background-color: rgb(0 0 0 / 60%);
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1;
+
+ .clip-wrapper {
+ position: absolute;
+ width: 100vw;
+ height: 100vh;
+
+ .clip-content {
+ width: 100vw;
+ height: 100vh;
+ position: absolute;
+ z-index: 99;
+ display: flex;
+ flex-direction: column;
+ pointer-events: none;
+
+ .flex-auto {
+ flex: auto;
+ }
+
+ .clip-content-top,
+ .clip-content-footer {
+ width: 100%;
+ pointer-events: none;
+ }
+
+ .clip-content-middle {
+ width: 100%;
+ height: 400rpx;
+ display: flex;
+ box-sizing: border-box;
+
+ .clip-content-middle-left,
+ .clip-content-middle-right {
+ height: 100%;
+ }
+
+ .clip-content-middle-center {
+ position: relative;
+ border: 1px solid;
+ box-sizing: border-box;
+
+ .clip-edge {
+ position: absolute;
+ left: 6rpx;
+ width: 34rpx;
+ height: 34rpx;
+ border: 2rpx solid #fff;
+ pointer-events: auto;
+ box-sizing: border-box;
+
+ &.clip-edge-top-left {
+ border-bottom-width: 0 !important;
+ border-right-width: 0 !important;
+ }
+
+ &.clip-edge-top-right {
+ border-bottom-width: 0 !important;
+ border-left-width: 0 !important;
+ }
+
+ &.clip-edge-bottom-left {
+ border-top-width: 0 !important;
+ border-right-width: 0 !important;
+ }
+
+ &.clip-edge-bottom-right {
+ border-top-width: 0 !important;
+ border-left-width: 0 !important;
+ }
+ }
+ }
+ }
+ }
+
+ .bg-transparent {
+ background-color: rgb(0 0 0 / 60%);
+ transition-duration: 0.35s;
+ }
+ }
+
+ .cropper-image {
+ width: 100%;
+ border-style: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 2;
+ backface-visibility: hidden;
+ backface-visibility: hidden;
+ transform-origin: center;
+ }
+
+ .clipper-canvas {
+ position: fixed;
+ z-index: 10;
+ left: -2000px;
+ top: -2000px;
+ pointer-events: none;
+ }
+
+ .footer-tools {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ z-index: 99;
+
+ .tools-icon {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: 20rpx 40rpx;
+ box-sizing: border-box;
+
+ &-image {
+ display: block;
+ width: 50rpx;
+ height: 50rpx;
+ }
+ }
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/image-clipper/index.wxml b/app/miniprogram_npm/lin-ui/image-clipper/index.wxml
new file mode 100644
index 000000000..6c3ab4728
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/image-clipper/index.wxml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/image-picker/image/add.png b/app/miniprogram_npm/lin-ui/image-picker/image/add.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b5dc49274e4c16c42a50d2ffbeea154847d4b47
GIT binary patch
literal 381
zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&c?9@`xB}_@q=0?<_5qb+lF<=X
z=|Ho@OM?7@83Ysz90KAK3hMhO%wNA@|AF%t?mu|{f&Ie7V?ZTmJzX3_DsH{K<;c}+
zAmDH@BWd+k-$l7|f8XEY`q+w*m-*BGs5$IOV$MB^N=iyrQ)Js_Kl>B+&v)&u8ue^P
zUV}V_%qSeAEbX&wJf!My`~_$xGMkssZBCRF%4v3h~e9?zVzz5vhSJyGq2nVTRK;6
gfuz0AT(ILV@gK3N&xrC}U;@(V>FVdQ&MBb@02m>m0ssI2
literal 0
HcmV?d00001
diff --git a/app/miniprogram_npm/lin-ui/image-picker/index.js b/app/miniprogram_npm/lin-ui/image-picker/index.js
new file mode 100644
index 000000000..ff99d9d11
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/image-picker/index.js
@@ -0,0 +1,318 @@
+import nodeUtil from '../core/utils/node-util';
+import deviceUtil from '../utils/device-util';
+import eventUtil from '../core/utils/event-util';
+import {promisic} from '../utils/util';
+
+Component({
+
+ options: {
+ // 纯数据字段
+ pureDataPattern: /urls|cells|preview|remove|sizeType|maxImageSize|clear/
+ },
+ behaviors: ['wx://form-field'],
+ externalClasses: ['l-class', 'l-item-class'],
+ properties: {
+ // 图片 url 数组,与 cells 二选一传入
+ urls: {
+ type: Array,
+ value: null
+ },
+ // 图片 url 对象数组,与 urls 二选一传入
+ cells: {
+ type: Array,
+ value: null
+ },
+ // 每行可显示的个数
+ size: {
+ type: Number,
+ value: null
+ },
+ // 图片显示模式
+ mode: {
+ type: String,
+ value: 'aspectFit',
+ },
+ // 图片是否可预览
+ preview: {
+ type: Boolean,
+ value: true
+ },
+ // 图片是否可被删除
+ remove: {
+ type: Boolean,
+ value: true
+ },
+ // 最大可选择图片数量
+ count: {
+ type: Number,
+ value: 9
+ },
+ sizeType: {
+ // 该写法经测试有效
+ optionalTypes: [Array, String],
+ value: ['original', 'compressed']
+ },
+ // 所选图片最大限制,单位字节
+ // 0 为无限制
+ maxImageSize: {
+ type: Number,
+ value: 0,
+ },
+ // 清除 value
+ clear: {
+ type: Boolean,
+ value: false
+ },
+ // 是否传入自定义 slot
+ // 已弃用,直接传入 slot 即可,无需修改该属性
+ // todo 1.0.0 移除
+ custom: {
+ type: Boolean,
+ value: false
+ },
+ // 存放图片 url 的数组
+ // 放在 properties 中是因为引入了 behaviors: ['wx://form-field'],
+ // wx://form-field 中的 value 为 null,会引起很多报错
+ // value 放在 data 中没有 properties 优先级高,覆盖不了
+ // 所以只能放在此处
+ value: {
+ type: Array,
+ value: []
+ }
+ },
+
+ data: {
+ // 根据 size 不同,计算的图片显示大小不同
+ itemSizePercentage: null
+ },
+
+ observers: {
+
+ /**
+ * 监听 clear
+ * @param clear
+ */
+ clear(clear) {
+ if (clear) {
+ console.warn('clear 属性已废弃,请使用 linClearImage 函数' +
+ ' 或 urls 属性清空图片\n 详情信息参考:');
+ this.setData({
+ value: [],
+ clear: false
+ });
+ }
+ },
+
+ /**
+ * 监听 urls、cells 更新 value 字段
+ * @param urls
+ * @param cells
+ */
+ 'urls,cells': function (urls, cells) {
+ if (!urls && !cells) {
+ return;
+ }
+
+ let value = [];
+ if (urls) {
+ value = urls;
+ } else if (cells) {
+ for (const cell of cells) {
+ if (Object.prototype.hasOwnProperty.call(cell, 'url')) {
+ value.push(cell.url);
+ }
+ }
+ }
+
+ this.setData({
+ value: value.slice(0, this.data.count)
+ });
+ },
+
+ /**
+ * size 属性变化时,重新调整图片大小
+ * @param size 新值
+ */
+ async size(size) {
+ if (!size) {
+ this.setData({itemSizePercentage: null});
+ return;
+ }
+
+ // 获取 .lin-image-picker__container 容器宽度
+ const res = await nodeUtil.getNodeRectFromComponent(this, '.lin-image-picker__container');
+ const widthRpx = deviceUtil.px2rpx(res.right - res.left);
+
+ // 根据容器宽度计算单张图片宽度百分比
+ const itemSizePercentage = ((10 / size * 10) - 20 / widthRpx * 100) + '%;';
+ this.setData({itemSizePercentage});
+ },
+
+ custom(custom) {
+ if (custom) {
+ console.warn('custom 已弃用,请勿使用该属性,直接传入 slot 即可');
+ }
+ }
+ },
+
+ methods: {
+
+ // ============== 事件监听函数 =============
+
+ /**
+ * 点击图片触发的事件
+ * 进行图片预览,抛出自定义事件
+ * @param e
+ */
+ onTapImage(e) {
+ const that = this;
+ const value = this.data.value;
+ const imageIndex = e.currentTarget.dataset.imageIndex;
+ const imageUrl = value[imageIndex];
+ const detail = {
+ all: value,
+ index: imageIndex,
+ current: imageUrl
+ };
+
+ eventUtil.emit(this, 'lintap', detail);
+
+ // 预览图片
+ if (this.data.preview) {
+ wx.previewImage({
+ urls: value,
+ current: imageUrl,
+ success() {
+ eventUtil.emit(that, 'linpreview', detail);
+ }
+ }, true);
+ }
+ },
+
+ /**
+ * 点击删除按钮触发的事件
+ * @param e 事件对象
+ */
+ onTapRemove(e) {
+ const value = this.data.value;
+ const imageIndex = e.currentTarget.dataset.imageIndex;
+ const imageUrl = value[imageIndex];
+ const detail = {
+ all: value,
+ index: imageIndex,
+ current: imageUrl
+ };
+
+ eventUtil.emit(this, 'linremovetap', detail);
+
+ if (this.data.remove) {
+ this._removeImageByIndex(imageIndex);
+ }
+ },
+
+ /**
+ * 点击添加按钮触发的事件
+ * @returns {Promise}
+ */
+ async onTapAdd() {
+ let {value, count, sizeType, maxImageSize} = this.data;
+ const remainCount = count - value.length;
+ if (value.length >= count || remainCount <= 0) {
+ return;
+ }
+
+ // 调用微信 api 选择图片
+ const chooseImageRes = await promisic(wx.chooseImage)({
+ count: remainCount,
+ sizeType,
+ sourceType: ['album', 'camera'],
+ });
+
+ // 即将被添加的图片的 url 数组
+ const addImageUrlArray = [];
+ // 超过了大小限制的图片的 url 数组,不会被添加到 image-picker 中
+ const oversizeImageUrlArray = [];
+
+ chooseImageRes.tempFiles.forEach((tempFile) => {
+ const {path, size} = tempFile;
+ if (size > maxImageSize && maxImageSize > 0) {
+ oversizeImageUrlArray.push(path);
+ } else {
+ addImageUrlArray.push(path);
+ }
+ });
+
+ // 赋值并触发事件
+ this.setData({
+ value: value.concat(addImageUrlArray)
+ }, () => {
+ const detail = {
+ all: this.data.value,
+ current: addImageUrlArray,
+ oversize: oversizeImageUrlArray
+ };
+ eventUtil.emit(this, 'linadd', detail);
+ // todo 1.0.0 版本去除 linchange 事件
+ eventUtil.emit(this, 'linchange', detail);
+ // todo 1.0.0 版本去除 linoversize 事件
+ eventUtil.emit(this, 'linoversize', detail);
+ });
+ },
+
+ /**
+ * 供 Form 组件调用的取值方法
+ * @returns {*}
+ */
+ getValues() {
+ return this.data.value;
+ },
+
+ // ======= 内部函数 =========
+ /**
+ * 根据图片索引删除图片
+ * @param index 图片索引
+ * @private
+ */
+ _removeImageByIndex(index) {
+ const value = this.data.value;
+ const current = value[index];
+ value.splice(index, 1);
+
+ const detail = {
+ index,
+ current,
+ all: value
+ };
+ this.setData({value}, () => {
+ eventUtil.emit(this, 'linremove', detail);
+ });
+ },
+
+ // ============== 开放函数 ==============
+ /**
+ * 删除图片
+ * @param imageIndex 图片索引
+ */
+ linRemoveImage(imageIndex) {
+ this._removeImageByIndex(imageIndex);
+ },
+
+ /**
+ * 清空所有图片
+ * 不会触发 linremove 事件
+ */
+ linClearImage() {
+ this.setData({
+ value: []
+ });
+ },
+
+ /**
+ * 获取所有 url 图片链接
+ * @returns {Array}
+ */
+ linGetValue() {
+ return this.data.value;
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/image-picker/index.json b/app/miniprogram_npm/lin-ui/image-picker/index.json
new file mode 100644
index 000000000..4bc15bca5
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/image-picker/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {
+ "l-icon": "../icon/index"
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/image-picker/index.less b/app/miniprogram_npm/lin-ui/image-picker/index.less
new file mode 100644
index 000000000..241dceaf4
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/image-picker/index.less
@@ -0,0 +1,88 @@
+.lin-image-picker__container {
+ position: relative;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.lin-image-picker__item {
+ position: relative;
+ width: 220rpx;
+ padding-bottom: 220rpx;
+ height: 0;
+}
+
+// size 不同时,对应的图片间距设置
+// size 仅支持 1-10
+each(range(2, 10), {
+@valuePlusOne : @value+1;
+.lin-image-picker__item--@{value}:nth-of-type(n+@{valuePlusOne}) {
+ margin-top : 20rpx;
+}
+.lin-image-picker__item--@{value}:not(:nth-of-type(@{value}n+1)) {
+ margin-left : 20rpx;
+}
+})
+// 当 size 为 null,每行会显示 3 张图片
+.lin-image-picker__item--null:nth-of-type(n+4) {
+ margin-top: 20rpx;
+}
+
+.lin-image-picker__item--null:not(:nth-of-type(3n+1)) {
+ margin-left: 20rpx;
+}
+
+.lin-image-picker__image {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ border: 1rpx solid #eee;
+ border-radius: 4rpx;
+}
+
+.lin-image-picker__remove {
+ position: absolute;
+ right: 10rpx;
+ top: 10rpx;
+ height: 40rpx;
+ width: 40rpx;
+ border-radius: 50%;
+ background: rgb(0 0 0 / 40%);
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+}
+
+.lin-image-picker__item--add {
+ border: 1rpx solid #eee;
+ border-radius: 4rpx;
+ background-color: white;
+}
+
+.lin-image-picker__image--add {
+ visibility: hidden;
+ position: absolute;
+ width: 50%;
+ height: 50%;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+.lin-image-picker__item-slot-wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+}
+
+.lin-image-picker__item-slot-wrapper:empty + .lin-image-picker__image--add {
+ visibility: visible;
+}
diff --git a/app/miniprogram_npm/lin-ui/image-picker/index.wxml b/app/miniprogram_npm/lin-ui/image-picker/index.wxml
new file mode 100644
index 000000000..84d5b992f
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/image-picker/index.wxml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/index-anchor/index.js b/app/miniprogram_npm/lin-ui/index-anchor/index.js
new file mode 100644
index 000000000..7c6710d2a
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-anchor/index.js
@@ -0,0 +1,115 @@
+import nodeUtil from '../core/utils/node-util';
+
+Component({
+
+ externalClasses:['l-anchor-class'],
+
+ options: {
+ multipleSlots: true,
+ pureDataPattern: /^_/
+ },
+
+ relations: {
+ '../index-list/index': {
+ type: 'parent'
+ }
+ },
+
+ data: {
+ // 锚点 Slot 节点信息
+ anchorSlot: {
+ height: -1
+ },
+ // Anchor 节点高度
+ anchor: {
+ height: 0
+ },
+ // 锚点文本内容
+ anchorText: '',
+ // 锚点样式
+ anchorStyle: '',
+ // Anchor 设置为 fixed 布局后
+ // 用来支持原来 Anchor 节点的高度
+ anchorWrapperStyle: ''
+ },
+
+ lifetimes: {
+ attached() {
+ this.parseAnchorSlotRect();
+ },
+ },
+
+ methods: {
+ /**
+ * 把 Anchor 锚点 Slot位置信息放入 data
+ */
+ async parseAnchorSlotRect() {
+ const anchorSlotRect = await nodeUtil.getNodeRectFromComponent(this, '.anchor-slot');
+ if (anchorSlotRect) {
+ this.setData({
+ ['anchorSlot.height']: anchorSlotRect.height
+ });
+ } else {
+ this.setData({
+ ['anchorSlot.height']: 0
+ });
+ }
+ },
+
+ /**
+ * 获取 Anchor 节点信息
+ * @returns {Promise}
+ */
+ async parseAnchorRect() {
+ const anchorRect = await nodeUtil.getNodeRectFromComponent(this, '.anchor');
+ if (anchorRect) {
+ this.setData({
+ ['anchor.height']: anchorRect.height
+ });
+ }
+ },
+
+ /**
+ * 把 Anchor 设置为吸附状态
+ */
+ setFixed(stickOffsetTop, anchorHeight) {
+ const anchorStyle = `
+ position:fixed;
+ top:${stickOffsetTop}rpx;
+ `;
+ const anchorWrapperStyle = `height:${anchorHeight}px;`;
+ this.setData({anchorStyle, anchorWrapperStyle});
+ },
+
+ /**
+ * 把 Anchor 设置为相对定位
+ * @param translateY
+ */
+ setRelative(translateY) {
+ const anchorStyle = `
+ position:relative;
+ transform: translate3d(0, ${translateY}px, 0);
+ `;
+ this.setData({anchorStyle});
+ },
+
+
+ /**
+ * 把 Anchor 样式复原
+ */
+ clearStyle() {
+ this.setData({anchorStyle: '', anchorWrapperStyle: ''});
+ },
+
+ /**
+ * 当前 Anchor 是否是 relative 布局
+ */
+ isRelative() {
+ return this.data.anchorStyle.indexOf('relative') > 0;
+ },
+
+ isFixed(){
+ return this.data.anchorStyle.indexOf('fixed') > 0;
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/index-anchor/index.json b/app/miniprogram_npm/lin-ui/index-anchor/index.json
new file mode 100644
index 000000000..aa80c042b
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-anchor/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-index-list": "../index-list/index"
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/index-anchor/index.less b/app/miniprogram_npm/lin-ui/index-anchor/index.less
new file mode 100644
index 000000000..44a21b3dd
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-anchor/index.less
@@ -0,0 +1,19 @@
+.anchor-wrapper {
+ width: 100%;
+
+ .anchor {
+ width: 100%;
+
+ &-default {
+ width: 100%;
+ background-color: #f7f8fa;
+ display: flex;
+ align-items: center;
+ padding: 8rpx 0 8rpx 30rpx;
+ font-size: 26rpx;
+ font-weight: bold;
+ color: #323132;
+ box-sizing: border-box;
+ }
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/index-anchor/index.wxml b/app/miniprogram_npm/lin-ui/index-anchor/index.wxml
new file mode 100644
index 000000000..44729cb1c
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-anchor/index.wxml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+ {{anchorText}}
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/index-list/index.js b/app/miniprogram_npm/lin-ui/index-list/index.js
new file mode 100644
index 000000000..00a5c94b9
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-list/index.js
@@ -0,0 +1,451 @@
+import nodeUtil from '../core/utils/node-util';
+import dataUtil from '../core/utils/data-util';
+import eventUtil from '../core/utils/event-util';
+import pixelUtil from '../core/utils/pixel-util';
+
+// 默认的 Sidebar 数据
+const defaultSidebarData = [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
+];
+
+
+Component({
+
+ externalClasses: [
+ 'l-tip-class', 'l-tip-text-class', 'l-sidebar-class', 'l-selected-class', 'l-unselected-class', 'l-sidebar-item-class'
+ ],
+
+ relations: {
+ '../index-anchor/index': {
+ type: 'child'
+ }
+ },
+
+ options: {
+ multipleSlots: true,
+ pureDataPattern: /^_/
+ },
+
+ lifetimes: {
+ attached() {
+ this.init();
+ }
+ },
+
+ properties: {
+ // Anchor 是否吸附
+ isStick: {
+ type: Boolean,
+ value: false
+ },
+
+ // 页面垂直滚动距离
+ // 微信官方 onScrollTop() 监听函数获取
+ scrollTop: {
+ type: Number,
+ value: 0
+ },
+
+ // Sidebar 显示的索引内容
+ sidebarData: {
+ type: Array,
+ value: defaultSidebarData
+ },
+
+ // 是否显示 Sidebar
+ showSidebar: {
+ type: Boolean,
+ value: true
+ },
+
+ // Anchor 吸附时距离顶部的距离(单位 rpx)
+ stickOffsetTop: {
+ type: Number,
+ value: 0
+ }
+ },
+
+ data: {
+ // Sidebar 节点信息
+ _sidebar: {
+ top: 0,
+ height: 0,
+ sidebarItemCenterPoints: [],
+ // 该变量用于标识是否正在滑动 Sidebar
+ // 滑动侧栏的时候需要禁止页面滚动去改变 Sidebar 激活项
+ // 不然会出现 Sidebar 激活项乱跳动的问题
+ isMoving: false,
+ // sidebar-item 节点 rect 信息
+ sidebarItemRect: {}
+ },
+ // Anchor 节点信息
+ _anchor: {
+ // 每个 Anchor 距离页面顶部的像素
+ anchorTopLocations: [],
+ // index-anchor 所有组件实例
+ indexAnchorComponents: [],
+ // 当前吸附的 Anchor 索引
+ currentStickAnchorIndex: -1,
+ // 每个 Anchor 的高度
+ anchorItemsHeight: []
+ },
+ // stickOffsetTop px数值
+ _stickOffsetTopPx: 0,
+ // 当前激活的索引项 的索引
+ activeSidebarItem: 0,
+ // Tip 提示绝对定位的top值
+ tipTop: 0,
+ // 是否显示 Tip
+ showTip: false,
+ // tip 高度
+ tipHeight: 0
+ },
+
+ observers: {
+ 'scrollTop': function (scrollTop) {
+ this.setIndexListStyle(scrollTop);
+ },
+ 'stickOffsetTop': function (stickOffsetTop) {
+ this.setData({
+ _stickOffsetTopPx: pixelUtil.rpx2px(stickOffsetTop)
+ });
+ }
+ },
+
+
+ methods: {
+
+ // ================================== 组件初始化函数 ==================================
+
+ /**
+ * 组件初始化函数,主要计算一些必要的信息
+ * 该函数内的多个异步函数调用顺序非常重要,不要随意更改,否则会出错
+ */
+ async init() {
+ // 解析 Sidebar Rect 信息
+ await this.parseSidebarRect();
+ // 解析 SidebarItem Rect 信息
+ await this.parseSidebarItemRect();
+ // 获取 index-anchor 所有组件实例
+ await this.parseIndexAnchors();
+ // 解析 Anchor Rect 信息
+ this.parseAnchorRect();
+
+ wx.lin = wx.lin || {};
+ // 传入scrollTop的值的函数
+ wx.lin.setScrollTop = (scrollTop) => {
+ dataUtil.setDiffData(this, { scrollTop });
+ };
+ },
+
+ // ================================== 节点信息获取函数 ==================================
+
+ /**
+ * 把 Sidebar 在页面中的位置信息存到 data 中
+ */
+ async parseSidebarRect() {
+ const sidebarRect = await nodeUtil.getNodeRectFromComponent(this, '.sidebar');
+ this.setData({
+ ['_sidebar.height']: sidebarRect.height,
+ ['_sidebar.top']: sidebarRect.top
+ });
+ },
+
+ /**
+ * 把 Sidebar 每个 Item 的中点位置存到 data 中
+ * 用于 Tip 定位使用
+ */
+ async parseSidebarItemRect() {
+ // Sidebar 索引个数
+ const sidebarLength = this.data.sidebarData.length;
+ // 获取 sidebar-item 节点
+ const sidebarItemRect = await nodeUtil.getNodeRectFromComponent(this, '.sidebar-item');
+ // Sidebar 单个索引高度(包含了 margin 空隙)
+ const sidebarItemHeight = this.data._sidebar.height / sidebarLength;
+ // Sidebar 单个索引真实高度
+ const sidebarItemRealHeight = sidebarItemRect.height;
+ // 获取 sidebar-item margin-top 属性
+ const sidebarItemFields = await nodeUtil.getNodeFieldsFromComponent(this, '.sidebar-item', {
+ computedStyle: ['margin-top']
+ });
+ // 获取 tip height 属性
+ // 只能用 height 获取高度,因为 tip 旋转后,rect的宽高发生了变化
+ const tipFields = await nodeUtil.getNodeFieldsFromComponent(this, '.tip', {
+ computedStyle: ['height']
+ });
+ const sidebarItemCenterPoints = [];
+ const sidebarItemMarginTop = sidebarItemFields['margin-top'].replace('px', '');
+
+ for (let i = 1; i <= sidebarLength; i++) {
+ sidebarItemCenterPoints.push((i * 2 - 1) * sidebarItemRealHeight / 2 + i * parseInt(sidebarItemMarginTop));
+ }
+
+ const tipHeight = parseInt(tipFields.height.replace('px', ''));
+ this.setData({
+ tipHeight,
+ // tip 旋转后,中线位置下移了 20.5%
+ tipHeightOverflow: tipHeight * 0.205,
+ ['_sidebar.sidebarItemRect']: sidebarItemRect,
+ ['_sidebar.sidebarItemHeight']: sidebarItemHeight,
+ ['_sidebar.sidebarItemRealHeight']: sidebarItemRealHeight,
+ ['_sidebar.sidebarItemCenterPoints']: sidebarItemCenterPoints
+ });
+ },
+
+ /**
+ * 获取所有的 index-anchor 节点实例
+ */
+ parseIndexAnchors() {
+ // 获取该 index-list 内部所有的 index-anchor
+ const indexAnchors = this.getRelationNodes('../index-anchor/index');
+
+ // 没获取到节点实例的异常情况
+ if (!indexAnchors) {
+ console.error('获取 index-anchor 节点实例失败,请参考文档检查您的代码是否书写正确');
+ return;
+ }
+
+ // 存入 data
+ this.setData({
+ ['_anchor.indexAnchorComponents']: indexAnchors
+ });
+
+ for (let i = 0; i < indexAnchors.length; i++) {
+ indexAnchors[i].setData({
+ anchorText: this.data.sidebarData[i]
+ });
+ }
+ },
+
+ /**
+ * 把 Anchor 在页面中的位置信息存到 data 中
+ */
+ async parseAnchorRect() {
+ // 每个 Anchor 距离页面顶部的像素
+ const anchorTopLocations = [];
+ // 每个 Anchor 的高度
+ const anchorItemsHeight = [];
+ // index-anchor 组件实例
+ const indexAnchorComponents = this.data._anchor.indexAnchorComponents;
+
+ for (const indexAnchorComponent of indexAnchorComponents) {
+ // todo 此处获取 .anchor 节点,不知为什么在 index-anchor 组件中获取到的为空,后期再调研修改
+ const anchorRect = await nodeUtil.getNodeRectFromComponent(indexAnchorComponent, '.anchor');
+ if (anchorRect === null) {
+ continue;
+ }
+ anchorTopLocations.push(anchorRect.top);
+ anchorItemsHeight.push(anchorRect.height);
+ }
+
+ this.setData({
+ // 每个 Anchor 距离页面顶部的像素
+ ['_anchor.anchorTopLocations']: anchorTopLocations,
+ // 每个 Anchor 的高度
+ ['_anchor.anchorItemsHeight']: anchorItemsHeight
+ });
+
+ },
+
+ // ================================== 页面元素控制函数 ==================================
+ /**
+ * 设置 Tip 显示隐藏
+ * @param isShow 是否显示 Tip
+ */
+ switchTipShow(isShow) {
+ dataUtil.setDiffData(this, {
+ showTip: isShow
+ });
+ },
+
+ /**
+ * 切换 Sidebar 激活的选项
+ * @param index 被激活选项的索引
+ */
+ switchSidebarIndex(index) {
+ dataUtil.setDiffData(this, {
+ activeSidebarItem: index,
+ });
+ },
+
+ /**
+ * 切换是否正在滑动 Sidebar
+ */
+ switchIsMovingSidebar(isMoving) {
+ dataUtil.setDiffData(this, {
+ ['_sidebar.isMoving']: isMoving
+ });
+ },
+
+ /**
+ * 根据 scrollTop 调整 Anchor、Sidebar 样式
+ * @param scrollTop onScrollTop() 函数监听得到的值
+ */
+ setIndexListStyle(scrollTop) {
+ // 当前应该激活的索引
+ const currentShouldActiveIndex = this.countCurrentActiveIndex(scrollTop);
+ if (currentShouldActiveIndex === undefined) {
+ return;
+ }
+
+ // 设置 Anchor 的样式
+ this.data.isStick && this.setAnchorStyle(scrollTop);
+ // 激活 Sidebar 选项
+ if (this.data.showSidebar && !this.data._sidebar.isMoving) {
+ this.switchSidebarIndex(currentShouldActiveIndex);
+ }
+ },
+
+ /**
+ * 设置 Anchor 样式
+ * @param scrollTop onScrollTop() 函数监听得到的值
+ */
+ setAnchorStyle(scrollTop) {
+ const {
+ // 每个 Anchor 距离页面顶部的 px 值
+ anchorTopLocations,
+ // 所有 Anchor 的高度
+ anchorItemsHeight,
+ // 所有 index-anchor 组件实例
+ indexAnchorComponents
+ } = this.data._anchor;
+
+ // 当前应该激活的索引
+ const currentShouldActiveIndex = this.countCurrentActiveIndex(scrollTop);
+
+ // 当前应该激活的 index-anchor 组件实例
+ const currentIndexAnchorComponent = indexAnchorComponents[currentShouldActiveIndex];
+ // 当前应该激活的 Anchor top 值
+ const currentIndexAnchorTop = anchorTopLocations[currentShouldActiveIndex];
+ // 当前应该激活的 Anchor 高度
+ const currentIndexAnchorHeight = anchorItemsHeight[currentShouldActiveIndex];
+
+ // 下一个应该激活的 Anchor top 值
+ const nextIndexAnchorTop = anchorTopLocations[currentShouldActiveIndex + 1];
+
+ // stickOffsetTop px值
+ const stickOffsetTop = this.data._stickOffsetTopPx;
+ if (scrollTop + stickOffsetTop >= currentIndexAnchorTop && scrollTop + stickOffsetTop <= nextIndexAnchorTop - currentIndexAnchorHeight && !currentIndexAnchorComponent.isFixed()) {
+ // 该条件下,当前 Anchor 应该设置为 fixed 布局,并把其他 Anchor 样式清空
+ currentIndexAnchorComponent.setFixed(this.data.stickOffsetTop, currentIndexAnchorHeight);
+ for (let i = 0; i < indexAnchorComponents.length; i++) {
+ if (i !== currentShouldActiveIndex) {
+ indexAnchorComponents[i].clearStyle();
+ }
+ }
+ } else if (scrollTop + stickOffsetTop > nextIndexAnchorTop - currentIndexAnchorHeight && scrollTop + stickOffsetTop < nextIndexAnchorTop && !currentIndexAnchorComponent.isRelative()) {
+ // 该条件下,当前 Anchor 应该设置为 relative 布局,并把其他 Anchor 样式清空
+ currentIndexAnchorComponent.setRelative(nextIndexAnchorTop - currentIndexAnchorTop - currentIndexAnchorHeight);
+ for (let i = 0; i < indexAnchorComponents.length; i++) {
+ if (i !== currentShouldActiveIndex) {
+ indexAnchorComponents[i].clearStyle();
+ }
+ }
+ } else if (scrollTop + stickOffsetTop < currentIndexAnchorTop) {
+ // 该条件下,清空所有 Anchor 样式
+ for (let i = 0; i < indexAnchorComponents.length; i++) {
+ indexAnchorComponents[i].clearStyle();
+ }
+ }
+ },
+
+ /**
+ * 计算当前页面滚动到了第几个索引
+ * @param scrollTop onScrollTop() 函数监听得到的值
+ */
+ countCurrentActiveIndex(scrollTop) {
+ let result = 0;
+ // 每个 Anchor 距离页面顶部的 px 值
+ const { anchorTopLocations } = this.data._anchor;
+
+ for (let i = 0; i < anchorTopLocations.length; i++) {
+ if (scrollTop + this.data._stickOffsetTopPx < anchorTopLocations[i]) {
+ result = i - 1;
+ break;
+ }
+ }
+ if (result < 0) {
+ result = 0;
+ }
+ return result;
+ },
+
+ // ================================== 事件监听函数 ==================================
+
+ /**
+ * 监听 手指触摸后移动 事件
+ * @param event 事件对象
+ */
+ onTouchMove(event) {
+ // 显示 Tip
+ this.switchTipShow(true);
+ // 标识正在滑动 Sidebar
+ this.switchIsMovingSidebar(true);
+
+ // 取出 Sidebar 位置信息
+ const { top: sidebarTop, sidebarItemHeight } = this.data._sidebar;
+ // Sidebar 索引个数
+ const sidebarLength = this.data.sidebarData.length;
+ // 触摸点 Y 坐标
+ const touchY = event.touches[0].clientY;
+ // 计算当前触摸点在第几个索引处
+ let index = Math.floor((touchY - sidebarTop) / sidebarItemHeight);
+
+ // 滑动超过范围时限制索引边界值
+ if (index < 0) {
+ index = 0;
+ } else if (index > sidebarLength - 1) {
+ index = sidebarLength - 1;
+ }
+
+ // 选中的索引文字
+ const tipText = this.data.sidebarData[index];
+ dataUtil.setDiffData(this, {
+ tipText,
+ activeSidebarItem: index,
+ tipTop: this.data._sidebar.sidebarItemCenterPoints[index]
+ });
+
+ // 页面应该滚动到的位置
+ let scrollPageToLocation = this.data._anchor.anchorTopLocations[index] - this.data._stickOffsetTopPx;
+
+ // 滚动页面到对应索引处
+ wx.pageScrollTo({
+ duration: 0,
+ scrollTop: scrollPageToLocation
+ });
+
+ /**
+ * fix issue1078
+ * 当点击 sidebar 时,onTouchend 会先于 onTouchMove 执行
+ * 导致滑动状态无法正常关闭,固此处添加一个延时状态修改(页面滚动需要一定时间)
+ */
+ event.type === 'tap' && setTimeout(() => {
+ this.switchIsMovingSidebar(false);
+ }, 100);
+
+ // 触发 linselected 事件
+ eventUtil.emit(this, 'linselected', { index, tipText });
+ },
+
+ /**
+ * 监听 手指触摸动作结束 事件
+ */
+ onTouchend() {
+ // 500 毫秒后隐藏 Tip
+ setTimeout(() => {
+ this.switchTipShow(false);
+ }, 500);
+ this.switchIsMovingSidebar(false);
+ },
+
+ /**
+ * 监听 点击侧边栏
+ */
+ onTapSidebar(event) {
+ // 把事件对象传入触摸滑动监听函数即可
+ this.onTouchMove(event);
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/index-list/index.json b/app/miniprogram_npm/lin-ui/index-list/index.json
new file mode 100644
index 000000000..a89ef4dbe
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-list/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/app/miniprogram_npm/lin-ui/index-list/index.less b/app/miniprogram_npm/lin-ui/index-list/index.less
new file mode 100644
index 000000000..c8a78c337
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-list/index.less
@@ -0,0 +1,49 @@
+@import "../../config/styles/_base";
+
+.index-list {
+ //侧栏样式
+ .sidebar {
+ font-size: 24rpx;
+ position: fixed;
+ right: 30rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ &-item {
+ width: 40rpx;
+ height: 40rpx;
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: 8rpx;
+ }
+
+ &-item-active {
+ color: white;
+ background-color: @default-color;
+ }
+ }
+
+ // 提示样式
+ .tip {
+ width: 90rpx;
+ height: 90rpx;
+ background-color: #d8d8d8;
+ border-radius: 90px 90px 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: absolute;
+ left: -160rpx;
+ transform: rotate(-45deg) translateY(-35%);
+
+ &-text {
+ font-size: 30rpx;
+ transform: rotate(45deg);
+ }
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/index-list/index.wxml b/app/miniprogram_npm/lin-ui/index-list/index.wxml
new file mode 100644
index 000000000..f64fb2469
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/index-list/index.wxml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/input/index.js b/app/miniprogram_npm/lin-ui/input/index.js
new file mode 100644
index 000000000..378c9ec72
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/input/index.js
@@ -0,0 +1,165 @@
+// input/input.js
+import eventBus from '../core/utils/event-bus.js';
+import validator from '../behaviors/validator';
+import rules from '../behaviors/rules';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ options: {
+ multipleSlots: true,
+ },
+ behaviors: ['wx://form-field', validator, rules],
+ externalClasses: ['l-class', 'l-label-class', 'l-error-text', 'l-error-text-class','l-input-class','l-row-class'],
+ properties: {
+ // 表单标题(label)的文本
+ label: String,
+ // 是否隐藏label
+ hideLabel: Boolean,
+ // 是否自定义label部分
+ labelCustom: Boolean,
+ // 是否显示下划线
+ showRow: {
+ type: Boolean,
+ value: true
+ },
+ // 是否必选
+ required: Boolean,
+ // 占位文本
+ placeholder: String,
+ // 输入框类型
+ type: {
+ type: String,
+ value: 'text',
+ options: ['text', 'idcard', 'digit', 'password', 'number']
+ },
+ // 输入框的值
+ value: String,
+ // 是否需要冒号
+ colon: Boolean,
+ // 获取焦点
+ focus: Boolean,
+ // 是否显示清除按钮
+ clear: Boolean,
+ // 最大输入长度
+ maxlength: {
+ type: Number,
+ value: 140
+ },
+ // 表单项的宽度,单位rpx
+ width: {
+ type: Number,
+ value: null
+ },
+ // 表单项标题部分的宽度,单位rpx
+ labelWidth: {
+ type: Number,
+ value: 200
+ },
+ // label标题的显示位置 left top right
+ labelLayout: {
+ type: String,
+ value: 'left',
+ options: ['left', 'right']
+ },
+ // 是否禁用
+ disabled: Boolean,
+ // 占位文字的样式
+ placeholderStyle: String,
+ // 是否显示显隐密码图标
+ showEye: {
+ type: Boolean,
+ value: false
+ },
+ // 键盘弹起时,是否自动上推页面
+ adjustPosition:{
+ type: Boolean,
+ value: true
+ }
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {},
+ attached() {
+ // this.initRules();
+ },
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+
+ handleInputChange(event) {
+ const {
+ detail = {}
+ } = event;
+ const {
+ value = ''
+ } = detail;
+
+ this.setData({
+ value
+ });
+ eventBus.emit(`lin-form-change-${this.id}`, this.id);
+ this.triggerEvent('lininput', event.detail);
+ },
+
+ handleInputFocus(event) {
+ this.triggerEvent('linfocus', event.detail);
+ },
+
+ handleInputBlur(event) {
+ this.validatorData({
+ [this.data.name]: event.detail.value
+ });
+ eventBus.emit(`lin-form-blur-${this.id}`, this.id);
+ this.triggerEvent('linblur', event.detail);
+ },
+ handleInputConfirm(event) {
+ const {
+ detail = {}
+ } = event;
+ const {
+ value = ''
+ } = detail;
+
+ this.setData({
+ value
+ });
+
+ this.triggerEvent('linconfirm', event.detail);
+ },
+ onClearTap(event) {
+ this.setData({
+ value: ''
+ });
+ this.triggerEvent('linclear', event.detail);
+ },
+ getValues() {
+ return this.data.value;
+ },
+ reset() {
+ this.setData({
+ value: ''
+ });
+ },
+
+ /**
+ * 监听:点击输入框右侧显隐密码图标
+ */
+ onTapEyeIcon() {
+ const type = this.data.type;
+ if (type === 'text') {
+ this.setData({
+ type: 'password'
+ });
+ } else if (type === 'password') {
+ this.setData({
+ type: 'text'
+ });
+ }
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/input/index.json b/app/miniprogram_npm/lin-ui/input/index.json
new file mode 100644
index 000000000..fe1a1ffde
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/input/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-icon": "../icon/index",
+ "l-error-tip":"../error-tip/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/input/index.less b/app/miniprogram_npm/lin-ui/input/index.less
new file mode 100644
index 000000000..8ffcaaa07
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/input/index.less
@@ -0,0 +1,94 @@
+@import "../../config/styles/_base.less";
+
+.form-item {
+ position: relative;
+ font-size: 28rpx;
+ color: #333;
+ height: 88rpx;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding-right: 25rpx;
+ box-sizing: border-box;
+}
+
+.row {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ height: 2rpx;
+ width: 730rpx;
+ background: #f3f3f3;
+}
+
+.text-require {
+ color: #e23;
+ vertical-align: middle;
+}
+
+.form-label {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 88rpx;
+ padding-left: 25rpx;
+ padding-right: 15rpx;
+ box-sizing: border-box;
+}
+
+.disabled {
+ color: #9a9a9a !important;
+}
+
+.mask {
+ position: absolute;
+ z-index: 999;
+ height: 100%;
+ width: 100%;
+}
+
+.form-label-right {
+ justify-content: flex-end;
+}
+
+.form-label-left {
+ justify-content: flex-start;
+}
+
+.input {
+ height: 100%;
+ line-height: 100%;
+ flex: 1;
+}
+
+.close {
+ height: 36rpx;
+ width: 36rpx;
+ background: #ddd;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ margin-right: 20rpx;
+}
+
+.pls-class {
+ color: #9a9a9a;
+}
+
+.hideLabel {
+ padding-left: 25rpx;
+}
+
+.l-eye {
+ padding: 10rpx;
+
+ &-text {
+ color: @default-color !important;
+ }
+
+ &-password {
+ color: fadeout(@default-color, 40%) !important;
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/input/index.wxml b/app/miniprogram_npm/lin-ui/input/index.wxml
new file mode 100644
index 000000000..badb0031e
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/input/index.wxml
@@ -0,0 +1,55 @@
+
+
diff --git a/app/miniprogram_npm/lin-ui/label/index.js b/app/miniprogram_npm/lin-ui/label/index.js
new file mode 100644
index 000000000..db8488095
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/label/index.js
@@ -0,0 +1,119 @@
+// input/input.js
+import eventBus from '../core/utils/event-bus.js';
+import validator from '../behaviors/validator';
+import rules from '../behaviors/rules';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ options: {
+ multipleSlots: true,
+ },
+ behaviors: ['wx://form-field', validator, rules],
+ externalClasses: [
+ 'l-class',
+ 'l-label-class',
+ 'l-error-text',
+ 'l-error-text-class',
+ 'l-desc-class',
+ 'l-row-class',
+ ],
+ properties: {
+ // 表单标题(label)的文本
+ label: String,
+ // 是否隐藏label
+ hideLabel: Boolean,
+ // 是否自定义label部分
+ labelCustom: Boolean,
+ // 是否显示下划线
+ showRow: {
+ type: Boolean,
+ value: true,
+ },
+ // 是否必选
+ required: Boolean,
+ // 占位文本
+ placeholder: {
+ type: String,
+ value: '请选择',
+ },
+ arr: {
+ type: Array,
+ },
+ // 传入的值
+ value: {
+ type: null,
+ optionalTypes: [String, Number],
+ value: '',
+ },
+ // 是否需要冒号
+ colon: Boolean,
+ // 获取焦点
+ focus: Boolean,
+ // 是否显示清除按钮
+ clear: Boolean,
+ showIcon: {
+ type: Boolean,
+ value: true,
+ },
+ // 表单项的宽度,单位rpx
+ width: {
+ type: Number,
+ value: null,
+ },
+ // 表单项标题部分的宽度,单位rpx
+ labelWidth: {
+ type: Number,
+ value: 200,
+ },
+ // label标题的显示位置 left top right
+ labelLayout: {
+ type: String,
+ value: 'left',
+ options: ['left', 'right'],
+ },
+ // 是否禁用
+ disabled: Boolean,
+ // 占位文字的样式
+ placeholderStyle: String,
+ special: {
+ type: Boolean,
+ value: false,
+ },
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {},
+ attached() {
+ // this.initRules();
+ },
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ handleTap(e) {
+ this.triggerEvent(
+ 'lintap',
+ {
+ e,
+ },
+ { bubbles: true, composed: true }
+ );
+ },
+ onClearTap(e) {
+ this.triggerEvent(
+ 'linclear',
+ {
+ e,
+ },
+ { bubbles: true, composed: true }
+ );
+ },
+ getValues() {
+ return this.data.value;
+ },
+ },
+});
diff --git a/app/miniprogram_npm/lin-ui/label/index.json b/app/miniprogram_npm/lin-ui/label/index.json
new file mode 100644
index 000000000..fe1a1ffde
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/label/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-icon": "../icon/index",
+ "l-error-tip":"../error-tip/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/label/index.less b/app/miniprogram_npm/lin-ui/label/index.less
new file mode 100644
index 000000000..1f813ead4
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/label/index.less
@@ -0,0 +1,93 @@
+@import "../../config/styles/_base.less";
+
+.form-item {
+ position: relative;
+ font-size: 28rpx;
+ color: #333;
+ height: 88rpx;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding-right: 25rpx;
+ box-sizing: border-box;
+}
+
+.row {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ height: 2rpx;
+ width: 730rpx;
+ background: #f3f3f3;
+}
+
+.text-require {
+ color: #e23;
+ vertical-align: middle;
+}
+
+.form-label {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 88rpx;
+ padding-left: 25rpx;
+ padding-right: 15rpx;
+ box-sizing: border-box;
+}
+
+.disabled {
+ color: #9a9a9a !important;
+}
+
+.mask {
+ position: absolute;
+ z-index: 999;
+ height: 100%;
+ width: 100%;
+}
+
+.form-label-right {
+ justify-content: flex-end;
+}
+
+.form-label-left {
+ justify-content: flex-start;
+}
+
+.desc {
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 88rpx;
+ flex: 1;
+
+ .descText {
+ font-size: 28rpx;
+ flex: 1;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+}
+
+.close {
+ height: 36rpx;
+ width: 36rpx;
+ background: #ddd;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ margin-right: 20rpx;
+}
+
+.pls-class {
+ color: #9a9a9a;
+}
+
+.hideLabel {
+ padding-left: 25rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/label/index.wxml b/app/miniprogram_npm/lin-ui/label/index.wxml
new file mode 100644
index 000000000..7d0defe21
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/label/index.wxml
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/list/index.js b/app/miniprogram_npm/lin-ui/list/index.js
new file mode 100644
index 000000000..6d430cc0e
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/list/index.js
@@ -0,0 +1,107 @@
+import hover from '../behaviors/hover';
+
+Component({
+ behaviors:[hover],
+ relations: {
+ '../list/index': {
+ type: 'parent', // 关联的目标节点应为子节点
+ linked() {
+ // 每次有custom-li被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
+ },
+ linkChanged() {
+ // 每次有custom-li被移动后执行,target是该节点实例对象,触发在该节点moved生命周期之后
+ },
+ unlinked() {
+ // 每次有custom-li被移除时执行,target是该节点实例对象,触发在该节点detached生命周期之后
+ }
+ }
+ },
+
+ options: {
+ multipleSlots: true
+ },
+ externalClasses: [
+ 'l-class',
+ 'l-class-icon',
+ 'l-icon-class',
+ 'l-class-image',
+ 'l-image-class',
+ 'l-class-right',
+ 'l-right-class',
+ 'l-class-content',
+ 'l-content-class',
+ 'l-class-desc',
+ 'l-desc-class',
+ 'l-link-icon-class'
+ ],
+ properties: {
+ icon: String,
+ iconColor: {
+ type: String,
+ value: '#3963BC'
+ },
+ iconSize: {
+ type: String,
+ value: '28'
+ },
+ image: String,
+ title: String,
+ desc: String,
+ tagPosition: {
+ type: String,
+ value: 'left'
+ },
+ tagContent: String,
+ tagShape: {
+ type: String,
+ value: 'square'
+ },
+ tagColor: String,
+ tagPlain: Boolean,
+ badgePosition: {
+ type: String,
+ value: 'left'
+ },
+ dotBadge: Boolean,
+ badgeCount: Number,
+ badgeMaxCount: {
+ type: Number,
+ value: 99
+ },
+ badgeCountType: {
+ type: String,
+ value: 'overflow'
+ },
+ rightDesc: String,
+ gap: Number,
+ leftGap: Number,
+ rightGap: Number,
+ isLink: {
+ type: Boolean,
+ value: true,
+ },
+ linkType: {
+ type: String,
+ value: 'navigateTo'
+ },
+ url: String
+
+ },
+
+ methods: {
+ tapcell: function (e) {
+ const {
+ linkType,
+ url
+ } = e.currentTarget.dataset;
+ if (url) {
+ wx[linkType]({
+ url
+ });
+ }
+ this.triggerEvent('lintap', {
+ e
+ }, { bubbles: true, composed: true });
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/list/index.json b/app/miniprogram_npm/lin-ui/list/index.json
new file mode 100644
index 000000000..0dd8908db
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/list/index.json
@@ -0,0 +1,8 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-icon":"../icon/index",
+ "l-badge":"../badge/index",
+ "l-tag":"../tag/index"
+ }
+ }
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/list/index.less b/app/miniprogram_npm/lin-ui/list/index.less
new file mode 100644
index 000000000..3143b6780
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/list/index.less
@@ -0,0 +1,65 @@
+.l-list {
+ width: 100%;
+ min-height: 88rpx;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ color: #333;
+ font-size: 28rpx;
+ border-bottom: 1px solid #f3f3f3;
+ box-sizing: border-box;
+
+ &-hover {
+ opacity: 0.8;
+ }
+
+ .left-section {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .l-icon {
+ margin-right: 20rpx;
+ }
+
+ .l-desc {
+ color: #d1d3d7;
+ font-size: 24rpx;
+ }
+
+ .cell-tag {
+ margin-left: 20rpx;
+ }
+
+ .l-image {
+ width: 44rpx;
+ height: 44rpx;
+ margin-right: 20rpx;
+ }
+ }
+
+ .right-section {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ line-height: 1.2;
+
+ .l-text {
+ margin-right: 20rpx;
+ }
+
+ .cell-tag {
+ margin-right: 20rpx;
+ }
+ }
+
+ .badge-right {
+ border-radius: 28rpx;
+ min-width: 28rpx;
+ left: -20rpx;
+ right: auto;
+ top: 0;
+ bottom: 0;
+ transform: translate(-100%, 2rpx);
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/list/index.wxml b/app/miniprogram_npm/lin-ui/list/index.wxml
new file mode 100644
index 000000000..a300d6c50
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/list/index.wxml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{title}}
+ {{desc}}
+
+
+ {{tagContent}}
+
+
+ {{tagContent}}
+
+
+
+
+
+
+
+
+
+ {{tagContent}}
+
+
+ {{tagContent}}
+
+ {{rightDesc}}
+
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/loading/index.js b/app/miniprogram_npm/lin-ui/loading/index.js
new file mode 100644
index 000000000..9928c79c5
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loading/index.js
@@ -0,0 +1,87 @@
+import computeOffset from '../behaviors/computeOffset';
+import validator from '../behaviors/validator';
+
+Component({
+ behaviors: [computeOffset, validator],
+ externalClasses: ['l-container-class', 'l-class'],
+ properties: {
+ // 显示与隐藏
+ show: {
+ type: Boolean,
+ value: false
+ },
+ opacity: {
+ type: String,
+ value: '1'
+ },
+ bgColor: String,
+ zIndex:{
+ type:String,
+ value: '776'
+ },
+ // 类型
+ type: {
+ type: String,
+ value: 'rotate',
+ options: ['flash', 'flip', 'change', 'rotate', 'circle']
+ },
+ // 动画颜色
+ color: {
+ type: String,
+ value: ''
+ },
+ // loading 动画大小
+ size: {
+ type: String,
+ value: 'medium',
+ },
+ // 自定义
+ custom: Boolean,
+ // 全屏模式
+ fullScreen: Boolean
+ },
+
+ attached() {
+ this._init();
+ },
+
+ pageLifetimes: {
+ show() {
+ this._init();
+ },
+ },
+
+ methods: {
+ _init() {
+ wx.lin = wx.lin || {};
+ wx.lin.showLoading = (options) => {
+ const {
+ custom = false,
+ fullScreen = false,
+ color = '',
+ type = 'rotate',
+ size = 'medium',
+ opacity = '1'
+ } = { ...options };
+ this.setData({
+ custom,
+ fullScreen,
+ color,
+ type,
+ size,
+ opacity,
+ show: true
+ });
+ };
+ wx.lin.hideLoading = () => {
+ this.setData({
+ show: false
+ });
+ };
+ },
+ // 阻止滑动
+ doNothingMove() {
+ // do nothing……
+ },
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/loading/index.json b/app/miniprogram_npm/lin-ui/loading/index.json
new file mode 100644
index 000000000..4a42478ba
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loading/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/loading/index.less b/app/miniprogram_npm/lin-ui/loading/index.less
new file mode 100644
index 000000000..f825a3be7
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loading/index.less
@@ -0,0 +1,434 @@
+@import "../../config/styles/_base.less";
+@import "../../config/styles/_theme.less";
+
+.container-loading {
+ position: fixed;
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+}
+
+.content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ background: #fff;
+ height: 100%;
+}
+
+.spinner {
+ &-flash {
+ &-medium {
+ width: 60rpx;
+ height: 60rpx;
+ }
+
+ &-mini {
+ width: 40rpx;
+ height: 40rpx;
+ }
+
+ &-large {
+ width: 80rpx;
+ height: 80rpx;
+ }
+ }
+
+ &-flip {
+ &-medium {
+ width: 60rpx;
+ height: 60rpx;
+ }
+
+ &-mini {
+ width: 40rpx;
+ height: 40rpx;
+ }
+
+ &-large {
+ width: 80rpx;
+ height: 80rpx;
+ }
+ }
+
+ &-change {
+ &-medium {
+ width: 30rpx;
+ height: 30rpx;
+ }
+
+ &-mini {
+ width: 20rpx;
+ height: 20rpx;
+ }
+
+ &-large {
+ width: 50rpx;
+ height: 50rpx;
+ }
+ }
+}
+
+/* flash */
+
+.flash-spinner {
+ position: relative;
+}
+
+.flash-bounce1,
+.flash-bounce2 {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background-color: @default-color;
+ opacity: 0.6;
+ position: absolute;
+ top: 0;
+ left: 0;
+ animation: bounce 2s infinite ease-in-out;
+ animation: bounce 2s infinite ease-in-out;
+}
+
+.flash-bounce2 {
+ animation-delay: -1s;
+ animation-delay: -1s;
+}
+
+@keyframes bounce {
+ 0%,
+ 100% {
+ transform: scale(0);
+ }
+
+ 50% {
+ transform: scale(1);
+ }
+}
+
+@keyframes bounce {
+ 0%,
+ 100% {
+ transform: scale(0);
+ transform: scale(0);
+ }
+
+ 50% {
+ transform: scale(1);
+ transform: scale(1);
+ }
+}
+
+/* flip */
+
+.flip-bounce1 {
+ background-color: @default-color;
+ animation: rotateplane 1.2s infinite ease-in-out;
+ animation: rotateplane 1.2s infinite ease-in-out;
+}
+
+@keyframes rotateplane {
+ 0% {
+ transform: perspective(120px);
+ }
+
+ 50% {
+ transform: perspective(120px) rotateY(180deg);
+ }
+
+ 100% {
+ transform: perspective(120px) rotateY(180deg) rotateX(180deg);
+ }
+}
+
+@keyframes rotateplane {
+ 0% {
+ transform: perspective(120px) rotateX(0deg) rotateY(0deg);
+ transform: perspective(120px) rotateX(0deg) rotateY(0deg);
+ }
+
+ 50% {
+ transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
+ transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
+ }
+
+ 100% {
+ transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+ transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+ }
+}
+
+/* change */
+
+.change-spinner {
+ width: 240rpx;
+ text-align: center;
+}
+
+.change-bounce1 {
+ background-color: @default-color;
+ border-radius: 100%;
+ display: inline-block;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation-fill-mode: both;
+ animation-fill-mode: both;
+ animation-delay: -0.32s;
+ animation-delay: -0.32s;
+}
+
+.change-bounce2 {
+ background-color: @default-color;
+ border-radius: 100%;
+ display: inline-block;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation-fill-mode: both;
+ animation-fill-mode: both;
+ animation-delay: -0.16s;
+ animation-delay: -0.16s;
+}
+
+.change-bounce3 {
+ background-color: @default-color;
+ border-radius: 100%;
+ display: inline-block;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+@keyframes bouncedelay {
+ 0%,
+ 80%,
+ 100% {
+ transform: scale(0);
+ }
+
+ 40% {
+ transform: scale(1);
+ }
+}
+
+@keyframes bouncedelay {
+ 0%,
+ 80%,
+ 100% {
+ transform: scale(0);
+ transform: scale(0);
+ }
+
+ 40% {
+ transform: scale(1);
+ transform: scale(1);
+ }
+}
+
+// circle
+.spinner-circle {
+ position: relative;
+}
+
+.spinner-circle-mini {
+ width: 40rpx;
+ height: 40rpx;
+}
+
+.spinner-circle-medium {
+ width: 60rpx;
+ height: 60rpx;
+}
+
+.spinner-circle-large {
+ width: 70rpx;
+ height: 70rpx;
+}
+
+.container1 > .container-view,
+.container2 > .container-view,
+.container3 > .container-view {
+ border-radius: 50%;
+ position: absolute;
+ background-color: @theme-color;
+ animation: bouncedelay4 1.2s infinite ease-in-out;
+ animation: bouncedelay4 1.2s infinite ease-in-out;
+ animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+.circle-mini {
+ width: 12rpx;
+ height: 12rpx;
+}
+
+.circle-medium {
+ width: 15rpx;
+ height: 15rpx;
+}
+
+.circle-large {
+ width: 20rpx;
+ height: 20rpx;
+}
+
+.spinner-circle .spinner-container {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.container2 {
+ transform: rotateZ(45deg);
+ transform: rotateZ(45deg);
+}
+
+.container3 {
+ transform: rotateZ(90deg);
+ transform: rotateZ(90deg);
+}
+
+.circle1 {
+ top: 0;
+ left: 0;
+}
+
+.circle2 {
+ top: 0;
+ right: 0;
+}
+
+.circle3 {
+ right: 0;
+ bottom: 0;
+}
+
+.circle4 {
+ left: 0;
+ bottom: 0;
+}
+
+.container2 .circle1 {
+ animation-delay: -1.1s;
+ animation-delay: -1.1s;
+}
+
+.container3 .circle1 {
+ animation-delay: -1s;
+ animation-delay: -1s;
+}
+
+.container1 .circle2 {
+ animation-delay: -0.9s;
+ animation-delay: -0.9s;
+}
+
+.container2 .circle2 {
+ animation-delay: -0.8s;
+ animation-delay: -0.8s;
+}
+
+.container3 .circle2 {
+ animation-delay: -0.7s;
+ animation-delay: -0.7s;
+}
+
+.container1 .circle3 {
+ animation-delay: -0.6s;
+ animation-delay: -0.6s;
+}
+
+.container2 .circle3 {
+ animation-delay: -0.5s;
+ animation-delay: -0.5s;
+}
+
+.container3 .circle3 {
+ animation-delay: -0.4s;
+ animation-delay: -0.4s;
+}
+
+.container1 .circle4 {
+ animation-delay: -0.3s;
+ animation-delay: -0.3s;
+}
+
+.container2 .circle4 {
+ animation-delay: -0.2s;
+ animation-delay: -0.2s;
+}
+
+.container3 .circle4 {
+ animation-delay: -0.1s;
+ animation-delay: -0.1s;
+}
+
+@keyframes bouncedelay4 {
+ 0%,
+ 80%,
+ 100% {
+ transform: scale(0);
+ }
+
+ 40% {
+ transform: scale(1);
+ }
+}
+
+@keyframes bouncedelay4 {
+ 0%,
+ 80%,
+ 100% {
+ transform: scale(0);
+ transform: scale(0);
+ }
+
+ 40% {
+ transform: scale(1);
+ transform: scale(1);
+ }
+}
+
+// rotate
+.rotate {
+ border-radius: 50%;
+ animation: rotate 0.7s linear infinite;
+}
+
+.rotate-mini {
+ height: 40rpx;
+ width: 40rpx;
+ border-top: 6rpx solid @default-color;
+ border-right: 6rpx solid transparent !important;
+ border-bottom: 6rpx solid @default-color;
+ border-left: 6rpx solid @default-color;
+}
+
+.rotate-medium {
+ height: 50rpx;
+ width: 50rpx;
+ border-top: 6rpx solid @default-color;
+ border-right: 6rpx solid transparent !important;
+ border-bottom: 6rpx solid @default-color;
+ border-left: 6rpx solid @default-color;
+}
+
+.rotate-large {
+ height: 70rpx;
+ width: 70rpx;
+ border-top: 8rpx solid @default-color;
+ border-right: 8rpx solid transparent !important;
+ border-bottom: 8rpx solid @default-color;
+ border-left: 8rpx solid @default-color;
+}
+
+@keyframes rotate {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/loading/index.wxml b/app/miniprogram_npm/lin-ui/loading/index.wxml
new file mode 100644
index 000000000..34cbd49ce
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loading/index.wxml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/loadmore/index.js b/app/miniprogram_npm/lin-ui/loadmore/index.js
new file mode 100644
index 000000000..483563ba9
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loadmore/index.js
@@ -0,0 +1,84 @@
+import validator from '../behaviors/validator';
+
+Component({
+ externalClasses: ['l-class', 'l-loading-class', 'l-end-class', 'l-line-class'],
+ options: {
+ multipleSlots: true // 在组件定义时的选项中启用多slot支持
+ },
+ behaviors: [validator],
+ properties: {
+ show: Boolean,
+ custom: Boolean,
+ line: Boolean,
+ color: String,
+ size: {
+ type: String,
+ value: '28'
+ },
+ type: {
+ type: String,
+ value: 'loading',
+ options: ['loading', 'end']
+ },
+ endText: {
+ type: String,
+ value: '我是有底线的~'
+ },
+ loadingText: {
+ type: String,
+ value: '加载中...'
+ }
+ },
+
+ data: {
+
+ },
+
+ attached() {
+ this._init();
+ },
+
+ pageLifetimes: {
+ show() {
+ this._init();
+ },
+ },
+
+ methods: {
+ _init() {
+ wx.lin = wx.lin || {};
+ wx.lin.showLoadmore = (options) => {
+ const {
+ custom = false,
+ line = false,
+ color = '',
+ size = '28',
+ type = 'loading',
+ endText = '我是有底线的',
+ loadingText = '加载中...'
+ } = { ...options };
+ this.setData({
+ custom,
+ line,
+ color,
+ size,
+ type,
+ endText,
+ loadingText,
+ show: true
+ });
+ };
+ wx.lin.hideLoadmore = () => {
+ this.setData({
+ show: false
+ });
+ };
+ },
+ onLoadmore() {
+ this.triggerEvent('lintap', {}, {
+ bubbles: true,
+ composed: true
+ });
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/loadmore/index.json b/app/miniprogram_npm/lin-ui/loadmore/index.json
new file mode 100644
index 000000000..270874fc5
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loadmore/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-loading":"../loading/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/loadmore/index.less b/app/miniprogram_npm/lin-ui/loadmore/index.less
new file mode 100644
index 000000000..a449f6331
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loadmore/index.less
@@ -0,0 +1,53 @@
+.loadmore-container {
+ display: flex;
+ flex-direction: column;
+ background-color: transparent;
+}
+
+.loading {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+ height: 72rpx;
+ align-items: center;
+ justify-content: center;
+ background-color: transparent;
+}
+
+.loading .loading-view:nth-child(2) {
+ margin-left: 36rpx;
+}
+
+.loading-text {
+ color: #bbb;
+ font-size: 28rpx;
+ margin: 0 12rpx;
+}
+
+.line {
+ width: 80rpx;
+ height: 2rpx;
+ background-color: #d1d3d7;
+}
+
+.rotate {
+ border-radius: 50%;
+ animation: rotate 0.7s linear infinite;
+ height: 28rpx;
+ width: 28rpx;
+ border-top: 4rpx solid #bbb;
+ border-right: 4rpx solid transparent !important;
+ border-bottom: 4rpx solid #bbb;
+ border-left: 4rpx solid #bbb;
+ margin-left: 12rpx;
+}
+
+@keyframes rotate {
+ 0% {
+ transform: rotate(0);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/loadmore/index.wxml b/app/miniprogram_npm/lin-ui/loadmore/index.wxml
new file mode 100644
index 000000000..05137d68e
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/loadmore/index.wxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{loadingText}}
+ {{endText}}
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/mask/index.js b/app/miniprogram_npm/lin-ui/mask/index.js
new file mode 100644
index 000000000..b25eaf9f0
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/mask/index.js
@@ -0,0 +1,84 @@
+import zIndex from '../behaviors/zIndex';
+Component({
+ /**
+ * 组件的属性列表
+ */
+ behaviors: [zIndex],
+ externalClasses: ['l-class','l-mask-class'],
+ properties: {
+ // 显示与隐藏
+ show: {
+ type: Boolean,
+ value: false
+ },
+ // 不透明度
+ opacity: {
+ optionalTypes: [String, Number],
+ value: .4
+ },
+ // mask的z-index值
+ zIndex: {
+ type: Number,
+ value: 99,
+
+ },
+ // slot是否居中
+ center: {
+ type: Boolean,
+ value: false,
+ },
+ // 锁定
+ locked: {
+ type: Boolean,
+ value: true
+ },
+ // 全屏幕模式 暂不可用
+ fullScreen: {
+ type: String,
+ value: ''
+ },
+ // 导航栏颜色
+ NavColor: {
+ type: String,
+ value: ''
+ },
+
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ // 阻止滑动
+ doNothingMove() {
+ // do nothing……
+ },
+
+ // 点击事件
+ onMaskTap() {
+
+ let detail = true;
+ let option = { bubbles: true, composed: true };
+
+ if (this.data.locked !== true) {
+ this.setData({
+ // fullScreen: 'hide',
+ show: false,
+ });
+ }
+ this.triggerEvent('lintap', detail, option);
+ }
+ },
+
+ attached: function () {
+ },
+
+
+});
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/mask/index.json b/app/miniprogram_npm/lin-ui/mask/index.json
new file mode 100644
index 000000000..4a42478ba
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/mask/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/mask/index.less b/app/miniprogram_npm/lin-ui/mask/index.less
new file mode 100644
index 000000000..86002695c
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/mask/index.less
@@ -0,0 +1,30 @@
+.container-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ transition: all 0.3s;
+}
+
+.mask-bg {
+ height: 100%;
+ width: 100%;
+ background: #fff;
+ // position: absolute;
+ z-index: 99;
+}
+
+.mask-content {
+ display: inline-block;
+ // position: absolute;
+ z-index: 101;
+ overflow: hidden;
+}
+
+.center {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/app/miniprogram_npm/lin-ui/mask/index.wxml b/app/miniprogram_npm/lin-ui/mask/index.wxml
new file mode 100644
index 000000000..18383c116
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/mask/index.wxml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/message/index.js b/app/miniprogram_npm/lin-ui/message/index.js
new file mode 100644
index 000000000..2a3bda7d3
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/message/index.js
@@ -0,0 +1,95 @@
+import zIndex from '../behaviors/zIndex';
+import watchShow from '../behaviors/watchShow';
+import validator from '../behaviors/validator';
+
+Component({
+ behaviors: [zIndex, watchShow, validator],
+ externalClasses: ['l-class', 'l-image-class','l-class-image'],
+ properties: {
+ show: Boolean,
+ icon: String,
+ iconColor: {
+ type: String,
+ value: '#fff'
+ },
+ iconSize: {
+ type: String,
+ value: '28'
+ },
+ image: String,
+ content: String,
+ type: {
+ type: String,
+ value: 'primary',
+ options: ['primary', 'warning', 'success', 'error']
+ },
+ duration: {
+ type: Number,
+ value: 1500
+ },
+ openApi: {
+ type: Boolean,
+ value: true
+ },
+ /**
+ * message距离顶部的距离
+ */
+ top: {
+ type: Number,
+ value: 0
+ }
+ },
+
+ data: {
+ status: false
+ },
+
+ // 解决 addListener undefined 的错误
+ observers: {
+ 'icon': function () {
+ }
+ },
+
+ attached() {
+ this.initMessage();
+ },
+
+ pageLifetimes: {
+ show() {
+ this.initMessage();
+ },
+ },
+
+ methods: {
+ initMessage() {
+ wx.lin = wx.lin || {};
+ wx.lin.showMessage = (options = {}) => {
+ const {
+ content = '',
+ icon = '',
+ image = '',
+ type = 'primary',
+ duration = 1500,
+ success = null,
+ top = 0
+ } = options;
+ this.data.success = success;
+ this.setData({
+ content,
+ icon,
+ image,
+ duration,
+ type,
+ top
+ });
+ this.changeStatus();
+ return this;
+ };
+ wx.lin.hideMessage = () => {
+ this.setData({
+ status: false
+ });
+ };
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/message/index.json b/app/miniprogram_npm/lin-ui/message/index.json
new file mode 100644
index 000000000..c01e2d7e6
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/message/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-icon":"../icon/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/message/index.less b/app/miniprogram_npm/lin-ui/message/index.less
new file mode 100644
index 000000000..f1b30ffb1
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/message/index.less
@@ -0,0 +1,47 @@
+@import "../../config/styles/_base.less";
+
+.l-message {
+ width: 750rpx;
+ height: 0;
+ border-radius: 0rpx 0rpx 16rpx 16rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: fixed;
+ left: 50%;
+ font-size: 28rpx;
+ color: #fff;
+ opacity: 0;
+ box-shadow: 0rpx 6rpx 16rpx 0rpx rgb(217 212 191 / 50%);
+ transform: translateX(-50%) translateZ(0) translateY(-100%);
+ transition: all 0.4s ease-in-out;
+
+ &-success {
+ background-color: @success-color;
+ }
+
+ &-error {
+ background-color: @error-color;
+ }
+
+ &-warning {
+ background-color: @warning-color;
+ color: #333;
+ }
+
+ &-primary {
+ background-color: @theme-color;
+ }
+}
+
+.l-message-show {
+ transform: translateX(-50%) translateZ(0) translateY(0);
+ height: 72rpx;
+ opacity: 1;
+}
+
+.l-message-image {
+ width: 30rpx;
+ height: 30rpx;
+ margin-right: 15rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/message/index.wxml b/app/miniprogram_npm/lin-ui/message/index.wxml
new file mode 100644
index 000000000..3337d6a65
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/message/index.wxml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ {{content}}
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/notice-bar/index.js b/app/miniprogram_npm/lin-ui/notice-bar/index.js
new file mode 100644
index 000000000..a26425587
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/notice-bar/index.js
@@ -0,0 +1,161 @@
+import nodeUtil from '../core/utils/node-util';
+Component({
+ externalClasses: ['l-class', 'l-icon-class'],
+
+ properties: {
+ type: {
+ type: String,
+ value: 'still'
+ },
+ // 轮播数组
+ swipArr: Array,
+ // 前置图标
+ frontIconName: {
+ type: String,
+ value: ''
+ },
+ frontIconSize: {
+ type: Number,
+ value: 28
+ },
+ frontIconColor: {
+ type: String,
+ value: '#3683D6'
+ },
+ endIconName: {
+ type: String,
+ value: ''
+ },
+ endIconSize: {
+ type: Number,
+ value: 28
+ },
+ endIconColor: {
+ type: String,
+ value: '#3683D6'
+ },
+ // 背景颜色
+ backgroundcolor: {
+ type: String,
+ value: '#DFEDFF'
+ },
+ // 字体及图标颜色
+ color: {
+ type: String,
+ value: '#3683D6'
+ },
+ // 滚动速度
+ speed: {
+ type: Number,
+ value: 1500
+ },
+ show: {
+ type: Boolean,
+ value: true
+ },
+ close: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ data: {
+ wrapWidth: 0,
+ width: 0,
+ duration: 0,
+ animation: null,
+ timer: null,
+ },
+
+ detached() {
+ this.destroyTimer();
+ },
+
+ ready() {
+ if (this.properties.type === 'roll' && this.properties.show) {
+ this.initAnimation();
+ }
+ },
+
+ methods: {
+ async initAnimation() {
+ const rect = await nodeUtil.getNodeRectFromComponent(this, '.l-noticebar-content');
+ const wrapRect = await nodeUtil.getNodeRectFromComponent(this, '.l-noticebar-content-wrap');
+ const duration = rect.width / 40 * this.data.speed;
+ const animation = wx.createAnimation({
+ duration: duration,
+ timingFunction: 'linear',
+ });
+ this.setData({
+ wrapWidth: wrapRect.width,
+ width: rect.width,
+ duration: duration,
+ animation: animation
+ }, () => {
+ this.startAnimation();
+ });
+ },
+ startAnimation() {
+ //reset
+ if (this.data.animation.option.transition.duration !== 0) {
+ this.data.animation.option.transition.duration = 0;
+ const resetAnimation = this.data.animation.translateX(this.data.wrapWidth).step();
+ this.setData({
+ animationData: resetAnimation.export()
+ });
+ }
+ this.data.animation.option.transition.duration = this.data.duration;
+ const animationData = this.data.animation.translateX(-this.data.width).step();
+ setTimeout(() => {
+ this.setData({
+ animationData: animationData.export()
+ });
+ }, 100);
+ const timer = setTimeout(() => {
+ this.startAnimation();
+ }, this.data.duration);
+ this.setData({
+ timer,
+ });
+ },
+ destroyTimer() {
+ if (this.data.timer) {
+ clearTimeout(this.data.timer);
+ }
+ },
+ handleTap() {
+ this.triggerEvent('lintap', {}, { bubbles: true, composed: true });
+ this.setData({
+ timer: null
+ });
+ },
+ onSwip(e) {
+ this.triggerEvent('lintap', {
+ ...e.currentTarget.dataset
+ }, { bubbles: true, composed: true });
+ },
+ onIconTap() {
+ this.triggerEvent('linicontap', {}, { bubbles: true, composed: true });
+ this.setData({
+ timer: null
+ });
+ },
+ onClose() {
+ this.setData({
+ timer: null,
+ show: false
+ });
+ },
+
+
+ // ============ 开放函数 =============
+
+ /**
+ * 动态设置通告栏内容后刷新动画
+ */
+ linFlush(){
+ this.destroyTimer();
+ this.initAnimation();
+ },
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/notice-bar/index.json b/app/miniprogram_npm/lin-ui/notice-bar/index.json
new file mode 100644
index 000000000..b5e3f5668
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/notice-bar/index.json
@@ -0,0 +1,8 @@
+{
+ "component": true,
+ "usingComponents":
+ {
+ "l-icon": "../icon/index"
+ }
+}
+
diff --git a/app/miniprogram_npm/lin-ui/notice-bar/index.less b/app/miniprogram_npm/lin-ui/notice-bar/index.less
new file mode 100644
index 000000000..931fe6c4e
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/notice-bar/index.less
@@ -0,0 +1,48 @@
+@import "../../config/styles/_base.less";
+
+.l-noticebar {
+ display: flex;
+ height: 72rpx;
+ width: 750rpx;
+ line-height: 72rpx;
+ font-size: 28rpx;
+ color: @theme-color;
+ background-color: #dfedff;
+ overflow: hidden;
+ box-shadow: 0 2px 5px 0 rgb(218 224 233 / 40%);
+ border-radius: 0 0 8px 8px;
+
+ &-icon {
+ display: flex;
+ margin-left: 20rpx;
+ margin-right: 18rpx;
+ align-items: center;
+
+ & + .l-noticebar-content-wrap-view {
+ margin-left: 5rpx;
+ }
+ }
+
+ &-operation {
+ display: flex;
+ margin-right: 16rpx;
+ margin-left: 8rpx;
+ align-items: center;
+ }
+
+ &-content-wrap {
+ display: flex;
+ margin-left: 5rpx;
+ flex: 1;
+ height: 72rpx;
+ position: relative;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ .l-noticebar-content {
+ position: absolute;
+ transition-duration: 20s;
+ }
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/notice-bar/index.wxml b/app/miniprogram_npm/lin-ui/notice-bar/index.wxml
new file mode 100644
index 000000000..107e6d206
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/notice-bar/index.wxml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/panel/index.js b/app/miniprogram_npm/lin-ui/panel/index.js
new file mode 100644
index 000000000..4ae787b94
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/panel/index.js
@@ -0,0 +1,30 @@
+Component({
+ options: {
+ multipleSlots: true,
+ },
+ externalClasses: [
+ 'l-class',
+ 'l-panel-class',
+ 'l-content-class',
+ 'l-title-box-class',
+ 'l-title-class',
+ ],
+ properties: {
+ title: {
+ type: String,
+ value: '',
+ },
+ hideTop: {
+ type: Boolean,
+ value: false,
+ },
+ showCircle: {
+ type: Boolean,
+ value: true,
+ },
+ showTitle: {
+ type: Boolean,
+ value: true,
+ },
+ },
+});
diff --git a/app/miniprogram_npm/lin-ui/panel/index.json b/app/miniprogram_npm/lin-ui/panel/index.json
new file mode 100644
index 000000000..128746de7
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/panel/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-circle": "../circle/index"
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/panel/index.less b/app/miniprogram_npm/lin-ui/panel/index.less
new file mode 100644
index 000000000..8b95a6bf9
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/panel/index.less
@@ -0,0 +1,26 @@
+@import "../../config/styles/_base.less";
+
+.l-panel {
+ background-color: #fff;
+ border-top-left-radius: 30rpx;
+ border-top-right-radius: 30rpx;
+ padding-top: 30rpx;
+ padding-bottom: 30rpx;
+
+ &-titleBox {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding: 0 25px 10px 25rpx;
+
+ &-title {
+ font-size: @size-font-base;
+ line-height: 1;
+ color: @title-color;
+ }
+ }
+}
+
+.top {
+ margin-top: 20rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/panel/index.wxml b/app/miniprogram_npm/lin-ui/panel/index.wxml
new file mode 100644
index 000000000..9172dd595
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/panel/index.wxml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/picker/index.js b/app/miniprogram_npm/lin-ui/picker/index.js
new file mode 100644
index 000000000..9ca182fe1
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/picker/index.js
@@ -0,0 +1,188 @@
+// input/input.js
+import eventBus from '../core/utils/event-bus.js';
+import validator from '../behaviors/validator';
+import rules from '../behaviors/rules';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ options: {
+ multipleSlots: true,
+ },
+ behaviors: ['wx://form-field', validator, rules],
+ externalClasses: [
+ 'l-class',
+ 'l-label-class',
+ 'l-error-text',
+ 'l-error-text-class',
+ 'l-picker-class',
+ 'l-row-class',
+ ],
+ properties: {
+ // 选择器的标题,仅安卓可用
+ headerText: String,
+ // 表单标题(label)的文本
+ label: String,
+ // 是否隐藏label
+ hideLabel: Boolean,
+ // 是否自定义label部分
+ labelCustom: Boolean,
+ // 是否显示下划线
+ showRow: {
+ type: Boolean,
+ value: true,
+ },
+ // 是否必选
+ required: Boolean,
+ // 占位文本
+ placeholder: {
+ type: String,
+ value: '请选择',
+ },
+ arr: {
+ type: Array,
+ },
+ // 输入框类型
+ mode: {
+ type: String,
+ value: 'selector',
+ options: ['selector', 'multiSelector', 'time', 'date', 'region'],
+ },
+ rangeKey: {
+ type: String,
+ value: '',
+ },
+ rangeValue: {
+ type: String,
+ value: 'value',
+ },
+ // 传入的值
+ value: {
+ type: null,
+ optionalTypes: [String, Number],
+ value: '',
+ },
+ // 是否需要冒号
+ colon: Boolean,
+ // 获取焦点
+ focus: Boolean,
+ // 是否显示清除按钮
+ clear: Boolean,
+ showIcon: {
+ type: Boolean,
+ value: true,
+ },
+ // 表单项的宽度,单位rpx
+ width: {
+ type: Number,
+ value: null,
+ },
+ // 表单项标题部分的宽度,单位rpx
+ labelWidth: {
+ type: Number,
+ value: 200,
+ },
+ // label标题的显示位置 left top right
+ labelLayout: {
+ type: String,
+ value: 'left',
+ options: ['left', 'right'],
+ },
+ // 是否禁用
+ disabled: Boolean,
+ // 占位文字的样式
+ placeholderStyle: String,
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {},
+ attached() {
+ this.valToIndex();
+ },
+ pageLifetimes: {
+ show() {
+ this.valToIndex();
+ },
+ },
+ observers: {
+ value: function (value) {
+ if (value) {
+ this.valToIndex();
+ }
+ },
+ },
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ valToIndex() {
+ const { value = '', arr, rangeKey, rangeValue, mode } = this.data;
+
+ if (mode === 'date' || mode === 'time') {
+ return;
+ }
+
+ let currentIndex;
+ if (rangeKey) {
+ // 对象
+ currentIndex =
+ arr && arr.findIndex((ele) => ele[rangeValue] === value);
+ } else {
+ //普通数组
+ currentIndex = arr && arr.findIndex((ele) => ele === value);
+ }
+
+ if (!(currentIndex >= 0)) {
+ currentIndex = '';
+ }
+
+ this.setData({
+ currentIndex,
+ });
+ },
+ handlePickerChange(event) {
+ const { arr, rangeKey, rangeValue, mode } = this.data;
+
+ const { detail = {} } = event;
+ let value;
+ if (!(mode === 'date' || mode === 'time')) {
+ const currentIndex = detail.value;
+ let data = arr[currentIndex];
+ if (rangeKey) {
+ value = data && data[rangeValue];
+ detail.value = value;
+ } else {
+ value = data;
+ detail.value = value;
+ }
+
+ this.setData({
+ currentIndex,
+ });
+ }
+ // this.validatorData({
+ // [this.data.name]: event.detail.value,
+ // });
+ eventBus.emit(`lin-form-change-${this.id}`, this.id);
+ this.triggerEvent('linchange', event.detail);
+ },
+ handlePickerCancel(event) {
+ const { detail = {} } = event;
+ const { value = '' } = detail;
+
+ this.triggerEvent('lincancel', event.detail);
+ },
+ onClearTap(event) {
+ this.setData({
+ value: '',
+ });
+ this.triggerEvent('linclear', event.detail);
+ },
+ getValues() {
+ return this.data.value;
+ },
+ },
+});
diff --git a/app/miniprogram_npm/lin-ui/picker/index.json b/app/miniprogram_npm/lin-ui/picker/index.json
new file mode 100644
index 000000000..fe1a1ffde
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/picker/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-icon": "../icon/index",
+ "l-error-tip":"../error-tip/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/picker/index.less b/app/miniprogram_npm/lin-ui/picker/index.less
new file mode 100644
index 000000000..9797ca6d8
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/picker/index.less
@@ -0,0 +1,97 @@
+@import "../../config/styles/_base.less";
+
+.form-item {
+ position: relative;
+ font-size: 28rpx;
+ color: #333;
+ height: 88rpx;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding-right: 25rpx;
+ box-sizing: border-box;
+}
+
+.row {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ height: 2rpx;
+ width: 730rpx;
+ background: #f3f3f3;
+}
+
+.text-require {
+ color: #e23;
+ vertical-align: middle;
+}
+
+.form-label {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 88rpx;
+ padding-left: 25rpx;
+ padding-right: 15rpx;
+ box-sizing: border-box;
+}
+
+.disabled {
+ color: #9a9a9a !important;
+}
+
+.mask {
+ position: absolute;
+ z-index: 999;
+ height: 100%;
+ width: 100%;
+}
+
+.form-label-right {
+ justify-content: flex-end;
+}
+
+.form-label-left {
+ justify-content: flex-start;
+}
+
+.picker-view {
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 88rpx;
+ flex: 1;
+
+ .picker {
+ width: 100%;
+
+ .pickerText {
+ font-size: 28rpx;
+ flex: 1;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+ }
+}
+
+.close {
+ height: 36rpx;
+ width: 36rpx;
+ background: #ddd;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ margin-right: 20rpx;
+}
+
+.pls-class {
+ color: #9a9a9a;
+}
+
+.hideLabel {
+ padding-left: 25rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/picker/index.wxml b/app/miniprogram_npm/lin-ui/picker/index.wxml
new file mode 100644
index 000000000..ca18b3afc
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/picker/index.wxml
@@ -0,0 +1,41 @@
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/popup/index.js b/app/miniprogram_npm/lin-ui/popup/index.js
new file mode 100644
index 000000000..d6235bbb1
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/popup/index.js
@@ -0,0 +1,145 @@
+import zIndex from '../behaviors/zIndex';
+import validator from '../behaviors/validator';
+import eventUtil from '../core/utils/event-util';
+import doNothing from '../core/behaviors/doNothingBehavior';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ behaviors: [zIndex, validator, doNothing],
+ externalClasses: ['l-bg-class', 'l-panel-class', 'l-class'],
+ properties: {
+ // 显示与隐藏
+ show: {
+ type: Boolean,
+ value: false
+ },
+ // 动画效果的显示和隐藏
+ animation: {
+ type: Boolean,
+ value: true
+ },
+ // 替代 animation
+ transition: {
+ type: Boolean,
+ value: null
+ },
+ // slot的位置
+ contentAlign: {
+ type: String,
+ value: 'center',
+ options: ['top', 'right', 'left', 'bottom', 'center']
+ },
+ // 替代 contentAlign
+ direction: {
+ type: String,
+ value: null,
+ options: ['top', 'right', 'left', 'bottom', 'center']
+ },
+ // 锁定
+ locked: {
+ type: Boolean,
+ value: false
+ }
+ },
+
+ attached() {
+ this._init();
+ },
+
+ pageLifetimes: {
+ show() {
+ this._init();
+ },
+ },
+ /**
+ * 组件的初始数据
+ */
+ data: {
+ status: 'hide'
+ },
+
+ observers: {
+ show(show) {
+ if (show) {
+ this.setData({
+ status: 'show'
+ });
+ }
+ }
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ _init() {
+ wx.lin = wx.lin || {};
+ wx.lin.showPopup = (options) => {
+ console.warn('wx.lin 方法已废弃,请使用开放函数代替 https://doc.mini.talelin.com/start/open-function.html');
+ this.linShow(options);
+ };
+ wx.lin.hidePopup = () => {
+ console.warn('wx.lin 方法已废弃,请使用开放函数代替 https://doc.mini.talelin.com/start/open-function.html');
+ this.linHide();
+ };
+ },
+
+ // 点击事件
+ onPopupTap() {
+ if (this.data.locked !== true) {
+ this._hidePopup();
+ }
+
+ eventUtil.emit(this, 'lintap');
+ },
+
+ _hidePopup(){
+ if(this.data.animation){
+ this.setData({
+ status: 'hide'
+ });
+ // 延迟 300ms 等动画结束再去掉节点
+ setTimeout(() => {
+ this.setData({
+ show: false
+ });
+ }, 300);
+ }else{
+ this.setData({
+ show: false,
+ status: 'hide'
+ });
+ }
+ },
+
+ // ================= 开放函数 ========================
+ /**
+ * 显示 Popup
+ */
+ linShow(options) {
+ const {
+ zIndex = 99,
+ animation = true,
+ contentAlign = 'center',
+ locked = false
+ } = {...options};
+ this.setData({
+ zIndex,
+ animation,
+ contentAlign,
+ locked,
+ show: true
+ });
+ },
+
+ /**
+ * 隐藏 Popup
+ * 会忽略 locked 属性
+ */
+ linHide() {
+ this._hidePopup();
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/popup/index.json b/app/miniprogram_npm/lin-ui/popup/index.json
new file mode 100644
index 000000000..e8cfaaf80
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/popup/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/popup/index.less b/app/miniprogram_npm/lin-ui/popup/index.less
new file mode 100644
index 000000000..b0760832b
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/popup/index.less
@@ -0,0 +1,161 @@
+@positions: center, top, left, right, bottom;
+@animationPostions: {
+ top: translate3d(0, -100%, 0);
+ left: translate3d(-100%, 0, 0);
+ right: translate3d(100%, 0, 0);
+ bottom: translate3d(0, 100%, 0);
+}
+
+// 不同位置的动画使用
+each(@positions,{
+ .popup-fade-@{value}-active-show{
+ animation: ~"popup-@{value}-fadein 0.3s forwards";
+ }
+
+ .popup-fade-@{value}-active-hide{
+ animation: ~"popup-@{value}-fadeout 0.3s forwards";
+ }
+
+});
+
+// 不同位置的动画定义
+each(@animationPostions,{
+ @keyframes ~"popup-@{key}-fadein" {
+ 0% {
+ transform: @value;
+ opacity: 0;
+ }
+
+ 100% {
+ transform: translate3d(0, 0, 0);
+ opacity: 1;
+ }
+ }
+
+ @keyframes ~"popup-@{key}-fadeout" {
+ 0% {
+ transform: translate3d(0, 0, 0);
+ opacity: 1;
+ }
+
+ 100% {
+ transform: @value;
+ opacity: 0.1;
+ }
+ }
+});
+
+@keyframes popup-center-fadein {
+ 0% {
+ transform: scale(0.8);
+ opacity: 0;
+ }
+
+ 50% {
+ transform: scale(1.1);
+ }
+
+ 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+@keyframes popup-center-fadeout {
+ 0% {
+ transform: scale(1);
+ opacity: 1;
+ }
+
+ 50% {
+ transform: scale(1.1);
+ }
+
+ 100% {
+ transform: scale(0.8);
+ opacity: 0;
+ }
+}
+
+@keyframes bg-fadein {
+ 0% {
+ opacity: 0;
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
+
+@keyframes bg-fadeout {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ }
+}
+
+.container-popup {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.container-bg-show {
+ animation: bg-fadein 0.3s forwards;
+}
+
+.container-bg-hide {
+ animation: bg-fadeout 0.3s forwards;
+}
+
+.container-bg {
+ display: block;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 6;
+ background: rgb(0 0 0 / 40%);
+}
+
+.popup-content {
+ position: absolute;
+ z-index: 100;
+ width: 100%;
+ max-width: 100%;
+ height: 100%;
+}
+
+.center {
+ display: flex;
+ height: 100%;
+ width: 100%;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
+
+.left {
+ display: flex;
+ flex-direction: row;
+ height: 100%;
+}
+
+.right {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+ height: 100%;
+}
+
+.bottom {
+ display: flex;
+ flex-direction: column-reverse;
+ width: 100%;
+}
diff --git a/app/miniprogram_npm/lin-ui/popup/index.wxml b/app/miniprogram_npm/lin-ui/popup/index.wxml
new file mode 100644
index 000000000..a28fa38e9
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/popup/index.wxml
@@ -0,0 +1,12 @@
+
diff --git a/app/miniprogram_npm/lin-ui/price/index.js b/app/miniprogram_npm/lin-ui/price/index.js
new file mode 100644
index 000000000..459653112
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/price/index.js
@@ -0,0 +1,108 @@
+import validator from '../behaviors/validator';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ externalClasses: ['l-deleted-class', 'l-unit-class', 'l-value-class', 'l-class', 'l-decimal-class', 'l-dot-class'],
+ behaviors: [validator],
+ properties: {
+ unit: {
+ type: String,
+ value: '¥'
+ },
+ size: {
+ type: String,
+ value: '28'
+ },
+ color: {
+ type: String,
+ value: '#3963BC'
+ },
+ bold: {
+ type: String,
+ value: '500'
+ },
+ unitColor: String,
+ unitSize: String,
+ unitBold: String,
+ value: {
+ type: String,
+ value: '0.00'
+ },
+ mode: {
+ type: String,
+ value: 'number',
+ options: ['number', 'text']
+ },
+ valueColor: String,
+ valueSize: String,
+ valueBold: String,
+ deleted: Boolean,
+ delColor: String,
+ reserveDigit: {
+ type: Number,
+ value: 2
+ },
+ autofix: Boolean
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+ // 价格整数部分
+ priceInteger: {
+ type: String,
+ value: '0'
+ },
+ // 价格小数部分
+ priceDecimal: {
+ type: String,
+ value: '00'
+ }
+ },
+
+ observers: {
+ 'value': function () {
+ this.reserveNumber();
+ }
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ reserveNumber() {
+ this.setData({
+ priceInteger: null,
+ priceDecimal: null
+ });
+ const countToNumber = Number(this.data.value);
+ const isText = isNaN(Number(countToNumber)) || (this.data.mode === 'text');
+ if (!isText && this.data.autofix) {
+ const result = countToNumber.toFixed(this.data.reserveDigit);
+ const price = result.toString().split('.');
+ this._setPrice(price);
+ } else {
+ const price = this.data.value.split('.');
+ this._setPrice(price);
+ }
+ },
+
+ _setPrice(price) {
+ if (price.length === 1) {
+ this.setData({
+ priceInteger: price[0]
+ });
+ }else if(price.length === 2){
+ this.setData({
+ priceInteger: price[0],
+ priceDecimal: price[1]
+ });
+ }else{
+ throw 'price 格式有误,请仔细检查!';
+ }
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/price/index.json b/app/miniprogram_npm/lin-ui/price/index.json
new file mode 100644
index 000000000..e8cfaaf80
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/price/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/price/index.less b/app/miniprogram_npm/lin-ui/price/index.less
new file mode 100644
index 000000000..8edb0c25f
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/price/index.less
@@ -0,0 +1,12 @@
+@import "../../config/styles/_base.less";
+
+.price-del {
+ text-decoration: line-through !important;
+}
+
+.price-container {
+ display: inline-block;
+ text-align: center;
+ color: @theme-color;
+ font-size: 28rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/price/index.wxml b/app/miniprogram_npm/lin-ui/price/index.wxml
new file mode 100644
index 000000000..f548f94fa
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/price/index.wxml
@@ -0,0 +1,7 @@
+
+
+ {{unit}}
+
+ {{priceInteger}}{{priceDecimal?'.':''}}{{priceDecimal?priceDecimal:''}}
+
+
diff --git a/app/miniprogram_npm/lin-ui/progress/index.js b/app/miniprogram_npm/lin-ui/progress/index.js
new file mode 100644
index 000000000..fc8cb6fdc
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/progress/index.js
@@ -0,0 +1,137 @@
+// components/progress/index.js
+import {
+ px2rpx
+} from '../utils/util.js';
+import validator from '../behaviors/validator';
+Component({
+ /**
+ * 组件的属性列表
+ */
+ externalClasses: ['l-class', 'l-text-class', 'l-active-class', 'l-background-class'],
+ behaviors: [validator],
+ properties: {
+ percent: {
+ type: Number,
+ value: 0,
+ },
+ strokeWidth: {
+ type: Number,
+ value: 12
+ },
+ borderRadius: {
+ type: Number,
+ value: 6,
+ },
+ activeColor: {
+ type: String,
+ },
+ backgroundColor: {
+ type: String,
+ value: '#EBEBEB',
+ },
+ showInfo: {
+ type: Boolean,
+ value: false
+ },
+ textPosition: {
+ type: String,
+ value: 'right',
+ options: ['left', 'right']
+ },
+ textColor: {
+ type: String,
+ },
+ interval: {
+ type: Number,
+ value: 20,
+ },
+ active: {
+ type: Boolean,
+ value: false
+ },
+ duration: {
+ type: Number,
+ value: 30
+ }
+ },
+
+ options: {
+ multipleSlots: true,
+ pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+ _slotWidth: 0,
+ _slotHeight: 0,
+ _progressWidth: 0,
+ _progressHeight: 0,
+ _marginBottom: 0,
+ marginLeft: 0,
+ marginTop: 0,
+ _useSlot: false,
+ },
+
+ observers: {
+ '_slotWidth, _slotHeight, _progressWidth, _progressHeight, percent,_useSlot': function (_slotWidth, _slotHeight, _progressWidth, _progressHeight, percent, _useSlot) {
+ if (_useSlot) {
+ const marginTop = -(_slotHeight - _progressHeight) / 2;
+ const marginLeft = (_progressWidth - _slotWidth) * percent / 100;
+ this.setData({
+ marginTop,
+ marginLeft
+ });
+ }
+ }
+ },
+
+ lifetimes: {
+ attached() {
+ if (this.data.percent > 100) {
+ this.setData({
+ percent: 100
+ });
+ }
+
+ const querySlot = wx.createSelectorQuery().in(this);
+ querySlot.select('.slot').boundingClientRect(res => {
+ let _useSlot = this.data._useSlot;
+ if (res.width) {
+ _useSlot = true;
+ }
+ this.setData({
+ _useSlot,
+ _slotWidth: px2rpx(res.width),
+ _slotHeight: px2rpx(res.height)
+ });
+ }).exec();
+ const queryProgress = wx.createSelectorQuery().in(this);
+ queryProgress.select('.progress').boundingClientRect(res => {
+ this.setData({
+ _progressHeight: px2rpx(res.height),
+ _progressWidth: px2rpx(res.width)
+ });
+ }).exec();
+
+ const percent = this.data.percent;
+ let now = 0;
+ if (this.data.active) {
+ setInterval(() => {
+ if (now < percent) {
+ now += 1;
+ this.setData({
+ percent: now
+ });
+ }
+ }, this.data.duration);
+ }
+ },
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {}
+});
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/progress/index.json b/app/miniprogram_npm/lin-ui/progress/index.json
new file mode 100644
index 000000000..e8cfaaf80
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/progress/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/progress/index.less b/app/miniprogram_npm/lin-ui/progress/index.less
new file mode 100644
index 000000000..ff51f7b5c
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/progress/index.less
@@ -0,0 +1,43 @@
+/* components/progress/index.wxss */
+@import "../../config/styles/_base.less";
+
+.container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.progress {
+ position: relative;
+ width: 100%;
+ transition: all 0.25s ease-in-out;
+}
+
+.percent {
+ position: absolute;
+ z-index: 1;
+}
+
+.active {
+ background-color: @progress-active-color;
+}
+
+.text {
+ color: @progress-active-color;
+ font-size: 30rpx;
+}
+
+.background {
+ position: absolute;
+ width: 100%;
+}
+
+.header {
+ position: absolute !important;
+ z-index: 2;
+}
+
+.slot {
+ position: absolute;
+ z-index: 2;
+}
diff --git a/app/miniprogram_npm/lin-ui/progress/index.wxml b/app/miniprogram_npm/lin-ui/progress/index.wxml
new file mode 100644
index 000000000..c0a9dce0b
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/progress/index.wxml
@@ -0,0 +1,16 @@
+
+
+
+ {{percent}}%
+
+
+
+
+
+
+
+
+
+ {{percent}}%
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/radio-group/index.js b/app/miniprogram_npm/lin-ui/radio-group/index.js
new file mode 100644
index 000000000..7a657746f
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio-group/index.js
@@ -0,0 +1,115 @@
+import eventBus from '../core/utils/event-bus';
+import rules from '../behaviors/rules';
+
+
+Component({
+ externalClasses: ['l-class', 'l-error-text', 'l-error-text-class'],
+ behaviors: ['wx://form-field',rules],
+ relations: {
+ '../radio/index': {
+ type: 'child',
+ linked() {
+ // const currentLength = this.add();
+ // if (currentLength === this.properties.length) {
+ this.init();
+ // }
+ },
+ linkChanged() {
+ },
+ unlinked() {
+ this.init();
+ }
+ }
+ },
+ properties: {
+ current: {
+ type: String
+ },
+ noneChecked: {
+ type: Boolean,
+ value: true
+ },
+ placement: {
+ type: String,
+ value: 'column', //column row
+ },
+ },
+ data: {
+ currentLength: 0
+ },
+
+ methods: {
+ // add() {
+ // if (this.properties.length <= 0) {
+ // throw new Error('为提高性能,请主动设置radio-group的length属性');
+ // }
+ // return this.data.currentLength += 1;
+ // },
+ // reduce() {
+ // this.length -= 1;
+ // return this.data.currentLength -= 1;
+ // },
+
+ checkedKeyRepeat(items) {
+ let keys = items.map(item => {
+ return item.data.key;
+ });
+ const repeat = this.isRepeat(keys);
+ if (repeat !== false) {
+ throw new Error(`keys有重复元素, radio的key属性不能重复:${repeat}`);
+ }
+ },
+
+ isRepeat(arr) {
+ let hash = {};
+ for (let i in arr) {
+ if (hash[arr[i]]) //hash 哈希
+ return arr[i];
+ hash[arr[i]] = true;
+ }
+ return false;
+ },
+
+ init() {
+ const items = this.getRelationNodes('../radio/index');
+ this.checkedKeyRepeat(items);
+ this.onChangeHandle(items);
+ },
+
+ onChangeHandle(items) {
+ items.forEach((item) => {
+ let checked = this.properties.current === item.data.key;
+ item.setChecked(checked, item.data.key);
+ });
+ },
+
+ onEmitEventHandle(currentItem, select) {
+ this.properties.current = select?currentItem.key:null;
+ const items = this.getRelationNodes('../radio/index');
+ this.onChangeHandle(items);
+ // currentItem.currentKey = this.properties.current
+ Object.assign(currentItem, {
+ currentKey: this.properties.current
+ });
+ this.validatorData({
+ [this.data.name]: this.data.current
+ });
+ this.triggerEvent('linchange', currentItem, {
+ bubbles: true,
+ composed: true
+ });
+ eventBus.emit(`lin-form-change-${this.id}`,this.id);
+ },
+ getValues() {
+ return this.data.current;
+ },
+ reset() {
+ this.data.current = '';
+ }
+ },
+ observers: {
+ 'current': function() {
+ this.init();
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/radio-group/index.json b/app/miniprogram_npm/lin-ui/radio-group/index.json
new file mode 100644
index 000000000..9b5b1c530
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio-group/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-error-tip": "../error-tip/index",
+ "l-radio":"../radio/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/radio-group/index.less b/app/miniprogram_npm/lin-ui/radio-group/index.less
new file mode 100644
index 000000000..afb0b91f7
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio-group/index.less
@@ -0,0 +1,13 @@
+.radio-group {
+ width: 100%;
+
+ &-row {
+ display: flex;
+ flex-direction: row;
+ }
+
+ &-column {
+ display: flex;
+ flex-direction: column;
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/radio-group/index.wxml b/app/miniprogram_npm/lin-ui/radio-group/index.wxml
new file mode 100644
index 000000000..f22eb96a1
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio-group/index.wxml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/radio/index.js b/app/miniprogram_npm/lin-ui/radio/index.js
new file mode 100644
index 000000000..e11e02479
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio/index.js
@@ -0,0 +1,87 @@
+Component({
+ externalClasses: ['l-class', 'l-disabled-class'],
+ behaviors: ['wx://form-field'],
+ relations: {
+ '../radio-group/index': {
+ type: 'parent'
+ }
+ },
+ properties: {
+ key: String,
+ cell: Object,
+ // radio的大小
+ size: {
+ type: String,
+ value: '38rpx'
+ },
+ disabled: {
+ type: Boolean
+ },
+ custom: Boolean,
+ color: {
+ type: String,
+ value: '#ccc'
+ },
+ // 选中后的颜色
+ selectColor: {
+ type: String,
+ value: '#3963BC'
+ },
+ disabledColor: {
+ type: String,
+ value: '#ccc'
+ },
+ placement: {
+ type: String,
+ value: 'left'
+ },
+ transition: {
+ type: Boolean,
+ value: true
+ }
+ },
+ data: {
+ checked: false
+ },
+ methods: {
+ setChecked(checked) {
+ this.setData({
+ checked,
+ });
+ },
+ // 点击radio
+ onRadioChangeTap() {
+ if (this.properties.disabled) {
+ return;
+ }
+ const parent = this.getRelationNodes('../radio-group/index')[0];
+ const noneChecked = parent.properties.noneChecked;
+ const isCurrent = this.isCurrentSelectedKey(parent);
+ let select = true;
+ if (isCurrent) {
+ select = false;
+ if (!noneChecked) {
+ return;
+ }
+ }
+ const checked = !this.data.checked;
+ this.data.checked = checked;
+
+ // 子组件不能修改父组件属性
+ // parent.properties.current = null
+ const item = {
+ checked,
+ key: this.properties.key,
+ cell: this.properties.cell
+ };
+ if (parent) {
+ parent.onEmitEventHandle(item, select);
+ }
+ },
+
+ isCurrentSelectedKey(parent) {
+ const currentKey = parent.properties.current;
+ return currentKey === this.properties.key;
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/radio/index.json b/app/miniprogram_npm/lin-ui/radio/index.json
new file mode 100644
index 000000000..e8cfaaf80
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/radio/index.less b/app/miniprogram_npm/lin-ui/radio/index.less
new file mode 100644
index 000000000..85a64acaf
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio/index.less
@@ -0,0 +1,46 @@
+.label {
+ display: flex;
+ flex: 1;
+ align-items: center;
+ font-size: 30rpx;
+ color: #333;
+ width: 100%;
+
+ &-left {
+ flex-direction: row;
+ }
+
+ &-right {
+ flex-direction: row-reverse;
+ justify-content: space-between;
+ }
+
+ &-disabled {
+ color: #ccc;
+ }
+}
+
+.radio {
+ margin-right: 20rpx;
+}
+
+.iconfont {
+ font-family: iconfont !important;
+ display: inline-flex;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+@font-face {
+ font-family: iconfont;
+ src: url("data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMMAAsAAAAABwQAAAK9AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqBaIFyATYCJAMMCwgABCAFhG0HOxs9BsgekiQlqiBBkCKqgBDbFA9f+72eu7sf0SUKUEYCjq8CJBWhqlrpakx5POtO5RtaczeTEm4dEZ0nl3vZ/P4QsbZQwBuhkJZZe0ElkSkAzf+5nN4oP2/Mb1kucw086gUYBxToHtgmK5FAPIXhtYt1GOcJtC1qIDsxOz1Aq6DTAvGYpZNAm4sqilRoCvWatUW8V9NMb9Mt4F34/firLbQktYzOPXN3MgNGfhz/9uXVatVlHyGbzw1pExlbgEJcrfWep4izWxTahlppdgJ1RUhzJaqKUGrq6zv94yWijtZ3wRo06aZkroDgZ58ENGRb3WvkdwEvYZyONecufVjvlP/yCN9e6dcv/syKok+S/ILg5fk4v+4VjvzShk88ZPlDX7WRthx5hXV881Hg5krDX9Z84j7MqK4cjZR1JuLFnjJtMX7ePssP3xVQnfFiKPkScCUeVTcdonq0qYhT/P/M8y4Q5ZkuBeY3m1/gqWk5FFo2LcA/s72GnXZzDSQAVPNPvhv+Qobg0R/V/2uDnX/NTgHftl/fyIRqAfkuAJr34wv+r6xnVzEV1JaLLnWltj9bvld3AmI5oEKDYy/j9bPeaUIzJ5MgaViArGkJLdQtqOnYhrqmfWjbZNncMYEpRGlhwxaBMHQNSd8HyIbqaKE+Q83cH9QNQwFtZ2OyZ8dKsPpjjJIEZWBqDrLpUpFyHEQfNboQPZVP4qwiZPsQ5tgEbG1qKRYsqIjwHAu4abqNEApSuFSAZnIZyudLsIxLWZQmTQwh5b7mZqruTU3pUgHoHcOQJALJgFLmQKy0kiLK70/oS593QWhT8pJwC6kh7INgHHZ4qFWTlh6oRVvsRbqXazjTaG0IggJRsJICyExGIXl5JVC5flQWkkY0YUaky/o0s15UX23T+vrC9x2ANrogR4ocRfNNkUP5u9SpAwsAAAAA") format("woff2");
+}
+
+.icon-unselect::before {
+ content: "\e6a1";
+}
+
+.icon-select::before {
+ content: "\e73a";
+}
diff --git a/app/miniprogram_npm/lin-ui/radio/index.wxml b/app/miniprogram_npm/lin-ui/radio/index.wxml
new file mode 100644
index 000000000..0deb03e47
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/radio/index.wxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/rate/index.js b/app/miniprogram_npm/lin-ui/rate/index.js
new file mode 100644
index 000000000..a99af63bd
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/rate/index.js
@@ -0,0 +1,74 @@
+import eventBus from '../core/utils/event-bus';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ externalClasses: ['l-class', 'l-class-icon', 'l-class-image', 'l-icon-class', 'l-image-class'],
+ options: {
+ multipleSlots: true // 在组件定义时的选项中启用多slot支持
+ },
+ properties: {
+ count: {
+ type: Number,
+ value: 5
+ },
+ score: {
+ type: Number,
+ value: 0
+ },
+ size: {
+ type: String,
+ value: '36'
+ },
+ disabled: Boolean,
+ activeColor: {
+ type: String,
+ value: '#FF5252'
+ },
+ inActiveColor: {
+ type: String,
+ value: '#FFE5E5'
+ },
+ name: {
+ type: String,
+ value: 'favor-fill'
+ },
+ activeImage: String,
+ inActiveImage: String,
+ itemGap: {
+ type: Number,
+ value: 10
+ }
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ handleClick(e) {
+ if (this.data.disabled) return;
+ const { index } = e.currentTarget.dataset;
+ this.setData({
+ score: index + 1
+ });
+ this.triggerEvent('linchange', { score: index + 1 });
+ eventBus.emit(`lin-form-change-${this.id}`, this.id);
+ },
+ getValues() {
+ return this.data.score;
+ },
+ reset() {
+ this.setData({
+ score: 0
+ });
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/rate/index.json b/app/miniprogram_npm/lin-ui/rate/index.json
new file mode 100644
index 000000000..dd10af0a0
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/rate/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-icon":"../icon/index"
+ }
+ }
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/rate/index.less b/app/miniprogram_npm/lin-ui/rate/index.less
new file mode 100644
index 000000000..d1cf22b76
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/rate/index.less
@@ -0,0 +1,19 @@
+.l-rate-star,
+.l-rate {
+ display: inline-flex;
+}
+
+.l-rate-star {
+ position: relative;
+}
+
+.icon-checked {
+ position: absolute;
+ overflow: hidden;
+ display: flex;
+}
+
+.image-item {
+ width: 80rpx;
+ height: 80rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/rate/index.wxml b/app/miniprogram_npm/lin-ui/rate/index.wxml
new file mode 100644
index 000000000..abce9c206
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/rate/index.wxml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/search-bar/index.js b/app/miniprogram_npm/lin-ui/search-bar/index.js
new file mode 100644
index 000000000..4ba91dfb7
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/search-bar/index.js
@@ -0,0 +1,155 @@
+import validator from '../behaviors/validator';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ externalClasses: [
+ 'l-class',
+ 'l-container-class',
+ 'l-placeholder-class',
+ 'l-icon-class',
+ 'l-input-class',
+ 'l-cancel-class'
+ ],
+ behaviors: [validator],
+ options: {
+ multipleSlots: true // 在组件定义时的选项中启用多slot支持
+ },
+ properties: {
+ confirmType: {
+ type: String,
+ value: 'search'
+ },
+ placeholder: String,
+ cancelText: {
+ type: String,
+ value: '取消'
+ },
+ frontText: String,
+ custom: Boolean,
+ value: String,
+ type: String,
+ icon: {
+ type: String,
+ value: 'research'
+ },
+ iconColor: {
+ type: String,
+ value: '#bdbdbd'
+ },
+ iconSize: {
+ type: String,
+ value: '28'
+ },
+ bgColor: {
+ type: String,
+ value: '#f3f3f3'
+ },
+ showCancel: {
+ type: Boolean,
+ value: true
+ },
+ shape: {
+ type: String,
+ value: 'primary',
+ options: ['circle', 'primary']
+ },
+ textAlign: {
+ type: String,
+ value: 'left',
+ options: ['left', 'right']
+ },
+ // 获取焦点
+ focus: Boolean,
+ // 是否显示清除按钮
+ clear: {
+ type: Boolean,
+ value: true
+ },
+ // 最大输入长度
+ maxlength: {
+ type: Number,
+ value: 140
+ },
+ // 是否禁用
+ disabled: Boolean,
+ // 占位文字的样式
+ placeholderStyle: String
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ onCancel() {
+ this.triggerEvent('lincancel', {}, {
+ bubbles: true,
+ composed: true
+ });
+ },
+ // input属性列表
+ handleInputChange(event) {
+ const {
+ detail = {}
+ } = event;
+ const {
+ value = ''
+ } = detail;
+
+ this.setData({
+ value
+ });
+
+ this.triggerEvent('linchange', detail);
+ },
+
+ handleInputFocus(event) {
+ this.triggerEvent('linfocus', event.detail);
+ },
+
+ handleInputBlur(event) {
+ this.triggerEvent('linblur', event.detail);
+ },
+
+ handleInputConfirm(event) {
+ const {
+ detail = {}
+ } = event;
+ const {
+ value = ''
+ } = detail;
+
+ this.setData({
+ value
+ });
+
+ this.triggerEvent('linconfirm', detail);
+ },
+
+ onClearTap(event) {
+ this.setData({
+ value: ''
+ });
+ this.triggerEvent('linclear', event.detail, {
+ bubbles: true,
+ composed: true
+ });
+ },
+
+ /**
+ * 监听点击地址事件
+ * @param event
+ */
+ handleTapFrontText(event){
+ this.triggerEvent('linfronttap',event.detail);
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/search-bar/index.json b/app/miniprogram_npm/lin-ui/search-bar/index.json
new file mode 100644
index 000000000..ccccaa955
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/search-bar/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-input": "../input/index",
+ "l-icon": "../icon/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/search-bar/index.less b/app/miniprogram_npm/lin-ui/search-bar/index.less
new file mode 100644
index 000000000..ffbe3bea7
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/search-bar/index.less
@@ -0,0 +1,90 @@
+.search-bar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding: 0 20rpx;
+ box-sizing: border-box;
+ width: 100%;
+}
+
+.search-input {
+ height: 60rpx;
+ background-color: #f3f3f3;
+ display: flex;
+ flex-direction: row;
+ flex: 1;
+ align-items: center;
+ padding-left: 30rpx;
+ box-sizing: border-box;
+}
+
+.search-input-primary {
+ border-radius: 8rpx;
+}
+
+.search-input-circle {
+ border-radius: 30rpx;
+}
+
+.cancel {
+ font-size: 28rpx;
+ color: #666;
+ display: flex;
+ align-items: center;
+ width: 60rpx;
+ justify-content: center;
+ height: 60rpx;
+ margin-left: 15rpx;
+}
+
+.input {
+ height: 40rpx;
+ line-height: 40rpx;
+ flex: 1;
+ margin-left: 15rpx;
+ font-size: 28rpx;
+ color: #666;
+}
+
+.input-center {
+ text-align: center;
+}
+
+.input-left {
+ text-align: left;
+}
+
+.close-wrap {
+ padding: 10rpx;
+}
+
+.close {
+ height: 30rpx;
+ width: 30rpx;
+ background: #ddd;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ padding-top: 3rpx;
+ box-sizing: border-box;
+ margin-right: 15rpx;
+}
+
+.pls-class {
+ color: #bdbdbd;
+ font-size: 28rpx;
+}
+
+.icon-container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ margin-right: 15rpx;
+}
+
+.city {
+ font-size: 28rpx;
+ color: #333;
+ margin-right: 10rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/search-bar/index.wxml b/app/miniprogram_npm/lin-ui/search-bar/index.wxml
new file mode 100644
index 000000000..74b1155c4
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/search-bar/index.wxml
@@ -0,0 +1,38 @@
+
+
+
+ {{frontText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{cancelText}}
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/segment-item/index.js b/app/miniprogram_npm/lin-ui/segment-item/index.js
new file mode 100644
index 000000000..c9b540e3a
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/segment-item/index.js
@@ -0,0 +1,74 @@
+Component({
+ /**
+ * 组件的属性列表
+ */
+ options: {
+ multipleSlots: true // 在组件定义时的选项中启用多slot支持
+ },
+
+ relations: {
+ '../segment/index': {
+ type: 'parent',
+ linked() { },
+ unlinked() { }
+ },
+ },
+
+ properties: {
+ tab: String,
+ key: String,
+ icon: String,
+ iconSize: {
+ type: String,
+ value: '20'
+ },
+ image: Object,
+ picPlacement: {
+ type: String,
+ value: 'top'
+ },
+ dotBadge: Boolean,
+ badgeCount: {
+ type: Number,
+ },
+ badgeMaxCount: {
+ type: Number,
+ value: 99
+ },
+ badgeCountType: {
+ type: String,
+ value: 'overflow'
+ },
+ },
+ observers: {
+ '**': function (filed) {
+ this.updateData(filed);
+ }
+ },
+ /**
+ * 组件的初始数据
+ */
+ data: {},
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ updateData(filed) {
+ let parent = this.getRelationNodes('../segment/index')[0];
+ if (!parent) return;
+ const tabList = parent.data.tabList;
+ if (!(tabList && tabList.length > 0)) return;
+ const index = tabList.findIndex(tab => tab.key === this.data.key);
+ tabList[index] = filed;
+ parent.setData({
+ tabList: tabList
+ }, () => {
+ if (parent.data.scrollable) {
+ parent.queryMultipleNodes();
+ }
+ });
+
+ },
+ }
+});
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/segment-item/index.json b/app/miniprogram_npm/lin-ui/segment-item/index.json
new file mode 100644
index 000000000..62389a94f
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/segment-item/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+ }
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/segment-item/index.less b/app/miniprogram_npm/lin-ui/segment-item/index.less
new file mode 100644
index 000000000..e69de29bb
diff --git a/app/miniprogram_npm/lin-ui/segment-item/index.wxml b/app/miniprogram_npm/lin-ui/segment-item/index.wxml
new file mode 100644
index 000000000..49aeb95a1
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/segment-item/index.wxml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/segment/index.js b/app/miniprogram_npm/lin-ui/segment/index.js
new file mode 100644
index 000000000..014f04816
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/segment/index.js
@@ -0,0 +1,164 @@
+import scrollCenter from '../behaviors/scrollCenter';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ behaviors: [scrollCenter],
+ externalClasses: [
+ 'l-class',
+ 'l-header-class',
+ 'l-class-active',
+ 'l-active-class',
+ 'l-class-inactive',
+ 'l-inactive-class',
+ 'l-class-tabimage',
+ 'l-tab-image-class',
+ 'l-class-header-line',
+ 'l-header-line-class',
+ 'l-class-line',
+ 'l-line-class',
+ 'l-class-icon',
+ 'l-icon-class',
+ 'l-class-badge',
+ 'l-badge-class'
+ ],
+ options: {
+ multipleSlots: true,
+ pureDataPattern: /^_/
+ },
+
+ relations: {
+ '../segment-item/index': {
+ type: 'child',
+ linked(target) {
+ // 每次有子节点被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
+ this.initTabs(target);
+ }
+ },
+ },
+ properties: {
+ activeKey: {
+ type: String,
+ value: '',
+ observer: 'changeCurrent'
+ },
+ placement: {
+ type: String,
+ value: 'top',
+ },
+ scrollable: Boolean,
+ hasLine: {
+ type: Boolean,
+ value: true
+ },
+ animatedForLine: Boolean,
+ activeColor: {
+ type: String,
+ },
+ inactiveColor: {
+ type: String,
+ },
+ equalWidth: {
+ type: Boolean,
+ value: true
+ },
+ even: {
+ type: Boolean,
+ value: true
+ },
+ width: Number,
+ height: Number,
+ itemHeight: Number,
+ itemWidth: Number
+ },
+
+ observers: {
+ 'activeKey': function (newKey) {
+ if (!newKey) return;
+ const index = this.data.tabList.findIndex(tab => tab.key === newKey);
+ this.setData({
+ currentIndex: index
+ }, () => {
+ if (this.data.scrollable) {
+ this.queryMultipleNodes();
+ }
+ });
+ }
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+ // segment-item 绑定的 data-cell 数据
+ _cells:[],
+ tabList: [],
+ currentIndex: 0,
+ _segmentItemInstances: []
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ initTabs(segmentItemInstance) {
+ const val = this.data.activeKey;
+ let items = this.getRelationNodes('../segment-item/index');
+ if (items.length > 0) {
+ if (items.length === this.data.tabList.length && this.data._segmentItemInstances.indexOf(segmentItemInstance) > 0) return;
+ let activeKey = val,
+ currentIndex = this.data.currentIndex;
+ let _cells = [];
+ const tab = items.map((item, index) => {
+ activeKey = !val && index === 0 ? item.data.key : activeKey;
+ currentIndex = item.data.key === activeKey ? index : currentIndex;
+ // 存储 segment-item 绑定的 data-cell 数据
+ _cells[index] = item.dataset.cell;
+ return {
+ ...item.data
+ };
+ });
+ this.setData({
+ _cells,
+ activeKey,
+ tabList: tab,
+ currentIndex,
+ _segmentItemInstances: items
+ }, () => {
+ if (this.data.scrollable) {
+ this.queryMultipleNodes();
+ }
+ });
+ }
+ },
+
+ handleChange(e) {
+ const activeKey = e.currentTarget.dataset.key;
+ const currentIndex = e.currentTarget.dataset.index;
+ this._setChangeData({
+ activeKey,
+ currentIndex
+ });
+ },
+
+ _setChangeData({
+ activeKey,
+ currentIndex
+ }) {
+ this.setData({
+ activeKey,
+ currentIndex
+ }, () => {
+ if (this.data.scrollable) {
+ this.queryMultipleNodes();
+ }
+ });
+ this.triggerEvent('linchange', {
+ activeKey,
+ currentIndex,
+ cell:this.data._cells[currentIndex]
+ });
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/segment/index.json b/app/miniprogram_npm/lin-ui/segment/index.json
new file mode 100644
index 000000000..503bf6fa9
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/segment/index.json
@@ -0,0 +1,8 @@
+{
+ "component": true,
+ "usingComponents": {
+ "l-icon": "../icon/index",
+ "l-badge": "../badge/index",
+ "l-segment-item":"../segment-item/index"
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/segment/index.less b/app/miniprogram_npm/lin-ui/segment/index.less
new file mode 100644
index 000000000..717aa31d5
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/segment/index.less
@@ -0,0 +1,283 @@
+/* components/tabs/index.wxss */
+.l-tabs {
+ overflow: auto;
+ width: 100%;
+ // IOS 下开启惯性滚动
+ -webkit-overflow-scrolling: touch;
+}
+
+.l-tabs-header {
+ display: flex;
+ width: 100%;
+ flex-direction: row;
+ align-items: center;
+
+ .l-tabs-item {
+ font-size: 28rpx;
+ text-align: center;
+ box-sizing: border-box;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .l-icon-active,
+ .l-tabs-active {
+ color: #333;
+ }
+
+ .l-icon-active,
+ .l-icon-inactive {
+ font-size: 28rpx;
+ }
+
+ .l-icon-inactive,
+ .l-tabs-inactive {
+ color: #bbb;
+ }
+
+ .l-tabsitems-row {
+ flex-direction: row;
+
+ .l-icon-inactive,
+ .l-icon-active {
+ margin-right: 10rpx;
+ }
+ }
+
+ .l-tabsitems-row-reverse {
+ flex-direction: row-reverse;
+
+ .l-icon-inactive,
+ .l-icon-active {
+ margin-left: 10rpx;
+ }
+ }
+}
+
+.l-placement-top,
+.l-placement-bottom {
+ height: 80rpx;
+
+ .l-tabs-header {
+ height: 100%;
+
+ .l-tabs-item {
+ min-height: 100%;
+ }
+ }
+}
+
+.l-placement-right {
+ flex-direction: row-reverse;
+}
+
+.l-placement-bottom {
+ flex-direction: column-reverse;
+}
+
+// 滚动标签栏-水平
+.l-tabs-scroll.l-tabs-horizontal {
+ .l-tabs-header {
+ -webkit-overflow-scrolling: touch;
+ white-space: nowrap;
+
+ .l-tabs-item {
+ overflow: visible;
+ }
+ }
+}
+
+.l-tabs-vertical {
+ width: 160rpx;
+
+ .l-tabsscroll {
+ width: 160rpx;
+ box-sizing: border-box;
+ }
+
+ .l-tabs-equal-header {
+ height: 100%;
+ }
+
+ .l-tabs-header {
+ width: 100%;
+ flex-direction: column;
+ -webkit-overflow-scrolling: touch;
+ white-space: nowrap;
+ overflow-x: hidden;
+
+ .l-tabs-item.l-tabs-active {
+ background: #fff;
+ }
+
+ .l-tabs-unequal-width {
+ height: 80rpx;
+ }
+
+ .l-tabs-equal-width {
+ // flex: 1;
+ }
+
+ .l-tabs-item {
+ overflow: visible;
+ background: #f6f8fa;
+ width: 100%;
+ }
+ }
+}
+
+// 下划线
+.l-tabs-item {
+ position: relative;
+}
+
+.l-tab-line {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ background: #000;
+}
+
+.l-tabs-horizontal {
+ .l-tabs-equal-width {
+ flex: 1;
+ }
+
+ .l-tabs-unequal-width {
+ padding: 0 20rpx;
+ }
+
+ .l-tabsscroll {
+ height: 100%;
+ box-sizing: border-box;
+ }
+
+ .l-tab-line {
+ height: 4rpx;
+ width: 0;
+ left: 100%;
+ right: 0;
+ margin: 0 auto;
+ }
+
+ .l-line-aminmated {
+ transition: 0.2s all linear;
+ }
+
+ .l-tabs-active.l-tabs-item ~ .l-tabs-item {
+ .l-tab-line {
+ left: 0;
+ }
+ }
+
+ .l-tabs-active {
+ .l-tab-line {
+ width: 100%;
+ left: 0;
+ }
+
+ .l-line-aminmated {
+ transition-delay: 0.1s;
+ }
+ }
+}
+
+.l-placement-top {
+ .l-tab-line {
+ bottom: 0;
+ transform: translateY(-100%);
+ }
+
+ .l-tabs-header-line {
+ border-bottom: 1px solid #f3f3f3;
+ }
+}
+
+.l-placement-bottom {
+ .l-tab-line {
+ top: 0;
+ }
+
+ .l-tabs-header-line {
+ border-top: 1px solid #f3f3f3;
+ }
+}
+
+.l-tabs-vertical {
+ .l-tab-line {
+ width: 6rpx;
+ height: 0;
+ border-radius: 0 6rpx 6rpx 0;
+ top: 0;
+ margin: auto 0;
+ }
+
+ .l-line-aminmated {
+ transition: 0.2s all linear;
+ }
+
+ .l-tabs-active {
+ .l-tab-line {
+ height: 40rpx;
+ }
+
+ .l-line-aminmated {
+ transition-delay: 0.1s;
+ }
+ }
+
+ .l-tabs-active.l-tabs-item ~ .l-tabs-item {
+ .l-tab-line {
+ height: 0;
+ top: 0;
+ }
+ }
+}
+
+.l-placement-left {
+ .l-tab-line {
+ // left: 0;
+ right: auto;
+ }
+
+ .l-tabs-header-line {
+ border-left: 1px solid #f3f3f3;
+ }
+}
+
+.l-placement-right {
+ .l-tab-line {
+ right: 0;
+ left: auto;
+ }
+
+ .l-tabs-header-line {
+ border-right: 1px solid #f3f3f3;
+ }
+}
+
+.l-tab-image {
+ width: 100rpx;
+ height: 100rpx;
+}
+
+.l-tab-image-placement-top {
+ flex-direction: column;
+}
+
+.l-tab-image-placement-bottom {
+ flex-direction: column-reverse;
+}
+
+.l-tab-image-placement-left {
+ flex-direction: row;
+}
+
+.l-tab-image-placement-right {
+ flex-direction: row-reverse;
+}
+
+.l-tabs-header .badge-view {
+ top: -20rpx;
+}
diff --git a/app/miniprogram_npm/lin-ui/segment/index.wxml b/app/miniprogram_npm/lin-ui/segment/index.wxml
new file mode 100644
index 000000000..55c941dff
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/segment/index.wxml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ {{item.tab}}
+
diff --git a/app/miniprogram_npm/lin-ui/skeleton/index.js b/app/miniprogram_npm/lin-ui/skeleton/index.js
new file mode 100644
index 000000000..61681a9e0
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/skeleton/index.js
@@ -0,0 +1,100 @@
+import validator from '../behaviors/validator';
+
+Component({
+ /**
+ * 组件的属性列表
+ */
+ externalClasses: [
+ 'l-class',
+ 'l-title-class',
+ 'l-avatar-class',
+ 'l-row-class'
+ ],
+ behaviors: [validator],
+ properties: {
+ loading: {
+ type: Boolean,
+ value: true
+ },
+ title: {
+ type: Boolean,
+ value: true
+ },
+ paragraph: {
+ type: Boolean,
+ value: true
+ },
+ active: {
+ type: Boolean,
+ value: true
+ },
+ avatar: Boolean,
+ titleWidth: String,
+ avatarSize: String,
+ avatarShape: {
+ type: String,
+ value: 'circle',
+ options: ['circle', 'square']
+ },
+ rowsWidth: {
+ type: Array,
+ optionalTypes: [Array, String],
+ value: '60%'
+ },
+ rowsHeight: {
+ type: Array,
+ optionalTypes: [Array, String],
+ value: '34rpx'
+ },
+ rows: Number
+ },
+
+ observers: {
+ 'rows,rowsWidth,rowsHeight': function(rows, rowsWidth, rowsHeight) {
+ this._getResult(rows, rowsWidth, 'rowsW', '100%');
+ this._getResult(rows, rowsHeight, 'rowsH', '34rpx');
+ this._toRows(rows);
+ }
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ _arrRepeat(target, n) {
+ const r = [];
+ for (let i = 0; i < n-1; i++) {
+ r.push(target);
+ }
+ return r;
+ },
+ _getResult(rows, rowsPro, key, target) {
+ if (Array.isArray(rowsPro)) {
+ this.data[key] = rowsPro;
+ } else {
+ const r = this._arrRepeat(target, rows);
+ r.push(rowsPro);
+ this.data[key] = r;
+ }
+ },
+ _toRows(rows) {
+ let r = [];
+ for (let i = 0; i < rows; i++) {
+ r.push({
+ width: this.data.rowsW[i],
+ height: this.data.rowsH[i]
+ });
+ }
+ this.setData({
+ r
+ });
+ }
+ }
+});
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/skeleton/index.json b/app/miniprogram_npm/lin-ui/skeleton/index.json
new file mode 100644
index 000000000..e8cfaaf80
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/skeleton/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/skeleton/index.less b/app/miniprogram_npm/lin-ui/skeleton/index.less
new file mode 100644
index 000000000..c2544a357
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/skeleton/index.less
@@ -0,0 +1,59 @@
+.l-skeleton {
+ &-container {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ box-sizing: border-box;
+ }
+
+ &-avatar {
+ height: 72rpx;
+ width: 72rpx;
+ margin-right: 20rpx;
+
+ &-circle {
+ border-radius: 50%;
+ }
+ }
+
+ &-right {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ }
+
+ &-title {
+ width: 100%;
+ height: 34rpx;
+
+ &-container {
+ height: 72rpx;
+ width: 50%;
+ display: flex;
+ align-items: center;
+ }
+ }
+
+ &-rows {
+ margin-top: 20rpx;
+ }
+}
+
+.bg {
+ background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%);
+ background-size: 400% 100%;
+}
+
+.active {
+ animation: loading 1.4s ease infinite;
+}
+
+@keyframes loading {
+ 0% {
+ background-position: 100% 50%;
+ }
+
+ 100% {
+ background-position: 0 50%;
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/skeleton/index.wxml b/app/miniprogram_npm/lin-ui/skeleton/index.wxml
new file mode 100644
index 000000000..8f9dde09d
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/skeleton/index.wxml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/slide-view/index.js b/app/miniprogram_npm/lin-ui/slide-view/index.js
new file mode 100644
index 000000000..1f3834b9c
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/slide-view/index.js
@@ -0,0 +1,187 @@
+// slide-view/slide-view.js
+const _windowWidth = wx.getSystemInfoSync().windowWidth;
+Component({
+ /**
+ * 组件的属性列表
+ */
+ options: {
+ multipleSlots: true,
+ },
+ properties: {
+ // 组件显示区域的宽度
+ width: {
+ type: Number,
+ value: _windowWidth
+ },
+ // 组件显示区域的高度
+ height: {
+ type: Number,
+ value: 100,
+ },
+ // 组件滑动显示区域的宽度
+ slideWidth: {
+ type: Number,
+ value: 0
+ },
+ // 阈值
+ threshold: {
+ type: Number,
+ value: 0
+ },
+ // 禁用
+ disabled: {
+ type: Boolean,
+ value: false
+ },
+ // 自动关闭
+ autoClose: {
+ type: Boolean,
+ value: false
+ },
+ // 主动关闭
+ close: {
+ type: Boolean,
+ value: false,
+ observer: function (newVal) {
+ if (newVal) {
+ this.setData({
+ popup: false,
+ x: 0
+ });
+ this.onCloseTap();
+ }
+ }
+ }
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+ viewWidth: _windowWidth,
+ // movable-view偏移量
+ x: 0,
+ // movable-view是否可以出界
+ out: false,
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ ready() {
+ this.updateRight();
+ },
+ methods: {
+ updateRight() {
+
+ // 获取右侧滑动显示区域的宽度
+ const that = this;
+ const query = wx.createSelectorQuery().in(this);
+ query.select('.right').boundingClientRect(function (res) {
+ that._slideWidth = res.width;
+ let width = res.width <=50 ? res.width : 50;
+ that._threshold = that.properties.threshold ? that.properties.threshold : width;
+ that._viewWidth = that.data.width + res.width * (750 / _windowWidth);
+ that.setData({
+ viewWidth: that._viewWidth
+ });
+ }).exec();
+ },
+ onTouchStart(e) {
+ this._startX = e.changedTouches[0].pageX;
+ },
+ // 当滑动范围超过阈值自动完成剩余滑动
+ onTouchEnd(e) {
+ if (this.properties.disabled) return;
+
+ this._endX = e.changedTouches[0].pageX;
+ this._length = this._endX - this._startX;
+
+ const {
+ _endX,
+ _startX,
+ _threshold
+ } = this;
+
+ if (this._length > _threshold) {
+ this.setData({
+ popup: false,
+ x: 0,
+ });
+ this.onCloseTap();
+
+ }
+ if (_endX > _startX && this.data.out === false) return;
+ if (_startX - _endX >= _threshold) {
+ this.setData({
+ x: -this._slideWidth,
+ popup: true,
+ close: false
+ });
+ this.onOpenTap();
+ } else if (_startX - _endX < _threshold && _startX - _endX > 0 && this.data.popup !== true) {
+ this.setData({
+ x: 0
+ });
+ this.onCloseTap();
+
+ } else if (_endX - _startX >= _threshold) {
+ this.setData({
+ x: 0
+ });
+ this.onCloseTap();
+
+ } else if (_endX - _startX < _threshold && _endX - _startX > 0) {
+ this.setData({
+ x: -this._slideWidth,
+ close: false
+ });
+ this.onOpenTap();
+
+ }
+ },
+ // 根据滑动的范围设定是否允许movable-view出界
+ onChange(e) {
+ if (!this.data.out && e.detail.x < -this._threshold) {
+ this.setData({
+ out: true
+ });
+ } else if (this.data.out && e.detail.x >= -this._threshold) {
+ this.setData({
+ out: false
+ });
+ }
+ },
+
+ // 点击 右边区域
+ onRightTap() {
+ let detail = 'click right';
+ let option = { bubbles: true, composed: true };
+ if (this.properties.autoClose) {
+ this.setData({
+ popup: false,
+ x: 0
+ });
+ this.onCloseTap();
+ }
+
+ this.triggerEvent('lintap', detail, option);
+ },
+
+ // 打开后触发
+ onOpenTap() {
+ let detail = true;
+ let option = { bubbles: true, composed: true };
+
+ this.triggerEvent('slideopen', detail, option);
+ },
+
+ // 关闭后触发
+ onCloseTap() {
+ let detail = false;
+ let option = { bubbles: true, composed: true };
+
+ this.triggerEvent('slideclose', detail, option);
+ }
+ }
+});
diff --git a/app/miniprogram_npm/lin-ui/slide-view/index.json b/app/miniprogram_npm/lin-ui/slide-view/index.json
new file mode 100644
index 000000000..78013bdeb
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/slide-view/index.json
@@ -0,0 +1,5 @@
+{
+ "component": true,
+ "usingComponents": {
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/slide-view/index.less b/app/miniprogram_npm/lin-ui/slide-view/index.less
new file mode 100644
index 000000000..baab8328d
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/slide-view/index.less
@@ -0,0 +1,10 @@
+/* slide-view/slide-view.wxss */
+.movable-content {
+ display: flex;
+ direction: row;
+ overflow: hidden;
+}
+
+.container {
+ overflow: hidden;
+}
diff --git a/app/miniprogram_npm/lin-ui/slide-view/index.wxml b/app/miniprogram_npm/lin-ui/slide-view/index.wxml
new file mode 100644
index 000000000..ec640abfa
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/slide-view/index.wxml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/spin/index.js b/app/miniprogram_npm/lin-ui/spin/index.js
new file mode 100644
index 000000000..8afa7f1f9
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/spin/index.js
@@ -0,0 +1,19 @@
+Component({
+ externalClasses: ['l-class'],
+ properties: {
+ color: String,
+ show: Boolean,
+ type: {
+ type: String,
+ value: 'flash'
+ },
+ // 自定义
+ custom: Boolean,
+ size: {
+ type: String,
+ value: 'default',
+ },
+ },
+ methods: {
+ }
+});
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/spin/index.json b/app/miniprogram_npm/lin-ui/spin/index.json
new file mode 100644
index 000000000..4a42478ba
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/spin/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+
+ }
+}
\ No newline at end of file
diff --git a/app/miniprogram_npm/lin-ui/spin/index.less b/app/miniprogram_npm/lin-ui/spin/index.less
new file mode 100644
index 000000000..3e3c6e934
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/spin/index.less
@@ -0,0 +1,209 @@
+@import "../../config/styles/_base.less";
+
+.spinner {
+ &-flash {
+ &-default {
+ width: 60rpx;
+ height: 60rpx;
+ }
+
+ &-mini {
+ width: 40rpx;
+ height: 40rpx;
+ }
+
+ &-large {
+ width: 80rpx;
+ height: 80rpx;
+ }
+ }
+
+ &-flip {
+ &-default {
+ width: 60rpx;
+ height: 60rpx;
+ }
+
+ &-mini {
+ width: 40rpx;
+ height: 40rpx;
+ }
+
+ &-large {
+ width: 80rpx;
+ height: 80rpx;
+ }
+ }
+
+ &-change {
+ &-default {
+ width: 50rpx;
+ height: 50rpx;
+ }
+
+ &-mini {
+ width: 30rpx;
+ height: 30rpx;
+ }
+
+ &-large {
+ width: 70rpx;
+ height: 70rpx;
+ }
+ }
+}
+
+/* flash */
+
+.flash-spinner {
+ position: relative;
+}
+
+.flash-bounce1,
+.flash-bounce2 {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background-color: @default-color;
+ opacity: 0.6;
+ position: absolute;
+ top: 0;
+ left: 0;
+ animation: bounce 2s infinite ease-in-out;
+ animation: bounce 2s infinite ease-in-out;
+}
+
+.flash-bounce2 {
+ animation-delay: -1s;
+ animation-delay: -1s;
+}
+
+@keyframes bounce {
+ 0%,
+ 100% {
+ transform: scale(0);
+ }
+
+ 50% {
+ transform: scale(1);
+ }
+}
+
+@keyframes bounce {
+ 0%,
+ 100% {
+ transform: scale(0);
+ transform: scale(0);
+ }
+
+ 50% {
+ transform: scale(1);
+ transform: scale(1);
+ }
+}
+
+/* flip */
+
+.flip-bounce1 {
+ background-color: @default-color;
+ animation: rotateplane 1.2s infinite ease-in-out;
+ animation: rotateplane 1.2s infinite ease-in-out;
+}
+
+@keyframes rotateplane {
+ 0% {
+ transform: perspective(120px);
+ }
+
+ 50% {
+ transform: perspective(120px) rotateY(180deg);
+ }
+
+ 100% {
+ transform: perspective(120px) rotateY(180deg) rotateX(180deg);
+ }
+}
+
+@keyframes rotateplane {
+ 0% {
+ transform: perspective(120px) rotateX(0deg) rotateY(0deg);
+ transform: perspective(120px) rotateX(0deg) rotateY(0deg);
+ }
+
+ 50% {
+ transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
+ transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
+ }
+
+ 100% {
+ transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+ transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+ }
+}
+
+/* change */
+
+.change-spinner {
+ width: 240rpx;
+ text-align: center;
+}
+
+.change-bounce1 {
+ background-color: @default-color;
+ border-radius: 100%;
+ display: inline-block;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation-fill-mode: both;
+ animation-fill-mode: both;
+ animation-delay: -0.32s;
+ animation-delay: -0.32s;
+}
+
+.change-bounce2 {
+ background-color: @default-color;
+ border-radius: 100%;
+ display: inline-block;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation-fill-mode: both;
+ animation-fill-mode: both;
+ animation-delay: -0.16s;
+ animation-delay: -0.16s;
+}
+
+.change-bounce3 {
+ background-color: @default-color;
+ border-radius: 100%;
+ display: inline-block;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation: bouncedelay 1.4s infinite ease-in-out;
+ animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+@keyframes bouncedelay {
+ 0%,
+ 80%,
+ 100% {
+ transform: scale(0);
+ }
+
+ 40% {
+ transform: scale(1);
+ }
+}
+
+@keyframes bouncedelay {
+ 0%,
+ 80%,
+ 100% {
+ transform: scale(0);
+ transform: scale(0);
+ }
+
+ 40% {
+ transform: scale(1);
+ transform: scale(1);
+ }
+}
diff --git a/app/miniprogram_npm/lin-ui/spin/index.wxml b/app/miniprogram_npm/lin-ui/spin/index.wxml
new file mode 100644
index 000000000..4db93e807
--- /dev/null
+++ b/app/miniprogram_npm/lin-ui/spin/index.wxml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/miniprogram_npm/lin-ui/status-show/image/address.png b/app/miniprogram_npm/lin-ui/status-show/image/address.png
new file mode 100644
index 0000000000000000000000000000000000000000..add1bcf306ac704b7e9dcfe59fc7a9dcedf06735
GIT binary patch
literal 6578
zcmX|F1yodBv?i4hqy+|K=mu$!?(Ptf96Dt{T3Sk^Lt05ex{;6?x}*k%A%~Lg2ItNH
z|L?tToxATo-`@MXXPX8%c^fx>5@u(`R#f7kZk<52b=HPo6>U}k3i-zt>;zY9Q-|EDwmpYxwZ@hCx*
zot;~pnS-MWH#av?q5ptt92G)gZf*%RP*NzKgM(vw<{uFh{)_(Su&}V89F)Ss!UAfe
zkXs?B>D0_TO8@HmW*)Y*y1ucucd)d)w!Dg%gDyTiJlx&i?;jjJKK?~)Y;SGvUS3|E
zon37I**iKqUR+w;+}e43d|X3p-QC@vUtFSEURYedxw-wbyMJ*vdOcWFpK&Dd2yG`V28*(=u3XMKr`j69k5FU|3)FYzeNad&fdObpYG
z^jG(=mz$WFsHmt&NJ!|c_MT{SX)gyw_`ms@WMpotr>ColJZ&y5Esc+lANm;-73vV|
zZ)ap=WbWxCfI7R*@Ab6w(NZz^@9>{uMp2#*E@v7`vXD|50^U{OCt@H6&MI`ua66}
zob;GzdV5HYhRQWN^MYR{ana8Z{}x0;qmWirkTvjIJj}ZcVN|3Xcv@!u_S;ryvj>fj
zM|Ar?(7cAZF3lLv2$yIUaFhA|3#5pOFl@q|-$nCQ5dT9+SbJytq*Pwk{C1wnnKX3Q
z!uR&c=ISsQE{xs@DSv-iT_Ww=E`%<>kSLnIJT-tB=+rGleTr$bkSChPe4?wC
zx)75j;A4rmsTW~Af}^e0?E@(|2y@i!!+PDWwzBx;O&Xs+F>zU!%rx=ej#zxR4|fFa@HX`T$dh9;Ggz6h8mh$y-odubs;G@+mJn^9&r9zrlf
zw(#zmpO@G>#Rp0s7DAh#k7X}q>1;pLbH{_Y5nKromaEw}!1$*T8zdjjI^LUYH%Kzv
zd6DRSyI2in;vE&t7N$=CX+AqK%KZFd!@!lar)>jx
z`i7G9#Y@V{7(oADh-xJvT}Wh|6BW9|Nk&APlyd)<9L8QtYmKAJZezvjk0pU5JGDF{
zY3;oW3i1ArBPUM;y00L72T?ldtv!`o3GYCE*a9}s4tHsDlB0Ieo;iNEBLm^AIPY|y
ze5)xjMl;*PivA@oXBvUPeo#t&FB;1@Z-RHQszIGE?AKTgM?YRj;Z?rYK?ZK#ldw_K8ndE9P(B1Lbcaig`(|KYFV~
z%sj;ov1J%DjK;7Of-(_I>;aBvJBF#m-C{^U;hvQ8nr{6Y=@35G89ACBT%rbg-jL6Q
zC%-wOfHN)FV632$R;Hv<8qf)Jme#Dt1E8DW>D
zLb&N*G_!3HrbJ8pXSM>arK72xVJ?$awb=P7#t92z{fB0IKZK74H}PmF64Ye9!?qY}G+PA0d~{op=gQP+oy=^u+{^>esw*Lm+F%!e^%N(o~1bAL9H>0-|44nbdsYiz*+Y-LT3
ziE34cLkirjviH`h<>)n=%q&d`-4A3a(lCkm#3$=0tPJ9~tx7qTbu-Ew!j}C;#TLWP
z!EG`vVG0Buv4$^$$>upxf|b$sw(Yv3o3c*eP1UyY@{;>rucU{IeMzFE@sK%^R`<6C+XU5P
ze3C$1HfG^s?%l#;YD)IS7GVnt5MuU>m`!g4pbW75VWFTig#_<5Lrjr&WqQyihOuo7H-5PcsK29hunAEtW&d
z{MwXqmUPW;>=dVC@D7RKFNRlA_Q!@kVk_IS2KJjp9rFvAQm;eP(ivQ%;HNYYMBDZj
z?0ePwp3?B%QirOxMe2-1Wr4ty2{0jUiw`I~pweJEf(Wx-zlO4rfM)M
zCiA_MRQ;ZYCGF>FcH*7T(xo3ecJMK8zu%GO1&lDYVJ=d@f4f-cWl9o<+)JUD{33?>
z4pK&A*YBbJzk9;RXrEusd(6CTgkV0$=YMKx+aLYCmg0D={ky5z5RlzhcC+oC$}fz7
z%i-x49RB&B)ya(`*7C8LNqm0RcO@aN(luDWXjtc$KLV?=Gh~74m#r^jybjBFrJ}r=
zYwejQNo|8$JHJj6T)#2u5eXk74lweP-m;q(El#&lU*4M1+xb9@nfTI1OG}d)B)axQ
zxDl~5vREBdWcdY=P0%Ku*;7_Lr!@*0k6}@Rn3@G0_
zcGGeR=B|Aagn7S^v{8Omz>H@{$}rfOR-Dsm>02oit!&C(^48=iv47)6p}*`FumHk%
zeE~R6AW4^IO%qic{PvN|a&`dhscTm|>p7hw>n4eX6y(*u9+{CB%*nc^;c{v3T>S{J
zFbK}J^Bz1gmz5jFxmrsDJtb%4H*BicdqP}lu#eN14*ek-;3Igk96jun5}(7vyZW8%
z`ODPD<^B#cL;vxtMZLkr%2qUkuX^6!FT-E)LWmru2m1kOO9pV34%wA3un3HuXj~mq=q*dY@QqrtkR|yy9{kj
zhP?g^>?$6+SY|JM3Hd<`mHxoqBH9s#DDKQ1JjLMSmY%pqIjsqEF^UqIpMZ{0K>y*MW?tx>te`6;{k&dP}Bts`z&2
zzErv4SN^~@K`*i5krx_w)KH>NAMCXO=T9!w3RErV21yv6VrLAAe?Je?0V)OJrsluv-&8><;KS0Uj5(7w*_wgA<
z$n050<+tR^XpBdsQ!CZ4oU&W(mx}eB4GUs|As;3ir2pQy9&W(c>^jII@&@6Bcm`Ka
z0X}+SzHbckS)4#bZ&pZE3n8-_QU~E(5}$hbKBqz7V4buJVdH*LJ>D`Yc`u{ADDV5n
z;PXlWUJ09>rG}jzb^6Zu{oV35E8K2N2)PptXlXS|SKHIsRgeC~-O?0**`aX<`0d@;L3pK?zfuzDHFQzP$5Ol0Y((_z*nR_jPsfYCCVH
zrcQ18ZkLOd!rR*hFpb!k{w_z7&D%emOuinzYh`Mz=*-5~wh?=e^LJXxxD_5!0{WQ(1?@Uu8tbatDU
z8anr?VbjVTtc&i}pWBDjpE&NCEIl7<{Xud{2HaLRe3P6V#?o-IpAk&RYY-P01}Kmi
z=;b9G4Ily`qUOvm(zBgkVOz2B5$9+{&x9RVu`#2oJlR|udB;OoW&e|-hUVV2snx;1
z&Q5`?{>QqBlih*BM?<3tO~v9-xgwHAgTkZGNN5X9_V|aMoJSh>S?6}$#{+KDbUqTD5Juz)EwL1>U@6X_49W8g?qFNDp!1*MFESv02iOp_cb3v&K~bD<0{|2-FU$D7g@0FtPe0rHXptxgihD+
z`m$QA{&_>BPn_lRhVJQ)m#=}^{M+YCnQOwkbpX}Qn5?(z8J_^NGj!SVurrRI*}wSf
zfGg?iD~jMj#(T1n%D~vuF=a@h;q!fej7TJ0U-ncEbYW-zG@WnTXeC-
zlY5<^J7b^k%WF~GeCVMS6=shNI(TWTIepvzfcO%JO?%W~K53vel6po0O5Bzw`sQto
z%%QHp3Gkp;iyPBJeHuOXZ4|u^&g!{3XFU=&dMoPpRm`kzuk>7z4@vA
zEumIvwcX)(voYj#*LL))0Igc!k>`&syy{k8yFt#uv>kWFgPE`g33w{G?JvkOq@!E4
zeeCc&-QxAv&ugK#M1z&XH5e6q@RC~{$hPk=cNQ<$cNo^vvBtyXwbAV_#4g*|GM3uf
z{#A$i$ixx!MKRhcdjf!IoI1;$Kn|LD-heH_3YGmd0dRLU>q2!YO=f)DoBPMPx3(%v
zgfi~u`zPXDps9zLz*}59Wc#1>JuC733Lc6Pm84Tk>69%db*|b}ubsrROSQ
zwIpO<^;au^&VXg>ZU5GN8x7A_-gzcra>|OuUn>iAuZ$g~(4ya20Qj3LV+%N*|EeSe
zSHkz%VLJ79XNuw3LNStr4o9K$A)Z=r@Izi2c{aUoL5tlH!kGD-hk2Zs$F{2Pvtf)R
z)O}hU7ePD~yv72Rx~A)QFO~xL3Y~@PC#0I!8qy*t+s|EwP3UU#bl>%Q8v2o5*&GJ+
zFW)BRLV~=jKx|p9Pd|MSWd-NZjHm~h+5CA6@|2xu{gGS}G0Umdx-|z{@a{ao5?+oh
z>t{D-yXsGt1kO31+jO}%bWs={avYd^75%9dX#O!^)A1G(q_T|26wj=LX7pv-KLOz@
zEF5VCdIcf0#C6%u9xfAKvFdyg9oSClT@G%S*1%PL;Ww&&Wqx^+-ZX@$<~qye(t32%YEdwa6E=k>8%eYV
z%Xy4h_eu{~4=!}A3M7z2FvM+!9%zP)SaFd+RueA8iUb{ng?8#X9{aIt{duBox_heM
zxCi0d(ruM)BXwD2)6cfb}yF
z=)cNKkl97Z{K70ua&d8L2B!J%^Dh&|fhoYU|Eu$#{huB(w>16#nX}NDxdq5Pbar+L
z=7r4!7WkhIECn4M-NM59Kf{@Mm=4SWTLcCMhJTbHP?#6Shk5^V!K#B1VAJ?-_&*G*
z0)}CYnVC61KOd%`q@?Wb;kCWJEh;LSkdR<$X$f1vf`S5A4{ND~uP_DJB0oRBfWcr`
z;h80`K4DX%-R_cyn<
zmsi)b^GlD9PZt-LyL$&Ks~e}M=lcgo=jRs>4-ZQ#>vPcMzq|Xh^NV}?hqrfkN5`j^
zmsiIpr#pZ5=NFdQ*w{`^&um<3ghkck;^KC8c64-f7#P`73SLgnE`noMHT6T)bOIuh
zcjxBjB2xC=zh^i&e$B0TVCUd{dU`#(c-`E2=HcbLxqbcJ^IHA;wYdH@uj)0u__e*g
z9lG*5I`cX({t}kBm6|haZ67%eeXVbQP0YQ^tvHKHJ@5=3{brS|YZ9xb?Qdi21Xgm;
z(zTTYnTSg&@_dpK7Z<;~f9)B0ZD>0h85xO6=ydk(C@(L!bB_1&^0Kh7P*+#)=zm>W
zd%C~BADh1ayLXUX@;9q^D==m$F}1$3veG}K!Y8meJv}`*IM~q8uzO%LCb>5;z0=97
zJw72TDJjX%&rhx#E**C6T^*I=l>yJ32oKjt3uwq^aK2aART1>qqhO*f5z-5cyI<-w
zPlv8Hx|An-+lvGBK}yr3MUDoN{H&ySPwQot?Nuq?yPI;;-8i8=DW--XE~b@=0;(cX!MKg1D`i6Eyb7-B!e|aAn@N8)F_m}%g%kFsGR_w>lt3DZC
zK9X5a#4d~N?+`rdL!56zQz@p!qT@!PWEjMDGy_Mm0etpco0#zBp_^oUBxi5J-pvVi
z1#cHuxdV{PaSH-xwu{S9ciao<
z_HJZ`Jx+2Bhf-qxzIx1aeHdjyn~({~tx8ey)?GKIG2SCX37F?;Vv%$i=x-kMa
zGx32b?F?Z$U>VbKgu#(7$FoARztxX4ls(2Hoo)=%%Z3e;Jw+5hybJ`h>p?#A2Q>|O
z6=Gwb(u^b7@w#J~gnJn3E=L8iDzb&S7nRrmcrs!oDqXU(yO3;vX?W>=UU<|DKNk}E
zher`v7V8R%CNN~>Yf2v4k3d3#QXd~X$YWXkaC`)A$k=l)=a88c`1V%C;w(NXP%S&f
z>gx7mzA|qbD>6R#4ce)uqEIf}>)di5op(a;f&nJg1G9r7pPGy(LiDFBK-xQkW^k5N
z7fVvVLaYBga#4Prz$jMLAQq_kv&lO7uM
zt!aT-VAA1d4;d5XcOmE4R9A7jLafp{{_me{MbNjeKf9ct{;E
z;R|dv(N>0Tkr;{4_UGcQf8azcW<;Ebv8tdR=FZQKrM<)&XBPk1!2f+7sd$Ou;@qe<
zSyPNd8{lCXHZqB^;MCi{v15#=ny)&z6Bji|AY9(&b<+cC<-ydc7Zgq}!Aj@J6Up^>
z$5&Kc0C6RVX`Kn6Z|6o>?3j{Jt6-IkjlE*
zU2Wxl*w1O}(mNa7`-SIi_T4-^1vV4qv0?mPlO68FF)Bb;9G)vK&KS%v66^|P^08}G
z)8?*h()R)ZC=s0{=X#$MS_-j(EXmKgi++F2l+-W*ON;f6G~5AmvdC7lD7(nMA_&JG
zZa*t;Q~ur$!a+o9)d}B2uv|Gaar1B`5*hAk06xcHo(1aSdi3mDB)cI4;QEktMxw%`
zL!Wsn<<;fHTn;ynR4Lou+v6X4QBr;|vwBqu8k$(u{Qc9P%cdR3;6cV2k4#Nk9%=~b
z2yPB;aidE2-`@C8Q=eBXLQQM032lLX(-IvdssiSRd?u3@NuD5ba3Zyd%j@P2%3hdD
z5J|<0dPlpU(k*1K@`iepz^EE8obJ9FzA`qioY33OQ@HJGRPEuJy(ei3WpL$NNoyYl
z)XVKjIhwA>7`tC&X{eUAG|m}ek_#DjL`qUvdC~Fy<5a_uj9ue|U<{jeI9_@m^+7|O
zPZg&C_8A((4)5zHuz9>G!|0PYn$dGOJeN&`f;J0vPvq}c6ktuPq)1F&Sb*+qr<;2`nxG^+nsRm}tC~Z<$TfJa73OPjDfO%WH^yL#BGox)3+@
zn602h4(kk*HhW^9(z~0UPke+DNWrXxh1B20@ko7{?6+t)eoT*DW5NXzlp|4rS?
z7)9IitSL|6@Y(n__V94^Ckx{Rw(FaNCb=~-B$KV7h^&OBWarKRKss7VUQ%n6t}t~t
z8e{pBR6gwN@ML@<&skU~{y+fi62Mgbed43{-Q7&3eh
zbo6UTXJJ4m%8y@fG5j-9_@+{6q&=LqQl7;s0NzlLHulC;&@vY8WHPk+%J!#XwM>Px
z`5U@Q=Dn3cvLkX6`_}X9pE~x9((nIp7lU{Z12^X0hfH)$ysBcp-|kmC?Wr^EBzHYj
zJ+f7ehDI$ry|v>(Tsr?!+JZRL0~Ro>(*Grz!kT-m@mpUi;T4y&xs`6cwV|QGO#eBB
z-vUvS$92Q{dG7IC8@f|iVKc(yxK@?ezPK?wfe2hku$CIReRJYa$3s2YY_rk=y@hJ^
zNkKrD3Jdk&Q$-~^NijQrLloQV%DsO%QV4dc-9VKgqW;o#pnk4~J1jlT>;TF$X0
zr@?Ct*pC_fdt^5id?}Ay4LVy3YI0(9TQaYCIE{ri}^ASzSF@An1;xWon
z3Pv#iKYHoz-T1|9(_5C#R_(mB72f;s_dEnhPD)kGg#&m+-{iSzo}5!$gYIdadQ<3v
zK;K={ydOUHrW03jK}d9+)*Nk>UdEPFrFazs;5?EFa}cq&_Yi9A39+<9B{4;(nD)dG
z1r`3dt=|j2zPqgWQxBS<2d6jYyOafn`882$so>!&w%K6g+jt&a-nc$(SzF!8?m4=c
zneklR5~d0ljt-1Bt!0vtRTYWR$AYPV8G~iOG}+Os9<8i?)oq2C=$b8(L8`bRlDBrq
z7ic0*rl=`gY2TtJfjp{5N@3pEk~E_V=mklSLli~CYfyOe)O&lr)X%rrmhd4Zixj1QxZ+ZU6mX$w
z)N#)CIl#n@&BRBau{v!ZrDdGZWZtCtMpXcpO)mfN@*AW6iiZLniRp1{(3FDDkOV!t
zYc
z```FG?hx#EyYa5g4
zhp*9buk$1DI*UMp+!(YR7}$0;G|II@lgbj(vY8H2jI?V;4?RfKF>SNbrEv2BHu7b?
z^V=Q_dE+Gw>Lqo9$!vve{1jF4=-(Q~si)y9UcMY;5V+Tj=9YBSb6R(=|H^a9#t~3e
za}t4rD8qI0gkw})6rgj(BkvMXl?fCu*3@N-7f>^e#+#mg{!&E&b!k0ZKAmZ4T&fmv
zsU=AoViX~I`&J2#2l|fGHPAWAyZ8|3JzeK6uI8eSu3|v4&BeEGh#4XGJ(Eb}hdJw^?)yc~cV)Rh4C?gEXLX-^2t>sC-KX7y
zQu>Ro$!1f3OWg~C5m1FLr!&!%Bf^IHQ`qtzXk`M6yIdt3pYptakU;a9IWIo*5*ey<
z)2@~@kLCeOQ0!8YMX@Y;j3~ee+K!hEF71O~Hn34vM{)wu6uUpl7D`8JmKU8|hTgb;
z!J5vyv2eet(AT6-`yE*d!G6Imb*CKYAo(pl70>*0adtxQjD|t;?46Sx*9I
zsPvV1|1@oDO^?N}tG?{c0Tj^8O~;?X$7_m8nPnufu#K
zu-j$|t(~7#Nw@j3n3QXS1CLeorQzPi_w_!BxWo@w$V7|>IOKwENLkCf&Y^AiHuxP8ajl0
z_Z#YLHUN;##$}dtCAj%57;jnMKQKnp8o%trLUuCtMtpq@sHj+uU;r
z-d%R0c)7n`+xxh#-W-tuqaR<mK|5HuL@w^{
z+@$EW*2D~|4#I6}kJVPhm=9Vz^n6pyp9a+Z&F&eTQE$Y2G&mC_m{+A4|H+;X|EQ=h
z=#%B5>`ySd`C*700bezUPqS3y?=-GkxJ3)HSb8x_sjWgj*(q#qz`o>@gx>Li3
zmQieg&yD8l{dhk6$-lrcit%cU*$D*7KOkF81K~fV=CmjfzY#2pw&FWje*2k>kWkD}
z8%YHi)D|=rJsC`mNBcUa4tOd^RG~&C0%bU$x=E?QBKqH)Pzn(7@!)>bdpqU?5wT(@
zL+YhyE=w7fP!*&O6kpgQ*Zkp$NA$7T-=lZ1MpNSr7G|M@KFOktv2R>$5{Bq(B_~NE
z<2+@CEEe49pweMp*Qme1AxzN$>FY3DNFw?dpfLpJoF48fs=PrMZB(%Nl7(jAo8;WE
z+*uW2i+dzh^$kMrlES1w?c4(c$L0Dsa|BsBw?mXtmp;8h#}(zBRXZtsuCe7@wu?#S
zwW7h_Kbg-ZeU28EUpI6<5mL5^I<0c!74qzf)Ts{sPs2K%ES=8*a|8jU;giQG1T6&W
z1~U3C)%zbIejRhMBE@*CE4>v6&>A_&D6VVHEQ}GT5fkYWAZZ%^H7Dg;<1g^N$tdcW
zx_bb%rx4C(T1CI$VxUE)TpV8mnPrpQ(?%RttDN7ztjP4d_p2Oggj!r``b&fHOWzyJ
z$NEG;eydXxu;U?TK(s8%Pt3<-UHgS??AAxVI6o+_hDHYbM-|E#un;Q3LGD3^Hv=}M+unx47lJis<1_W?+
ziT}y_#{vJPa!O`cqN1M)q|`RBm^h
zW?Bkcvmke!S*gQ?)>>6Xh|ZYfoT+$+ZJg0qZ;*q9Zn~MEorbgeorb5BOM7@P>4r7~
z#j!$nN6ZX|FY|za*89Y?=XwZfjdn`iI
zk*w)pmt~)eM
zzc95TgruFFhryA33~TNJyM3<@xiVH0k*X15rig5mM)^R9HDnOrwjARtZiY@|)MNIR
z{1fmtMy?-6J5Pv7ynm%45`HvGe3_E;c~BI$mi&a%FlOQ1X2h`n_1uN|3CO269Z*Ov
zrDJ%7qK`xKrL{Kr(}25ye_~rHRkm{|Gh9qlmn_T)@uz;1r@J7Y5&y?XPtx5YxeWqV
z^f^!dhV3$V;>L5b+Qv<^{QKTI3ozs!VY{U^-u=sr;96HmcE@TKz*iSVYt8wm$Zm~b
zu`lV-BMP))3~%R~n0-aOX7dIBDNDxzD8!_T>KNZqK9{TP{%DsROzn*jYP30h@{Sg*
zY-2X_>CF5PdPfCO`-@EE06Fgke>-&ffnJcwelqQ*cQef@Z(UF`z;9JOGhWnslLB5g
zK)l;xImSo&euK~jMVu>@6>M+RbpQS9_{2@|+N(V$>Spg~)p#CrS)6}_7zaHlC%jPF
zFYi>wptMU(#)agEMtSY_igBkRi^1>U=3YOpKnWLhQ;dQguR*$#4-x{}G1dc$KkPCR
zdzz%ol*|xLsIm&MO7n;IHp7aADm;y&C@Xz~Jw?~6865pjm+>_EJ@$%0nQXs_v`8cM
zVmuDl+wT&WBZHrN_7gpDZtsY0ZQ)LFP|EO7d(H=ln9cDDTTT6Qy5)tB*5ngkypLBz
zEpSC)A5DoZ!zQtCI8YZfP_2~mjkNQjrIaLcmJosfH`q(m9Xm5~>DA=XTAM-XM_fv{jo>;5&MXASi8+bi3M?df#P4R!8K8q8l{rZlE%l
zD(*JoCs!enW!6t%Ve?h!645=Z-Q
z33_-n>nkiSgo#J$(hq47LsoR?ybStoyQ`w5I^XJ`nI#ilOt4E0umnX1NLtoaM#)he
z+`e^z=F8)EU1-tAq@t$(=$~wGaqBJ7X(IF0!IdUrja^_;Hy~n+!R?t9sc#9Xb!xPI
z$lx$dzu32w&aE#opcPyGX~X{3D}0eH4ZzIAjbE1+|5NwE*>jDNmjlTSw|B>I*$iI}
z-8F%{s;*h|)7JhD`N)HEY-`dV?V99V;rT3tO-G0C;d1R^A~#ttxoAFmlo=-;!*^kt
zwN;GnO>&|JH*gzoqOIIp1>6DO%Vi}FK~5OO7iMj38i~!p_p0S~D|i
zv^CiIbn}J?jVN-;zRTv075dS2^M$i%+mNsk3rKxH3pk`{hu10#*ER3?)EE@VwedjQ
z9tUK#*`LMEX8(#2x)ksj?Z|_w5@w38z*VBWeT=F;zpDnA^uYNIW!lh@+&t$>?QBg6
gL(B^x74`-^{ORP`kWdbX{X_tOB;_S4#SHxZ5B_J|Q~&?~
literal 0
HcmV?d00001
diff --git a/app/miniprogram_npm/lin-ui/status-show/image/data.png b/app/miniprogram_npm/lin-ui/status-show/image/data.png
new file mode 100644
index 0000000000000000000000000000000000000000..6c9baf34e3f85e18069fe7073e87e011c3c18ff7
GIT binary patch
literal 4679
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
literal 0
HcmV?d00001
diff --git a/app/miniprogram_npm/lin-ui/status-show/image/network.png b/app/miniprogram_npm/lin-ui/status-show/image/network.png
new file mode 100644
index 0000000000000000000000000000000000000000..f82ec6d7917d73a88b3bbc27905784682e14335f
GIT binary patch
literal 6493
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
O2Pn&Hy!$3=8TNmVtqr9B
literal 0
HcmV?d00001
diff --git a/app/miniprogram_npm/lin-ui/status-show/image/order.png b/app/miniprogram_npm/lin-ui/status-show/image/order.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e95de8bcbee20667ffdb4f0789c1b060d01e833
GIT binary patch
literal 5756
zcmYjVcQ{;Mw`LGV4I*mvUZN*aqZ6X{-fQ$SCWxOwlqf;;p6H@P?~Lf(V8$q;Gli$5_wI{VOnF4*oAM*bL%73jeEv>1ShOgO!yPqsGU_
zH#0Xsv%Zc=F-DjQ24F4>=idNR`ET*x0COPKHFbJ=dYFbW9N6sq-|c@edmkSDU>woA
z`-@AfsFn4-{e!EkYj1CF3k!?5xVSmQ;@$oIuY;qvs-l})XgC~xdwU0;UqUXTe*gZx
zv$NA$Y8w_7c65Alc6PqHzO}Kry|T7>etx;Vv$wUgJHN1eb9;Mnd9{REb8>RJzPZ5=
z&(AMTPtOhykJmT05y+*T-F@T&N?t}#T3UK^YMJm5bf9yO&@1P4+nW$Q)x>hNi_*YQp~$z?XRb$k0ty}X&L9>
z9C6Esy|*<~0{nfY!|~+ANiZ|o%Tk1EtR*j81Glz9g^8Y=c(uF1Se^ROV*fWgaaMe2
zduWiGy!5NPsW0&$KjJVWq7CvJ*q5EDB!8Ndf%-y;sOOEw6TaE3SXh+BZz>CYv
zre2iBPoSqu>ZWf14$)8LndwWyT=eLeBRSkLS|>(Ll6Su*!S1h->D$}A=AFtuPoueH
zz3hh)?VWQ6o0;uH1?$8FW!umze&}V|@3oca(ceUuG97r*RywP-^pTK`*?p;|ZzI8!
zbWWUefqT5^F<_LCSZTMa25zxK89|S=p0mHLo%dZY9vtrx3%etXy=v8nsv(1vJ2=kk
z_|kVRe;=S-S6pc$B32$6+C}+Npe(uIf51
z)$-yiFQ?}fAlYA@O3Tbt3!u%PBD*D(vZG2(tQx^16dSOUrLvu{wZu=c!y2p*yrev{ojz}Cm
z`x!j*&S<#!V2Q0DyQZ?GEP>asuxvihP;i_%Y2*uAQNglL?P8KH!{nOO?#G@f+*I$G
zoaFu(bK@oF#`wcn&!bY+SpH?H~bK
z+*5IKRPASX>VdDN#44-9f><%0>+mpynA(sUOeWjY*pJ6Z9xGJR4wVKMD?h)WJ`EgD
zQK`_rA$Bzc%+mk*B(731bf7UtOvE>GTuIc~@z%qJ1)4`>Ibw6-`%ot{{s9KEkpy@fS63OyT=~B*b
z)W(25)e&jmYvgxHT4^n=t+3!_M@uDncZX65-A!MSoMKFY?BwlO}G6EcsJ9ws=PmoSSDmP)P++th5$4H%u|&+{ysvBcPbx(%s(O)BV>CAC?%r#@`s?A@
ztIMbpnfX;i*%f>1#pb}Ofa7xg%y&iOhTYTbOEWKsj=n3-K0Ig<`n+xU^KDr)G6^Y^
z_~!*B>crEP#**f*z3u*G3<%lm?|~&FT0Zv*Irtb@ws{-Q=crN~D|C5O!>wxi9zZ-L
zJ