# v2 git bundle
26be228f0aacd38f9fae1e90402d8065f576c920 refs/heads/bundle
26be228f0aacd38f9fae1e90402d8065f576c920 HEAD

PACK     _x +tree d273e728a53ed1e85f5bee2385ed6e8f3dafbd31
parent 33a9adfbefafc3a5598bf77e485809f60b729612
author Lufaneng <Lufaneng@foxmail.com> 1760492681 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1760492681 +0800

1
6u@0x +tree 580b5d95769ebcdec9d405be0a5cefd48e64fb37
parent 555f04380b3c368596c79934d37062d01cfd6a8a
author Lufaneng <Lufaneng@foxmail.com> 1759220931 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1759220931 +0800

1
?1x +tree beb5cc50a3887dda9f57ec732a686e5c7c768acb
parent 1000dd70222aa4ce95012584ec5e31db75ca03d0
author Lufaneng <Lufaneng@foxmail.com> 1759217681 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1759217681 +0800

1
?x +tree 5114eac4795ef94ad5a1ca57ac8114da4b8c6bff
parent d7c95a7d713d8895aa2e22ebb5175d761a07ec31
author Lufaneng <Lufaneng@foxmail.com> 1759067944 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1759067944 +0800

1
n?x +tree 5df646579c2e344ee47e3b865abfe53bc1baee0c
parent 3d4a802ba5278817ad6612865be925ae589e1600
author Lufaneng <Lufaneng@foxmail.com> 1759065418 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1759065418 +0800

1
?+x +tree bc53563fbdfaf0c1d64d89ebc877d90ee68c70ac
parent f43fc7b4cae58c3e47e95f3ff3a807887e6b11fc
author Lufaneng <Lufaneng@foxmail.com> 1758792486 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758792486 +0800

1
@ܔx +tree 2555a376dc70f9ca09ed49272c0f2d79e55bdc70
parent 2cdd13090aec656985c5d1b8fb58cacb36d6e365
author Lufaneng <Lufaneng@foxmail.com> 1758790258 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758790258 +0800

1
Y?x +tree bc4cdbe5fecb891073eec8dffd9d764fc5016b77
parent fd4a737396f76a9342268fce6d12498aa493aaf3
author Lufaneng <Lufaneng@foxmail.com> 1758785551 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758785551 +0800

1
O@Dx +tree cbed09883f57a207d9f849ec4d80a756ff555036
parent c452b83a66374e59ef8b5b207ca94a0f9ded7322
author Lufaneng <Lufaneng@foxmail.com> 1758765124 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758765124 +0800

1
m0?x +tree 7421acedcabd1d1f1f84f5d4dfe6c5d8b305ffda
parent 0abb3ae1178f9be95b739d19a6bbb16c990289fe
author Lufaneng <Lufaneng@foxmail.com> 1758763821 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758763821 +0800

1
VAx +tree 73bea2ba0f0ed02261324654537b5d3251117522
parent d827e4e6c0a72bc7387ccce6b2d774d9a52b5244
author Lufaneng <Lufaneng@foxmail.com> 1758605474 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758605474 +0800

1
 >Ix +tree caaf1f2dc454be353c9f4e0a2201cc9df4d245a5
parent 9cd2a71df93b11bc7837bb3f83a6e77c944c9c64
author Lufaneng <Lufaneng@foxmail.com> 1758001240 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758001240 +0800

1
L?x +tree baddd502fbd60acd224e65ba4e26bcab4c859f46
parent 265bda45d610f101607ac7a90ce7955dd573056c
author Lufaneng <Lufaneng@foxmail.com> 1758000972 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1758000972 +0800

1
?x +tree 91d03ee82042598e09406596762fafb963aaa3eb
parent 384dede6add2dffb5b633909b0a2fcf2bea1675b
author Lufaneng <Lufaneng@foxmail.com> 1757999697 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757999697 +0800

1
+@x +tree 0086df3b51493d9e86c3c4d4f913c5eedf04b730
parent 3565433ce978f59621e42267b7e183148158c879
author Lufaneng <Lufaneng@foxmail.com> 1757927721 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757927721 +0800

1
=Δx +tree 1dd324223d90e6376e33d9106722cbe3da9e25c8
parent 04bbcfcf02eb2c216a65703ae39dac704607180b
author Lufaneng <Lufaneng@foxmail.com> 1757926840 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757926840 +0800

1
7>֔x +tree 6e5058ed4aa064691df000fcaf7d5a87a5ff5d88
parent 27484b9d564b44f2464299304d0811824e865dbe
author Lufaneng <Lufaneng@foxmail.com> 1757926076 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757926076 +0800

1
>x +tree 6e0b3255acb03a2eba1fa99683161866a557a64c
parent d9b50796c16a0d3f5b514710b17b5c06a2cadc74
author Lufaneng <Lufaneng@foxmail.com> 1757923903 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757923903 +0800

1
<>Ԕx +tree f08cdcfdb83d7a563d6d48ec9e62927c0486907b
parent 1f735c5c53f5b3f72aebd938d97f70bd4ee5b7f8
author Lufaneng <Lufaneng@foxmail.com> 1757922908 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757922908 +0800

1
@x +tree db76aa649b6e54331897408e99043bbc9af0be6e
parent 158713e3b8b95887a299d11386babdb8fc5121bd
author Lufaneng <Lufaneng@foxmail.com> 1757921609 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757921609 +0800

1
U ?
x +tree 1940f02d6361a9073f879f19c90317a44e968a4f
parent 198738cff23a356346f53fa95b8bd00cfff594aa
author Lufaneng <Lufaneng@foxmail.com> 1757669278 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757669278 +0800

1
>
x Xtree ecd36c6e2eee7cb40c62caabccf2f72a72f8347e
author Lufaneng <Lufaneng@foxmail.com> 1757667701 +0800
committer Lufaneng <Lufaneng@foxmail.com> 1757667701 +0800

init
~4NJx340031QK,+)J*f6Pvm?XRBզd%e30}y|Qّ4>++KI-K/M+aH CO#(?4$3? 鸫Κ$p3u̒T+OmdqF P(-ήdt-tě-o]fȳ%)/9It3&
M-(J-)L-ڻ)ڃڟ|[9ڂJ!$VܘCTLn9CU:蕕2(MMP(moJ|<]]_.qnܳkY]x
$U/7[	ʾ|$02nb[n~Eq٬8﷞Y`㧘!ń]NU$ђ}Nb-L]{}S"AݑZQPj:Ӓy2Y}C?_BLONIev#oWz/Ͼe>|jLnbf(RN3-Mso;	WJ2RKʀ	%_|wc*,TaAbr60z!?-빻wdg9/.=H$kv޾iWo`8aۯZ[ON^ol#Cs3/kֲjTANizf^1r5R"GmDM9($_1;gf{31VQ_Q L%U-X2zҿoԦR笋}WKhY ԫ%Őlm su7`M+y3Tai^^qrq1CऄϾ5,?Spr1CˀJs6.yqp~PU%9roc>Vh*Z{e'Ԧ̒T=N؇)>	 qᑲx2module.exports = {
  // 继承的规则
  extends: ["@commitlint/config-conventional"],
  // 自定义规则
  rules: {
    // @see https://commitlint.js.org/#/reference-rules

    // 提交类型枚举，git提交type必须是以下类型
    "type-enum": [
      2,
      "always",
      [
        "feat", // 新增功能
        "fix", // 修复缺陷
        "docs", // 文档变更
        "style", // 代码格式（不影响功能，例如空格、分号等格式修正）
        "refactor", // 代码重构（不包括 bug 修复、功能新增）
        "perf", // 性能优化
        "test", // 添加疏漏测试或已有测试改动
        "build", // 构建流程、外部依赖变更（如升级 npm 包、修改 webpack 配置等）
        "ci", // 修改 CI 配置、脚本
        "revert", // 回滚 commit
        "chore", // 对构建过程或辅助工具和库的更改（不影响源文件、测试用例）
      ],
    ],
    "subject-case": [0], // subject大小写不做校验
  },

  prompt: {
    messages: {
      type: "选择你要提交的类型 :",
      scope: "选择一个提交范围（可选）:",
      customScope: "请输入自定义的提交范围 :",
      subject: "填写简短精炼的变更描述 :\n",
      body: '填写更加详细的变更描述（可选）。使用 "|" 换行 :\n',
      breaking: '列举非兼容性重大的变更（可选）。使用 "|" 换行 :\n',
      footerPrefixesSelect: "选择关联issue前缀（可选）:",
      customFooterPrefix: "输入自定义issue前缀 :",
      footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
      generatingByAI: "正在通过 AI 生成你的提交简短描述...",
      generatedSelectByAI: "选择一个 AI 生成的简短描述:",
      confirmCommit: "是否提交或修改commit ?",
    },
    // prettier-ignore
    types: [
      { value: "feat",     name: "特性:     ✨  新增功能", emoji: ":sparkles:" },
      { value: "fix",      name: "修复:     🐛  修复缺陷", emoji: ":bug:" },
      { value: "docs",     name: "文档:     📝  文档变更(更新README文件，或者注释)", emoji: ":memo:" },
      { value: "style",    name: "格式:     🌈  代码格式（空格、格式化、缺失的分号等）", emoji: ":lipstick:" },
      { value: "refactor", name: "重构:     🔄  代码重构（不修复错误也不添加特性的代码更改）", emoji: ":recycle:" },
      { value: "perf",     name: "性能:     🚀  性能优化", emoji: ":zap:" },
      { value: "test",     name: "测试:     🧪  添加疏漏测试或已有测试改动", emoji: ":white_check_mark:"},
      { value: "build",    name: "构建:     📦️  构建流程、外部依赖变更（如升级 npm 包、修改 vite 配置等）", emoji: ":package:"},
      { value: "ci",       name: "集成:     ⚙️  修改 CI 配置、脚本",  emoji: ":ferris_wheel:"},
      { value: "revert",   name: "回退:     ↩️  回滚 commit",emoji: ":rewind:"},
      { value: "chore",    name: "其他:     🛠️  对构建过程或辅助工具和库的更改（不影响源文件、测试用例）", emoji: ":hammer:"},
    ],
    useEmoji: true,
    emojiAlign: "center",
    useAI: false,
    aiNumber: 1,
    themeColorCode: "",
    scopes: [],
    allowCustomScopes: true,
    allowEmptyScopes: true,
    customScopesAlign: "bottom",
    customScopesAlias: "custom",
    emptyScopesAlias: "empty",
    upperCaseSubject: false,
    markBreakingChangeMode: false,
    allowBreakingChanges: ["feat", "fix"],
    breaklineNumber: 100,
    breaklineChar: "|",
    skipQuestions: [],
    issuePrefixes: [
      { value: "closed", name: "closed:   ISSUES has been processed" },
    ],
    customIssuePrefixAlign: "top",
    emptyIssuePrefixAlias: "skip",
    customIssuePrefixAlias: "custom",
    allowCustomIssuePrefix: true,
    allowEmptyIssuePrefix: true,
    confirmColorize: true,
    maxHeaderLength: Infinity,
    maxSubjectLength: Infinity,
    minSubjectLength: 0,
    scopeOverrides: undefined,
    defaultBody: "",
    defaultIssues: "",
    defaultScope: "",
    defaultSubject: "",
  },
};
x# http://editorconfig.org
root = true

# 表示所有文件适用
[*]
charset = utf-8 # 设置文件字符集为 utf-8
end_of_line = lf # 控制换行类型(lf | cr | crlf)
indent_style = space # 缩进风格（tab | space）
indent_size = 2 # 缩进大小
insert_final_newline = true # 始终在文件末尾插入一个新行

# 表示仅 md 文件适用以下规则
[*.md]
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪
Dt	x h# H5应用端口
VITE_APP_PORT = 3000

# H5代理前缀
VITE_APP_PROXY_PREFIX = "/dev-api"

# 接口地址
VITE_APP_BASE_URL = "http://localhost:8080"
y8Jx5 # 接口地址
VITE_APP_BASE_URL = "http://prod-api"
o4xc .idea
.vscode
.hbuilderx
.project
.DS_Store
node_modules
unpackage
package-lock.json
pnpm-lock.yaml#xL 100644 commit-msg +)'I%),G2100644 pre-commit }ҷ`NlE~4hx& npx --no-install commitlint --edit $1
ѹx npm run lint:lint-staged
z	8xb module.exports = {
  "*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}": ["prettier --write"],
};
!ixT unpackage
node_modules
uni_modules
static
.husky
.hbuilderx
.vscode
.idea
*.sh
*.md
6:d~x// Prettier配置文档：https://prettier.io/docs/en/options.html
module.exports = {
  // (x)=>{},单个参数箭头函数是否显示小括号。(always:始终显示;avoid:省略括号。默认:always)
  arrowParens: "always",
  // 开始标签的右尖括号是否跟随在最后一行属性末尾，默认false
  bracketSameLine: false,
  // 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar})
  bracketSpacing: true,
  // 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto)
  embeddedLanguageFormatting: "auto",
  // 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css)
  htmlWhitespaceSensitivity: "ignore",
  // 当文件已经被 Prettier 格式化之后，是否会在文件顶部插入一个特殊的 @format 标记，默认false
  insertPragma: false,
  // 在 JSX 中使用单引号替代双引号，默认false
  jsxSingleQuote: false,
  // 每行最多字符数量，超出换行(默认80)
  printWidth: 80,
  // 超出打印宽度 (always | never | preserve )
  proseWrap: "preserve",
  // 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;)
  quoteProps: "as-needed",
  // 是否只格式化在文件顶部包含特定注释(@prettier| @format)的文件，默认false
  requirePragma: false,
  // 结尾添加分号
  semi: true,
  // 使用单引号 (true:单引号;false:双引号)
  singleQuote: false,
  // 缩进空格数，默认2个空格
  tabWidth: 2,
  // 元素末尾是否加逗号，默认es5: ES5中的 objects, arrays 等会添加逗号，TypeScript 中的 type 后不加逗号
  trailingComma: "es5",
  // 指定缩进方式，空格或tab，默认false，即使用空格
  useTabs: false,
  // vue 文件中是否缩进 <style> 和 <script> 标签，默认 false
  vueIndentScriptAndStyle: false,

  endOfLine: "auto",
  overrides: [
    {
      files: "*.html",
      options: {
        parser: "html",
      },
    },
  ],
};
!Fxf<script setup>
	import {
		onLaunch,
		onShow,
		onHide,
		onError,
		onPageNotFound,
	} from "@dcloudio/uni-app";
	import {
		checkForUpdate
	} from "@/utils";

	onLaunch(() => {
		console.log("App Launch");
		// #ifdef MP-WEIXIN
		checkForUpdate();
		// #endif
		
		// #ifdef H5
		if (navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1) {
			// 动态添加样式处理重复标题问题
			const style = document.createElement('style')
			style.textContent = `
		    uni-page-head {
		  		  display:none !important;
		    }       
  	  `
			document.head.appendChild(style)
		}
		// #endif
	});

	onShow(() => {
		console.log("App Show");
	});

	onHide(() => {
		console.log("App Hide");
	});

	onError((error) => {
		console.error("App Error", error);
	});

	onPageNotFound((res) => {
		console.error("PageNotFound", res);
		uni.redirectTo({
			url: "/pages/404/404",
		});
	});
</script>

<style lang="scss">
	/* 每个页面公共css */
	page {
		height: 100%;
	}

	/* uv-ui基础样式 */
	@import "@/uni_modules/uv-ui-tools/index.scss";
</style>_ZBx*MIT License

Copyright (c) 2024 白開水

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
rVux vue3+uniapp+uv-ui9a]xF 100644 index.js >R%@|+>40000 modules ~+X
0_NxYKsAtxj import AuthAPI from "./modules/auth";
import UserAPI from "./modules/user";

export { AuthAPI, UserAPI };
#KxF 100644 auth.js ̝T}KBg`^ZP100644 user.js  镂$To5sximport http from "@/utils/request";

class AuthAPI {
  // 注册
  static signUp(data) {
    return http.post("/auth/signup", data, {
      custom: {
        loading: true,
      },
    });
  }

  // 登录
  static signIn(data) {
    return http.post("/auth/signin", data, {
      custom: {
        loading: true,
      },
    });
  }

  // 刷新token
  static refreshToken(header = {}) {
    return http.post("/auth/refresh", undefined, {
      header,
    });
  }
}

export default AuthAPI;
8xqximport http from "@/utils/request";

class UserAPI {
  // test get api
  static getUserList(params = {}) {
    return http.get("/user/list", {
      params,
      custom: {
        auth: true,
        loading: true,
      },
    });
  }
}

export default UserAPI;
CNx31 Ĕ"\i3ײtYTUCvM<JWXgQ=a	_ J|҃SsRK|?cQ]\uYKT}*Oc0H\ҚEDܪ-OLqIe`~Xxor𠣢qOGx, 100644 HeaderCustom.vue 7_Fw>)GTx   <template>
	<uv-sticky>
		<view class="head">
			<div class="title">
				<div class="backIcon" v-if="showBack" @click="goBack">
					<uv-icon class="backIcon" name="arrow-left" color="#fff" size="20"></uv-icon>
				</div>
				{{title}}
			</div>
		</view>
	</uv-sticky>
</template>
<script setup>
	const props = defineProps({
		title: [String],
		showBack: {
			type: Boolean,
			default: false
		}
	});
	
	const goBack = () => {
		uni.navigateBack()
	}
</script>

<style lang="scss" scoped>
	.head {
		// background-color: rgba(3, 0, 255, 0.6);
		// background: center / 100% 100% url('/static/imgs/head_bg.png') no-repeat;
		background-image: url('data:image/png;base64,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   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[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');
		background-repeat: no-repeat;
		background-size: 100% 100%;
		background-position: center;
		height: 90px;
		position: sticky;

		.title {
			position: absolute;
			bottom: 10px;
			font-size: 16px;
			left: 0;
			text-align: center;
			width: 100%;
			color: #fff;
		}

		.backIcon {
			position: absolute;
			top: 50%;
			transform: translate(50%,-50%);
		}
	}
</style>64?x 100644 IconFont.vue 0K&5,*100644 iconfont.css l"<g:F\~100644 iconfont.json RUprz{hg>qđ100644 iconfont.ttf ؇$6n:?~I100644 iconfont.woff F\iH8KX100644 iconfont.woff2 M!6j~ !qq7mI`r x<template>
  <text
    :class="`iconfont icon-${name}`"
    :style="{
      color: color,
      'font-size': size + 'px',
    }"
    @click="handleClick"
  />
</template>

<script setup>
const emit = defineEmits(["click"]);
const props = defineProps({
  name: {
    type: String,
    required: true,
  },
  color: {
    type: String,
    default: "#333333",
  },
  size: {
    type: [Number, String],
    default: 16,
  },
});

function handleClick() {
  emit("click");
}
</script>

<style>
@import "./iconfont.css";
</style>
²x-@font-face {
  font-family: "iconfont"; /* Project id 4657887 */
  src:
    url("iconfont.woff2?t=1724050101808") format("woff2"),
    url("iconfont.woff?t=1724050101808") format("woff"),
    url("iconfont.ttf?t=1724050101808") format("truetype");
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-uniapp:before {
  content: "\e624";
}
lx2{
  "id": "4657887",
  "name": "vue3-uniapp-template",
  "font_family": "iconfont",
  "css_prefix_text": "icon-",
  "description": "",
  "glyphs": [
    {
      "icon_id": "19317486",
      "name": "uniapp",
      "font_class": "uniapp",
      "unicode": "e624",
      "unicode_decimal": 58916
    }
  ]
}
ЏRfxd       0GSUB %z  8   TOS/2<9H     `cmapL    pglyfO6  l   `head(zg      6hhea      $hmtx       loca 0    d   maxp '      name<    gpostji  4   0    \                        V_<      5    5                          
 
             
 0 > DFLT latn                      liga                              2                         PfEd $$                                 ,     T      N     ,  
  T  "       $  $                                                                                                                                                                                                                                                                                          $  $        0         !!3!2?2 &7>3TU:!':  Q                                      "        *        2        =      
 + E        p  	   &   	     	     	     	     	     	     	 
 V  	  &cCreated by iconfonticonfontRegulariconfonticonfontVersion 1.0iconfontGenerated by svg2ttf from Fontello project.http://fontello.com C r e a t e d   b y   i c o n f o n t i c o n f o n t R e g u l a r i c o n f o n t i c o n f o n t V e r s i o n   1 . 0 i c o n f o n t G e n e r a t e d   b y   s v g 2 t t f   f r o m   F o n t e l l o   p r o j e c t . h t t p : / / f o n t e l l o . c o m         
                        uniapp  lCڋAxwOFF          d                       GSUB     ;   T %zOS/2  D   D   `<9Hcmap     K  pLglyf     `   `O6head  4   /   6(zghhea  d       $hmtx          loca         0  maxp          'name    @  g<post        0jixc`d``b0`c`rq	aI,cb`a <21'3=ʱi f &;H xc`aaftB3f0b 223`i)<San|H20(b kxc```e```b fa``a`d ?(#X, V?Y$#(2P8  	        !!3!2?2 &7>3TU:!':  Qxc`d`` |efa G/f",@.H W xc`d``n?;P0 rv          0  xc`d```bb0 Q6  x=n@(J4iV)(HPGZ/H9MhsHyCEo޾ .%+pO~pp/xncŬwaU_>[ש
70񮅛hys5۩UhȤxbO<6_TuQTc|9ȚDyب̚]t.ۑAh`1cCa
!RDEtg6YiuOȩr.t\#y:M-_Qut+n˚4ZIb<ܭ,}P̐ؓoWxc`b .쀉4/3  jL)xcwOF2          d  R                       T` p
`s6$  g0Փ+d_p'@@nFӺ%.^Oo9D$}&f_xFFѼH&M<\!_Mi> rq]5'd9<+ h:,poS@-Df`hbgGqz|9rpNEi܋FW+5Ory"^0,N̾=w]qV]Yg `:@A#SX-J	WsЌC8A 4*/~\M
ƕ>t~yy߾tk+q(OR}2S_YQ]A tϯ=c6"kۢnp`A CaR ~#-$/{LQB7^:᧖"*X'܁!=X< yi~M$TP0ji8{CN/S?,\_ 1gؕـ")UhT*sۦɴeT5GBAZLﻡ}'A )X =5ǮyTxtBm\.*	.9,wa 2%Kx* 100644 LangSelect.vue ːYc%?r'vEQx]<template>
  <view>
    <picker
      range-key="label"
      :range="langOptions"
      :value="langIndex"
      @change="handleLangChange"
    >
      <slot>
        <image
          :style="langStyle"
          src="data:image/png;base64,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"
        ></image>
      </slot>
    </picker>
  </view>
</template>

<script setup>
import { computed } from "vue";
import { useI18n } from "vue-i18n";

const emit = defineEmits(["change"]);
const props = defineProps({
  size: {
    type: Number,
    default: 40,
    required: false,
  },
});

const { locale, t } = useI18n();
const langStyle = {
  width: props.size + "rpx",
  height: props.size + "rpx",
};
const langOptions = computed(() => {
  return [
    { label: t("locale.en"), value: "en" },
    { label: t("locale.zh-hans"), value: "zh-Hans" },
    { label: t("locale.zh-hant"), value: "zh-Hant" },
    { label: t("locale.ja"), value: "ja" },
  ];
});
const langIndex = computed(() => {
  return langOptions.value.findIndex((item) => {
    return item.value === locale.value;
  });
});
function handleLangChange(event) {
  const lang = langOptions.value[event.detail.value].value;
  locale.value = lang;
  uni.setLocale(lang);
  emit("change", lang);
}
</script>

<style lang="scss" scoped></style>
*	mx% 100644 Login.vue ɯfpc*cO	V>xi<template>
  <view class="login-overlay">
    <view class="login-container">
      <!-- 关闭按钮 -->
      <view class="close-btn" @click="closeLogin">
        <uv-icon name="close" color="#FFFFFF" size="24"></uv-icon>
      </view>

      <!-- 登录类型切换 -->
      <view class="login-type">
        <view
          class="type-item"
          :class="{ active: loginType === 'personal' }"
          @click="loginType = 'personal'"
        >
          个人
        </view>
        <view
          class="type-item"
          :class="{ active: loginType === 'enterprise' }"
          @click="loginType = 'enterprise'"
        >
          企业
        </view>
      </view>

      <!-- 登录表单 -->
      <view class="login-form">
        <!-- 用户名输入 -->
        <view class="input-item">
          <view class="icon">
            <uv-icon name="account" color="#AAAAAA" size="20"></uv-icon>
          </view>
          <input
            class="input"
            type="text"
            v-model="username"
            placeholder="请输入8位数字或英文字母"
            maxlength="20"
          />
        </view>

        <!-- 密码输入 -->
        <view class="input-item">
          <view class="icon">
            <uv-icon name="eye" color="#AAAAAA" size="20"></uv-icon>
          </view>
<!--          <input
            class="input"
            :type="showPassword ? 'text' : 'password'"
            v-model="password"
            placeholder="请输入六密码"
            maxlength="20"
          /> -->
		  <uv-input class="input" placeholder="请输入密码" :type="showPassword ? 'text' : 'password'" border="none" v-model="password"></uv-input>
          <view class="eye-icon" @click="togglePasswordVisibility">
            <uv-icon
              :name="showPassword ? 'eye-fill' : 'eye-off'"
              color="#AAAAAA"
              size="20"
            ></uv-icon>
          </view>
        </view>

        <!-- 登录按钮 -->
        <view class="login-btn" @click="handleLogin">登录</view>

        <!-- 用户协议 -->
        <view class="agreement">
          <checkbox
            :checked="agreePolicy"
            @click="agreePolicy = !agreePolicy"
            color="#4080FF"
            style="transform: scale(0.7)"
          />
          <text class="agreement-text">
            阅读
            <text class="link" @click.stop="openUserPolicy">用户政策</text>
            和
            <text class="link" @click.stop="openPrivacyPolicy">隐私政策</text>
          </text>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref } from "vue";
import { useAuthStore } from "@/store";

// 登录类型：个人/企业
const loginType = ref("personal");
// 用户名和密码
const username = ref("");
const password = ref("");
// 是否显示密码
const showPassword = ref(false);
// 是否同意用户协议
const agreePolicy = ref(false);

// 切换密码可见性
const togglePasswordVisibility = () => {
  showPassword.value = !showPassword.value;
};

// 处理登录
const handleLogin = () => {
  // 表单验证
  if (!username.value) {
    return uni.showToast({
      title: "请输入用户名",
      icon: "none",
    });
  }

  if (!password.value) {
    return uni.showToast({
      title: "请输入密码",
      icon: "none",
    });
  }

  if (!agreePolicy.value) {
    return uni.showToast({
      title: "请阅读并同意用户政策和隐私政策",
      icon: "none",
    });
  }

  // 登录逻辑
  const authStore = useAuthStore();

  // 显示加载中
  uni.showLoading({
    title: "登录中...",
  });

  // 模拟登录请求
  setTimeout(() => {
    uni.hideLoading();

    // 这里应该调用实际的登录API
    // 示例：模拟登录成功
    authStore.signIn({
      token: "sample_token_123456",
      userInfo: {
        id: "1",
        username: username.value,
        type: loginType.value,
      },
    });

    // 登录成功提示
    uni.showToast({
      title: "登录成功",
      icon: "success",
    });

    // 关闭登录弹窗
    emit("close");
  }, 1500);
};

// 打开用户政策
const openUserPolicy = () => {
  uni.navigateTo({
    url: "/pages/policy/user-policy",
  });
};

// 打开隐私政策
const openPrivacyPolicy = () => {
  uni.navigateTo({
    url: "/pages/policy/privacy-policy",
  });
};

// 关闭登录弹窗
const emit = defineEmits(["close"]);
const closeLogin = () => {
  emit("close");
};
</script>

<style lang="scss" scoped>
.login-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 999;
}

.login-container {
  width: 85vw;
  background-color: #f0f4ff;
  border-radius: 20rpx;
  position: relative;
  padding: 40rpx 0;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}

.close-btn {
  position: absolute;
  top: 0;
  right: 0;
  width: 80rpx;
  height: 80rpx;
  background-color: #a0b4ff;
  border-radius: 0 20rpx 0 20rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

.login-type {
  display: flex;
  justify-content: center;
  margin-bottom: 40rpx;

  .type-item {
    font-size: 32rpx;
    padding: 10rpx 40rpx;
    margin: 0 20rpx;
    color: #999999;
    position: relative;

    &.active {
      color: #333333;
      font-weight: bold;

      &::after {
        content: "";
        position: absolute;
        bottom: -10rpx;
        left: 40rpx;
        right: 40rpx;
        height: 6rpx;
        background-color: #4080ff;
        border-radius: 3rpx;
      }
    }
  }
}

.login-form {
  padding: 0 40rpx;

  .input-item {
    background-color: #ffffff;
    border-radius: 50rpx;
    height: 90rpx;
    display: flex;
    align-items: center;
    padding: 0 30rpx;
    margin-bottom: 30rpx;

    .icon {
      margin-right: 20rpx;
    }

    .input {
      flex: 1;
      height: 90rpx;
      font-size: 28rpx;
    }

    .eye-icon {
      padding: 0 10rpx;
    }
  }

  .login-btn {
    background-color: #4080ff;
    color: #ffffff;
    height: 90rpx;
    border-radius: 50rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 32rpx;
    font-weight: bold;
    margin: 40rpx 0;
  }

  .agreement {
    display: flex;
    align-items: center;
    justify-content: center;

    .agreement-text {
      font-size: 24rpx;
      color: #666666;

      .link {
        color: #4080ff;
      }
    }
  }
}
</style>
R;#xQ 100644 UploadFile.vue 2A=A100644 example.vue zNVW^/3AĒPS"Lxh$<template>
  <view class="upload-file">
    <view class="upload-area" @click="chooseFile">
      <view v-if="!uploading" class="upload-placeholder">
        <text class="upload-icon">{{ getUploadIcon() }}</text>
        <text class="upload-text">{{ getUploadText() }}</text>
      </view>

      <view v-if="uploading" class="uploading">
        <text class="upload-icon">⏳</text>
        <text class="upload-text">上传中...</text>
        <progress :percent="uploadProgress" show-info />
      </view>

<!--      <view v-if="fileInfo && !uploading" class="file-info">
        <text class="file-name">{{ fileInfo.name }}</text>
        <text class="file-size">{{ formatFileSize(fileInfo.size) }}</text>
      </view> -->
    </view>

<!--    <view v-if="error" class="error-message">
      <text>{{ error }}</text>
    </view> -->
  </view>
</template>

<script setup>
import { ref } from "vue";
import {
	useAuthStore
} from "@/store/modules/auth";

// 定义 props
const props = defineProps({
  // 允许的文件类型
  accept: {
    type: String,
    default: "*",
  },
  // 最大文件大小 (MB)
  maxSize: {
    type: Number,
    default: 10,
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false,
  },
});

// 定义 emits
const emit = defineEmits(["onSuccess", "onError", "onProgress"]);

// 响应式数据
const uploading = ref(false);
const uploadProgress = ref(0);
const fileInfo = ref(null);
const error = ref(null);

// 选择文件
const chooseFile = () => {
  if (props.disabled || uploading.value) return;

  error.value = null;

  // 根据 accept 属性判断文件类型并选择对应的方法
  const fileType = getFileTypeFromAccept();

  if (fileType === "image") {
    chooseImageFile();
  } else if (fileType === "video") {
    chooseVideoFile();
  } else {
    chooseMessageFile();
  }
};

// 根据 accept 属性判断文件类型
const getFileTypeFromAccept = () => {
  if (props.accept === "*") return "file";

  const accept = props.accept.toLowerCase();

  // 检查是否为图片类型
  const imageTypes = [
    ".jpg",
    ".jpeg",
    ".png",
    ".gif",
    ".bmp",
    ".webp",
    "image/",
  ];
  if (imageTypes.some((type) => accept.includes(type))) {
    return "image";
  }

  // 检查是否为视频类型
  const videoTypes = [
    ".mp4",
    ".avi",
    ".mov",
    ".wmv",
    ".flv",
    ".webm",
    "video/",
  ];
  if (videoTypes.some((type) => accept.includes(type))) {
    return "video";
  }

  // 其他文件类型
  return "file";
};

// 选择图片
const chooseImageFile = () => {
  uni.chooseImage({
    count: 1,
    sourceType: ["album", "camera"],
    success: (res) => {
      console.log("选择图片成功:", res);
      if (res.tempFilePaths && res.tempFilePaths.length > 0) {
        // 获取文件信息
        uni.getFileInfo({
          filePath: res.tempFilePaths[0],
          success: (fileInfo) => {
            const file = {
              name: "image_" + Date.now() + ".jpg",
              size: fileInfo.size,
              path: res.tempFilePaths[0],
            };
            validateAndUpload(file);
          },
          fail: () => {
            // 如果获取文件信息失败，使用默认值
            const file = {
              name: "image_" + Date.now() + ".jpg",
              size: 0,
              path: res.tempFilePaths[0],
            };
            validateAndUpload(file);
          },
        });
      } else {
        error.value = "未选择到图片";
      }
    },
    fail: (err) => {
      console.error("选择图片失败:", err);
      error.value = "选择图片失败: " + (err.errMsg || "请重试");
      emit("onError", err);
    },
  });
};

// 选择视频
const chooseVideoFile = () => {
  uni.chooseVideo({
    sourceType: ["album", "camera"],
    maxDuration: 60,
    camera: "back",
    success: (res) => {
      console.log("选择视频成功:", res);
      const file = {
        name: "video_" + Date.now() + ".mp4",
        size: res.size || 0,
        path: res.tempFilePath,
      };
      validateAndUpload(file);
    },
    fail: (err) => {
      console.error("选择视频失败:", err);
      error.value = "选择视频失败: " + (err.errMsg || "请重试");
      emit("onError", err);
    },
  });
};

// 选择文件
const chooseMessageFile = () => {
  uni.chooseMessageFile({
    count: 1,
    type: "all",
    success: (res) => {
      console.log("选择文件成功:", res);
      if (res.tempFiles && res.tempFiles.length > 0) {
        const file = res.tempFiles[0];
        validateAndUpload(file);
      } else {
        error.value = "未选择到文件";
      }
    },
    fail: (err) => {
      console.error("选择文件失败:", err);
      error.value = "选择文件失败: " + (err.errMsg || "请重试");
      emit("onError", err);
    },
  });
};

// 验证文件类型
const validateFileType = (fileName) => {
  if (props.accept === "*") return true;

  const acceptTypes = props.accept.split(",").map((type) => type.trim());
  const fileExt = "." + fileName.split(".").pop().toLowerCase();

  return acceptTypes.some((type) => {
    if (type.startsWith(".")) {
      return type.toLowerCase() === fileExt;
    }
    return fileName.toLowerCase().includes(type.toLowerCase());
  });
};

// 验证并上传文件
const validateAndUpload = (file) => {
  error.value = null;

  // 验证文件大小
  if (file.size > props.maxSize * 1024 * 1024) {
    error.value = `文件大小不能超过 ${props.maxSize}MB`;
    return;
  }

  // 验证文件类型
  if (props.accept !== "*" && !validateFileType(file.name)) {
    error.value = "文件类型不支持";
    return;
  }

  fileInfo.value = {
    name: file.name,
    size: file.size,
    path: file.path,
  };

  uploadFile(file);
};

// 处理上传错误
const handleUploadError = (message) => {
  uploading.value = false;
  uploadProgress.value = 0;
  error.value = message;
  emit("onError", message);
};

// 上传文件
const uploadFile = (file) => {
  uploading.value = true;
  uploadProgress.value = 0;

  console.log("开始上传文件:", file);

  const uploadTask = uni.uploadFile({
    url: "https://lift-dev.ruixininfo.com/filestransfer/upload",
    filePath: file.path,
    name: "file",
	header:{
		session:useAuthStore().accessToken
	},
    // formData: {
    //   fileName: file.name,
    // },
    success: (res) => {
      console.log("上传成功:", res);
      try {
        const data = JSON.parse(res.data);
        uploading.value = false;
        uploadProgress.value = 100;

        // 将接口返回信息传递给父组件的 onSuccess 方法
        emit("onSuccess", {
          response: data,
          fileInfo: fileInfo.value,
        });
      } catch (err) {
        console.error("解析响应失败:", err);
        handleUploadError("响应数据解析失败");
      }
    },
    fail: (err) => {
      console.error("上传失败:", err);
      handleUploadError(err.errMsg || "上传失败");
    },
  });

  // 监听上传进度
  uploadTask.onProgressUpdate((res) => {
    console.log("上传进度:", res.progress);
    uploadProgress.value = res.progress;
    emit("onProgress", res.progress);
  });
};

// 格式化文件大小
const formatFileSize = (bytes) => {
  if (bytes === 0) return "0 B";

  const k = 1024;
  const sizes = ["B", "KB", "MB", "GB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
};

// 获取上传图标
const getUploadIcon = () => {
  const fileType = getFileTypeFromAccept();
  switch (fileType) {
    case "image":
      return "🖼️";
    case "video":
      return "🎬";
    default:
      return "📁";
  }
};

// 获取上传文字
const getUploadText = () => {
  const fileType = getFileTypeFromAccept();
  switch (fileType) {
    case "image":
      return "点击选择图片";
    case "video":
      return "点击选择视频";
    default:
      return "点击选择文件";
  }
};

// 重置组件状态
const reset = () => {
  uploading.value = false;
  uploadProgress.value = 0;
  fileInfo.value = null;
  error.value = null;
};

// 暴露方法给父组件使用
defineExpose({
  reset,
});
</script>

<style scoped>
.upload-file {
  width: 100%;
}

.upload-area {
  border: 2px dashed #dcdfe6;
  border-radius: 8px;
  padding: 0 20px;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.3s;
  background-color: #fafafa;
}

.upload-area:hover {
  border-color: #409eff;
}

.upload-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.upload-icon {
  font-size: 24px;
}

.upload-text {
  color: #606266;
  font-size: 14px;
}

.uploading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.file-info {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

.file-name {
  font-size: 16px;
  font-weight: bold;
  color: #303133;
}

.file-size {
  font-size: 12px;
  color: #909399;
}

.error-message {
  margin-top: 10px;
  padding: 8px 12px;
  background-color: #fef0f0;
  border: 1px solid #fbc4c4;
  border-radius: 4px;
  color: #f56c6c;
  font-size: 12px;
  text-align: center;
}

progress {
  width: 100%;
  height: 100%;
  margin-top: 10px;
}
</style>pxD<template>
  <view class="upload-example">
    <text class="title">文件上传示例</text>

    <!-- 图片上传 -->
    <view class="upload-section">
      <text class="section-title">图片上传</text>
      <UploadFile
        ref="imageUploadRef"
        :accept="'.jpg,.jpeg,.png,.gif'"
        :maxSize="5"
        @onSuccess="handleImageUploadSuccess"
        @onError="handleUploadError"
        @onProgress="handleUploadProgress"
      />
    </view>

    <!-- 视频上传 -->
    <view class="upload-section">
      <text class="section-title">视频上传</text>
      <UploadFile
        ref="videoUploadRef"
        :accept="'.mp4,.avi,.mov'"
        :maxSize="50"
        @onSuccess="handleVideoUploadSuccess"
        @onError="handleUploadError"
        @onProgress="handleUploadProgress"
      />
    </view>

    <!-- 文档上传 -->
    <view class="upload-section">
      <text class="section-title">文档上传</text>
      <UploadFile
        ref="fileUploadRef"
        :accept="'.pdf,.doc,.docx,.txt'"
        :maxSize="10"
        @onSuccess="handleFileUploadSuccess"
        @onError="handleUploadError"
        @onProgress="handleUploadProgress"
      />
    </view>

    <!-- 显示上传结果 -->
    <view v-if="uploadResult" class="result">
      <text class="result-title">{{ uploadResult.type }}上传成功！</text>
      <text class="result-info">文件名: {{ uploadResult.fileInfo.name }}</text>
      <text class="result-info">文件大小: {{ uploadResult.fileInfo.size }} 字节</text>
      <text class="result-info">
        服务器响应: {{ JSON.stringify(uploadResult.response) }}
      </text>
    </view>

    <!-- 重置按钮 -->
    <button @click="resetAllUploads" class="reset-btn">重置所有</button>
  </view>
</template>

<script setup>
import { ref } from "vue";
import UploadFile from "./UploadFile.vue";

// 响应式数据
const uploadResult = ref(null);
const imageUploadRef = ref(null);
const videoUploadRef = ref(null);
const fileUploadRef = ref(null);

// 处理图片上传成功
const handleImageUploadSuccess = (result) => {
  console.log("图片上传成功:", result);
  uploadResult.value = { ...result, type: '图片' };
  
  uni.showToast({
    title: "图片上传成功",
    icon: "success",
  });
};

// 处理视频上传成功
const handleVideoUploadSuccess = (result) => {
  console.log("视频上传成功:", result);
  uploadResult.value = { ...result, type: '视频' };
  
  uni.showToast({
    title: "视频上传成功",
    icon: "success",
  });
};

// 处理文档上传成功
const handleFileUploadSuccess = (result) => {
  console.log("文档上传成功:", result);
  uploadResult.value = { ...result, type: '文档' };
  
  uni.showToast({
    title: "文档上传成功",
    icon: "success",
  });
};

// 处理上传错误
const handleUploadError = (error) => {
  console.error("上传失败:", error);

  uni.showToast({
    title: "上传失败",
    icon: "error",
  });
};

// 处理上传进度
const handleUploadProgress = (progress) => {
  console.log("上传进度:", progress + "%");
};

// 重置所有上传组件
const resetAllUploads = () => {
  uploadResult.value = null;
  imageUploadRef.value?.reset();
  videoUploadRef.value?.reset();
  fileUploadRef.value?.reset();
};
</script>

<style scoped>
.upload-example {
  padding: 20px;
}

.title {
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 20px;
  display: block;
}

.result {
  margin-top: 20px;
  padding: 15px;
  background-color: #f0f9ff;
  border: 1px solid #b3d8ff;
  border-radius: 8px;
}

.result-title {
  font-size: 16px;
  font-weight: bold;
  color: #409eff;
  display: block;
  margin-bottom: 10px;
}

.result-info {
  font-size: 14px;
  color: #606266;
  display: block;
  margin-bottom: 5px;
}

.reset-btn {
  margin-top: 15px;
  padding: 10px 20px;
  background-color: #409eff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.reset-btn:hover {
  background-color: #337ecc;
}

.upload-section {
  margin-bottom: 30px;
  padding: 20px;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  background-color: #fafafa;
}

.section-title {
  font-size: 16px;
  font-weight: bold;
  color: #303133;
  display: block;
  margin-bottom: 15px;
}
</style>
</template>*"x, 100644 usePermission.js Xz	e(%i]	xFimport { hasPerm } from "@/plugins/permission";
import { currentRoute } from "@/router";

// 对某些特殊场景需要在页面onShow生命周期中校验权限:
// 1.微信小程序端点击tabbar的底层逻辑不触发uni.switchTab
// 2.h5在浏览器地址栏输入url后跳转不触发uni的路由api
// 3.首次启动加载的页面不触发uni的路由api
export async function usePermission() {
  return hasPerm(currentRoute());
}
|A,x:<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script>
      var coverSupport =
        "CSS" in window &&
        typeof CSS.supports === "function" &&
        (CSS.supports("top: env(a)") || CSS.supports("top: constant(a)"));
      document.write(
        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
          (coverSupport ? ", viewport-fit=cover" : "") +
          '" />'
      );
    </script>
    <title></title>
    <!--preload-links-->
    <!--app-context-->
  </head>
  <body>
    <div id="app"><!--app-html--></div>
    <script type="module" src="/main.js"></script>
  </body>
</html>
vx 100644 en.json =3
L	=100644 index.js 'N}?%5100644 ja.json J4-+&꿯wjJ100644 uni-app.ja.json Ac@bo:uQBU 100644 zh-Hans.json '(t<dFX	Cy100644 zh-Hant.json nCQO|܏w[WZi Ynx "{
  "locale.auto": "System",
  "locale.en": "English",
  "locale.zh-hans": "Simplified Chinese",
  "locale.zh-hant": "Traditional Chinese",
  "locale.ja": "Japanese",
  "index.demo": "uni-app internationalization demo"
}
F!ximport { createI18n } from "vue-i18n"; // v9.x
import en from "./en.json";
import ja from "./ja.json";
import zhHans from "./zh-Hans.json";
import zhHant from "./zh-Hant.json";

const i18n = createI18n({
  legacy: false, // 必须设置false才能使用Composition API
  globalInjection: true, // 为每个组件注入$为前缀的全局属性和函数
  locale: uni.getLocale(),
  messages: {
    en,
    "zh-Hans": zhHans,
    "zh-Hant": zhHant,
    ja,
  },
});

export function setupI18n(app) {
  app.use(i18n);
}

export { i18n };
7x '{
  "locale.auto": "システム",
  "locale.en": "英語",
  "locale.zh-hans": "簡体字中国語",
  "locale.zh-hant": "繁体字中国語",
  "locale.ja": "日本語",
  "index.demo": "uni-app 国際化デモ"
}
g]l}x"{
  "common": {
    "uni.app.quit": "もう一度押すと、アプリケーションが終了します",
    "uni.async.error": "サーバーへの接続がタイムアウトしました。画面をクリックして再試行してください",
    "uni.showActionSheet.cancel": "キャンセル",
    "uni.showToast.unpaired": "使用するには、showToastとhideToastをペアにする必要があることに注意してください",
    "uni.showLoading.unpaired": "使用するには、showLoadingとhideLoadingをペアにする必要があることに注意してください",
    "uni.showModal.cancel": "キャンセル",
    "uni.showModal.confirm": "OK",
    "uni.chooseImage.cancel": "キャンセル",
    "uni.chooseImage.sourceType.album": "アルバムから選択",
    "uni.chooseImage.sourceType.camera": "カメラ",
    "uni.chooseVideo.cancel": "キャンセル",
    "uni.chooseVideo.sourceType.album": "アルバムから選択",
    "uni.chooseVideo.sourceType.camera": "カメラ",
    "uni.previewImage.cancel": "キャンセル",
    "uni.previewImage.button.save": "画像を保存",
    "uni.previewImage.save.success": "画像をアルバムに正常に保存します",
    "uni.previewImage.save.fail": "画像をアルバムに保存できませんでした",
    "uni.setClipboardData.success": "コンテンツがコピーされました",
    "uni.scanCode.title": "スキャンコード",
    "uni.scanCode.album": "アルバム",
    "uni.scanCode.fail": "認識に失敗しました",
    "uni.scanCode.flash.on": "タッチして点灯",
    "uni.scanCode.flash.off": "タップして閉じる",
    "uni.startSoterAuthentication.authContent": "指紋認識...",
    "uni.picker.done": "完了",
    "uni.picker.cancel": "キャンセル",
    "uni.video.danmu": "「弾幕」",
    "uni.video.volume": "ボリューム",
    "uni.button.feedback.title": "質問のフィードバック",
    "uni.button.feedback.send": "送信"
  },
  "ios": {},
  "android": {}
}
|ڳx <{
  "locale.auto": "系统",
  "locale.en": "英语",
  "locale.zh-hans": "简体中文",
  "locale.zh-hant": "繁体中文",
  "locale.ja": "日语",
  "index.demo": "uni-app 国际化演示"
}
߃Nx <{
  "locale.auto": "系統",
  "locale.en": "英語",
  "locale.zh-hans": "簡體中文",
  "locale.zh-hant": "繁體中文",
  "locale.ja": "日語",
  "index.demo": "uni-app 國際化演示"
}
VN˷x (import App from "./App";
import { createSSRApp } from "vue";
import setupPlugins from "@/plugins";

export function createApp() {
  const app = createSSRApp(App);
  app.use(setupPlugins);
  return {
    app,
  };
}
FxO{
    "name" : "智能电梯图纸生成",
    "appid" : "__UNI__214B910",
    "description" : "",
    "versionName" : "1.0.0",
    "versionCode" : "100",
    "transformPx" : false,
    /* 5+App特有相关 */
    "app-plus" : {
        "usingComponents" : true,
        "nvueStyleCompiler" : "uni-app",
        "compilerVersion" : 3,
        "splashscreen" : {
            "alwaysShowBeforeRender" : true,
            "waiting" : true,
            "autoclose" : true,
            "delay" : 0
        },
        /* 模块配置 */
        "modules" : {},
        /* 应用发布信息 */
        "distribute" : {
            /* android打包配置 */
            "android" : {
                "permissions" : [
                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
                    "<uses-feature android:name=\"android.hardware.camera\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                ],
                "minSdkVersion" : 21
            },
            /* ios打包配置 */
            "ios" : {},
            /* SDK配置 */
            "sdkConfigs" : {}
        }
    },
    /* 快应用特有相关 */
    "quickapp" : {},
    /* 小程序特有相关 */
    "mp-weixin" : {
        "appid" : "wxc504638e03981812",
        "setting" : {
            "urlCheck" : false,
            "es6" : true,
            "postcss" : true,
            "minified" : true
        },
        "usingComponents" : true,
        "permission" : {
            "scope.userLocation" : {
                "desc" : "获取当前位置"
            },
            "scope.userFuzzyLocation" : {
                "desc" : "您的位置信息将用于小程序位置接口的效果展示"
            }
        },
        /* 地理位置相关接口配置项 @see https://developers.weixin.qq.com/community/develop/doc/000a02f2c5026891650e7f40351c01 */
        "requiredPrivateInfos" : [ "getLocation", "chooseLocation" ]
    },
    "mp-alipay" : {
        "usingComponents" : true
    },
    "mp-baidu" : {
        "usingComponents" : true
    },
    "mp-toutiao" : {
        "usingComponents" : true
    },
    "uniStatistics" : {
        "enable" : false
    },
    "vueVersion" : "3",
    "h5" : {
        "optimization" : {
            "treeShaking" : {
                "enable" : false
            }
        },
        "devServer" : {
            "https" : false
        },
        "router" : {
            "mode" : "history"
        }
    },
    "locale" : "auto"
}
959xo{
  "name": "lift-drawing-wechat",
  "version": "1.0.0",
  "description": "电梯图纸生成",
  "main": "main.js",
  "scripts": {
    "prepare": "husky",
    "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
    "lint:lint-staged": "lint-staged",
    "commit": "git-cz"
  },
  "keywords": [
    "智能电梯图纸生成"
  ],
  "author": "Lufaneng",
  "license": "MIT",
  "dependencies": {
    "crypto-js": "^4.2.0",
    "dayjs": "^1.11.18",
    "three": "^0.178.0",
    "vue-draggable-plus": "^0.6.0"
  },
  "devDependencies": {
    "@commitlint/cli": "^19.1.0",
    "@commitlint/config-conventional": "^19.1.0",
    "@dcloudio/types": "^3.4.11",
    "commitizen": "^4.3.0",
    "cz-git": "^1.9.0",
    "husky": "^9.0.11",
    "lint-staged": "^15.2.2",
    "prettier": "^3.2.5"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-git"
    }
  }
}
xV[kG~^
C[,mJmԤe{2Yfgc#0MEipvCqŔ6$N}Qk)s]lx<3{9ߜۜJ8wG_M~Jz_?Iw:y]q8(Khu7p\Ju4pBCT-rPtϥ-qM+E(4rQ v8aFq)SiĖ
i v/xЮߍV1vIOh[ ž"yv =S&9)+k{g;o?Gk08𾥄2l6sFٯo.j	Nd&"wT?*_ߕ.1x̓tskar6XJ-Y.={ZYLOzb-V,K:vs x7ޕp5-%PJHz'ֹqY74Hy9VS-Pӣc\Xz84RC,yKƥAB&c>ubZ8 5LJ::-[c\Kcox)0#REI*YNmQܘ`$wb(Y6Hu2b8VC>h.Nܰٶe/ynoCLvfƳ! 8"ci4G+s[3}ü2s15o{'eqUjpc.P׬tb(\?N>Z$KrNv;;|EtAݑaI=TqP[4_Mh.~yqvv\[at!zdCM9PEDy/Dpč3}M#.:Ĳ-|S<a?w8gY'~"r}]N]p7Ŵw&1M#4[ejf3fqH"QcWƝJ?;x31 2'w)kՎ'Lyť%yvs+5NuH૘yJUy)wb4hlי1sW&E<S
;|1CL]dĦgnf2\ޱoh{۟|[/JI-bxxEhj_e
V]d;iQx# 100644 404.vue DeaB=bRȖ*xQ<template>
  <div class="not-found">
    <uv-navbar leftIconSize="40rpx" @leftClick="handleBack"></uv-navbar>
    <uv-empty
      mode="page"
      textSize="20"
      text="Page Not Found"
      icon="/static/404.png"
      width="380"
      height="380"
    ></uv-empty>
  </div>
</template>

<script setup>
import { HOME_PATH, isTabBarPath } from "@/router";

function handleBack() {
  uni.$uv.route({
    type: isTabBarPath(HOME_PATH) ? "switchTab" : "redirectTo",
    url: HOME_PATH,
  });
}
</script>

<style lang="scss" scoped>
.not-found {
  height: 100%;
  overflow: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
</style>
fx+ 100644 consumption.vue 3ֻb43dxkoZ?*[<ׁ6"$QYwgNvuVPMZR%EC>8P];uEjKy9gnocJGfJU!AВtϥr/1T,;>ͭWG?eWZ.{緤iJHL3 oIVLiHKMZUS9G"-F̀DаNUj+@Bo6Ԓ5SU-5~9E{mu}	ēP.]^~2%.I'_?9ESM))}l֒ZH+g`k/[7K*PtA干m4.i4gU6Yd3"02ZJm9h|ױ9e_l`"M&FYcӹ.ͤbyфXAH-R)cĉRll*ΤtA,E0)T2Uz։QWH$/c)+e Г`r*R&%@`й_j#<ma&ɞ5z<YCRn<8k=b`
5Q޲9UU
 J#;'>ΜGrim$
~W1MݻëZd(	QMD!8YщKTcHyW?bI,_Ɵɇ4;޵U2[ĊM.!.bC힧zTba)0D`1G@([ҒL&2EB{ ,KmB!FSWݸNEF3RvZ9biwz$O+&1Y5}O,Ea鱜STa"ϲ=l{V
̞{{<J='^hX^-t-c2y
F_瀬Z Y3|L.p"sY5ֲ܋Rw%!v_BC}),7SbE5 lC3ZLLDUF+f,qv[p@*UrY);H@="+]y6!JJRPL@VBa6RBa4I&Ulnv`~gd-G7;{7vx*	215$ϫ*@-,ZWsj}A`9L4d!-m^VSF7`غR!wgCop=?}^hlLs;<ѮXwn^r!̌Ɏ.3{wP|	\dO|g0\[A|08Vw>cE!`wSX&r6@nϻN0*>5J]BςQ*~|>BsJW9巄̀ld:xhOC=醑m,Ia*γB%o%B
|F\[öMhAE<+
Q!kz0¢$`0GUD+f-]\UIz_/h0EHJψ(q"ᤎ+i*J/|Ir,,8`5Ȇ!@M\ c)Ћ}d[퀐LTw+I^"=OWEjR&+&gq{(3sp练G71|q?ӝMfNSf#Ft$Yq( ݖցf%.*=$˕{D_qh뗺>$ϐ'/Ղ". y]N6M1 6Y5+7QS~y-.*@dm+/;s=["A|3hf)MXx/OsRh~:-#G5=)uHE<A"O)[;A	zX`aul#2:&@zd"
X$>kѤ4!D&$ WiR痲kI	|]gPUc"$-0c!O|8cƂIrb	JzAK!+l1
~M3ɓ'c)PϧoLʧ<s*Ez}ȅ!{>Qa.u1^ȊNeb<1"	s*Iji-X-?Q;Z	cdC'؝U\L6k'`<+
Xd'M\5$#q3Q%jxK 100644 index.vue BZ"d 1&X'T100644 index1.vue U$YVxIhC RxZ[s~T?ػkk/HJ+B<Pwwٙ\t)+1`\qI	|U-njEN\y2hs9ݧI'pqLfInfd8{1	-)7hq5;gz>*9MCRD"C,f(V%qL

Nx-u|-  u]kvJ#$tT>%K.Ny>μ[9Sa%9XNNֻzwl\_IϾ;w3w.	=7ݸyAhe=]:&CڄB0?Ⓜ`-|)#.}/B%ڬ[BSO&I1׭#x) 5od1?&i^ҩq0W`aīi9JDьBn:JX.\6v:q&tV;[{4c)y5;`Q=j̈(.BX9FdTZkF
O@I^Fd̵|ez;{ZҾms,\0^`|Ef@{CCJ4AY@5+e-KgBjWl+fy-/Qvuwrz{	iJkh}׶9u6Eم5"[r23	Orq\K\KP~J	$%%?	Vc+ąbK@7$Mi+ՂdA2:IaID/%{aNTIݘDP}Vp%N:rP/HbTc#<A<z
ڢqAbs$
|<vXymeVV
\ᇰխ^6i.PM|$Hߵw}0	 nm]_ݺn+2nkVSYd!`/__'Zwob !?SL(küYhBmq;ebi<hڹwӕtSyXE.CyoX&BcAK?|ay	Ŗ$V,Z''z_]ݺuf*<"*w!?B+6!o\9ged_-)aBG֠Un$3HcOȚ7/fWn^ZH(٦Tg>$?\RB{l^<r#]?]E][e,l>#ShQ+컷/kҰχDY>S1UlPD$`a{{O^dC:={9yΘBH1i-L~}Pc~Px`$"}!d!`JeLg$nT	;J^"aF$dFhJ;<(FXن4P<2WhM)41lɊAd8U^Eq(G]-|Y2`kU9gjuyDoݎ"yG?y˯0EGs1ԩ:c1	b9nL=YWfyǠV,QcN䎛h%/]\*%f\ @D*2Ф&wec.U^NOroWy$t*9E#c9P0!;DhGDv>si5T-AI4 Ҵ^+c,_>IŌf6GGaC/ `8ois0rDjPLҋ&.eb/^ҙhIb&Ty= dX3A<ú\e:w&*Wޠ]Yղ(B̡jא"MCXf)rG=#B^ywtZzv5V@'y$pr/o";5KSg)W8#}엢XIFN/cr隁[ғon]ۼu=m~&⻤KߣmƧgkZJBy_$oJސatRf?Yl?ɁKiy Ԑ;СKoG8!ZBa%d@p@x sAه0̀Z+QO[)Zjk FC6n]ٸyZPT7/?vkr1&*<]@랬і"rd%d։$&1`#RƙeGwfȆuE6>]50	6r'jϷ9X9%՜b?bt"w\G	6DOTFqﮎK[ӏ \m}z'6?[kTr$b/(ƍgpo XV?,J=L5rٻhC j0C	7G0^J%rjMxɲy{-+ D\PS4jnhpRAH U2C!*AGZ\!yRfB*}Jfb/bk%[E_؁hBd2UmFTOi^.HPHĔ'Sҫ.GVY)ްDu 8$*%!\C#gi#AĄ aNezNF@i8?{(iNPt<M3dubi(lv\#Kp 2lE&ϴY㪣Ո%;(avXC슗F
r]h:[XyŸ%JOX1oeP`ܔb
?V 3L}
)FVmLf?^*V3{Ƨ&{d	ƫ}P5e.GҞe<YNY]XS(!߿tEgWK!5j&]$,kQQi`WS"~BSet"dSx29&Q۞<(6)5H@Bdda՘E'K?eWkWGqxĚ\wZSaN+B@/ʃ=SzA5k6=x1<template>
  <view class="container">
    <!-- 顶部图片和标题 -->
    <view class="header-section">
      <image
        class="header-image"
        src="/static/imgs/indexImg.png"
        mode="aspectFill"
      ></image>
      <view class="header-overlay">
        <view class="header-title">生成电梯图纸</view>
        <view class="header-subtitle">
          选择模板并设置参数，快速生成专业电梯施工图
        </view>
      </view>
    </view>

    <!-- 选择图纸模板 -->
    <view class="section">
      <view class="section-title">选择图纸模板</view>
      <view class="template-grid">
        <view
          class="template-item"
          :class="{ active: selectedTemplate === 'passenger' }"
          @click="selectTemplate('passenger')"
        >
          <u-icon name="edit-pen" color="#4285f4" size="24"></u-icon>
          <view class="template-name">乘客电梯标准图纸</view>
          <view class="template-desc">适用于住宅、商业建筑</view>
        </view>
        <view
          class="template-item"
          :class="{ active: selectedTemplate === 'freight' }"
          @click="selectTemplate('freight')"
        >
          <u-icon name="car" color="#4285f4" size="24"></u-icon>
          <view class="template-name">货运电梯专用图纸</view>
          <view class="template-desc">适用于仓库、工厂</view>
        </view>
        <view
          class="template-item"
          :class="{ active: selectedTemplate === 'medical' }"
          @click="selectTemplate('medical')"
        >
          <u-icon name="plus-circle" color="#4285f4" size="24"></u-icon>
          <view class="template-name">医用电梯专业图纸</view>
          <view class="template-desc">适用于医院、医疗场所</view>
        </view>
        <view
          class="template-item"
          :class="{ active: selectedTemplate === 'sightseeing' }"
          @click="selectTemplate('sightseeing')"
        >
          <u-icon name="eye" color="#4285f4" size="24"></u-icon>
          <view class="template-name">观光电梯定制图纸</view>
          <view class="template-desc">适用于商场、酒店</view>
        </view>
      </view>
    </view>

    <!-- 设置参数 -->
    <view class="section">
      <view class="section-title">设置参数</view>

      <!-- 电梯类型 -->
      <view class="param-item">
        <view class="param-label">电梯类型</view>
        <u-picker
          :show="showTypePicker"
          :columns="elevatorTypes"
          @confirm="onTypeConfirm"
          @cancel="showTypePicker = false"
        ></u-picker>
        <view class="param-value" @click="showTypePicker = true">
          {{ selectedType }}
          <u-icon name="arrow-down" size="16"></u-icon>
        </view>
      </view>

      <!-- 载重 -->
      <view class="param-item">
        <view class="param-label">载重(kg)</view>
        <view class="param-control">
          <u-icon
            name="minus-circle"
            @click="decreaseWeight"
            color="#999"
          ></u-icon>
          <input class="param-input" v-model="weight" type="number" />
          <u-icon
            name="plus-circle"
            @click="increaseWeight"
            color="#4285f4"
          ></u-icon>
        </view>
      </view>

      <!-- 井道宽度 -->
      <view class="param-item">
        <view class="param-label">井道宽度(mm)</view>
        <view class="param-control">
          <u-icon
            name="minus-circle"
            @click="decreaseWidth"
            color="#999"
          ></u-icon>
          <input class="param-input" v-model="shaftWidth" type="number" />
          <u-icon
            name="plus-circle"
            @click="increaseWidth"
            color="#4285f4"
          ></u-icon>
        </view>
      </view>

      <!-- 井道深度 -->
      <view class="param-item">
        <view class="param-label">井道深度(mm)</view>
        <view class="param-control">
          <u-icon
            name="minus-circle"
            @click="decreaseDepth"
            color="#999"
          ></u-icon>
          <input class="param-input" v-model="shaftDepth" type="number" />
          <u-icon
            name="plus-circle"
            @click="increaseDepth"
            color="#4285f4"
          ></u-icon>
        </view>
      </view>

      <!-- 顶层高度 -->
      <view class="param-item">
        <view class="param-label">顶层高度(mm)</view>
        <view class="param-control">
          <u-icon
            name="minus-circle"
            @click="decreaseTopHeight"
            color="#999"
          ></u-icon>
          <input class="param-input" v-model="topHeight" type="number" />
          <u-icon
            name="plus-circle"
            @click="increaseTopHeight"
            color="#4285f4"
          ></u-icon>
        </view>
      </view>

      <!-- 底坑深度 -->
      <view class="param-item">
        <view class="param-label">底坑深度(mm)</view>
        <view class="param-control">
          <u-icon
            name="minus-circle"
            @click="decreasePitDepth"
            color="#999"
          ></u-icon>
          <input class="param-input" v-model="pitDepth" type="number" />
          <u-icon
            name="plus-circle"
            @click="increasePitDepth"
            color="#4285f4"
          ></u-icon>
        </view>
      </view>
    </view>

    <!-- 备注说明 -->
    <view class="section">
      <view class="section-title">备注说明</view>
      <u-textarea
        v-model="remarks"
        placeholder="如有特殊需要请备注"
        :maxlength="200"
        count
        height="120"
      ></u-textarea>
    </view>

    <!-- 底部按钮 -->
    <view class="bottom-actions">
      <u-button
        type="primary"
        size="large"
        @click="generateDrawing"
        :loading="generating"
      >
        生成图纸
      </u-button>
      <u-button type="default" size="large" @click="viewHistory" plain>
        查看记录
      </u-button>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted } from "vue";
import {
  onShow,
  onLoad,
  onShareAppMessage,
  onShareTimeline,
  onReachBottom,
} from "@dcloudio/uni-app";
import { useAuthStore, useUserStore } from "@/store";
import RPC from "@/utils/request";

const authStore = useAuthStore();
const userStore = useUserStore();

// 响应式数据
const selectedTemplate = ref("passenger");
const showTypePicker = ref(false);
const selectedType = ref("曳引式电梯");
const weight = ref(1000);
const shaftWidth = ref(2100);
const shaftDepth = ref(2100);
const topHeight = ref(4500);
const pitDepth = ref(4500);
const remarks = ref("");
const generating = ref(false);

// 电梯类型选项
const elevatorTypes = ref([["曳引式电梯", "液压式电梯", "螺杆式电梯"]]);

// 选择模板
const selectTemplate = (template) => {
  selectedTemplate.value = template;
};

// 电梯类型选择确认
const onTypeConfirm = (e) => {
  selectedType.value = e.value[0];
  showTypePicker.value = false;
};

// 载重控制
const decreaseWeight = () => {
  if (weight.value > 100) {
    weight.value -= 100;
  }
};
const increaseWeight = () => {
  weight.value += 100;
};

// 井道宽度控制
const decreaseWidth = () => {
  if (shaftWidth.value > 100) {
    shaftWidth.value -= 100;
  }
};
const increaseWidth = () => {
  shaftWidth.value += 100;
};

// 井道深度控制
const decreaseDepth = () => {
  if (shaftDepth.value > 100) {
    shaftDepth.value -= 100;
  }
};
const increaseDepth = () => {
  shaftDepth.value += 100;
};

// 顶层高度控制
const decreaseTopHeight = () => {
  if (topHeight.value > 100) {
    topHeight.value -= 100;
  }
};
const increaseTopHeight = () => {
  topHeight.value += 100;
};

// 底坑深度控制
const decreasePitDepth = () => {
  if (pitDepth.value > 100) {
    pitDepth.value -= 100;
  }
};
const increasePitDepth = () => {
  pitDepth.value += 100;
};

// 生成图纸
const generateDrawing = async () => {
  if (!selectedTemplate.value) {
    uni.showToast({
      title: "请选择图纸模板",
      icon: "none",
    });
    return;
  }

  generating.value = true;
  try {
    const params = {
      template: selectedTemplate.value,
      type: selectedType.value,
      weight: weight.value,
      shaftWidth: shaftWidth.value,
      shaftDepth: shaftDepth.value,
      topHeight: topHeight.value,
      pitDepth: pitDepth.value,
      remarks: remarks.value,
    };

    // 这里调用生成图纸的API
    // const result = await RPC.post('/api/generate-drawing', params)

    uni.showToast({
      title: "图纸生成中...",
      icon: "loading",
      duration: 2000,
    });

    // 模拟生成过程
    setTimeout(() => {
      uni.showToast({
        title: "图纸生成成功",
        icon: "success",
      });
      generating.value = false;
    }, 2000);
  } catch (error) {
    console.error("生成图纸失败:", error);
    uni.showToast({
      title: "生成失败，请重试",
      icon: "none",
    });
    generating.value = false;
  }
};

// 查看历史记录
const viewHistory = () => {
  uni.navigateTo({
    url: "/pagesA/generate-record/generate-record",
  });
};

// 分享给朋友
onShareAppMessage((data) => {
  console.log("🚀 ~ onShareAppMessage ~ data:", data);
  return {
    title: "电梯图纸生成平台",
    path: "/pages/index/index",
  };
});

// 分享到朋友圈
onShareTimeline((data) => {
  console.log("🚀 ~ onShareTimeline ~ data:", data);
  return {
    title: "电梯图纸生成平台",
    query: "a=1&b=2",
  };
});

onLoad(() => {
  console.log("index-onLoad");
});
</script>

<style lang="scss" scoped>
.container {
  font-size: 14px;
  min-height: 100vh;
  background-color: #f8f8f8;
  padding-bottom: 120px;
}

.header-section {
  position: relative;
  height: 200px;
  overflow: hidden;

  .header-image {
    width: 100%;
    height: 100%;
  }

  .header-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.4);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    color: white;

    .header-title {
      font-size: 24px;
      font-weight: bold;
      margin-bottom: 8px;
    }

    .header-subtitle {
      font-size: 14px;
      opacity: 0.9;
      text-align: center;
      padding: 0 20px;
    }
  }
}

.section {
  margin: 16px;
  background: white;
  border-radius: 12px;
  padding: 16px;

  .section-title {
    font-size: 16px;
    font-weight: bold;
    color: #333;
    margin-bottom: 16px;
  }
}

.template-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;

  .template-item {
    border: 1px solid #e5e5e5;
    border-radius: 8px;
    padding: 16px 12px;
    text-align: center;
    transition: all 0.3s;

    &.active {
      border-color: #4285f4;
      background-color: #f0f7ff;
    }

    .template-name {
      font-size: 14px;
      font-weight: 500;
      color: #333;
      margin: 8px 0 4px;
    }

    .template-desc {
      font-size: 12px;
      color: #999;
    }
  }
}

.param-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;

  &:last-child {
    margin-bottom: 0;
  }

  .param-label {
    font-size: 14px;
    color: #333;
    flex-shrink: 0;
  }

  .param-value {
    display: flex;
    align-items: center;
    color: #666;
    font-size: 14px;
    gap: 4px;
  }

  .param-control {
    display: flex;
    align-items: center;
    gap: 12px;

    .param-input {
      width: 80px;
      text-align: center;
      border: 1px solid #e5e5e5;
      border-radius: 4px;
      padding: 6px 8px;
      font-size: 14px;
    }
  }
}

.bottom-actions {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: white;
  padding: 16px;
  border-top: 1px solid #e5e5e5;
  display: flex;
  gap: 12px;

  .u-button {
    flex: 1;
  }
}
</style>DJx% 100644 login.vue Igq&:r(H~ 
䵇	x<ksGU!Ar]kdcl@XdIrŦȭ\XICF3ȏeUE$flH 66dg<)aFRKݧO>}ݭYeY.eexW,Z;rgGo<TvgVla/m#	͸WtͺxnV}s9wS9ursژ69:zpa2m&ߨ-7[j|4敢{^A-:zwK`޵#XxB]ʣ'go]{ܾمҩ;x	%T5 !SXvkO7]YÚ̊]P]RUt,Ղ::ľO:@N]U5dX@۰Q,)(GgMRwzAW\<AawjܬUx?|T<_bZm-J.:q`0Fi2R*Er܂ah3븰u}i CEX;/ZFA=LG􆱱-[Hpuǟr*Qd9I9=yl
){n][/._`Av@g9~kB@+D~*.VubЖ]30 Q6*( {>::}{`4b+Oѕum\ں\	-vA.8|Xͺ49(-*'P~֗(ȬIhof! r*`xbÃmbR]ĥȏT'h xy#nzUDCXxWuƽdjɶ0Owʽc?y<Fe~)^3p27[lٴrqxtH΂yXd'E(q7
(uިS#U$İ}p@Jh9ޅ$3\K_M-@+4RAJ]"=وKMGa^c\w8!XjknpXp8QP^xŗ'$ՐȆk{ _QladfnsXY`vph.S܎zHAcYS$vuIf$cc)aykPf2ە2ďYyexZCɊd4Msbu$K`EQc߇EPHp.,sRTF!%F8ɅubI΅#;caZ?.m&6(uׄq)nM
6riWpɨ/\y-Ჳ:X)qCs1+lb^a.M;|UJK%+7 Kzn
ѡc#[m[oXwTvZ::PV:iHp{}rӏԣ%bai<3|PVw\_9AدM|i*H5u{~_MF=޴>Sw'au{͙3~0)߅:f=k|['~uw\c50[:;^
(NaY?K`lAN|BIR
Laf`ip*)  T.O
.,]n!.!E8G0>w/8z
GʦQ%u
etĆR$tR8u@1ĩU%2i&'F7S2`F)na*U	ATpOoVU;-
Ѥ<`
@	켒7Gmr=fX=~oIT$-6apS)z5C)o'Ja>Ja]t}؅Úѱ]E%~5h"&i9ECvtϰ%vOY, п&*#~õ&1!|0SD2/@ZFIQCɩպv'n	npR_G80Z݁%\y]A"Ӄ
W@IL(5jI(UHs9as9iAlp`#^XK&&ڊ_>(A忭p<N"JB>ȟWo^lW 
'Oו&Se实hw'cIwP3x	xG@yէ.~|/w)ˀ]0J0Iч'/q$UZj֨7*hԀ|!-,$,gJ*{v91چ'9{!6ʐ#b\MBX" KJE7SД4Zo.\Y}rjqj~Ş3]ǮqQ7	cكycoY3;q9qc$)vG):0ZSWEY?< ]ϙsD֢.cQ}8(Đ>PjfRo*0mq[NLNf'bXʽ//ߗ^${|!"dW-9xMӨ33Èe_+MHBc8, u읞gjm^=uț.OdoQ^3J1d, AL&?$jmO%O;oә@G"`J`}v|O	'c{#ƜFpb˹|Fا?14K0	J^`H|#p*H4)Z05
t 18d|&,nrmuۣ*d!uWȊvuX;ģTQQjB#_dƅ݉de<nPP(r^%ڪR!_xɥWSPʖݣl=aS,Xf2ŨF
y64(Vs)2xB^=Mv_r:*V<dG% C%?-dͬv&ONМkˬ zN}`fCt'Ĕ刃s_0>/vuJ-j[j݉'f9(6Z_<`0>V ynWp'h_rG<<b=/xs5awlgI(x5R_X)j臜%PJWG"R\g{zݜA7,]<a>°WT ehlg>C\֍KAe47δ_]ב vQZcYkM^m+S5G:LeZ̷8"X\UeOhB /Aԇ-YA&et˚t;;Ke)[.k)w(11!L	lc6?Dj4\Z%>d3fȉ*	͍d+mn`G{>=e~B_>^3{C'ÊtiRL{
a5NH[\Y$]|H Զtn|N^	^;rvGHP'>.aaCMrC&,UG<(494Vxr:O6+?/+ˋ']0풅$\I̽O3xwvwKE\%`%'Iy5_3 1TwQ6klK$,'ޢ3L 8Ӥ	:O)R %jNm&R~ʆ\Wb(H*2TOBV!tk!|S^*7GbyuP,7lxS%"H]2DDwѐ>-a}#0B`4Je:zĹʐlwT5 1%ب3Jԁs=!XpjN[&)rFP0{K`KUG*"?S
88~:e?~IzB^|_Z__;d껝E$+N1+GGE]Jzs0M+?^;z&p@S+ϵo<Nh8FrGJuRKK<6E)J,J$h?s]'g&&'g|05z>(lyI̊DN|yus/(_^y3]:gACQ;+d{IHMb~39)+^)24-]&jI9(H,LY0C嫖[Ent1GD4\b7Kh%їqq+eO]!lWD{v5""È9`$^Kb~f*hFKgysɧ_O*R`KxPh508zg̍nNG`z$(t"9E
cǅAHX14QTb*&LMx:ɣI 	Cio܁IwmXlJ#DtCGnil9XS̑#@5_ubBt*#68:<,y<BD}%Ȅ׆8@ܪT?%NA_c{J-Kw*gB>$УL#$WBXDźeEb;i4:oMByhzO-x!_HtX곢*ݕ':|	YCbkRD9ؕ)_IL`!)	bex!QcD)"D8u4tUR2H~R71r*:VFq 0#noڬmT2*LʬٲePT6e66uڷnFb6mtE.}ʄ^?ʨO|r6tׂ[PQ[QX9v,/fb@D^LBCp
VX4b$,=4,v,>"^^4C|
J=N[R:yzI
Wfڥps6?NAo}(x˳NxW.|(\0JlEB7#ũ&q$k0s=ܵcJ<U93y>m<ݜ	<n!mh_bc8_S]#bCl
U3b=KpHX8%jUl=ig2X|s$ˢ@ьɟ'MYLя%)xΰZj!DZC30{ˆ&HhEǴҔ9,_lFdq o ^"mc
$jӿؔ `x$ 100644 mine.vue L؁˫π<%ؽ$	xMb<template>
	<view class="container">
		<!-- 顶部标题 -->
		<view class="header">
			<view class="header-title">管理您的账户信息和服务</view>
		</view>

		<!-- 用户信息卡片 -->
		<view class="user-card">
			<view class="user-info">
				<image class="avatar" src="/static/imgs/avatar.png" mode="aspectFill"></image>
				<view class="user-details">
					<view class="username">
						{{userStore.userInfo.username}}
						<u-icon name="checkmark-circle-fill" color="#ffa500" size="16"></u-icon>
					</view>
					<view class="user-id">用户ID: {{userStore.userInfo.id}}</view>
					<view class="membership">
						会员等级: <span v-if="memberInfo.is_vip">{{memberInfo.plan?.name}} (有效期至:
							{{memberInfo.end_at ? dayjs(memberInfo.end_at * 1000).format('YYYY-MM-DD') : ''}})</span><span
							v-else>无</span>
					</view>
				</view>
			</view>
			<view class="edit-btn" @click="editProfile">
				<text>点击编辑资料</text>
			</view>
		</view>

		<!-- 账户余额 -->
		<view class="balance-card">
			<div>
				<view class="balance-header">
					<view class="balance-label">账户余额</view>
				</view>
				<view class="balance-amount">¥{{memberInfo.wallet_balance || 0}}</view>
			</div>
			<uv-button type="primary" color="#fff" customStyle="color:#000;width:90px" shape="circle" @click="recharge">
				充值
			</uv-button>
		</view>

		<!-- 会员套餐 -->
		<view class="membership-section">
			<view class="membership-grid">
				<view class="membership-item" :class="{ active: selectedPlan === item.id }" v-for="item in planList"
					:key="item.id" @click="selectPlan(item)">
					<view class="tag" v-if="item.tags">{{item.tags}}</view>
					<view class="plan-name">{{item.name}}</view>
					<view class="plan-price">¥{{item.price}}</view>
				</view>
				<!--        <view
          class="membership-item"
          :class="{ active: selectedPlan === 'season' }"
          @click="selectPlan('season')"
        >
          <view class="tag">最受欢迎</view>
          <view class="plan-name">包季会员</view>
          <view class="plan-price">¥300</view>
          <view class="plan-discount">立减¥60</view>
        </view>
        <view
          class="membership-item"
          :class="{ active: selectedPlan === 'yearly' }"
          @click="selectPlan('yearly')"
        >
          <view class="tag">年度首享</view>
          <view class="plan-name">包年会员</view>
          <view class="plan-price">¥1000</view>
          <view class="plan-discount">立减¥440</view>
        </view> -->
			</view>
		</view>

		<!-- 支付方式 -->
		<view class="payment-section">
			<!-- 微信支付 -->
			<view class="payment-item" :class="{ active: selectedPayment === 'wallet' }"
				@click="selectPayment('wallet')">
				<view class="payment-info">
					<uv-icon name="empty-coupon" color="#07c160" size="24"></uv-icon>
					<text class="payment-name">钱包支付</text>
				</view>
				<uv-icon name="checkmark-circle-fill" :color="selectedPayment === 'wallet' ? '#ff3333' : '#ccc'"
					size="20"></uv-icon>
			</view>
			<view class="payment-item" :class="{ active: selectedPayment === 'wxpay' }" @click="selectPayment('wxpay')">
				<view class="payment-info">
					<uv-icon name="weixin-fill" color="#07c160" size="24"></uv-icon>
					<text class="payment-name">微信支付</text>
				</view>
				<uv-icon name="checkmark-circle-fill" :color="selectedPayment === 'wxpay' ? '#ff3333' : '#ccc'"
					size="20"></uv-icon>
			</view>

			<!-- 支付宝支付 - 仅在H5环境显示 -->
			<view v-if="showAlipay" class="payment-item" :class="{ active: selectedPayment === 'alipay' }"
				@click="selectPayment('alipay')">
				<view class="payment-info">
					<uv-icon name="/static/imgs/alipay.png" color="#1677ff" size="24"></uv-icon>
					<text class="payment-name">支付宝</text>
				</view>
				<uv-icon name="checkmark-circle-fill" :color="selectedPayment === 'alipay' ? '#ff3333' : '#ccc'"
					size="20"></uv-icon>
			</view>
		</view>

		<!-- 底部按钮 -->
		<view class="bottom-section">
			<uv-button type="primary" size="large" @click="confirmPayment" :loading="paying">
				确认支付
			</uv-button>
			<view class="agreement">
				购买前请仔细阅读
				<text class="link" @click="showAgreement">《会员服务协议》</text>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		ref,
		onMounted
	} from "vue";
	import {
		onShow,
		onPullDownRefresh
	} from "@dcloudio/uni-app";
	import HeaderCustom from "/components/HeaderCustom/HeaderCustom.vue";
	import {
		useAuthStore,
		useUserStore
	} from "@/store";
	import RPC from "@/utils/request";
	import dayjs from 'dayjs'

	const modal = ref(null);
	const authStore = useAuthStore();
	const userStore = useUserStore();

	const balance = ref(null)
	// const getBalance = () => {
	// 	RPC.post('/wallet/balance', {
	// 		user_id: userStore.userInfo.id
	// 	}).then(res => {
	// 		balance.value = res.balance_cents || 0
	// 	})
	// }
	const memberInfo = ref({})
	const getMemberInfo = () => {
		uni.showLoading();
		RPC.post('/membership/user/info', {
			user_id: userStore.userInfo.id
		}).then(res => {
			memberInfo.value = res || {}
		}).finally(() => {
			uni.hideLoading();
		})
	}

	// 响应式数据
	const selectedPlan = ref("");
	const selectedPayment = ref("wxpay"); // 默认选中微信支付
	const paying = ref(false);
	const showAlipay = ref(true); // 控制是否显示支付宝选项
	const planList = ref([])
	const getPlanList = () => {
		RPC.post('/membership_plan/list', {
			page: 1,
			limit: -1,
			orderby: [{
				sort: 'asc'
			}]
		}).then(res => {
			planList.value = (res.rows || []).filter(item => item.enabled)
			selectedPlan.value = planList.value[0] ? planList.value[0].id : ''
		})
	}
	// 选择会员套餐
	const selectPlan = (plan) => {
		selectedPlan.value = plan.id;
	};

	// 选择支付方式
	const selectPayment = (payment) => {
		selectedPayment.value = payment;
	};

	// 编辑资料
	const editProfile = () => {
		uni.navigateTo({
			url: "/pagesA/edit-profile/edit-profile",
		});
	};

	// 充值
	const recharge = () => {
		uni.navigateTo({
			url: "/pagesA/recharge/recharge",
		});
	};


	// 微信支付
	const wechatPay = async (orderInfo) => {
		// #ifdef MP-WEIXIN
		// 微信小程序支付
		try {
			const paymentResult = await uni.requestPayment({
				provider: "wxpay",
				timeStamp: orderInfo.timeStamp,
				nonceStr: orderInfo.nonceStr,
				package: orderInfo.package,
				signType: orderInfo.signType,
				paySign: orderInfo.paySign,
			});

			console.log("微信支付成功:", paymentResult);
			return {
				success: true,
				data: paymentResult
			};
		} catch (error) {
			console.error("微信支付失败:", error);
			if (error.errMsg === "requestPayment:fail cancel") {
				throw new Error("用户取消支付");
			}
			throw new Error("微信支付失败");
		}
		// #endif

		// #ifdef H5
		// H5微信支付
		if (typeof WeixinJSBridge !== "undefined") {
			return new Promise((resolve, reject) => {
				WeixinJSBridge.invoke(
					"getBrandWCPayRequest", {
						appId: 'wxc504638e03981812',
						timeStamp: orderInfo.timeStamp,
						nonceStr: orderInfo.nonceStr,
						package: orderInfo.package,
						signType: orderInfo.signType,
						paySign: orderInfo.paySign,
					},
					(res) => {
						if (res.err_msg === "get_brand_wcpay_request:ok") {
							resolve({
								success: true,
								data: res
							});
						} else if (res.err_msg === "get_brand_wcpay_request:cancel") {
							reject(new Error("用户取消支付"));
						} else {
							reject(new Error("微信支付失败"));
						}
					}
				);
			});
		} else {
			// 不在微信环境，跳转到支付页面
			const payUrl = orderInfo.mwebUrl; // 后端返回的H5支付链接
			window.location.href = payUrl;
			return {
				success: true,
				redirect: true
			};
		}
		// #endif
	};

	function showModalAsync(options) {
		return new Promise((resolve, reject) => {
			uni.showModal({
				...options,
				success: (res) => {
					resolve(res); // 将用户操作结果传递给 await
				},
				fail: (err) => {
					reject(err); // 处理失败情况
				}
			});
		});
	}

	// 支付宝支付（仅H5环境）
	const alipayPay = async (orderInfo) => {
		// #ifdef H5
		// H5支付宝支付
		const payUrl = orderInfo.payUrl; // 后端返回的支付宝H5支付链接
		window.location.href = payUrl;
		return {
			success: true,
			redirect: true
		};
		// #endif
	};

	// 确认支付
	const confirmPayment = async () => {
		if (!selectedPlan.value) {
			uni.showToast({
				title: "请选择会员套餐",
				icon: "none",
			});
			return;
		}

		if (!selectedPayment.value) {
			uni.showToast({
				title: "请选择支付方式",
				icon: "none",
			});
			return;
		}

		paying.value = true;
		try {
			// 1. 创建订单参数
			const orderParams = {
				user_id: userStore.userInfo?.id,
				plan_id: selectedPlan.value,
				pay_channel: selectedPayment.value
			};

			uni.showLoading({
				title: "正在创建订单...",
			});

			// 2. 创建订单
			const orderNum = await RPC.post('/membership/order/create', orderParams);

			// 模拟创建订单返回的数据
			// const orderResult = {
			// 	orderId: "ORDER_" + Date.now(),
			// 	amount: orderParams.amount,
			// 	// 微信支付参数（实际应该由后端返回）
			// 	wechatPayInfo: {
			// 		appId: "wx1234567890",
			// 		timeStamp: String(Date.now()),
			// 		nonceStr: "random_string_" + Date.now(),
			// 		package: "prepay_id=wx_prepay_id_123456",
			// 		signType: "RSA",
			// 		paySign: "mock_pay_sign_123456",
			// 		// H5支付链接
			// 		mwebUrl: "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx_prepay_id_123456",
			// 	},
			// 	// 支付宝支付参数（实际应该由后端返回）
			// 	alipayInfo: {
			// 		orderString: "mock_alipay_order_string_123456",
			// 		payUrl: "https://openapi.alipay.com/gateway.do?mock_pay_url",
			// 	},
			// };

			uni.hideLoading();

			// 3. 根据支付方式调用对应的支付方法
			let paymentResult;
			if (selectedPayment.value === "wxpay") {
				const res = await uni.login({
					provider: 'weixin'
				})
				const orderResult = await RPC.post('/membership/order/pay_by_wechat_mini', {
					code: res.code,
					"order_no": orderNum.order_no
				})
				uni.showLoading({
					title: "正在跳转微信支付...",
				});
				console.log('orderResult', orderResult)
				paymentResult = await wechatPay(orderResult);
			} else if (selectedPayment.value === "alipay") {
				uni.showLoading({
					title: "正在跳转支付宝...",
				});
				paymentResult = await alipayPay(orderResult.alipayInfo);
			} else if (selectedPayment.value === 'wallet') {
				const res = await showModalAsync({
					title: '确认支付',
					content: '确认使用钱包余额支付？'
				});

				// 同步判断逻辑
				if (res.confirm) {
					paymentResult = await RPC.post('/membership/order/pay_by_wallet', {
						order_no: orderNum.order_no
					})
					console.log('paymentResult', paymentResult)
				} else if (res.cancel) {
					console.log('用户点击了取消');
					paymentResult={success:false}
				}
			}

			uni.hideLoading();
			console.log('paymentResult111',paymentResult)
			// 4. 处理支付结果
			if (paymentResult?.success) {
				if (paymentResult.redirect) {
					// H5跳转支付，不需要额外处理
					uni.showToast({
						title: "正在跳转支付页面...",
						icon: "loading",
						duration: 2000,
					});
				} else {
					// 支付成功
					setTimeout(() => {
						uni.showToast({
							title: "支付成功",
							icon: "success",
						});
						setTimeout(()=>{
							getMemberInfo()
						},500)
					}, 1000)
					// getMemberInfo()

					// 延迟跳转到订单页面或刷新用户信息
					// setTimeout(() => {
					// 可以跳转到订单详情页面
					// uni.navigateTo({
					// 	url: `/pages/order-detail/order-detail?orderId=${orderResult.orderId}`,
					// });

					// 或者刷新当前页面的用户信息
					// loadUserInfo();
					// }, 1500);
				}
			}
		} catch (error) {
			uni.hideLoading();
			console.error("支付失败:", error);
			console.log('error', error)
			let errorMessage = "支付失败，请重试";
			if (error.message === "用户取消支付") {
				errorMessage = "支付已取消";
			} else if (error.message) {
				errorMessage = error.message;

			} else if (error) {
				errorMessage = error
			}

			uni.showToast({
				title: errorMessage,
				icon: "none",
			});
		} finally {
			paying.value = false;
		}
	};

	// 显示协议
	const showAgreement = () => {
		uni.navigateTo({
			url: "/pagesA/user-agreement/user-agreement",
		});
	};

	// 检查支付结果（用于H5支付回调）
	const checkPaymentResult = async (orderId) => {
		try {
			// 调用后端接口检查支付结果
			// const result = await RPC.get(`/api/order/check-payment/${orderId}`);

			// 模拟检查结果
			const result = {
				success: true,
				status: "paid", // paid, pending, failed
			};

			if (result.status === "paid") {
				uni.showToast({
					title: "支付成功",
					icon: "success",
				});

				// 更新用户信息或跳转到成功页面
				setTimeout(() => {
					uni.navigateTo({
						url: `/pages/order-detail/order-detail?orderId=${orderId}`,
					});
				}, 1500);
			} else if (result.status === "failed") {
				uni.showToast({
					title: "支付失败",
					icon: "none",
				});
			} else {
				uni.showToast({
					title: "支付处理中，请稍后查看订单状态",
					icon: "none",
				});
			}
		} catch (error) {
			console.error("检查支付结果失败:", error);
		}
	};

	// 页面显示时检查是否有支付回调参数
	const handlePaymentCallback = () => {
		// #ifdef H5
		const urlParams = new URLSearchParams(window.location.search);
		const orderId = urlParams.get("orderId");
		const payResult = urlParams.get("payResult");

		if (orderId && payResult) {
			// 清理URL参数
			const url = new URL(window.location);
			url.searchParams.delete("orderId");
			url.searchParams.delete("payResult");
			window.history.replaceState({}, document.title, url.pathname + url.search);

			// 检查支付结果
			if (payResult === "success") {
				checkPaymentResult(orderId);
			} else {
				uni.showToast({
					title: "支付失败或取消",
					icon: "none",
				});
			}
		}
		// #endif
	};

	// 检查当前环境并设置支付选项
	const checkEnvironment = () => {
		// #ifdef MP-WEIXIN
		// 微信小程序环境，隐藏支付宝选项，默认选择微信支付
		showAlipay.value = false;
		// #endif

		// #ifdef H5
		// H5环境，显示所有支付选项
		showAlipay.value = true;
		// 如果在微信浏览器内，默认选择微信支付
		const ua = navigator.userAgent.toLowerCase();
		const isWechat = ua.indexOf("micromessenger") !== -1;
		// #endif
	};

	// 页面挂载时处理支付回调和环境检查
	onMounted(() => {
		checkEnvironment();
		getPlanList()
		// handlePaymentCallback();
	});

	// 页面显示时也检查支付回调（从其他页面返回时）
	onShow(() => {
		handlePaymentCallback();
		// getBalance()
		getMemberInfo()
	});
	onPullDownRefresh(() => {
		getPlanList()
		// getBalance()
		getMemberInfo()
	});
</script>

<style lang="scss" scoped>
	.container {
		font-size: 14px;
		background: linear-gradient(180deg, #7b9cdb 0%, #f8f8f8 40%);
		padding-bottom: 120px;

		/* #ifdef H5 */
		padding-bottom: 170px;
		/* H5环境下需要更多空间 (底部按钮高度 + tabBar高度 + 间距) */
		/* #endif */
	}

	.header {
		padding: 20px 16px 16px;

		.header-title {
			color: white;
			font-size: 18px;
			font-weight: 500;
		}
	}

	.user-card {
		margin: 0 16px 16px;
		background: white;
		border-radius: 12px;
		padding: 16px;
		position: relative;

		.user-info {
			display: flex;
			align-items: center;
			// margin-bottom: 12px;

			.avatar {
				width: 60px;
				height: 60px;
				border-radius: 50%;
				margin-right: 12px;
				overflow: hidden;

				.img {
					width: 100%;
					height: 100%;
				}
			}

			.user-details {
				flex: 1;

				.username {
					display: flex;
					align-items: center;
					gap: 4px;
					font-size: 18px;
					font-weight: bold;
					color: #333;
					margin-bottom: 4px;
				}

				.user-id {
					font-size: 12px;
					color: #999;
					margin-bottom: 2px;
				}

				.membership {
					font-size: 12px;
					color: #999;
				}
			}
		}

		.edit-btn {
			text-align: right;
			color: #4285f4;
			font-size: 14px;
			position: absolute;
			top: 10px;
			right: 20px;
		}
	}

	.balance-card {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin: 0 16px 16px;
		background: linear-gradient(135deg, #4285f4 0%, #6fa8f5 100%);
		border-radius: 12px;
		padding: 16px;
		color: white;

		.balance-header {
			display: flex;
			justify-content: space-between;
			align-items: center;
			margin-bottom: 6px;

			.balance-label {
				font-size: 14px;
				opacity: 0.9;
			}
		}

		.balance-amount {
			font-size: 28px;
			font-weight: bold;
		}
	}

	.membership-section {
		margin: 0 16px 16px;

		.membership-grid {
			display: flex;
			justify-content: space-between;
			gap: 8px;
			overflow-x: auto;

			.membership-item {
				width: 24%;
				flex-shrink: 0;
				background: white;
				border-radius: 12px;
				padding: 16px 12px;
				text-align: center;
				position: relative;
				border: 2px solid transparent;
				transition: all 0.3s;
				overflow: hidden;

				&.active {
					border-color: #4285f4;
					background-color: #f0f7ff;
				}

				.tag {
					position: absolute;
					top: 0px;
					left: 0;
					padding: 2px 8px;
					border-radius: 0 0 10px 0;
					font-size: 10px;
					color: white;
					background: #ff3333;
				}

				.plan-name {
					font-size: 14px;
					color: #333;
					margin: 12px 0 8px;
				}

				.plan-price {
					font-size: 20px;
					font-weight: bold;
					color: #ff3333;
					margin-bottom: 4px;
				}

				.plan-discount {
					font-size: 12px;
					color: #999;
				}
			}
		}
	}

	.payment-section {
		margin: 0 16px 24px;

		.payment-item {
			display: flex;
			align-items: center;
			justify-content: space-between;
			background: white;
			border-radius: 12px;
			padding: 16px;
			margin-bottom: 8px;
			border: 1px solid #e5e5e5;
			transition: all 0.3s;

			&.active {
				border-color: #4285f4;
				background-color: #f0f7ff;
			}

			&:last-child {
				margin-bottom: 0;
			}

			.payment-info {
				display: flex;
				align-items: center;
				gap: 12px;

				.payment-name {
					font-size: 14px;
					color: #333;
				}
			}
		}
	}

	.bottom-section {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		background: white;
		padding: 16px;
		border-top: 1px solid #e5e5e5;

		/* #ifdef H5 */
		bottom: 50px;
		/* H5环境下给tabBar留出空间 */
		/* #endif */

		.agreement {
			text-align: center;
			font-size: 12px;
			color: #999;
			margin-top: 12px;

			.link {
				color: #4285f4;
			}
		}
	}
</style>	OL+xI#֓o< _u!			let orderResult = {}(|
				// #ifdef MP-WEIXIN+4)2k)/
				// #endif
				
				
				// #ifdef H5
				k)?h5', {)#,
				})
				// #endif
				uni.showLoading({
_.&*8*5
				if(1==1) return+*L
				l)7
alipay', {)#)9+A*H:+*,+
		uni.stopPullDownRefresh();>&Zܥx% 100644 order.vue mCt.r3^E{RxIE<template>
	<view class="container">
		<uv-sticky bgColor="#fff" :offsetTop="isWeChatH5 ? -50 : 0">
			<div class="tabBox">
				<div class="tabItem" :class="{selected:active==='全部'}" @click="switchTab('全部')">全部</div>
				<div class="tabItem" :class="{selected:active==='图纸生成'}" @click="switchTab('图纸生成')">图纸生成</div>
				<div class="tabItem" :class="{selected:active==='会员购买'}" @click="switchTab('会员购买')">会员购买</div>
				<div class="tabItem" :class="{selected:active==='钱包充值'}" @click="switchTab('钱包充值')">钱包充值</div>
			</div>
		</uv-sticky>
		<!-- 订单列表 -->
		<view class="order-list">
			<view class="order-item" v-for="order in list" :key="order.id">
				<!-- 订单头部 -->
				<view class="order-header">
					<view class="order-info">
						<text class="order-number">订单编号: {{ order.order_no }}</text>
						<view class="order-type-tag" @click="copyOrderNo(order.order_no)">复制</view>
					</view>
					<view class="order-status" :class="{paid:order.status === 'paid',pending:order.status === 'created' || order.status === 'pending',
					cancelled:order.status === 'failed' || order.status === 'canceled' || order.status === 'refunded'}">
						<span v-if="order.status === 'created'">待付款</span>
						<span v-if="order.status === 'pending'">待支付</span>
						<span v-if="order.status === 'paid'">已支付</span>
						<span v-if="order.status === 'failed'">支付失败</span>
						<span v-if="order.status === 'canceled'">已取消</span>
						<span v-if="order.status === 'refunded'">已退款</span>
					</view>
				</view>

				<!-- 订单详情 -->
				<view class="order-details">
					<view class="detail-row">
						<text class="label">用户名称:</text>
						<text class="value">{{ order.user_name }}</text>
					</view>
					<view class="detail-row">
						<text class="label">用户ID:</text>
						<text class="value">{{ order.user_id }}</text>
					</view>
					<view class="detail-row">
						<text class="label">订单类型:</text>
						<text class="value">{{ order.order_type }}</text>
					</view>
					<view class="detail-row">
						<text class="label">订单金额:</text>
						<text class="value price">¥{{ order.amount }}</text>
					</view>
					<view class="detail-row">
						<text class="label">支付渠道:</text>
						<text class="value">
							<template v-if="order.pay_channel === 'wallet'">钱包</template>
							<template v-if="order.pay_channel === 'wxpay'">微信</template>
							<template v-if="order.pay_channel === 'alipay'">支付宝</template>
						</text>
					</view>
					<!-- 				<view class="detail-row" v-if="order.discount > 0">
						<text class="label">折扣金额:</text>
						<text class="value discount">-¥{{ order.discount }}</text>
					</view> -->
					<!-- 		<view class="detail-row">
						<text class="label">实付金额:</text>
						<text class="value final-price">¥{{ order.finalAmount }}</text>
					</view> -->
					<view class="detail-row">
						<text class="label">创建时间</text>
						<text
							class="value">{{ order.created_at ? dayjs(order.created_at * 1000).format('YYYY-MM-DD HH:mm:ss') :'' }}</text>
					</view>
				</view>

				<!-- 订单操作 -->
				<view class="order-actions" v-if="order.status === 'pending' || order.status === 'created'">
					<div>
						<!-- <div class="countdown-text" v-if="order.status === 'pending'">支付剩余时间: {{ order.countdown }}
						</div> -->
					</div>
					<div class="buttonBox">
						<template v-if="order.status === 'pending' || order.status === 'created'">
							<uv-button type="error" size="small" @click="cancelOrder(order)">
								取消订单
							</uv-button>
							<uv-button type="primary" size="small" @click="payOrder(order)">
								去支付
							</uv-button>
						</template>
						<!-- 						<template v-else>

							<uv-button type="default" size="small" @click="deleteOrder(order)">
								删除订单
							</uv-button>
							<uv-button type="primary" color="#3F70FF" size="small" @click="viewOrderDetail(order)">
								查看详情
							</uv-button>
						</template> -->
					</div>
				</view>
			</view>
		</view>

		<!-- 空状态 -->
		<view v-if="list.length === 0 && loadingStatus !== 'loading'" class="empty-state">
			<u-icon name="file-text" size="60" color="#ccc"></u-icon>
			<text class="empty-text">暂无订单记录</text>
		</view>
		<uv-load-more v-else :status="loadingStatus" />
	</view>
</template>

<script setup>
	import {
		computed,
		onMounted,
		ref
	} from "vue";
	import {
		onShow,
		onReachBottom
	} from "@dcloudio/uni-app";
	import {
		useAuthStore,
		useUserStore
	} from "@/store";
	import HeaderCustom from '/components/HeaderCustom/HeaderCustom.vue'
	import RPC from "@/utils/request";
	import dayjs from "dayjs";

	const isWeChatH5 = ref(false)
	// #ifdef H5
	if (navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1) {
		isWeChatH5.value = true
	}
	// #endif

	const active = ref('全部')

	const authStore = useAuthStore()
	const userStore = useUserStore()

	const copyOrderNo = (orderNo) => {
		uni.setClipboardData({
			data: orderNo,
			success: () => {
				uni.showToast({
					title: '订单号已复制',
					icon: 'success'
				})
			}
		})
	}

	const list = ref([{
			id: 1,
			orderNumber: 'ORD20230515001',
			typeLabel: '续费',
			status: 'paid',
			statusText: '已支付',
			userName: '张三',
			userId: 'U12345678',
			orderType: '包年会员',
			amount: '1200.00',
			discount: 200.00,
			finalAmount: '1000.00',
			payTime: '2025-05-15 10:30',
			type: 'yearly'
		},
		{
			id: 2,
			orderNumber: 'ORD20230515002',
			typeLabel: '续费',
			status: 'paid',
			statusText: '已支付',
			userName: '李四',
			userId: 'U12345666',
			orderType: '充值',
			amount: '500.00',
			discount: 0,
			finalAmount: '500.00',
			payTime: '2025-06-15 11:30',
			type: 'recharge'
		},
		{
			id: 3,
			orderNumber: 'ORD20230515332',
			typeLabel: '续费',
			status: 'pending',
			statusText: '待支付',
			userName: '小客',
			userId: 'U12345555',
			orderType: '包月会员',
			amount: '120.00',
			discount: 12.00,
			finalAmount: '108.00',
			payTime: '2025-08-12 15:20',
			countdown: '30分钟',
			type: 'monthly'
		}
	])

	// 切换标签
	const switchTab = (tab) => {
		list.value = []
		active.value = tab
		page.value = 1
		if (tab === '全部') {
			typeParams.value = ''
		} else {
			typeParams.value = tab
		}
		getList()
	}

	// 查看订单详情
	const viewOrderDetail = (order) => {
		uni.navigateTo({
			url: `/pagesA/order-detail/order-detail?id=${order.id}`
		})
	}

	// 取消订单
	const cancelOrder = (order) => {
		uni.showModal({
			title: '确认取消',
			content: '确定要取消这个订单吗？',
			success: async (res) => {
				if (res.confirm) {
					try {
						// 调用取消订单API
						await RPC.post('/membership/order/cancel', {
							order_no: order.order_no
						})

						// 更新订单状态
						const index = list.value.findIndex(item => item.id === order.id)
						if (index !== -1) {
							list.value[index].status = 'canceled'
						}

						uni.showToast({
							title: '订单已取消',
							icon: 'success'
						})
					} catch (error) {
						console.error('取消订单失败:', error)
						uni.showToast({
							title: '取消失败，请重试',
							icon: 'none'
						})
					}
				}
			}
		})
	}

	// 删除订单
	const deleteOrder = (order) => {
		uni.showModal({
			title: '确认删除',
			content: '确定要删除这个订单吗？删除后无法恢复。',
			success: async (res) => {
				if (res.confirm) {
					try {
						// 调用删除订单API
						// await RPC.post('/api/order/delete', { orderId: order.id })

						// 从列表中移除订单
						const index = orders.value.findIndex(item => item.id === order.id)
						if (index !== -1) {
							orders.value.splice(index, 1)
						}

						uni.showToast({
							title: '订单已删除',
							icon: 'success'
						})
					} catch (error) {
						console.error('删除订单失败:', error)
						uni.showToast({
							title: '删除失败，请重试',
							icon: 'none'
						})
					}
				}
			}
		})
	}

	// 微信支付
	const wechatPay = async (orderInfo) => {
		// #ifdef MP-WEIXIN
		// 微信小程序支付
		try {
			const paymentResult = await uni.requestPayment({
				provider: "wxpay",
				timeStamp: orderInfo.timeStamp,
				nonceStr: orderInfo.nonceStr,
				package: orderInfo.package,
				signType: orderInfo.signType,
				paySign: orderInfo.paySign,
			});

			console.log("微信支付成功:", paymentResult);
			return {
				success: true,
				data: paymentResult
			};
		} catch (error) {
			console.error("微信支付失败:", error);
			if (error.errMsg === "requestPayment:fail cancel") {
				throw new Error("用户取消支付");
			}
			throw new Error("微信支付失败");
		}
		// #endif

		// #ifdef H5
		// H5微信支付
		if (typeof WeixinJSBridge !== "undefined") {
			return new Promise((resolve, reject) => {
				WeixinJSBridge.invoke(
					"getBrandWCPayRequest", {
						appId: 'wxc504638e03981812',
						timeStamp: orderInfo.timeStamp,
						nonceStr: orderInfo.nonceStr,
						package: orderInfo.package,
						signType: orderInfo.signType,
						paySign: orderInfo.paySign,
					},
					(res) => {
						if (res.err_msg === "get_brand_wcpay_request:ok") {
							resolve({
								success: true,
								data: res
							});
						} else if (res.err_msg === "get_brand_wcpay_request:cancel") {
							reject(new Error("用户取消支付"));
						} else {
							reject(new Error("微信支付失败"));
						}
					}
				);
			});
		} else {
			// 不在微信环境，跳转到支付页面
			const payUrl = orderInfo.mwebUrl; // 后端返回的H5支付链接
			window.location.href = payUrl;
			return {
				success: true,
				redirect: true
			};
		}
		// #endif
	};

	// 支付宝支付（仅H5环境）
	const alipayPay = async (orderInfo) => {
		// #ifdef H5
		// H5支付宝支付
		const payUrl = orderInfo.payUrl; // 后端返回的支付宝H5支付链接
		window.location.href = payUrl;
		return {
			success: true,
			redirect: true
		};
		// #endif
	};

	function showModalAsync(options) {
		return new Promise((resolve, reject) => {
			uni.showModal({
				...options,
				success: (res) => {
					resolve(res); // 将用户操作结果传递给 await
				},
				fail: (err) => {
					reject(err); // 处理失败情况
				}
			});
		});
	}

	// 支付订单
	const payOrder = async (order) => {
		try {
			uni.showLoading({
				title: "正在处理支付...",
			});

			// 根据订单的支付渠道调用对应的支付方法
			let paymentResult;

			if (order.pay_channel === "wxpay") {
				const res = await uni.login({
					provider: 'weixin'
				})
				const orderResult = await RPC.post('/membership/order/pay_by_wechat_mini', {
					code: res.code,
					"order_no": order.order_no
				})
				uni.showLoading({
					title: "正在跳转微信支付...",
				});
				console.log('orderResult', orderResult)
				paymentResult = await wechatPay(orderResult);
			} else if (order.pay_channel === "alipay") {
				const orderResult = await RPC.post('/membership/order/pay_by_alipay', {
					order_no: order.order_no
				})
				uni.showLoading({
					title: "正在跳转支付宝...",
				});
				paymentResult = await alipayPay(orderResult);
			} else if (order.pay_channel === 'wallet') {
				const res = await showModalAsync({
					title: '确认支付',
					content: '确认使用钱包余额支付？'
				});

				// 同步判断逻辑
				if (res.confirm) {
					paymentResult = await RPC.post('/membership/order/pay_by_wallet', {
						order_no: order.order_no
					})
					console.log('paymentResult', paymentResult)
				} else if (res.cancel) {
					console.log('用户点击了取消');
					paymentResult = {
						success: false
					}
				}
			}

			uni.hideLoading();
			console.log('paymentResult', paymentResult)

			// 处理支付结果
			if (paymentResult?.success) {
				if (paymentResult.redirect) {
					// H5跳转支付，不需要额外处理
					uni.showToast({
						title: "正在跳转支付页面...",
						icon: "loading",
						duration: 2000,
					});
				} else {
					// 支付成功
					setTimeout(() => {
						uni.showToast({
							title: "支付成功",
							icon: "success",
						});
						// 更新订单状态
						const index = list.value.findIndex(item => item.id === order.id)
						if (index !== -1) {
							list.value[index].status = 'paid'
						}
						// 刷新订单列表
						setTimeout(() => {
							getList()
						}, 500)
					}, 1000)
				}
			}
		} catch (error) {
			uni.hideLoading();
			console.error("支付失败:", error);
			let errorMessage = "支付失败，请重试";
			if (error.message === "用户取消支付") {
				errorMessage = "支付已取消";
			} else if (error.message) {
				errorMessage = error.message;
			} else if (error) {
				errorMessage = error
			}

			uni.showToast({
				title: errorMessage,
				icon: "none",
			});
		}
	}

	const page = ref(1)
	const typeParams = ref('')
	const loadingStatus = ref('loadmore')
	const count = ref(0);
	const getList = () => {
		uni.showLoading();
		RPC.post('/membership/order/list', {
			user_id: userStore.userInfo.id,
			page: page.value,
			order_type: typeParams.value,
			size: 20
		}).then(res => {
			list.value = [...list.value, ...res.list];
			count.value = res.total;
			if (list.value.length >= count.value) {
				loadingStatus.value = "nomore";
			} else {
				loadingStatus.value = "loadmore";
			}
		}).catch(() => {
			loadingStatus.value = "loadmore";
		}).finally(() => {
			uni.hideLoading();
		})
	}

	onMounted(() => {

	})

	onReachBottom(() => {
		if (list.value.length >= count.value || loadingStatus.value === "loading")
			return;
		console.log("上拉加载:");
		loadingStatus.value = "loading";
		page.value = ++page.value;
		getList();
	});

	onShow(() => {
		// 页面显示时刷新订单列表
		list.value = []
		page.value = 1
		active.value = '全部'
		typeParams.value = ''
		getList()
	})
</script>

<style lang="scss" scoped>
	.container {
		font-size: 14px;
		min-height: 100vh;
		padding-bottom: 50px;
		background-color: #f8f8f8;
	}

	.tabBox {
		height: 50px;
		background-color: #fff;
		display: flex;

		.tabItem {
			height: 100%;
			font-weight: 600;
			display: flex;
			align-items: center;
			justify-content: center;
			flex: 1;

			&.selected {
				color: #5479ED;
				border-bottom: 1px solid #5479ED;
			}
		}
	}

	.order-list {
		padding: 16px;

		.order-item {
			background: white;
			border-radius: 12px;
			margin-bottom: 16px;
			overflow: hidden;

			.order-header {
				display: flex;
				justify-content: space-between;
				align-items: center;
				padding: 16px 16px 0;

				.order-info {
					display: flex;
					align-items: center;
					gap: 8px;

					.order-number {
						font-size: 14px;
						color: #333;
					}

					.order-type-tag {
						background: #f0f0f0;
						color: #666;
						padding: 2px 6px;
						border-radius: 4px;
						font-size: 12px;
					}
				}

				.order-status {
					padding: 4px 8px;
					border-radius: 4px;
					font-size: 12px;

					&.paid {
						background: #e8f5e8;
						color: #52c41a;
					}

					&.pending {
						background: #fff7e6;
						color: #fa8c16;
					}

					&.cancelled {
						background: #fff1f0;
						color: #ff4d4f;
					}
				}
			}

			.order-details {
				padding: 16px;

				.detail-row {
					display: flex;
					justify-content: space-between;
					align-items: center;
					margin-bottom: 8px;

					&:last-child {
						margin-bottom: 0;
					}

					.label {
						color: #666;
						font-size: 14px;
					}

					.value {
						color: #333;
						font-size: 14px;

						&.price {
							color: #333;
							font-weight: 500;
						}

						&.discount {
							color: #ff4d4f;
						}

						&.final-price {
							color: #333;
							font-weight: bold;
						}
					}
				}
			}

			.order-actions {
				display: flex;
				justify-content: space-between;
				align-items: center;
				gap: 8px;
				padding: 0 16px 16px;
				border-top: 1px solid #f0f0f0;
				padding-top: 16px;

				.countdown-text {
					color: #ff4d4f;
					font-size: 12px;
				}

				.buttonBox {
					display: flex;
					align-items: center;
					gap: 10px;
					justify-content: flex-end;
				}
			}

			.pending-footer {
				border-top: 1px solid #f0f0f0;
				padding: 16px;

				.countdown {
					margin-bottom: 12px;

					.countdown-text {
						color: #ff4d4f;
						font-size: 12px;
					}
				}

				.pending-actions {
					display: flex;
					gap: 12px;

					.u-button {
						flex: 1;
					}
				}
			}
		}
	}

	.empty-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 80px 20px;

		.empty-text {
			color: #999;
			font-size: 14px;
			margin-top: 16px;
		}
	}
</style>NZzx31 Ԕ݂̜T̦K3=eoO(h)2+KOK-J,I-JM/Ja-*齘Y^1^QQ	M-MI-Iak1rym^a,Ἵ`c_29Ext=lڬ_9 JJ%0$5ouY[ٿW,?| N7x, 100644 edit-profile.vue &;a!MJ"OJJxC<template>
	<view class="container">
		<!-- 个人信息设置 -->
		<view class="profile-section">
			<!-- 头像 -->
			<!--      <view class="profile-item" @click="changeAvatar">
        <view class="item-label">头像</view>
        <view class="item-content">
          <image
            class="avatar"
            :src="userInfo.avatar"
            mode="aspectFill"
          ></image>
          <uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
        </view>
      </view> -->

			<!-- 用户名 -->
			<view class="profile-item" @click="editUsername">
				<view class="item-label">用户名</view>
				<view class="item-content">
					<text class="item-value">{{ userStore.userInfo.username }}</text>
					<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
				</view>
			</view>

			<!-- 邮箱 -->
			<view class="profile-item" @click="editEmail">
				<view class="item-label">邮箱</view>
				<view class="item-content">
					<text class="item-value">{{ userStore.userInfo.email }}</text>
					<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
				</view>
			</view>

			<!-- 电话 -->
			<view class="profile-item" @click="changePhone">
				<view class="item-label">手机号</view>
				<view class="item-content">
					<text class="item-value">{{ userStore.userInfo.phone }}</text>
					<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
				</view>
			</view>
		</view>


		<!-- 应用设置 -->
		<view class="app-section">
			<!-- 缓存 -->
			<!-- 			<view class="profile-item" @click="clearCache">
				<view class="item-label">缓存</view>
				<view class="item-content">
					<text class="item-value">{{ cacheSize }}</text>
					<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
				</view>
			</view> -->

			<!-- 用户协议 -->
			<view class="profile-item" @click="viewUserAgreement">
				<view class="item-label">用户协议</view>
				<view class="item-content">
					<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
				</view>
			</view>

			<!-- 关于我们 -->
			<view class="profile-item" @click="viewAbout">
				<view class="item-label">关于我们</view>
				<view class="item-content">
					<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
				</view>
			</view>
		</view>

		<!-- 退出登录按钮 -->
		<view class="logout-section">
			<uv-button type="primary" size="large" @click="logout" :loading="logoutLoading">
				退出登录
			</uv-button>
		</view>

		<!-- 编辑弹窗 -->
		<uv-popup ref="editPopup" mode="center" @close="closeEditModal" :round="10">
			<view class="edit-modal">
				<view class="modal-title">
					编辑{{
            editType === "username"
              ? "用户名"
              : editType === "phone"
              ? "电话"
              : editType === "email"
              ? "邮箱"
              : ""
          }}
				</view>
				<uv-input v-model="editValue" :placeholder="getPlaceholder()" :type="
            editType === 'phone'
              ? 'number'
              : editType === 'email'
              ? 'email'
              : 'text'
          " border="bottom" clearable></uv-input>
				<view class="modal-actions">
					<uv-button type="default" @click="closeEditModal">取消</uv-button>
					<uv-button type="primary" @click="saveEdit">保存</uv-button>
				</view>
			</view>
		</uv-popup>

		<!-- 头像选择弹窗 -->
		<uv-popup ref="avatarSheet" mode="bottom" @close="closeAvatarSheet" :round="10">
			<view class="avatar-sheet">
				<view class="sheet-header">
					<view class="sheet-title">选择头像</view>
				</view>
				<view class="sheet-actions">
					<view class="action-item" @click="selectAvatarSource('camera')">
						<uv-icon name="camera-fill" size="24" color="#4285f4"></uv-icon>
						<text class="action-text">拍照</text>
					</view>
					<view class="action-item" @click="selectAvatarSource('album')">
						<uv-icon name="photo-fill" size="24" color="#4285f4"></uv-icon>
						<text class="action-text">从相册选择</text>
					</view>
				</view>
				<view class="sheet-cancel">
					<uv-button type="default" size="large" @click="closeAvatarSheet">
						取消
					</uv-button>
				</view>
			</view>
		</uv-popup>

		<uv-popup ref="popup" mode="center" :closeOnClickOverlay="false" :round="10">
			<view class="bind-phone-modal">
				<view class="modal-header">
					<view class="modal-title">换绑手机号</view>
					<view class="modal-subtitle">请输入换绑手机号信息</view>
				</view>

				<view class="modal-form">
					<uv-form :model="bindPhoneInfo" :rules="bindPhoneRules" ref="bindPhoneForm">
						<uv-form-item prop="phone">
							<uv-input v-model="bindPhoneInfo.phone" placeholder="请输入手机号" type="number" maxlength="11"
								border="surround"></uv-input>
						</uv-form-item>
						<uv-form-item prop="code">
							<uv-input v-model="bindPhoneInfo.code" placeholder="请输入验证码" border="surround">
								<template v-slot:suffix>
									<uv-code ref="bindCodeRef" @change="bindCodeChange" seconds="60"
										changeText="X秒重新获取"></uv-code>
									<text style="color: #4d82fd; font-size: 12px" @click="getBindCode">
										{{ bindCodeTips }}
									</text>
								</template>
							</uv-input>
						</uv-form-item>
					</uv-form>
				</view>

				<view class="modal-actions">
					<uv-button type="default" @click="closeBindPhoneModal" customStyle="margin-right: 12px;">
						取消
					</uv-button>
					<uv-button type="primary" @click="confirmBindPhone" :loading="bindingPhone">
						确认绑定
					</uv-button>
				</view>
			</view>
		</uv-popup>
	</view>
</template>

<script setup>
	import {
		ref,
		onMounted
	} from "vue";
	import {
		onShow
	} from "@dcloudio/uni-app";
	import {
		useAuthStore,
		useUserStore
	} from "@/store";
	import RPC from "@/utils/request";

	const authStore = useAuthStore();
	const userStore = useUserStore();

	// 响应式数据
	const userInfo = ref({
		avatar: "/static/imgs/avatar.png",
		username: "张三",
		phone: "15825556676",
		email: "235382903@qq.com",
	});

	const cacheSize = ref("36MB");
	const logoutLoading = ref(false);
	const editType = ref("");
	const editValue = ref("");
	const editPopup = ref(null);
	const avatarSheet = ref(null);

	// 更换头像
	const changeAvatar = () => {
		console.log("点击更换头像");
		avatarSheet.value.open();
	};

	// 关闭头像选择弹窗
	const closeAvatarSheet = () => {
		avatarSheet.value.close();
	};

	// 选择头像来源
	const selectAvatarSource = (source) => {
		console.log("选择头像方式:", source);
		avatarSheet.value.close();

		uni.chooseImage({
			count: 1,
			sizeType: ["compressed"],
			sourceType: source === "camera" ? ["camera"] : ["album"],
			success: (res) => {
				const tempFilePath = res.tempFilePaths[0];
				console.log("选择图片成功:", tempFilePath);

				// 这里应该上传图片到服务器
				// uploadAvatar(tempFilePath)

				// 临时更新头像显示
				userInfo.value.avatar = tempFilePath;

				uni.showToast({
					title: "头像更新成功",
					icon: "success",
				});
			},
			fail: (err) => {
				console.error("选择图片失败:", err);
				uni.showToast({
					title: "选择图片失败",
					icon: "none",
				});
			},
		});
	};

	// 编辑用户名
	const editUsername = () => {
		editType.value = "username";
		editValue.value = userStore.userInfo.username;
		editPopup.value.open();
	};

	// 编辑电话
	const editPhone = () => {
		editType.value = "phone";
		editValue.value = userStore.userInfo.phone;
		editPopup.value.open();
	};

	// 编辑邮箱
	const editEmail = () => {
		editType.value = "email";
		editValue.value = userStore.userInfo.email;
		editPopup.value.open();
	};

	// 获取输入框占位符
	const getPlaceholder = () => {
		switch (editType.value) {
			case "username":
				return "请输入用户名";
			case "phone":
				return "请输入手机号";
			case "email":
				return "请输入邮箱地址";
			default:
				return "请输入";
		}
	};

	// 关闭编辑弹窗
	const closeEditModal = () => {
		editPopup.value.close();
		editType.value = "";
		editValue.value = "";
	};

	// 保存编辑
	const saveEdit = async () => {
		if (!editValue.value.trim()) {
			uni.showToast({
				title: "请输入内容",
				icon: "none",
			});
			return;
		}
		if (editType.value === 'username') {
			RPC.post('/user/update', {
				id: userStore.userInfo.id,
				username: editValue.value
			}).then(() => {
				uni.showToast({
					title: "保存成功",
					icon: "success",
				});
				userStore.setUserInfo({
					...userStore.userInfo,
					username: editValue.value
				})
				closeEditModal()
			})
		}
		if (editType.value === 'email') {
			RPC.post('/user/update', {
				id: userStore.userInfo.id,
				email: editValue.value
			}).then(() => {
				uni.showToast({
					title: "保存成功",
					icon: "success",
				});
				userStore.setUserInfo({
					...userStore.userInfo,
					email: editValue.value
				})
				closeEditModal()
			})
		}

		// try {
		//   // 调用更新用户信息API
		//   // await RPC.post('/api/user/update', {
		//   //   [editType.value]: editValue.value
		//   // })

		//   // 更新本地数据
		//   userInfo.value[editType.value] = editValue.value;

		//   uni.showToast({
		//     title: "保存成功",
		//     icon: "success",
		//   });

		//   closeEditModal();
		// } catch (error) {
		//   console.error("保存失败:", error);
		//   uni.showToast({
		//     title: "保存失败，请重试",
		//     icon: "none",
		//   });
		// }
	};

	// 清除缓存
	const clearCache = () => {
		uni.showModal({
			title: "清除缓存",
			content: "确定要清除应用缓存吗？",
			success: (res) => {
				if (res.confirm) {
					uni.showLoading({
						title: "清除中...",
					});

					// 模拟清除缓存
					setTimeout(() => {
						uni.hideLoading();
						cacheSize.value = "0MB";
						uni.showToast({
							title: "缓存清除成功",
							icon: "success",
						});
					}, 1500);
				}
			},
		});
	};

	// 查看用户协议
	const viewUserAgreement = () => {
		uni.navigateTo({
			url: "/pagesA/user-agreement/user-agreement",
		});
	};

	// 查看关于我们
	const viewAbout = () => {
		//   uni.navigateTo({
		//     url: "/pagesA/about/about",
		//   });
	};

	// 退出登录
	const logout = () => {
		uni.showModal({
			title: "退出登录",
			content: "确定要退出登录吗？",
			success: (res) => {
				if (res.confirm) {
					logoutLoading.value = true;

					// 模拟退出登录
					setTimeout(() => {
						authStore.signOut();
						logoutLoading.value = false;

						// 清除用户信息和token
						// authStore.logout()

						uni.showToast({
							title: "已退出登录",
							icon: "success",
						});

						// 跳转到登录页
						uni.reLaunch({
							url: "/pages/login/login",
						});
					}, 1000);
				}
			},
		});
	};

	// 加载用户信息
	const loadUserInfo = async () => {
		try {
			// 调用获取用户信息API
			// const result = await RPC.get('/api/user/info')
			// userInfo.value = result.data
		} catch (error) {
			console.error("加载用户信息失败:", error);
		}
	};

	// 计算缓存大小
	const calculateCacheSize = () => {
		// 实际项目中应该计算真实的缓存大小
		// const size = await getCacheSize()
		// cacheSize.value = formatSize(size)
	};

	onMounted(() => {
		loadUserInfo();
		calculateCacheSize();
	});

	onShow(() => {
		// 页面显示时刷新用户信息
		loadUserInfo();
	});

	const popup = ref(null);
	const bindingPhone = ref(false);
	const bindCodeTips = ref("获取验证码");
	const bindCodeRef = ref(null);
	const bindPhoneForm = ref(null);
	const bindPhoneInfo = ref({
		phone: "",
		code: "",
	});
	
	const changePhone = () => {
		bindPhoneInfo.value = {
			phone: "",
			code: "",
		}
		popup.value.open()
	}
	const bindPhoneRules = ref({
		phone: [{
				required: true,
				message: "请输入手机号",
				trigger: ["blur", "change"],
			},
			{
				pattern: /^1[3-9]\d{9}$/,
				message: "请输入正确的手机号",
				trigger: ["blur", "change"],
			},
		],
		code: {
			required: true,
			message: "请输入验证码",
			trigger: ["blur", "change"],
		},
	});
	
	const bindCodeChange = (text) => {
		bindCodeTips.value = text;
	};
	
	const closeBindPhoneModal = () => {
		popup.value.close();
		bindPhoneInfo.value = {
			phone: "",
			code: "",
		};
		bindCodeTips.value = "获取验证码";
	};
	
	const confirmBindPhone = async () => {
		try {
			await bindPhoneForm.value.validate();
	
			bindingPhone.value = true;
	
			// 调用绑定手机号API
			RPC.post('/user/bind_phone', {
				phone: bindPhoneInfo.value.phone,
				code: bindPhoneInfo.value.code,
				token: authStore.accessToken
			}).then((res) => {
				console.log('bind_phone', res)
				bindingPhone.value = false;
				uni.showToast({
					title: "换绑成功",
					icon: "success",
				});
				popup.value.close()
				RPC.post('/user/info', {
						token: authStore.accessToken,
					})
					.then((res) => {
						userStore.setUserInfo(res)
					})
			})
		} catch (error) {
			console.error("换绑手机号失败:", error);
			bindingPhone.value = false;
		}
	};
	
	const getBindCode = () => {
		if (!bindPhoneInfo.value.phone) {
			uni.showToast({
				title: "请输入手机号",
				icon: "none",
			});
			return;
		}
	
		if (!/^1[3-9]\d{9}$/.test(bindPhoneInfo.value.phone)) {
			uni.showToast({
				title: "请输入正确的手机号",
				icon: "none",
			});
			return;
		}
	
		if (bindCodeRef.value.canGetCode) {
			uni.showLoading({
				title: "正在获取验证码",
			});
			// 调用发送验证码API
			RPC.post('/user/bind_phone/send_code', {
				phone: bindPhoneInfo.value.phone,
				token: authStore.accessToken
			}).then(() => {
				uni.hideLoading()
				uni.showToast({
					title: '验证码已发送',
					icon: 'success'
				})
				bindCodeRef.value.start()
			}).catch(() => {
				uni.hideLoading()
				uni.showToast({
					title: '发送失败，请重试',
					icon: 'none'
				})
			})
		} else {
			uni.showToast({
				title: "倒计时结束后再发送",
				icon: "none",
			});
		}
	};
</script>

<style lang="scss" scoped>
	.container {
		font-size: 14px;
		min-height: 100vh;
		background-color: #f8f8f8;
		padding: 16px;
	}

	.profile-section,
	.app-section {
		background: white;
		border-radius: 12px;
		margin-bottom: 16px;
		overflow: hidden;

		.profile-item {
			display: flex;
			align-items: center;
			justify-content: space-between;
			padding: 16px;
			border-bottom: 1px solid #f0f0f0;

			&:last-child {
				border-bottom: none;
			}

			.item-label {
				font-size: 16px;
				color: #333;
				font-weight: 500;
			}

			.item-content {
				display: flex;
				align-items: center;
				gap: 8px;

				.avatar {
					width: 40px;
					height: 40px;
					border-radius: 50%;
				}

				.item-value {
					font-size: 14px;
					color: #666;
				}
			}
		}
	}

	.logout-section {
		margin-top: 32px;
	}

	.edit-modal {
		width: 300px;
		padding: 24px;

		.modal-title {
			font-size: 18px;
			font-weight: bold;
			color: #333;
			text-align: center;
			margin-bottom: 20px;
		}

		.modal-actions {
			display: flex;
			gap: 12px;
			margin-top: 20px;

			.uv-button {
				flex: 1;
			}
		}
	}

	.avatar-sheet {
		padding: 20px;

		.sheet-header {
			text-align: center;
			margin-bottom: 20px;

			.sheet-title {
				font-size: 18px;
				font-weight: bold;
				color: #333;
			}
		}

		.sheet-actions {
			display: flex;
			justify-content: space-around;
			margin-bottom: 20px;

			.action-item {
				display: flex;
				flex-direction: column;
				align-items: center;
				gap: 8px;
				padding: 20px;
				border-radius: 8px;
				background: #f8f9fa;
				min-width: 100px;
				transition: all 0.3s;

				&:active {
					background: #e9ecef;
					transform: scale(0.95);
				}

				.action-text {
					font-size: 14px;
					color: #333;
				}
			}
		}

		.sheet-cancel {
			margin-top: 10px;
		}
	}
	.bind-phone-modal {
		width: 320px;
		padding: 24px;
	
		.modal-header {
			text-align: center;
			margin-bottom: 24px;
	
			.modal-title {
				font-size: 18px;
				font-weight: bold;
				color: #333;
				margin-bottom: 8px;
			}
	
			.modal-subtitle {
				font-size: 14px;
				color: #666;
			}
		}
	
		.modal-form {
			margin-bottom: 24px;
	
			.uv-form-item {
				margin-bottom: 16px;
			}
		}
	
		.modal-actions {
			display: flex;
			gap: 12px;
	
			.uv-button {
				flex: 1;
			}
		}
	}
</style>X8x/ 100644 generate-record.vue Sn}ֶΡ e|xXo|?L	ΊwkCVQֻw^PJBUЖǔ]Oz73<gf>ƽgxj.^CgFQ[?6]YͿhݭ{Hٲ5VںF1\OVhcݴb7liZwAt\k;
:c7V'T Ъa.>BZk5"ץZY"Y0kϞN9vr{%Iq=|7{ezXQc6=xؒ믿J.H!qBo!|G'psόگ/-鋋D5Ҵp(m+*{:>sǱΏb3N"=6; >Wa 16vMO"SE<S"At:E~tlA(3v݇_'|j?g_|§?zYFɐI&xm=3h(règz&a+>XSN".'DrGnOD+HYXBZ|<`w\_N7nImay)}~w{[AqFZ
"ۍeӿe430䥚̫+*X1KB
aw)>h^Dw6o>>OAU<	r(~$T8wlS:Ҳ	q=ݾ$۸v2mxt0$^$-^&cBV/5葜#
E8N0FDvI?ć!r k$cGF^ogBDNFL`=x"`8vBuqlZݟÞavF⻺ְ1bďyԆR?HI~~}Si~&eZ`}H83֬h{8>8$F	'P{1#ˁ/p$@W'k[B91
`4
a`>ݤf -(jtCo+12"Ϙuqؐ]y6%R7ov|]ӝo/=^'kXn
فmL05yFȌ.J-' 0IIPI%[?F -1^LXL-	}{` z1zvlRtg[}bS{*.n]umQ?9=<|_#VĲp)a m]c/9?;Χ/]x߇xHEr7˕S~V9LAY@-8+fY:Ħ]RH`czo6'T "\j$̸KԉRO39	qidm\h'i&zUg(,iVz=uz_"zjNEOjTLq*|4NjM^Hq)7dX9b^TFΝݭM|$Lcni.µ?bKe*ݼSh/I<?A=g <McqߤD+\GE@ijz	9uydE:RT&p k	\v{CJppROc` !|KEQ#QvPi"TQE -ڈ0ri[PM<#P)D$!P~"@'#6Ħ
bmc۪]/p]aWrˌn`>\ W)[%ܜ.сzri1207oA1(x(7K[2\b@.r*N&wmg̸OuV;E8e?eUz+7Ppॶ&{~7ʾqgqh$l+$vO ڋ :m-B/}i2=Ś2lj蹾5i\Yy-v̑?Mf!<3^}c[2!#bj?W,TfO`*FPq-xOaWՂlcV*#~(O_dV$$s܁k3f>?bd2,KU>P|bQ-/$s/,М`5iJ_-|8?&slsԬp^C<[L3FoMOkjNΔ8Sqܤqe*BQ|TϹV y<)JJq[LMݔ	)ll4"ȣicu쏒(v.ʚ\0)2͐`
U$pn)y(ZhhSSTE*O"w0x, 100644 order-detail.vue Eq `8j_'ǅa2S<˽x2<template>
  <view class="order-detail-page">
    <!-- 顶部状态栏 -->
    <view class="status-bar">
      <text class="status-text">交易成功</text>
    </view>

    <!-- 主要内容区域 -->
    <view class="content-container">
      <!-- 用户信息卡片 -->
      <view class="user-card">
        <view class="user-info">
          <image class="avatar" src="/static/imgs/avatar.png" mode="aspectFill"></image>
          <view class="user-details">
            <view class="user-name-row">
              <text class="user-name">{{ orderDetail.userName }}</text>
              <view class="vip-badge">
                <text class="vip-text">V</text>
              </view>
            </view>
            <text class="vip-expire">VIP有效时间：{{ orderDetail.vipExpireTime }}</text>
          </view>
        </view>
      </view>

      <!-- 订单详情 -->
      <view class="order-info">
        <view class="info-row">
          <text class="label">订单编号：</text>
          <text class="value">{{ orderDetail.orderNo }}</text>
          <text class="copy-btn" @tap="copyOrderNo">复制</text>
        </view>
        
        <view class="info-row">
          <text class="label">用户名称：</text>
          <text class="value">{{ orderDetail.realName }}</text>
        </view>
        
        <view class="info-row">
          <text class="label">用户ID：</text>
          <text class="value">{{ orderDetail.userId }}</text>
        </view>
        
        <view class="info-row">
          <text class="label">订单类型：</text>
          <text class="value">{{ orderDetail.orderType }}</text>
        </view>
        
        <view class="info-row">
          <text class="label">订单金额：</text>
          <text class="value price">¥{{ orderDetail.originalAmount }}</text>
        </view>
        
        <view class="info-row">
          <text class="label">折扣金额：</text>
          <text class="value discount">-¥{{ orderDetail.discountAmount }}</text>
        </view>
        
        <view class="info-row">
          <text class="label">实付金额：</text>
          <text class="value price">¥{{ orderDetail.paidAmount }}</text>
        </view>
        
        <view class="info-row">
          <text class="label">支付时间：</text>
          <text class="value">{{ orderDetail.payTime }}</text>
        </view>
      </view>

      <!-- 联系客服按钮 -->
      <view class="contact-service">
        <button class="service-btn" @tap="contactService">联系客服</button>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'

// 订单详情数据
const orderDetail = ref({
  userAvatar: '/static/images/default-avatar.png',
  userName: '尊敬的包年会员',
  vipExpireTime: '2026/05/15',
  orderNo: 'ORD20230515001',
  realName: '张三',
  userId: 'U12345678',
  orderType: '线上交易 包年会员',
  originalAmount: '1200.00',
  discountAmount: '200.00',
  paidAmount: '1000.00',
  payTime: '2025-05-15 10:30'
})

onMounted(() => {
  // 获取订单详情
  getOrderDetail()
})

// 获取订单详情
const getOrderDetail = () => {
  // 这里可以根据路由参数获取订单ID，然后调用API获取详情
  const pages = getCurrentPages()
  const currentPage = pages[pages.length - 1]
  const orderId = currentPage.options.orderId
  
  if (orderId) {
    // 调用API获取订单详情
    // fetchOrderDetail(orderId)
  }
}

// 复制订单号
const copyOrderNo = () => {
  uni.setClipboardData({
    data: orderDetail.value.orderNo,
    success: () => {
      uni.showToast({
        title: '订单号已复制',
        icon: 'success'
      })
    }
  })
}

// 联系客服
const contactService = () => {
//   uni.showActionSheet({
//     itemList: ['在线客服', '电话客服'],
//     success: (res) => {
//       if (res.tapIndex === 0) {
//         // 跳转到在线客服页面
//         uni.navigateTo({
//           url: '/pages/customer-service/customer-service'
//         })
//       } else if (res.tapIndex === 1) {
//         // 拨打客服电话
        uni.makePhoneCall({
          phoneNumber: '400-123-4567'
    //     })
    //   }
    // }
  })
}
</script>

<style lang="scss" scoped>
.order-detail-page {
    min-height: 100vh;
  background-color: #f8f8f8;;
}

.status-bar {
  padding: 20px 10px 50px;
  background: linear-gradient(180deg, #8B9DC3 0%, #DFE3EC 100%);
  
  .status-text {
    font-size: 18px;
    font-weight: bold;
    color: #FFFFFF;
  }
}

.content-container {
  padding: 0 32rpx;
  margin-top: -30px;
}

.user-card {
  background: #FFFFFF;
  border-radius: 24rpx;
  padding: 32rpx;
  margin-bottom: 32rpx;
  
  .user-info {
    display: flex;
    align-items: center;
    
    .avatar {
      width: 120rpx;
      height: 120rpx;
      border-radius: 60rpx;
      margin-right: 24rpx;
    }
    
    .user-details {
      flex: 1;
      
      .user-name-row {
        display: flex;
        align-items: center;
        margin-bottom: 12rpx;
        
        .user-name {
          font-size: 36rpx;
          font-weight: bold;
          color: #333333;
          margin-right: 16rpx;
        }
        
        .vip-badge {
          width: 48rpx;
          height: 48rpx;
          background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          
          .vip-text {
            font-size: 24rpx;
            font-weight: bold;
            color: #FFFFFF;
          }
        }
      }
      
      .vip-expire {
        font-size: 28rpx;
        color: #999999;
      }
    }
  }
}

.order-info {
  background: #FFFFFF;
  border-radius: 24rpx;
  padding: 32rpx;
  margin-bottom: 60rpx;
  
  .info-row {
    display: flex;
    align-items: center;
    padding: 24rpx 0;
    border-bottom: 1rpx solid #F5F5F5;
    
    &:last-child {
      border-bottom: none;
    }
    
    .label {
      font-size: 32rpx;
      color: #666666;
      width: 180rpx;
    }
    
    .value {
      flex: 1;
      font-size: 32rpx;
      color: #333333;
      text-align: right;
      
      &.price {
        color: #333333;
        font-weight: bold;
      }
      
      &.discount {
        color: #FF4444;
      }
    }
    
    .copy-btn {
      font-size: 28rpx;
      color: #4A90E2;
      margin-left: 16rpx;
      padding: 8rpx 16rpx;
      border: 1rpx solid #4A90E2;
      border-radius: 8rpx;
    }
  }
}

.contact-service {
  padding: 0 32rpx 60rpx;
  
  .service-btn {
    width: 100%;
    height: 96rpx;
    background: #3F70FF;
    border-radius: 48rpx;
    border: none;
    font-size: 36rpx;
    font-weight: bold;
    color: #FFFFFF;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
</style>Sk1x( 100644 recharge.vue W/)KT)Me&xYkpו.H'HGB3ҠaR@l6.5#{ZL@` 6m(r O[ڤJ=e7V*ک439vp9-}Aǋ>2ؗ:/!,z
r
h΃?Z#k,do(A^󠞞"+*1%<b5cu5\.a	lkl٘ﵵl=ͣGb(-9|zқХco#p`͖#?E.d?Cd%n9Ay[ÉrPxTRu9W2G8qg&l#6[C"6s'ۄl06JDfB{:@]>DHϗ׎Kg E5H-KȦdd.R[A"S'-D,
=^ZgeAhD	DAR(EL$3	Ȩb+,Ge8
T1֨R#(
pu$6FAC1"r~~8,xͻǠf	zʲ]뵅&>Ūtg")YlI.}ytvErͅ.WHyk,!saG^9&בᩰPW,4YNAuA]QHjbV#^1B+%#s>GΞVO}>dn̉wB}܉ϜQf % ̇1j6%ee<g57Xf¬.N-ph<XkU?]bt???͝_p5v!3>0c/Yx/ 4oގ6cKjjJ0Oqa@/~$E\jZKynʆg2չ޻No_GqR\۟/ܟ[xtI=~ʔ^PY[sYkM!sӋgpnލ}t?65tx	uzrqod;ٔoĮ^x~Y>~⭇8  G7 ,P;:ьh8X~EZAu?(HH[%JZ&P=h(ZߠJ>To+miD5=l(z 5P1ip}"ܠ6^d5-躞5ph> ֵBz;%XUg:x[J`OILgBA]MS !Ne2a=1\Gi틤);8<E#@j؊Q>H;fYK7YYZL4pՊ]s3&OJK3SycZlø]MO-CƅLhKIddtn7ڗ+DHbY}/vIs܌qetZD!q΢zV_όprߍY>,DEQY:ySMzHN^o3oɀΙLa%dPFX(mM*3 (^sd\)QHS;h^kܠ}t&<ӒКaPD3ݫyS?V'dfԌs? R8˜^AVKnFO5.özE'wNşKUhj+p|,?kgoyn\F}[*_T!/C|$KC60nMf5.<,s#RΉ7΂]	WKK\v(^CVo z0yXbxΪgI{rZ}몇{JvO߾vUYJ 2,	u>YvM=ɻ깋;g@Cv:C**_cG `}HLUIۤkp##	jCcS[jWׁgj-%LMx:@H/9%
XUS^΃j@*WSSMW_
$gĈ(ct	mzyD#KAA.qϤGS'S[]#&ʓ(@aztȸi	kG	> $=u<ƹS^%S	lm~r9y(5$̠4gxF>|@oSވ;"UfF#z!=R<LZ1H#D5!ƹ}2F'Ҩi{4Zǟ;tYyu`MODٷb﻾LjEN	14ㅣ3sR@f=TI Z?Q|FCt:MZϝDT>xfz2{?uc(Js"OօBC!Dr5G!dӨp6a/Peӿ6@ZPf};V 6`v@?L$s83HD-\gZcg}}?"f-Ap~9YPD8؛ym{(L>@JߖE=P&&Lt0V~>! h
oг;0*fp^C/R}b	n߽g0t˾u>+qGyÚ( :+7(NGrlюhJ$;52ۆ~2{98?K#]8({tjRFSse!2ģz$u`lL4+M
'.{k񥙟@̹LC@
7[{bZH&O#KwUIX?&{,-ae{muukz\r]UXXzYP:X|dTTXy´ܵ1iNY䁣>9lʲ֥.Αdۨ=<$cbw$?6yF3|aM}<Ɋa2)V'&U,qնy̍͸y5V}"-:Ia@'eڊ godDCБߟ~ws)ҐlF63 9yahX.G1k޲ I;
3"kqծiZt
WyM?'o*׻6@uJ-ML&S]V.Uːs1YI!3Dfu̎"]m{*aIqৌ\5"]s!A`5[᫽R_a9@ԙiv\ھa394djz8j[[[	DB;H>	vHR{!M`Acr/iCCx:B	!)/-#<'61 !Lʍ`P5)/ C2ZEB-dW}qP+_u'hKӖ`_5<o\BȒ&p`$^Oc;`[-{sK;N[=e}n@~kݚ98F_3+><FTɛ@E%X ms2UbtdJF)2hO$Ӭ}m_|+/[70_W7V,[WdQ$)ﵖd2vT@ZmDĒ8-aW|+Нw{*L(
=GDdv>UBkdV#i'ʼcun35خ||eÌ*O{ÈM)3h[T.D
>	&z$Z D>1e£Q#ʸ`Ux^ xpay#xpayxpay;
xpayKxpay7xpay' : 'alipay'"z xpay*x. 100644 user-agreement.vue UTܽ:z=X|ux
0<template>
	<view class="container">
		<HeaderCustom title="用户协议" :showBack="true"></HeaderCustom>
		<div class="contentBox">
			<div class="part">
				一、总则
			</div>
			<div class="part">
				<div class="line">1、用户在注册及使用前请认真阅读本协议，确保充分理解本协议中所有条款。除非您接受本协议所有条款，否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为将视为无条件接受本协议所有条款的约束。</div>
				<div class="line">2、除非另有明确规定，本产品所推出的新功能、新服务均无条件的使用本协议。</div>
				<div class="line">3、我公司保留在任何时候修改本协议条款的权利，且无需另行通知。在我公司修改协议条款后，如果您不接受修改后的条款，请立即停止使用本产品提供的服务，继续使用本产品提供的服务将被视为接受修改后的协议。</div>
			</div>
			<div class="part">
				二、免责声明
			</div>
			<div class="part">
				<div class="line">1、对于经由本产品服务而传送的内容，我公司不保证前述内容的正确性、完整性或品质。用户在接受有关服务时，有可能会接触到令人不快、不适当或令人厌恶的内容。在任何情况下，我公司均不对任何内容负责，包括但不限于任何内容发生任何错误或纰漏以及衍生的任何损失或损害。用户使用上述内容、应自行承担风险。</div>
				<div class="line">2、用户明确同意其使用本产品所存在的风险及其后果将完全由其自己承担，我公司对用户不承担任何责任。如因用户违反有关法律、法规或本协议项下的任何条款而给任何其他第三人造成损失，用户同意承担由此造成的损害赔偿责任。</div>
				<div class="line">3、我公司尊重并保护用户的个人隐私权。但因恶意的网络攻击等行为及其他无法控制的情形，导致用户隐私信息泄露的，用户同意我公司不承担任何责任。</div>
				<div class="line">4、对于因电信系统或互联网网络故障、计算机故障、计算机系统问题或其它任何不可抗力原因而产生损失，我公司不承担任何责任，但将尽力减少因此给用户造成的损失和影响。</div>
			</div>
		</div>
	</view>
</template>

<script setup>
	import {
		ref
	} from "vue";
	import HeaderCustom from '/components/HeaderCustom/HeaderCustom.vue'
</script>

<style lang="scss" scoped>
	.container {
		font-size: 14px;
	}

	.contentBox {
		padding: 20px;
		color: #000;
		font-weight: 400;
		line-height: 22px;
		.part {
			margin-bottom: 20px;
		}
	}
</style>XAj]x
 *q^
Ʈxn 100644 index.js mS锋	ި՘%100644 permission.js x:<RKS?:51100644 ui.js 10=uR|Ts.x{import { setupI18n } from "@/locale";
import { setupStore } from "@/store";
import { setupPermission } from "./permission";
import { setupUI } from "./ui";

export default {
  install(app) {
    // UI扩展配置
    app.use(setupUI);
    // 状态管理
    app.use(setupStore);
    // 国际化
    app.use(setupI18n);
    // 路由拦截
    app.use(setupPermission);
  },
};

ѹkxTNG}߯XQEۇ<M

S5=ڻ,",ʐ8N	$PڂmS)л;:6s̽sgDR7Zŝ&GjND}tߌ}8,l2MUE0Sh(pO"F`DPeQn`^J1+MI\$	٥KZܖsV'BTLqa@
<xЬnQ%@BD/YBƱq}NЍp¢@e*8N	)34$!^)Xy%eCNED
׼eh&%?(Qu)9DC3@Dnyi=ڷ=֖S%=ȃ6w[
}xݸЬ71!*CIen?cź'xˊWNeOT5MgjZ4nŰ6Rs=}gRMoƴZ{¸LW!˜/*+ѫEiҍ&pvZ%V>ZV_[&jhao9;u.?1Oةyx|s|R_`ᛋX1^5»N=԰[6숐	d䊀-?^`k,%l.$DigTγjKӫjUyp6TM"K[dn:Ww<}(I\i۩՜^geў}ҤVAvwrʶ묒xa> kyI7k]VOlVx݇MWd#z`vݸ*'x?ׅBHҼ+IУLbѸn!&IUR58	RH"O	ϼè73wԝli*#Uu:"yEB3{lo7@g1g~QrȦy-4t/cךZ/SCFDDLGku(r,?
~U0OAt_8xpimport uvUI from "@/uni_modules/uv-ui-tools";

export function setupUI(app) {
  // UV扩展配置 https://www.uvui.cn/components/setting.html
  app.use(uvUI);
  // 调用setConfig方法，方法内部会进行对象属性深度合并，可以放心嵌套配置
  uni.$uv.setConfig({
    // 修改$uv.config对象的属性
    config: {
      // 修改默认单位为rpx，相当于执行 uni.$uv.config.unit = 'rpx'
      // 用于在传入组件大小参数为数值时，指定默认单位
      unit: "px",
    },
    // 修改$uv.props对象的属性
    props: {
      // 修改uv-text组件的size参数的默认值，注意：默认值都要用default声明
      text: {
        color: {
          default: "#303133",
        },
      },
      // 其他组件属性配置，具体的参数名称可以去每个组件的props.js中进行查看
      // ......
    },
  });
}

export const $uv = uni.$uv;
x$ 100644 index.js R$)`Bb7P?x!import pagesJson from "@/pages.json";

// 路径常量
export const HOME_PATH = "/pages/index/index";
export const LOGIN_PATH = "/pages/login/login";
export const ERROR404_PATH = "/pages/404/404";

/**
 * 解析路由地址
 * @param {object} pagesJson
 * @returns [{"path": "/pages/index/index","needLogin": false},...]
 */
function parseRoutes(pagesJson = {}) {
  if (!pagesJson.pages) {
    pagesJson.pages = [];
  }
  if (!pagesJson.subPackages) {
    pagesJson.subPackages = [];
  }

  function parsePages(pages = [], rootPath = "") {
    const routes = [];
    for (let i = 0; i < pages.length; i++) {
      routes.push({
        path: rootPath ? `/${rootPath}/${pages[i].path}` : `/${pages[i].path}`,
        needLogin: pages[i].needLogin === true,
      });
    }
    return routes;
  }

  function parseSubPackages(subPackages = []) {
    const routes = [];
    for (let i = 0; i < subPackages.length; i++) {
      routes.push(...parsePages(subPackages[i].pages, subPackages[i].root));
    }
    return routes;
  }

  return [
    ...parsePages(pagesJson.pages),
    ...parseSubPackages(pagesJson.subPackages),
  ];
}
export const routes = parseRoutes(pagesJson);

/**
 * 当前路由
 * @returns {String}
 */
export function currentRoute() {
  const pages = getCurrentPages();
  if (pages.length === 0) {
    return;
  }
  const currentPage = pages[pages.length - 1];
  return currentPage?.$page?.fullPath || currentPage.route;
}

/**
 * 去除查询字符串
 * @param {String} path
 * @returns
 */
export function removeQueryString(path = "") {
  return path.split("?")[0];
}

/**
 * 路径是否存在
 * @param {String} path
 * @returns
 */
export function isPathExists(path = "") {
  const cleanPath = removeQueryString(path);
  return routes.some((item) => item.path === cleanPath);
}

/**
 * 是否是tabbar页面路径
 * @param {String} path
 * @returns
 */
export function isTabBarPath(path = "") {
  const cleanPath = removeQueryString(path);
  return (
    pagesJson.tabBar?.list?.some(
      (item) => `/${item.pagePath}` === cleanPath
    ) === true
  );
}
ix }100644 404.png 0)~%\40000 imgs ].Wm Җ WO40000 json y.)E:ƾy"X-40000 tabbar )$7ume/y1hx cHgҶx&!މPNG

   IHDR  ,  ,   N~G   gAMA  a   sRGB    DeXIfMM *    i                         ,      ,    `   PLTEGpLQp+q   tRNS >?BET1@CIR@K=YSDL[LQDGH>FO<V]NN?^JP_AF\MTPHaA?JJXXVAGWW=
ZZ1QICbIq.4_<LC>,1"N8l\'Z+$yG70j:mHTwh4`b<w;롰Br}&9qILe/igd_`ȕY͌JSP\U6MrXc"  jIDATxOyEi2}%pG9X`	]AHW.HSW=E%.ܡDP}p7CN;3môm2~7e:3"                                                F3%ſ,@CVHZ~%"@s=PΟR	dd nyRoS"7-'#_.KV~~\F\#ᐕh~1_&X|Pk[2ZxhKi륄/W4%Vֳs|Ɂ+!)_mf"579)QG[jmry*$k8$NLUIv%(-|W*uS9T}J`tH
UJ`Xd2!C[	:`a7<muRm<m|m	 $s	lր +qnWCOu<k[*H@&B迏\ŗid۶Cn%6RI)&
ՌE'r)IrzSvF$T']w?CEӠGnhJqitvu߰=W+ǠrcQfhY3ranĝ=K~"͵K-j)ӑB-[R{LQJU=g/{~5yޣ?_^|t(-.o[o*졪zZ%*ӟH~Z"~;%53^Q7K&cSPUZ{U1hn&c5=]7!X,kYrCjcotޚ28Uk&+r=oςϺQJ:~XQ&ю&Mڒ]_-f]z佬᪷w4yn@6eGOeK0fRt%!jZtxߴKk?Ҧӵfo72𲞹%a/$'ǲz*O}u =?נ(
TO^"^<gi!}bvcؗ@'Ou[#?LOEjd@Ax]66hLUYF76}='S4!0Ț;!>zz(Tʳpv)#fӠD}W&9'y3DGnp^{
q/#	1\f21rL+g.mڝlJe7''5KUQ?Q;nN'D>mj?opo*[?VE9@rٚ+/*`#;ذF°35	`L|``n=t.wz
`+m/qɹ}%>Ey|mk53"fe"~Nzae#@ Ch˕z! ~Fa7ѱ]q2
wh،!AGW^HHݟɕ+D~(dFWXO2왛Ce^
I*Ս3UQn4T ,߮u۾-lώlYPlPh4kFfT;$ֈϋ{Hmn/FH붡~2ū-
T6VV6>nʏ{2keeS
IZP>U\%mЭ	#g:fHGy0cKVvz8pdk 1ª{Xخ0\]u"vJ:v;tһm?1p(Tc %W[Lˉ28 #t;iK4Q8JX8/{zpʖ/8!Dc8qv3zeAOYoH=>B~"ⶣpJQ;BROꄉy,?X:6N)o.2pzT^zǱtm5@'Iw*w(-ZԛԝV0:VVH?>ٲ{_QˋۮQ-	Bb;`[^(rCD\ )Mjе'P¿,ZP-V8s+Y\qp
ّ~_B?|%!DW]{^|~leIS/LEqvhS۝ Z[h?5t|^V:?c-x(Λ.҃{}=Iڝ[s*iQ487^ͪ3#?,!'LmK1^3e8ׯ~FR84U6ľi\X,h"t@
 I̋#Sh'bBQxqa;{G6%0Ddއ s3Bj]=:d5,2z8 YRpG[Duƣ:;WЭQWgz	bIџ&ƌ:4W~]®e%ɣtۙec*5nDW71v@qX*j\b5M>ޜ#Ф_|,Rtw1qzzdF QW722M[m8:x'lb|gɍ	71DB$)m"P! Y
]^mlդ魽nZc7FͦnrÆl/	>sQ9s~p|̙93Za~@6\ l>fCiL!LݯG-alRKNzySxT+P[$0y\aB	ΨGV}ZqŢNMOK
bcNrQNe]祶sNI#GTEy/8EGPr9l{|UYX$٢ K(hz)Kc)v6Bm0jՎUYe׸%\gh]:r1=B1B®þ!IBDN,ΐ_@	=6teƅaXvAy+-kj
mJY)-,6"&,q=>FM_0g	sCE%YwIdMJ$XCW6Y{ݧnzcQA+-~FY=%,7,z5"=5HSe@I		Kr3\2mdi5JJ%%S3ճEo5	t(	ۄuװ<CDWz&˻AȿjUz".^Ek5IһR.T`u{6	]%H@a*,I/M.pB`Y&Sd<W)YMW3E}ǎ?I,$6hL捜TX1"Pl\^wr"&	#!;Jr@rJ1(1
TTdӤ"1> pzHZI"yL7_by&#CQ~DF5iBd/lh$^F1Ey7"ɿ둺dK$HH)WQYMB1UR흂 gȌHo(Pτ]JI3B:D){ԐOJ\&}g5)Nau H0zaCÀE d*%Y}Tdq4)դ>_ݠaz{3@1DAVΧ 0Mj+Bg`Yl =D$@!CGA8<! kLMzj*" ~ak@ / aО1YCd9kI&(-vCbL_<"J'L5i+{0ƴ#yTY.R4gV8,%@3|ׄ(yLj@VO$ZdҤ$Te$ډJ bޠR\Y?j$8*,,GWa!W_+,BR%%0[hJx]~I\V6c5	s%%E^*+e$Pn]JGYѤl>밲YI]R'%YCd-5W&{OjnYd=Ff
-.	lG^$R{IoSĚ>=A^dUs""4:Uahufjfd.5JI%|\ڻRAУ%n-H=-[.5wJ67E6gJD4A>,@rKf(MɒW\IѣxionA#^d	H@.Myhe|y6D*h$7m<i*;nH HBEȔ3f.DGOx?<k8V%$SjJMQdz@7NXȎ8ك({KRқói~`Iy||rrpp{27b~&^A\Ě]ZWJG` Vǋݜ G&&u:mc}հos$v$x+:n?U_uM<z
-Fk+;4bc+GksndGj?V?f51ÜB=a϶^v@]%".\tz@lbݎA湿)}d01͉No9/܇&2CMF#:R4T]O/%x@38	wy(@L3w5T/o YXyxyG3s0y
< {id'o~K]%|y1,NA' ^[̿5U*j%u4t DgC'p{6<BTZb:?<+F8#釀qxs0o0[@~TRX_
:V2~|On:jj>*7G*M\m n=d<'SipoNmxг_\䗞p,?R)kgwvn<qKCæ~O`X88y?O8iӖdyB4kxmmm55<7 9UwNm0mكd]вhRr_[X[Vۆ#Ux%3?'l |wl==-"qWMI[VojeVmmKmp!WdL"n +`|w_ЗK-BE@Ul:&q?# ;N zЀw4qwʑ r}ixMACb~9Lɦj-fY0c애)q10dTVf%P]F狾K0opwjh{><=^K<Rڱ]jv6?Qtv0ݤ)r6qnj^A V'5? 5l,~ۤ~˃^YUk{]J#hbR?R#fi`HlKfrMk*Ua߿xR/ج1{ͽX|H
qO> l	j2#Y:[>?/Wɠ_af gm4
q+6;ٝ]>v(9ASHyEdwpX煹O/l3c듓Ŋyzװg<͒cnDy`I'K~SՍcb2M'㜆ѧ?=2&॔K-PM'zY[MMju%9~ӔgD?GMqe4pO}pnQ*
LijW<T>Ws8<4Jtd_O-_::΄9Cr\IàLn0\n/7^?K
_uRիB}:<ƞ{ O||Ekp`"R[W]K20MVX){mWVL&l6햹e2Lӱqs>7B/xaY`:Mg1	d9O )*.Sч"+">![uz~SԂ9~֦ٜ66N 9Gѻ=60>8c0͎ngv=t>X!}ojZ`V.FfAf`$ϯHLW4?vŨz~p-2K{RٻNwNUN8 aJ؃5q.WI>:#$4&Ge0CpeKE[;CM&QMM(J}`vEəJQ׃I*MB],xVb7$/yŷ.ALh:j+fgI4L{XdDr=Lؿz;Gbi`RiEGOJ1:˯I3!̇2ŐwF6svJ)fv]*K58>ja`U8[=HgF"ԬiB//~;b Elc;드! AG@~b5_Fvl/XoI7O?J7w^ط'6~IpbQX`p(
0lܮ`r>\P>
-"ɬfxĮ[8,XHn΅~R!)D
0Uʠhe$|#xW?t1Sr3\g+8,YzZ<g0dE`5j~y.R(j555`n6NjJ[}]ϩfe0!!5C͇coT]]`u%վ3S                    7ʃ}    IENDB`׬x340031QH,H+Kg%i|ǜ*5>6zZKZ:;.xK,.'CU%秤mX햅_n_jDIP5y)`u,Uu䭎|+!2ePuyZt݇eNnb^q 0L9xdPNG

   IHDR   @   @   iq   sRGB   UIDATx^[u [Ӵœ$ԝ&=v I\ ]	~×!bUo)蟷'x#r1_c@<4~mP?6V< )r x <3IO_9<,&1 N}xsjW  kPUµgq{Ȱצ	//޿5 D[@?8UEͽTuF_r`ړ3gF; QrT>҄fXZwhr, x'Bo$ a0#f } h1-@xHy/+4 U"xI^@D11@˶lb$/z  M|^[bNSGƜmunm.I헻GZ@G1;a`GHxS(Lヱ Dצ,s}瘤+lO@頭?j8 CKI>%k(Bzv>?NGU튘><F%5H R-$^*f  g*
2Q,  r*dx X}5}TU!t*myr&E||

v'X-Maַ, +53Nr^	V	DCgB9 (-breÊ`vR1oi@pFe"C,:@`29 `vifi~	9KL0x6)'3E6}ʴ2pB8돧A*&+ Pyr    IENDB`Hv2x'PNG

   IHDR   @   @   iq   sRGB   IDATx^[v !QW`V]Yueڷ	=kTd>pV/~\Vۗ1ާ1.35JwZwFe^Z-0 7u}jKBrv %BJP ͨ[;Q"R !ړLM} Z>#J h"R9DU=ɽ >+dX \.ٕ`nvD,`1x ~(:P[68 `R8{n @j.`BS24 !{;`$9 R `J`A
Q@	F 'P Y\46ۋB0G,	-geB}ځ,MR%ph;K1g̹UxF#.q4/@{*c $o)~`@hzP1@)ы"I R'MUD4!I ]6I䜁`ߥ@?KD0d{%BTB(QĄ^ xN#w$KS<;Rϱ:/QEdz@/!"')^x	`RGn 0͈7Vos}LU?&`qdiݧ J?&aRmߓ=G?0V*FVz+H"t[j8o5ؽ_FPZ    IENDB`ua1xPNG

   IHDR   @   @   iq   sRGB   IDATx^[ ae;rف;2g3BHBc+PNwNN
nr9s׳t~B3 S\s 1K& @4y.)OcB@֙]*2`q#eL*"6X0;9XPxrjjIBR? c >P`iIG|t \p1sMAv?u_O f/ 64~B#x &xw U7
Z@Pnml)E ^J,!'^x@v
 QP̸:DD60rD<麍&bBϞwU䓝<+ Hk9,0B[> Q, @VO]hH@g\tN0	7Vɜ/\K<T9Y B-fdxjrB*5V% &5&ږUx8ׄjRn_Tx %j 5A_E9`N#aP:2hYkaH_+O@wy¨%W	ˁdu5m2 Rm`OƽJRsiWCM̫A,~<!y?XGԒ``T( `!ޠnu$u6Tߢx PY& $s"^KYPD+    IENDB`c1x   PNG

   IHDR  d      <   sRGB     IDATx^yYu<9繲f
!@R$!CBnw;Rm7meKH 93+yxӝg9~e&P)߻~9묽,n?^,^df
[M677o6/ݮxdJY*e~RfXThdȆi[.L:m8Z6,_[0tllcd2:8ߌ#F㑍-eHߧS)0z];yu[^^`Xfw|F&IYk,X&)FfŘk?Y\9T9[-[o0jjչ%+dV*ZL[\Rjrފy҂ךfuhu|q9T*e#g⋩tDsl>$O꿛w8L6y}![~>x=<Kc#pz-q8DI19\?1?JjyE{m8h0N},s2K]چm6|6ktK́FoۗfmҬ<IgY-͘tr}W7ڕG/Zѽ\rt~[\8?<Η	܋c.+KG̥Uₕr9ˤS-`oLΛכ͖rYaC۵RlV-4O;ήY)b!g|U+kSz?ʽv(eWzN_al.nyرu+˺	NJ% l0T٨D ܸ\.gn˲^gP;|l5--(:Ir@锎;us"'Eē'NX߳ 0k>J^ڴp'3?Z/,$@gC.X5G637g\x`bf9T*V.\*Z,cZÇ_8@H0</яAl3 oku #x+E)>|t-N}d78I@gFtQ#+2/h9BX~~Ps~g| SB⤄ppPvi\.д]۹uѶ,X._if>_RٟEZsPˀ?n{-;f]$Mu_ ^__7WG{vcRɞ~U;wq
ZR0}gp>]-\<orEϤ*ʽZzá˥̲z=i°r1/26e'FV?v. usLÁ 12S/'~ϊŒi  3Bdv˲.JIx	R`7,ZpKn+zNg\VN?nVCQ`V?n"~1{OHX8xA?7R+>'b>oRζ-p8+Vf4KFٙ9V,Z|" Bg;vxx"m8YUx_L5ɔ^\W>Q6~]EOYk6r_Ӆ}N@$$B& M٠UKX|u|8FFa<y|qk"S m4¯3{@_%ǜ)@4LzOmKuqr 9cT0Hi96__q!aV ð` q-0ahC1~E۾E{#|h[,YTB%0[{H[?p0T̙5$xq}pfrꍮpLPп)E)KCB|SӿO{8Y.P h9ir֊ɍq2ݎVNm?@Pu{,6
Bx=c@BI.PHv<3 ͊nhط^W T}I5H}atP;2fs~~=7TҒe
1b6eRJժE+V74nۯis;17M$ y8>kXQ≠$c&1	 YnYdD_3$qz}0yDAR_%g̅T eǬ ]PX-!#쑇|6c^_x # 08v!qA*}k{cۢ--kN 9,H)pFZ	:[>wܾTX!$9IIKD ؿ׊=vfliq6{\X"`x0N$ng |- i+Jf>ARapLJhV 3)5[}{bwRxӾk~~^pE7;;glΖ/[6#PmZpɷ+Wgl4Z!Neipq0&c+>0FfOM⋋ tvM6Ǳ P:qݶ>υ-@>UW&|`o;k)7cy8~>7K|uVz ytBު9+Vlۖuɐ;wB"'?_7~d.-Lc>L S6 $EDinx%N_!$;N m#Q@<7E?mzOuI ?-"BYmߎ9bO?ă9mc*Kudd3wb>9g掍
9nҖ+=?ф\dr1w򅜽k'ݟjl5!_Qs6Ȕ"Pv̩3۶}{O>wN]\Uts+aV{Tu:""nϠŢik5Zlxz6~"Bd9n`yTKYѶt6c@q.62t#'R?G^#ndEXBK%@*11d	^ ^`Ӫ`э!+0Y=H+P3_ÅJ9P8nӶgڠ=GsX\>7>=DysQaX4ߴl`LֶaaiV.\HLbZuwY_x<z'>D GHmg-\WF:]

LBP>d-]O{kS$܋yeHlƨ(>0᳦مEUMZt+1hMٱK	9&"(>d=HGzB\JJR{]r"HIk6	=F]U+Jw:=۱}mYBs <]ȔØu3oEO9DDX0Ir)cGW!%{CvҊUe۵}i6\DJȶ`,J|pG[=+VO?Ә#B.m$b9rVCH~]Յlz̅5m88qܬ\7BZz:1 X=Ҟ	a=]bM#8z EUz>
c΍;{mn|5$ATK	sv+{QוuÖYkݻ--zf9B.cbA\dJٚ|{P,o x9fN+!ðȚ7&-~cb'?#Y'PsC؞|kd	h@7#u¡q^#&2zẒARtͧ8O"q3H>7@yS=hǱ:d<4,B^tNtzNvہ|y"@5en#cHDۗjǎmm˜YIΒ!%.}`LS@|r1Ww\6n)'h.,WH }vmȗWV.;,aA}hYGI^_7$\V6[-Y6NYJ$<NY߷fJ}S5@"DosssBwdxbd*nв0Z,+<Ԝqh]h:kՀ]uGb0q9%$
YO$S(ʊ#{ qMgϜQ»Xx(sՊ}M:Vz0]L  LtP2$>r޽rf6ab CZ-{}|ud?ή\Y[L aO0б	>Ց7e3SOSJW'85N?|r5vJ$16.< K$t1ehړ8%	|ޜ6 pC8e `vr7_y^|9f̟adavg$IebPv';Rbr ܹͶoS?;, eO^!KNY ^+?|-OX!$eF踸6Gl]"<!V˶w.e\/ R'v0
+Zy8:`8¼+e wŌ;bZ$TԁyHղu:%SboBյuV,VY\	0Hd
X_r*,> MZ,L12"S(hj`aD Mfp'f{@҅6 l#D1li;k6g
}b5Ą&êhK@ɌV;b>m;vDH(CrZHYVNewN2X_s];`$hIřG芌zsMM+ncrf!Y]k1'z.\O?^_RHzl<z818eF'[ Kߞ{%92Yka.):?37ȍ%+$6$٨o5͗=۽k--*t2~k=Lyp@>wܾbn4d==aЌ{ql¥{왗[^Ͼbg/Lvoߪ(QAO@@ȐKV:y>AĦ]6Q6RɬI%(Ҩm<F(XJ9~ceT>CxuuUIX/r@X
7V7l%k.8TB^+ZQ8nb31L{ AGpc\7ǥ-5j5VB1%&૝#IjGaoڶm[la6 bY˥q[l1[{ݖ),]T${43g/uf̆B&z+IHG|:x#_;.^uuxQIf`N^I(~!y=Ɉ$	1_c<$ǥ
Oj1njHr]{ı^0ƤLX܎dn%,shVdgb$
 5Q9ylulέu˂\bKK(=s9wmMw?,GQTN,O} z۞|%pjW.]}Lm
ȳ3۳c[7N$Tlhȉ&Iv+ۭ'Mz M\Ʋ9qWp
p"@9Ґa%	@)_].s$/΋qX	6b |Xd]5V>n9Uچy-VabOʜ&SY3e|6$b,Ήck\ȌJl6RW83Zo6:ť[\:bbE&%aCٷg/=K.m:e/&;LNJ(]"Qf'$$*J&b@
NR|ĉOAg3^|fJ)KVYUX`AIGTJvLӫD.0a3S]Kv/^p瞱G,T6;_oa0ĐC(gAB$ e즕jUd֥9/hnJ}@??cdDL	Z-{I{Icb/^ =yE;O"^_`L
<g~q3EK0i&5Z!R1jA:'%2.x	E w>O`C/qXtJE
*聕KܔRtKLPMAw'(R5lNw&
<tǃkʴRR۹,3\$j4Vӂ#+<r'xu'B2 @ʨVT`68o[NlFhSr꒕Jyk7.[f|5ƴN ݾٲz{Nt|B5.^l3)oJ~>Y,pZD؉&>x$x'?+87YBBx Kt^$#gs\c/!e8)p^=Nc>:$%O	5rR(=Yx<Iϫ1
$,mV ٽ]!i5+¿]aw¯۞_c+hIPA}Bc{#X%g^'8Y[e;pC g+0SQRJbjѨ +tGuׅ3y#QYҳݳ$|&S2dnr^. ?59ou _JEpex349=.$n4U}~ݒk.J	=`|U~@KՠTD, 8T!]wؙ3,C ꃕkRb0d7|PEnp vֱH2pss6ȋR<A_)fA;x`׬j۽)0unylS\:YfG@2Y>k&uFptQ	kL7YH3^|:M+f$:9L^3^`\]3	Qe<zH.r1D'ۅ,nahI`l^2^MvTTZi+	*)Í'%uk Y&(ˤÝR9L6kٮعc/ڷ&:ϳuƼ\Ym#O`.x/Ģ,{p]>߰Gg^sWlVh$(C_"pn J<,P\CAOke7s*YȦT['n,lm<#n'TE>\X}cCaHB .U0GM⪞I`)[d*xŒV@Tzp0I'4)Bc)+&9SZ` ۛCYBQ	GM:9NмC 
G093 d%B5XrfgmaqQCIx_VMNi}MlyeE]yi (꽌uS%2%N`FP]Êͬ7t{''l~=9AM@7MXC pF"s?;8#,s5\+^p=-9hG0dg (]EjO<aW.~4
|H1&Ŝx"0ѧB 1)jYmvFgN۱}I{    IDAT	JE	z|:q1sOgwz֬VGΌ]l8R
Rj_{CvɢV*Žsw4i\d!<yQxXаeAoQrNIgbWE7񃃏ȤD]#C!h:bݥTR`V6\^7́ϸ5^6Z#H4~wxmP)m(0Ur-Tڱ ša
es=I,EТ,dzY0P_S:-fn/.qL2Pr1+`,MȪ\\T׾6|XuqY~:L1\KOϛBi7Hmf?cZ`<$0'ϩhC53)t8EmcHX	+&cHgZ	INp_C	CLeoM$Jz=EA'PFyΞ:c;2؝dkm}]xgjEXtݓF@k'T-lf&h۾=m-`%i徭/FHQ,~%Vg'\Gz&Ky1&/{p]:n8Wg^WVmZ۶Jt vAs̂>)`$sqz#\iwS~>2#9^`Nr;Gk0G`pi2G9[[[+gKVT}}4tm~auet浵5iTb+̑y{O$3(	r68NN6{76yH96R jX.4%9^=e)ؑXǣ2jyTkp5-n*/`޻m6_by:}"Iٴ7:;wmn	^BT6'(M+7~>O|fV$d{|Ŀ4n]I0J&5lWC(lM;T)[*[$Nsΰ>>G6ujGh,ظ0ktޯRjTy
S.[EGK_1	؋aZpqNJnhU7@O[@EY7^A~_=QEThuXFwaIT-X ݳvo_`1¢K@?\g}Y:Mߛ=:}^8ٷǯ-Kiwvp\~]bs۵ò (eu {@˥B󲱘X*ptE0YdDsT1"`	,UW`:cծ1丐sKʽnmSw61I)Feu ,"bjޮuXF@aumտudu+WҾ3)7E=ȠcJ<X
hΉ#DaH)W+_NRa Mч#*ʊ*fs̊2qh۷mŭ[6 YPV\V!Nݴ{8~*4&ZZaqᾨ's6g(΢6wS&ߦ.uI7?l]h|"$Z\T:a`V\=joXy+,"{MBДlY`%{߳P۷O|۶g[ߤj&2OXNFs94ۙ(9ĨR}e{{T}ƗkoVO\@/4ԓhK	,shI9o#uJm{wo;D.z׆hBJry7M wg5[]K[.6X2b-36??c?j3Uۿ{wE{PN S&sU9ubZ&+47 +4 n
CVI:/91FQ{#o~[I*@zšT@&bl߫#4{gаg,@[10EdQUGϞ ;X:{&&{aP5r<cQdc-ХR̈sMgюb;b;o;v'c+ti[z<jݷlYAaR7Vo_ B{Aޓ!$4;IW78ɮ%al{6]wS1`J%<+NXu~cV4'F,9fhidtÞg<-a}=
y,߭]l~l}~dn=`xGgþw?p+Rdϻ1bX)lB^!WKv	Ʒ6[^+!X`\<wڞz!k5ZldDF>r֐s,Aѐ\(0"|WeXͮbɳ+뼎d0kfV5XbԐ3ucӯГ"Tr_D5xdt=vey-!!yYwFsv;CG-s5ۻgQNvށpMML¼uq덶NblTAhd?B/MINY_|c@7U ӥqSԂւ>Z(fn ړZ	d<nt>_NW:JRԗG5\\hC8>G;挥zRb79/3E!iH
C"Wë͜!v鴭5逼g>58$$[IQӻ;relEf68 **Vh9``}IvɬIθFgҘ%ltG*+KVt]i`}Β[*W	aO h_:ԇ=[pW;o{nhd|鋶=oth6FY`y. =L=_2ai8bs}{Gvp?y^^|){Y]l4yĐ<	h*9GWnȈApEΩhP59rQ#j5Ya\kvm*ܢƽq/z=;w}gs"Ȃ{2.pO2#oyko'=vҚ ymn*RU,Zٱf!HC>djeqT\$VvO)Q34X9z=p`Z1
͆цS%ѣkkBA2)fq ߣ̙8 4ePMHJ&,KEW97\T@w&Qrg+8eϜ<%`ΰa0DPu*(LSCnzO
Zwt-J^:=r?uAh۶m}dNRՒ3ce/<UKy۹m2^dΝkX>SYbٍ	Q6Y66E >S7	r\C
Ip&."5C?isG?!!	<Xl8tSą!k^Px\h-qR_[;pAm?-t
=1*ƁZ}F`6SF;vqߵ{>򫶴k={Yţ'-kت嬕@l',>^5.	yf!t%EhsyGC9BΥ3]J瘧m[_oپ};ŐIf
;l)ط[2=1zc>=Za	[EyoTjS`F;~tpgqYLn޿3yϊؔ,~Cx>ZH$Oi(&חd[8.Js!ʨG`N^gGJ/|f%^pӓ.P*pW߰g<UW>5\Yq;^OyHl	#F{s@P}eqoI}O* `=_Ժ3TH$?glmHޥ!j
RC:mBN_%owQ ]ȇDLz%lymz!C-ESm7y@xOٳ<crvl]f+l ǝDG0K"uqK=K&"mf%-^%&]c۲4o>}[=}?cse鰫/=	G".ڱ80+~Aߖ_o>{>j=njng!Fp9Ԅ	 jvEOAH|WeoY<+kT}}N}՞|AgmZb.e%%}rRbHӇjlf&H*hoKo8n]gM=C\g+%X^kھ}lEYcb#;9\f#<1{	䉕:DibҾ?H| 67vSve~
KsUyN}GY:l	!8p$n:]R.`};@^}۽'8J*$z?=vAG݆FG6{Q],줁v!-H
kT荪Ĥi;h 6'Nn' :C$y	DdUԩS6PMăE"$5
t0jZmei1R#TJ!`utRsv更}WNC1oO<;.h2Zi@  H!u(0%Ac5		H.ג.9_333U߱/Ͼ637+fF+:C(d,F12qFpwm}Kۛ>˶aQ3m--#wŌLsܬ@_aT}3ǎ׾]{Uff5zwR[uvފY^>^Ӊ~0\{/v-!f.+E2YAZ6Tr#{9)֮Ѝ1HHj( tJ^Yo۾};l%wo",s
@ؙؑgQn|=tcFD 7܃ڑWO
kp`[jvˁ/f>|$5q6Ɠqsm䦱HWTlD"#·dؑ$f;JFQy?3ssþZ@-G*5XZS)Ub |7 tt7'$ dleuU7[ELe$ܴZvA]=XV(i,#Y8ZasB'mu`aSB@vUM߭tb<(w=hc;+JxF5+vqeuҗ|-/f|ɂ<lHNbGvf64(]-Ld$5Now[1cV|mӿ6)L+o6t1{nݕ<wSiCC㘩/^y<@(/,R5旿i|m7{r+?=w]ouA{O?a:rÚ=!wwgO?U{xU,="ih2VR\d0hHڧr`%sHZeXBO?^d'y_Ő]m yr|ƓIܸEtdf~}g,M(	YZ`J$=@,1w.{q|M7!B/X/alQR$eyB1㤐W\h5R qԯ6a[: BU*Ds"l9KcJݪjD7d[Lx4SZH_dP<hojuLZ`g+ޖ/4%rd1ȹU])|l~qn$Ǥ'<I2O]Codى'ln
m Q' sUw\3rr]ʻյ>U8:~FmJ9,16l]7ƶc|R%fiնOf~~CV̌l
T)lݴbvOD-\R%1%~4og5YdqD{"g-}薷~v8SSȃ߳+'_wj0L5k8GǲX$&_,Yٰvk~1-4p];:+R4R,b4r!G;*˽pb$;|x!g>l=Ws1ÔVY!=nheI"mTWF!2F\l[ʫ!)Op9~X8V#@4Z޶!/yR$0s|I7VT|=_2{10ު}B3$3ڽ^|t>y{5:?c79+u0f ׁp^SJ:o9/H\Ih%c_ŕzbxGtA'82?OQoLMqk(?@j3/S[x8$P=++!`NsiPUH0o'|{aх@<.{cn2dhϪpVQ#$l.H]0)ڊjBN{y]^]sxl{vn<^Li_[ۇ?X.=]ZLdmD^8AN9*U7ĭ&eWu&XoOtqH Şw䶤/Ɔ{rꈽwI mj350-48yD*Z"R*XUVk?]BR?۹s^=0tgL}uh)jгn%ʊ՗W'ݷa'^}E &	5SkkݴUd-
؊7Sa4RAe-RvzbHz2nXǂ2o{+P͋h@{ylm/iIB'adQm'^o|IG#$wqnCf0hR\I,ޱA"sΤ!/kean=[	&oUkׄqihS^-PbUFfT/{wKX6,Vל<Ys䘒_Th.fF66:uOW$^o'h̲g6hrPʎK&ǃ=]6ho2o0Bns:'OZc劘z 5`QT|$&0 &w=`*A }|[m5dAhlg/]];w7ި%!\M>~~߶Ljh6;;kjvzOxkM8걠'춨MtDS"8~͚r0oN&Rt)I(Ť_/<__vP|戽wY =3%*{w&0@BH`"Ji7<ao*[٩&UӖ-Rǃ
)MUY&1  ձq='X*y;Jep\Zk|iFFO	 pEsA'SiDuM=CcUX؉L{KE!<EU>Fiha+ku{詗^~q$:̓]p^,/ͫ$K+%E#=a g3x8oO=wHL	4+ufN (jD^ ̋ي}fmu7@Z7mi31[l-
pb-K~    IDATG4 - js'1lLCAґH{aİ-Ilz$zSv?2Zp_ag}k߫"Iht7#RlU^`V7͊"u yEP%Ӣ֚h~(YE@NwA:	>bp!aB!+ˡ:evಸC}HهQ1öŪT~:ЄNÁյv$rIPi'#(G&a5c!07$Xc_+~.:l?;mFɦ6vwM9h݄DgD3zI:xg4l+]{|d ͗;Ngs}7Y z5}k5֭bOp36'N@3^*MCd%|N7,3ϰFKYS@	"?|9@)VKlٲzm>T	vWO׾՛vN'ǱE,g'BHvƍX%넅/
G|5٪=!;{n[f<CئI+
4=n(@O+a7=r99W9:uvq1e+'piKoct\oj@SfA<%Y `244(;dP*`Pu%鿪/3q2>
oML:J%z

BYgݾBΜ<eIy>j8<0N>{*58xaTZi,O@/;NtGbQ򪪥=mWZl ziw|[+#ot4Z9|TR	%/t =[@&[΢}($O`YL0?Dn@v#٣/y[|l68璒|E=	zQ0Ǡ15d[&p|F.~vl_;-$8F<[P>M?#[r!뱋DmNV.+',W3t+(k.:v]#*Xȣ[IEu#ɇ,'٩ѽ7%OP %4<uo3qE2hhKsm4TcVim?h_foejU}-ni5Pׁ1wuMH:f!; 8fdI7iڱ1H<y_tPU9""8x{r</FZoICfd4leaTx6Dp,j⮨&r'#!6V3yvFFsPP+;u18}W]?S<J+ć\.Jcn,>	BXj\2rY̅KI'wnwG:_d|鈁i[XXމû`'"QKʞ;M0aRbIXݨ&dTk֤LD	f	n x2&r.ρ$&sPb;,ϟnx<V-,M6BФ b#;0B	9&͖vhamg}vbwukKK$YIm|
cA`NYjjh룵U뮭ӇOYc{זcBږ׿fO҃50^GHٷdȿpI)LPW	R٧ 6\TzL7mٲ`f꭮m۾$M<{lD@_--z=a@$.OHY d$ԟ"k|Yłv9QB>H^I9CLٞ|U2kn	S*ny/)3J{\%	C7YMC$^fMaa}]%~3L}s7Vc|2*^N |l;}v6tg5oΣ$'J|m6`4: 9[wSE1XfnΜ>mBZ`e=}ti  dZ(a͖'1%xM5t:}Იwn{kMc[[oگگ~]gg~-ΐ,xCbu1C ?kz<7sQ0VDncg/cgn`P	D'~ng}Gv@k*EBM.{} YEJQt9t*nkyݶe۶Ic{fo|D֘DCIh1/2Hcc>PmIit}eٞ}夵\WMIp-8`ygAִ/-vn+|wl>9nJ\hr^*`C#{"c-# ݕ͜}뒒z+MkF3ؕd߼HHm|e;qdر:	#*S-*rvKXÏ?o7ްf+G<%"fi	fncu+SZDԽM)kckG?fHOǄ^sslHIV,W]T³S"T*ذ&;鶚{o/x!;:n`ReF`.H	殼'NؠYWRD|njCU2֖ۏUUwґ:ŕHݻl&@פt+}6wETv>NIW!pdǎWV6hǺ:c656oQ	xKNrNak!*r2"Nʌ}n֙/Çٕg=x'L>#<m\sL5[<´)vbjn[}v[[8m߾N/,//oN!;gF8Ea/JXZ>\?Hz5׬}=iKJ<)py36d)˽U+:|h\} iT$]!Och"	
䉅ckwaP{ERlҼکp<G2A+
qx:{sf@gD#rְX2na-Ebyݶ/oG{kRtcB3BZ%ұOWmV"#J[m+KG,Xx[XxMk~=Lo%%bs,OD3Y$}[ >2VtMQ,2=Q+fX2ra,&No8}:Mm͠ b%ZIœzvW@:]ڒb\
(&qgR@fpg}=FLպ'~;q}ҥl[|&lId5M;q	.IM$ݜd^m@\iq$3UQ>S,WAo"C糚Uk7l{{uK2l,#{H @<[bǷ-"a\GE}nv߾잷ޫ$z=tĐXMm8"5p#cgڪ5/ؓ/\*F\o'Dm5-թzK;-
F*fT>Mb
fF1g+0̼:>>|ξ[8q+6#h'Ii>~^:rJvO}o;',a,w=!ԟ$2M
כ{#*}i4GHFz I=1;n`ȷݠk~iǚ,rGa_ϻql1?ٴ"+DG}#9#&!?[]oR롥>{9T7: `O/2?AO^=Fh਀M:I<Exbވ{T6Zy|Q߯VyҡfiJ;z۴	=xatNsf2CDߑ/رeQ8^8JHbm=vAGT`97v2#Sw5oQW 	K>}e$MI򆳝$(+ l8cO%c!N׃`Fu=9o}#NS)>v]:w$X3>lZ%ZN#VԪsWZaѱw۶8o۶m]75O|&ɪ"c<5'oմ)YmfV};wqYxd;v-Y4(.2ЫlWb0f	+c&٢$$!LHLrl͖R07k#Ψ]ܓuOx;7gyeGv3&TU'IH~p\h5!1=4['^<n箬Υ9ƽn-|c1	.9_)#^H'r)qyOcD.i?e).V>qlB*vC"n!ӎCS=uSI<k	}(=]>ѹT#drJk@H}%CĖY/8ƣdw؂I<ܸcGZIvf5
/L'+ڈt'3(<|ƅ++ak ypMڼP$?P]Hlee>+o <Ta/,QġPM|gG.%3?	G98K`胡⤈7R~%$9а㳟d&*dt(gcksln~ގ;aΝ6[uOmc-,аG'XaWK!a<`l_$@7golvGߺlϾ]-LE @SJiHbLһa7Ig^hϽzڶla\	.-oC-]P^zXtevp!؇fV+2Rr>W55Jgs*KMOuPʟŊCGP0ԢZ-F"cm@,;s7 Nȓ/O m_ZmG`/H0d߾8<t^ ?zնZ|KcַQX0Qbs}b= ͦ>ݸPb, !dXCb$Z@LY[IO7*	 1ۅY_wu¥	Ep#.acgv煗PS @/n_-m5 mERtjci!	Bן{ҵ&v>&qiue7v ZBC{Cnu6S.ʂW\eFϬ{?>JU8 \n҄Mh$`^aoʠpW~zCl$@!;}>޷)	a7tEg2=F?܁eݏ} Jkoػ.۵k#9~ݫʕ+%"+}.[*R6l	OQlׁVؙsɓ+637cwU^ɃZ=O
q2)f'b1\yd0mu'IV9vVY{Y;ztk5z7EP% 	<FY`+:+V*e2c=c䗮ސKQOj#ي$+u۶8k+aW%0.sq#,+S.Ab^KEFmDZh,3ƹ^h;<£H?%KMgoCG/K
2|$O:f]XbQ8ʦ>5?8Asy=`%=`Fă94Y0Tɹ[T^&L2%Z8/'̀Ш`:됆Mk%'vj燮/0\7+!J|\`!DrYnՏ7DWKф!>dAW8ǤZ}o7g空_-\6>.,	D|$@9J\$2jh5;q<'OO6[+KU-"$UsD)*Uk5Z|3?ӶwI/|{NstWӾʣa<k|1͵et=Q{-JN:{N<]غfo{g溮Mns] [ 9hnopP0%߇T)/HbOCZQM_9vƎ8SfM-BF,s_@saJ]7c3VM[(Mv[)S/+TUh~29.`RrkT	3葉~Ίμb<W-*Edc+\cEuf|@%
Kqg~{f>Q,:4	;p8@U,*ʐ'PYN|pG!0J
3VFMX]w9XGn ]{Ⱦ@L7uo;2I^l3LBw6V7)+=Fo⾜|E_L^m(ZҸN런}o%ېϧ=.-"Y^j 92zt$$^L z*Lp9.[	\u`	qD5qe,"\=tՋ67[7{ި6D'llqX!{8,h@SatvϾ>^rLf/l j(!ezj*M7M+WkY{_[23ܑS[UpN 0Y3hr/}:uIir31UsG'wno
/A3njrdFRnP$?IRJ;}qN\bq7*sΪZ3 b!Qzeל3d!(8ȇ<H80u _|dOt.6ko/M' C8߈÷ʚdJV8 =޴yr {9Vg{"7nlD@GpH4'Tܲ&vbas>Zuu9!uJ:?FCjeѫvƇ̗qJٵfIjM/o=:/nJ&V)tgE#*-eq9,ZTbէSǇSGՉv kl{$hR?b*ń&|x3(oLߛhy4&KEF8ִ0EՑ;}ʖ/_ cĐ{mF7|6@AnNsu RY,U@}vÁ}HϾ綸4owt:gvQwy& zdsYI)ܸBrX@!=mO|vASٙ!g3yYX׾R/:	PNS}-avM>D¶C~JM%X%<f [^{>4jfQĔ
nѐ_=y0I|&bzE	DD-bzh)s;8pBx@?TޑH=$b-T쩗ٕպ-V^ 7<{]&dWK2hݑer$\V.Z1Iy*AQNneؤ??VA B-btbgpV-nr0៷勶r`s^G%ouɋ    IDAT3i9z9iX҉|tZr.JsA3Q?,g'Op<a_:.[adRH]Ȩr\CyPx=9We5)> {!S|!ߪ|$MS#,-<E+jS龺}A9'G%}ndhs9u+?i DOx>&&ɘ̓V
>	qi[|fln~QS'~|t
)Ev?}rY6L
9`͌1>\*WeC7v7~l}/mݶ,3f1nu|B:l2MXaR[H겚={mw@յ9wrydo3_2.\!Ԝ a.i~Rh>d7:'w ]4{ooR361~.S6?7cGN^g/L>_j&XA@^IX+i/N##E>75$4cb)<Kv{mV-57-j@rmL{][7QĐK6fOlJJE x=Cȣf#!3RX>EF@7V?lɢ'e'Hxsh	0B9bUOy٨,4 {J9k8~~*Li;y층WPw1 e*^oNvÆy>ulv;0t@Őž}{[n}´9$ְ_ǿa}+*	xեfҊ's=Ik&#$ڦG0gYES;alΟ9m/
aGS'O]*a_|I3@3ydݤ:*l
@멖j[\: ׿Cŏ8hw*O&j\Q9ƕ0HɄJlol9{u~EbFW6F0fr/-5!
ag鐞) Or5?̳L;i9E#ߠv#5b96j)csU;z4o=P^V49{;3 f 0L (?e+QieRI"4"@I :ܷoYk9=`|Y`O|w^/,
>L0;DC9;NGhsd3|-rֿr\BxdIͿ~Pw+nP{*r*Z(PשQ|}H9 'ǝfr`2j-'4j%Q3P"tJϷW~N,Tin+i	gobE& X<Tn*C!8	h`]t.8C9j,4:!=s7byaNfy "WBp)d?Tł\<*Zĝө֢LMI`a/"ircWˡp6l֖Å̶4CJTضI{. 9dY"+:s%<)&T&Ƶ+WƵw<#\L6tt:)*ZN=7DI tl %C6/|#>?Ǐп{hq.[(OakOO_wb"n+#Z]݊;f;@oW~_|iĹWlTB&36P{w]Rҍ ntc.6S]dȃq}oTfE+g-5!(wlB'(Xl9b;T4zmJ\="իԱC14;wM(&ݨkSmYes/At#, Lyb&+zl|/	44S_Qd;]uh?3Ӛ9V¼(Aqq-"30z{Adqc*(iEظkt!ݘ&ŗa0AXd_pq-!ډ렁bAXLV]05f}7SXE$TmnI~'Y@uܟKwK9|zRrsX3Mt}	<TqCpJV-x~wl+J-3W0=MVS@ 3+L%*6 iߘe6U	VsNMw@/QUEݣ	m|etm-R<f1),d pW'bym#Iı#Ugcpt$yS"C%Zw3ɐ%9MӤ+a<Źq%{ յ}gFO5<:ߋ% 1_8P9G뎲PEX+L ٤V&b؞J/:	!l.^	6MATEgYd#LjUvYJz䢙RɌ&NL@>ʹҗ鰂2PE'MXo⁘|vGঢW0H66rh3\lxI(|֣40Ԣ\*ONGHqbӴMBOwvKŕ.t{]Z5,y*)/SRTl铷'/AWhs9nC^nMW!tV:zdHu]9l4-#{TB#q	g[9tz]zKҟ.=UI̔?FF`J D 
e#Vv8!'`A>f@} -8u#n	wgyI|3CkWƵ+]o}Z|Q|ܛ1U'+Ck }]0@y2_˂,N? 3xީգ<*ֈXG1-YBdJLܽ[g.CGtயԼZ$'CymEepm9 OCYKQ#'W_ƒk'2 2'1C2ە]2!|Ɨ 6pMf(Qjc|Үd٨bXk!4d1'J6>GlAgBd$5#i}kQ{T#HO<1gگ	 NqeE=&(XT`Κ;qll,`{LB-+uTߘN@!hBNM/gG*y!薦u
o٤`i\TrдS]].kkҧea9OC_:'*M=H#(-,OLb++:n7Ұk4ʘy2gQp*1u ,Aq/s̞67+@[6R<ɓwC"ഹ-h~~ڌڤ2\,;c~zZ +bZo A};.FFFP{0BSJs
8X+C^X\Dz7^?W'~&읈w󭢤15Rgz	4]Sj}?LwN_=DWGg,nƽ97So^]2dp=GQjY^P@c!ze[m>[٧F_rЮAUeu \l
{pϙhf
ruBa$Q̟d``jȢAy{#yb?_ʹk1=1joSOkFU	Mg*$ĺ%&6qw]Uq:\X=jD %_$z2[ePCF-Sҷp@6$1aRK!Z,Ud3G1/,R"&xЅͻ}}}cFGM!9=DR8	H[&<X"_>0`(ATv
GLuf{{8|8zؾx:n$L3!ÛO}_U\($F\"R0,Pbpo}5r!J((vMWRS53 Ȑ_f_s3V|<#w<ɐ/_<x-hY'Y	UV[ iv ̘#?8qHׂ!ML[6j_Kd 3'	N2+Y{҃X;sWc!hiܟZNyhd$:O=9BTXrIhJqn*Z*(ܰ,oT2ߟ2&2xdp,<{M{c׃u
(͋K52vjv f޶2qrwzZLأʵSm 9B{]uΆIq9Ĥb$ޠۍl1ՐMB<g\ɘP".t`':cPhcY^t0?4+Pْ+ԭLY>Dz@&K6-%J,4J-jY8 4`:&b
UvK3Q4̕עn|L:pꕳGiuk,"#RxÛ[n[ʈ(yx)ɹj=ζ8p`<ȣۮ=y8SO|_Prã|!jQfD͌}?fۨZ2m:5qJ{?x[:jd1U\md9$RrU<3C144"ŕ˗<zhğd*.۹o<]GHv o}8v7N}HA|mmEL/&i39#s՗N,KVvJ?(4So.vVEgg[*A)<]<͗>Dgadi%9IWm	&ֆvnu`-¼ߍ\YHY:΢:[t4
@% 7!;_G,z1%r8'Ӹ˫8M5-@s=v)c	OGa%\YNJh:SƯB >DE#D~BleSJؙ4'U\U[;ݨ,,')=-8K,Uq4	Vl {(^yYMMZYvGNMK&pOȒKZ!ŵlo>{8rG-lnʵ 	,OǗE,D{Kуr:6+s.bߚJ%h.v(M@8reUhYqݹsMҥKw$JB6J;[L`.{ĄXM^d|??ǎNzo>G'al޺U< )]tG k/-.̽qҵ{@4#Ҿoc{Dϩw_|>6V~HdS[vkoqH&m5el/YYh1kaYwܢV*b/JZoe LJx4zߪ*ۖVϾC6}Ӑz wCV]-kz|qaȧ/\c1=FX1 PK Ud[  xwL/j8?hȉ$DzB\<k1,~f̘zK1f%F^iQ;ĐJj^ض	rNLU,,ciYX;΄z8fk"pYFU̅&-Q"f(0Ȉ4~+i@4V+8lӡtK!ڞ^|XzׅKAFfPukM
\e1mW2D%[
hֿ凛WrtM;GLvD_iUW70t& [`Oj	A0owGؑC?ľ{YP,H_C[wb,0тTRdQ۫ҋ,-ŝWsch|&hέз5FSY[RL<dßJ@2Ύ#1K6ehr Hy 2싨(J0;HV̊ tG_*I#)([I4
:ӊ̦r	ԆRz|4Puً7bja)FǬY]ӿ9]lĳ~3ca8C'H1
f{H7HU-04rZXu&$SkKHۢޒ`ﰰ1^RwWGRp#i(pDq2!ŐhA	^+XJU3,f=P'<S+ącw}I|I$Q5*Ƣgطs	jzҕO*x$iN?GO\\GD4dzb<D;4ߕaЃ*fBJsE>ŉzS-fF--&7o~*]6+Rِŵk=;1;w&+z$_i~g bRՕ*wX\\s:~#G	?2䱑xqo,ְwH~m$)100( Ȍyyi>܎Wo^kD)XsbYn8D.S3kl0gi|
*WR3Dá-vkn?1ǠⲜ]Rĩ+0}K#3M7=D>Sf0\X>տdqԓzg/ݐ`o9oTS
Y[M,
vNp%s^Y+0ϙ)Ξnۄ[˯OEr&jQ_u	m`f;&3DR
P:<WНH@dXYR/'+`\jYuo+RZ7%!][U	hu2k&MP!9dwv*гnx}N@; >%
M=*w8v
vhA(nY;-rflGXb>Y}_cd)"mׄXm֫7P%ȖPBlc@hn!+ϣd8f@mO?0k$a$mqm	+cI(z:,8p@mo8?7+'i,x
:SYTupyaV`&ޭqٳ6$cw}Q"BC{ZokJ2_er5ǡP#m-h`{yNrpK};!M>e){,9)%R}4@)W6DJ`h/y`G[;E, Z~qɾnT|뒳bу{DA4qkXYGf|X(:dBa<cvz[J%ߩL8A7j
Uפ+f/u^_jF]R)
W=ytC*1JYxd;9vjV0YuF)R˙}J}"·[3F`vZ쮯TӼ[!"Rc#ӕq,ÂLus#G؉I3\fK/~!VX    IDAT @0 SeÅc
CR4CW;olgY|1r${$<d2kWoKo~Rz[0,uUD{mr/bN'ރTG*&.[GQ(~bx<#0(I&1%<ev+㻌N߽q5N_l=M#C=XߍݍqfKJ_B?`Q*y0dOYE˱CejDOt"WCT9~/wശi"?D@/ӣIē,-2dFUWE{˩W^ǁ,C8~D3;HU]_m/\y?ɂJIG 0|#>@o=~o'꼯Pp]W!=`euUo͎,&ss4WX򔉜Y#KXP3<F6ru .AE`B/ƪ2|js:$iySlJ͸~Zl-/Zd2)84B,3ar*@Z(v*S+gc%(}6Mľ-'P{&PC,YwR?_/r޾!u`+Z4CJ.nsZFnfZ8~7v#@
RMԹJoLSo~f:FC,0[j1(1M)BEf6Lgnr	u|G$<;k{:nQo;X_&C$sL!#ߘwj|#
d; 'cʐѲ.ܒ{OI{enDoRUbyG[ȟP|pAGTȓ+WV8!
-4!?Rˀ[<aYn!?HlrrˢaY;0K"Ia!T1}=[ 3FP5B=/M	֠2&gi?d<c(X]Z=ox* S&cGV
%@1XZZ[,³i.2ݜ8I%3Un4#L;w`MP4!
+}	$[Jyd>:# 2<)G,*^KπF)q'' M)6&Iwe)zBG-t
vbff>~?X@++ۺzumiEAsGJі次^xs١ؔ14;J6p	BւnX(V~3q;fSO={SeaaQPM?gycu`0"?+d2z4?}/~?g{<l@L@	Sz!`ֳnūbpl:ܼU8퍮o.jHnZI_Yȉ"z+)J䂩R^shɍ=|{#gMx2ש\\%d|B9t2"I	*K=R\G!R!O {g;ط,Ě&BxLn#L-דKYL06/0.{rKh?_p@C#[|HxAϢ&4~.qL/3˂ L ;6;(J0c7YP_
}c]ݢAj(oMWY`dOxMVX n(ٯnpΠp	'+#2kA{;x䨛jhGv4T J ąD{>#3ka%({zҝh9_Ӕݵ9uUGaL4_8M<_UʖXiްLBxŕkqxOy1mĲt"&b=2́4v+bc}Yյܪ.Ǐ~bI.G{De[çAcnkՎdho2Gi{7ƅcgW@Bvxl,N#Qd&4@f h/d/#j`2ʚ"Xct~ln/^kuBc]]0n5B,TR%yl~Ɔ1(&W%۵GPqm:+  _GGoW|Sy;#FܛYiΚ$vldJ݁K@&F-AE3n|8PDkf"d~9\ teSL^m
(fW]'iWyY)!1Nh\JOX]?9R!Ȏ+2dȐ6J$G3i ,aQ1nؖ\2t8zD/a8\|?_◄bfGwTDfy_)ϠxϿNߏ~r6f+xę&G:7?΋xHH@,
6d`.ڭkRobt<_/]<;Cl-A)D@]yoΌP/Xd`KRz82^neq15)u3hAme#Z,;IGWbݸ~Nhj55 b?vJ/r+J*4dpݛ AiWLXfj͖zq
)59*Dv:>ȴ3ׄJ`,У֪Oe췗C{0NjAr8wZ	ț!`UƟܣ^cG_wt3CTp<`<(}lSB/vTDlB DfJ[9~xtIH2qL%*E%g\2SLP "LfƛٖʣpPa$`[,͘| C VWW	2h%Y/rw%(Z9xM~d@@.]NS{5yREkCCS$ȥ cOMP3-ޑc<hR5s/	O|,ȇF̀FFJd#AYo0f&ŧ>#1gjiy^hPZ쳊FbyWRn(X'J͉8h7Wcޕݮ:F`u_Ї2%:8 o}xS+kDTd 4sh5u]и,ًC?q0ߍ?=cc*2un=pkH.UK۰Kmg'cݸvv= jn-gc龇٨o)q$HSG$jBmhz"MZ/<'x6"͓a&N/4[[(JCpFd`%;L$Jر׉udȒX.FMr6>570dq:ġq`/ψ\cGJqn1F^5IN49YQ qbn1DkrjWRm%\qm7k_rn vLK$  z(U&<ԶM\$xl4Xᩪ;{Np6O]gN *ȷViҡ{	숍y`5O6'%$Npft.Dމe_Ud?|
U=z=9-8]gIsO|</*)&JN>73HE-UsSrf&nbܞXm/Gdʶ$鍾=s˞YcՋm
Cnam-7䛱M&m	6Ə|S$kDқ.]?&I:i.=BSg>uTD0ņ֥^\XY\^Uox<IvI(,<R@cٞtd!:wnƕchlh/6Nviϩw}.piH^n~d,
ܸW774U
-XXG!<g	ȝ\aMV$͐Vn0~A
GUdN^eQK"QfsL "L=5"'!-YWC1<n ݝ8BC椨K2"i'#4=yXCp7/bwp_ź2JFWqB@tg7+ԜNYҰ^_yR2oQt̀*Tɰ/3ؒUV%#{P13Í	ͣ+ph`yfZ7@b%p9t,NAQM=,J]<D'dH@͆8~XxJ9C5:mlܧԧ?YNwGُ	&[li52Y=Kݩ==-mU؉fdZh&(ѥml
}Ls'&Ƈc77Conѡ]a)b1T+mʐk,>;Qd}pU4f˟FHdwbsi%zE+}{/᏾LRkŨGB3b`^f>?ø-5'o\D܍zQyuxb<zN#!*G0]4]^rC>u
S xA7隝y-B#+˫DVᦤӦi*EBUK.i
U8Gs*#BZv3͹iȫgea?$#&p8{:H8hzb1x`pC'qkm
L2"HDzrmPN4'Θ*2T4=Q`>FK?b5A G5у(@nB9}@8'̍)_s	H7`e9oϝYD=D9gʣ	2n]0Ev`Һzfu(ukoRR	,@&'&l,oی_py.KS,}ϗс6T\}7f6R,-Vf	pSw΍f{47;u34oj( 3Ĵ[-X#5ޟH /9n{3>lIW;rooCЧ_@3IWNǇ~o^%l싧D%x1?27qS?Czݑq5f:!w|{ge-[)	Fs
φP
{ɗrdɃ!Z2R]<f1ȶŶfJƈC&TyŕIag}ScgT37䟙%V!YAJN頽!Vܢ\WnnzzہHb;3JuAY$55U_)duEPfGM@ܿʰ!,~_J3
j\/vcxD~We8؂>46@+G.CI6ŕ)<(dhY3`*u*:88)b*K֫5u#DnwW*N
dPVP6}z1P	QfBSFc;C7@7}aΠ̳չ=t`X&Eݍ'?/|X[Ax͸un%RJM-qR}JIjtϟh_ۈ7oթvw*6bum#ֶ?r [d^{}GV_G[t֢5&{?~(f:bflU5d?,*vHk'/K<zj ˲0m`u8l=⻯b޽	_}!S Y-'P9,6^_޸W݊qEkL,j𐻎=3ɲp2#YO ѳ~2d#|[6e]PӶ[.ՓZdHZHSˎXVMKIX2!* +n2ID+]~RY)@7gS%1<8퀬+Bwqzȇ+s67=*2b_G*vq8)9вȪ&qE[5ݮ9kc*p]'ָIjs܊
ZK8QzC">9~>9Y!7oqJNZF+`C&zS"ݻGT,NuX%/2,Dvs @$[V\r56u!gK#,L*
ldje:2c ˢ,u'˹[5->J>P'Fp?p%#
f^\8/|S^"7<lƭ;[J%Pnd4dwѷWnގsd1k
|Ts[9'8ٵJllDav@=m1ѱUo5:Klb4tUebJ78kH\z%Ν=o}jPe8jҤR3zG6\v+D%natء=1Acz-K_r3=|2Pd\[^P<^KI}ۊ|[:Ɍ	SE]cSowOE4E"ЏNLD׉o}&jkb
I:DȺL2:5OeSEQ-P6ӴVPKc>4ewggm]M^tPNMm2ꖶ蓸PCXyJl~{zĥAeT_Hsg5]_cK~`71i^nJ# S	ۂ a1HS͝@jWڮĵfJ5nT$<j@7k׿_dXsaW-c%57D	<*jǌ=|Rzd<XO()Vi\Y2'΂5OH㷶|7ʍpbrpڃ- H@e12qEL!>ЍuAQw	4Mw0<z4Be!Y腃@ !+CFk7z	oɏdXLaĒŹ>ѱ]3r6Io敢'@ls2ƙ贩nWk-F{c`$۵߂[H,D<Ti#nM}-O>Ô@Ą)^R?0ITF:'J)	+:qxĞ=<S'O
6ֺ0͂JûxXetrxqq!ߺ7܍	l2,pt4zz0TsxKCY5&)\uY{V(//=je	Op]x%Fmn8OC؎&:B1Q|<
SVeW-y]LK:ysygPVLEEAy톞f%`qjhQhْ(CG
,k39ulkqNMdꮬA24.1:|JigSR4(&4>00(lQSvc\"n(Qm<tE_F^p!Vg-I9y4ANZUz>qSz2fa(XQ\>rr'O#2^CTsb"Oho#SU\y@}+8ϟ_PBy.s~ƭX\^wbvcK8dmWuһ4g%/SxnxxKy7IQ~VS|f5>
lRGʹK̹S0Wnoղ>}1xCE%dm    IDATX880iխ{A~3S@gE~HYةhJ%P%ZeKJ0	]5Y|v^ܾ7c{`Rᝁ{]1M6:dkk'ǈ[NB&~mr~M={"QPNݢdEd)k~䏩gdΒu^ucɉ!lKU^	Exd)x$Bp}(jo84F%cwB7z5~S`iV?w9`j(9^&|䞱SNrJ?Kz: ]W	͋冖&jѥY;xP2CڙK_J=uÅW_I	HPeobh+c\$C^Q9B|?Ù;T8 u2䊞2YCk6T.-496daJz<ÕX?NlzOOW)fE@z8ƂvHxn.w[S3qf>f7cEت0)&<R̓%.jlNj8'V8ҘnzX^8>p{z{w`XSW/^g[|DϔmH^fx-Ax	@r!KծlwHvِ9}#We#D{+MWaŲ &}\T4ގŲ ]]ߎy\Mh0zzWL}3ѲK2䆻XH|dhBՅBa,K 鳢VIU؎D}8s+Rqzm٩>
jP}	ra}u&MDl[;å2d{Y-	d@So73נYV. #dv|O{G LVY7սzu?C5gkH敭`Tp/Vp4h2ŉ2pIR~L6m#9eJ,7FdeC+F(1&ý1uvO`x	qX6UbZ?qĐ9'fS?bq!1ұf<XKKMz,k36u!-ҪJi>K(~g7z[5&c31۸dXOaX@&zrB={.3a2Kn.!}Sj4[HՀIL*L}nx%} C^Y|Y=zʀkJVİ쮘C Iѡ6d!Fn,.[qO[z΢|YѺcKY5kWXAO>d\r<KTH
+k##FFn![]۔;"CP&'\M$WC6eI,4ltaY( 1'Τ&՘#\!!P`	4ܬcGPԯH)BbҸTFYmdڍڿ07I#L^ū#!"[T%	s1^FFwɸS&]kTrzS4k36iv̔l2"s5Pn
MIJNʔ?D2?ЫUICgN:GN<ddTbmOwzzFE@:/
HRwf-V&ǽ鹸y:VbfaIc+i9~t_IE@MLYGLF1Zލzl\sT	F	\:=RwopHDj\q-`<w2h4cHUf̀ϑ,Vf+؃RKK|+/J~S'aYmWʊeH-0l,k+K,&bpnlg,=IvN!I=;ƀ!=
S͒)O5e.Sv57tЊڙ@Yi6r/ѵu.\$Y%;1|4rJoPP3$:LӠ~ϒU^?{)cgO=xȃ=11:"}(1iRj2Q
cឆ65'+En ?bO^Nj/8~*X}?_'B* 6TM
7 ]HՖdL	gE;Qh)WSJSO?5JY~~l7
4X<K.;CVXpW2d>t	`EVT\Lt}:J]puva!~c_Ѹ:>n\|-lS|Jf^|GWnɩuZSiX,mz4\M2TcgqrC!R/.z,^81c>032B6(%h3Ipڼdbd% xjtG8j2F
7,0,Kzp1}Ӡ/~Dw}eYncuS}}dRAs|kS7crz6ƕA/lܼ >߶,PV$pAˮVK7a,6 wb2,E	fܰ,PpPzIKo0UES#ȡ9HYbP|#de}%HV-̠|RKq(ԛ[,o|Tlq6hW\]aT]_3]`ѝU!3[f4ĖG*ME4Ȣnÿ'bi,OiApAMWPda?ZesH</V1,JYb>am4R20Ƥ=Ej)2I$K#=2b9PgGՁʙ=I.ιR|ܕYvVlq!!Z]jp'p^O~Lԓ\|]`j+y푮Z|mO\\w?fb~qEӋʐ-(Gre.z,mt7g+6iW{LPg[?'Vz>75,yy7Cd6t@\x>Ξ9o~IҲ^V,1ƣb#RC!Uk3h$;{5ܳV&Xs$O(C^ZV̛cv1
ӻb;VwU20:Y^cۙ0cPg@^' k ""p0=kkKUVnMscRxgYCó:\]52KV\ߗ!6oJ"٩R63j[|ri21&zu EœmOm':jR_[H*m1TF@vʄUD4^~.TH҃_Qe|p _b)9z{zEFœZ$}Ycm뢋$
)ز)s&Ke궺)W8QvAŗ55\OFn0T'5f03@f7"̢ /,78!,o@RZpQ9~,N>p@+F+ T⋺}=\K| |5g@*,--1?c1uv]^9=KH8-HlٜOJt A81DG-b3	`"'WaYR%QJmŪz_ {%3p@x|={6ԓ!XSvc)@oA%Uy*lw4ĲލW_?{9dx^/}oxK@#Aq:b$=WE@80cn^ܟaA۱g~X C^^ts=5Yy۵p{ꮬu!&zCLZZY}.[AFMĘ:Ų@T4dT9x^}^iA-=wS,`ֲhrY!N$R_?s1;C='4`dCAA.ވq*-FU⬦s(2qwٿ)GMB<YX5 MOCK$/TW'6J	/`l8J	Is J(Hiz?P|'뛌L	OhruT̬h?|ɐu*TԖUNJE&$\jV ڹ:du-EjoG5頔h8Ӡ`Y|c?_{e-tiϢe\3s_fS{Bm7qsj6f6cz~16w=3U,۲kZTvζni4u;zbqn/?$	,T2*Y1dʐi=x,FN&9qVqJ6m|枟x9cl|Tc쬛5AeВ JfEO.KE=ͺ-̐E&n^Ihkm⚱bC1{bۿKs`*cKRaۆ{;p>vvWi	iCH$G\gU/0ujz%[i!Ȑp	J*9Enʒ>/cOiSC*%5'Wu2b7^9wUNݝHqhb/{cZ?YusN5!ZCCu^V+FEfjY x61^tN i{sĕ͇^8r`eɍK8Ram
$@A ,YgoX31Fk[qYlEN)48{4UDSpuM4Z	'l9>G䣏'-ɩ"RجG㥗F zC.Ete	T`q@G['dOMə\\5+4ZS[mzdSu!I8(tDwKDW{zch?H@vFU]ic2F
\&S|b9s6~|C^]ӵgw@Nt:uMPE*42k> VpY_zđGX]"b$~A
(NNލٹǕ#vmH\A8|)u	LM{*s>,XdLԱNd'+X2خ٭Vâи]!/ò(j!kt:gfT6װp
2m6O߄P}rzb8~(Ȑdĥ`b _Ejzub</5Th!;VD+w&d2[1s[2Ǘ>x fONKQD|gS]F,VSf@Rm/y&jb
g&x25P1׹MH{SlDikLX&H,9xP(M[asc3*ma(ݝ?='⥯'#ҕ]i	A'$aJl&>رS>;ޏɕ՘[C
HjXc\}=CKwhzmm1#<9ࡽ1ˌaJ)JwU c}}Fx˛~@k-(ndȥdњd<MO=Ȃ網
޻g_>\zyp0?סB,d7dL+룷WDԌ?S3;V6t Dѷ}>V*ʕǙ/E	hӇI
loeۡE,PhdI@0b:i[ƨPe)0SRc3HAϚf`OP{Z,D)^LѮͰކ0qaAkcn)dR)GDNI­B@X.oPW¥!6g6@+'fF{zk܍G`x.Ĝ)fA'Zn=EG	Cj	M$m g\`稳LƱIPpNqyJ7BB׻Hp߸c~̮	;mts4F,iC;Ft M;vX|Q_
!?
n6%UiY|F6,*-kd<KYȭ-۲?'bdܘ{+Ӌ+ݠjՊ,9_c~U%3sKr%b;:5F}ޘRhuDΐ	M;A&3W.]OJt
K0)o$)9^1eɼSH(Vw/FGǤ=㯿Ly:$0ěY(^9:Jb2pRL!ODg`'䔟eGgbꛟcH	X`o`~T1yh-%8rd흱VFE[A)0`hu_%KF	!O6,VMɬ25%~CJ[M"dO!:y${{4UoVa1YL[*? CbhZ0<v3Xd$ߕ	6rRPϱٜcKw.}:5,]UA)B)%HKϢ| q\^PJXJJPۘBO!ɋ7I0fV	0ʖiIV5Ehk@&3$sOFhhg(sNlM oo>.i$%H"Efȟd=="`tڵ`nvd,ɜRZzӱ<9b-\ğDHp1)ӎFGYԢM{#[[-}$k%|ZtE,WAY`Tndt/?gΞTт[<,Y)];O!75Q#X^VP;a24Iiww; A?޿'s!Acy٪<ߊƪ'FNXLq=e XN2p{)4A`o͍5eТe"$^ԓN]V?oƺ40歲d79kHx*Ȧ@=?CJqaCaY{gBȂB7	Y=|OO$Ttl$M@IJ#4Vb_ào 9Ȟ@M)C<uq %Jd]e018Xwv
|>(=f߆jRJ"
(9Ȃ:wS+L`zrrB`KXC\0U-x!_܂Sɏ_~^8q'LUBN˷Tٲ:_?֘u;NNJL/-dym=P*OҴ,HMU8Gw[k 167vja!*ti?`H$^0E@&˄sܹ8{|<槕<1?Я`~2#M]2Ku@D{1B,Ȣ-_zС
25	G+ʖ<ןM=L BL޼!E'ZҿheAhmtpt@bwP 56=	RmjRqŕ8_hHo2 )FeAV5E5+.$"EvR sl5{5b,/Fθ!2    IDATE?YEuBQT!+8q[Gbx'wzܝWUb,)H3v[k$c,Qjg;Ҷa?j4b1i8I_lو#:Qr*Bͮu6ħ+ÍᘟUx2avF'8kk^OdQ ح|蔣8:k(q='CI{8jR*I Y1Ӕ',Vbչ⩇X;N>|*N<N)P(8!:,,NsdŰ/Hyj^)ER]c+>7T\}/n;_Yks9a$fKKzC9hkcY[g[uw!Uj􎘳[rdC)/ʶbAճޮ.%ϝj=QŮe=,dU6,8hoC~׌!މu1?Tk:nxtZ,]]7
d%8ޭ1y::z=^dfކ[ӟlr5ŕ4R$T5n,GDAd!"T8s3d9*9q!709u4=tQ̘/.{q
zHh,LtOvA`_|̕Y}tdXzufi*7Y`4kBq8 Y:	ZZU0+sL}K4
ŮYL.0GNtƼ:0_Hdp+ɜ
Fp,NecOR'Xw6АFtgI.#I͇k.4's!]zK7\Kǜ&&-̓ QuJWOQdy+f`^N:?aOp\rzz:>k/aƊaxcpU.roȐ62N
w?ߌ;3q{~)YY꼆M aH"B1GvGyQ@_"LI,rm6pKk5Ccra`l⹳q̙xaµ㫿@1E@'e|T'9ެd2ymoG) b>Gl?_ht oFo-1\Qv<
%v++&Dɷ̟}Nz5L{"dj*UzhQY杲<L
@YmV\`UZ%VAM1HY$L4raq</S~a!~8晑!:qHJN_,xJ{LZL]h؂2"%EI{49I~N.©PNW7w&7GRjzZT%ׯi1o^E
eIʢV&[,8Ux:4bH8G Z)iCgoH"&6CLcrK؂	(ԣy"mR`ܿ?^|)66/>w޷<_1}xa̭f튍?!ֽ鸿_AXhˣ3+!>GJfx<lX!}(ZΑF}RFz~NgY2	%NDZ慳g'7=84KcT|2U"K/_<̀xecǪ= gᢽL2)e2/֬09he+{	c29ߎlI$۔;D8y5qgqPR&	J41&$eqfW47b+?[&v\Atc|
JiS2^9֭@[ zڊ."pk㡓N@^=޷g:nz<$=gRTK=/l4S90L-#U%B yvvZ/̓$̰?!+yQvi$XTo԰>n2IS5ىK= I]2^9w+XtEν^>}&09e"pTU`! GH$SۂBɪpqYM$v`?)3 8u2N>'3[^hq Vܞ0IEQ]iʙwJL'1ftmO~z\u/6Jwp-pMEzkjxjM3V+X7vP[KBz#qm}7j=,*EYf V~&>Ihx$FFFzO=DeFS3:>2}'!5CJB+-ldYXf~H,/-(/u-;X(ݫQPhcʭG5Zӝ]qiE[O6JrNtX{GL}c^fsA4sȀ`_&D1nɼUYu Ia,ڴRW&)`tɶ1W\[_s|Ƴ gi}>al&(pRU@.e,%II]ή}1=s5, sWbAV$d
;QO7wQO'P햰c5(C(1$F4zOi[/ZoҲ2=@ΐZ)$c
,Z3{Ғj'29+-e(T9Dc7ѽ90YËe8:iڎݙ`}9Ο'MOlLVMz<,,;"J<)tXg2ϲtv?u2yq^/Opٙ~"^˩Э}59[bqX(+?luŏ뉸~z\=1Chhu
 >]WCӍWzUV%Y'6Nm1Ѯ}q}m'g8/s	dY,6K ӧ'3à?0V崯֎3NDĹ3=},iK!ؘkLʫ>{ăe̹>9li޿s+g梭O8Ʀ4CogbkeQT'sKⰲjH0b`7Tqvއ@D DG{KvںM!
z/W<z{R6abd&7J38aȢCvsF@Wɐ`_Ŵ>@_u~ V?-*7q=4ol*g$@6澑7h&˂
I 3uMqdT3)<d!01?(H&M0=t>a>S1{.4E Ǔ5{jfGS%S:cօǠQW,s⎀gu^Bb]vIa8@* 뤲]@
x>YtrMΣry{=~<{
?#IVA`g[O_62d[qg-W^5R
w|\Tܻ}7nߝ֔(:@#ojqs{	rrg<9<,֖+k?*\Њ>|5E'-&L!8yhX殞gk?~gFg){Zxɲ+
1#rZ!C3L\ZuxH2복-| 𞢽)v$ef^	C0!HGcG)XuCҁ&,]JɥS'y
]3Z ,2i;X7mL	tVFgF!V3!'7%,]!>ȷ/cɎ5B@LS^w,G	ms$
Ŷf3ͪRbp]{>MmQ+m3fO VRXӶLRVTRS֋*/5)"p-%-kM=IH:K`~.E(D.=<P0n62F~ӧ0YЫXА9+_pgŻ5;~>, .Mt[[c㏙ģM>HbY|/	'(\廓DJ\(y^LQ軞K/ō٘ZZzHn99-(͵0-FO]|0[YhOgtqk=FSL'M:Ԕov(z!y%bPz]qY?Y^7F={BE"[Zk*`ɿ`H)=8ʥg3 /' v͛ԫ`SP֫9&7-MZ8W/IP_K12>CuzUQ5%d
Gx;ϭsGt7$I@	$̟0_4,˲lȲУ@Kf"tW9TuUg4U{ssgoz6>}	G-,)5&0UdCodpzȕ*{S\հdHZdmI,Y(<5֣1qvv\_( W@uoڍh/=qֺX-aB |9ċ4Zi}F(ӟn+q94Vl~,LW/e*(Ф9Qb,-McՒsH &B?E{YDKRYlJVX>X4	rkMd_ 2dpcȓcߦZ2dkfv^]G6f 'aTRF~L25ZytIDsw<~'^?Iqgl)AٿaOK(Xay:87r!ݝY|61qo*ѭΪ{!9+̦	u!#@Xmj.2Jҷll*/k
S1WC"UU4!{vxXUaM9̲*RMj_>܄#bdxDZ4ftL1J}q>SfS<
8%Ka1tt4\AOr=PMz0kB5ݥV0vNnxAI UR"~N`<97+曷h/rfLȠ1Mٮ)FO Aဌ3MKV\[O<Vqо> tEk:.kJ8W#)9X='5%+BCfrS"Ky+FPg&l=yH,i㜒*/%9-'[QnرNd[rrv6bKrTd:?WN`){SMͶ$K]-Ҝ5P;i[o?=ݔk-tuJSn婦z=0+(o>GT2C_~)~kmhW&q$23"LZI1NፏѼ>_8?^.r<+87k/JX8eӰ|n}"yML57Doscq(펻mصc9Lg%RkȻ6VQ]ݽ-2s#gbhx8*2et!'jeJ|ݢ2!$DjHɲ'^k~gKj)ie6 ZyQF=gڛ'2r!/.Yz`h>d}珢AXs
sE@Wim~/Fp'Z
ݦ"BXO_KJФn\?<̵k̹d0c[3/άpEUq6>yzMTO?Qu2Ѹ9n+Zl!V=\5#bbh|ƨ,If+Xup9)631'TUp4nѯ74&bJ3ǘCQЀ&d,<2o~)L*C"KeIq3?lR<u%'IyrVdTM]0cIwr>;;]5(X&,JƆ8xPA-Y)?\;`o!KIB>kqޔ>skwj{\md:>~(.SYU- p.l[PW|5,`:TF/n!mlikhnl .-S6;vKLC#gY\ːeTj-,t,!JQLxNkMkghod9k0Бz&!k0z{Am5ޝ[!7vt̤~p"菖C*7;]`rxIRMZd%3g_*bj"F<dQ(?Ys	J!:;A;rJ8@mUfbjB!y0uyq,ob'![IJe(]mN|vzC3 Wb@u%$Jt@LWף=׉[v9EJeM}#({b06V}ı!O*Y'%H&TXA9[{r'ǉZ"Zbfe4
gqFu-YVsןKK9c-24%{%dSĘ,erO#ha/]wj9Ù\1eÇz(?=Ԇ؈x_f:'r,ljkqh\3kТt.;*v]HڷE%&<S4U[WOg.Eǎ=[Jާvtɬ̇+E%GT^@C'u`~F$k'O9s/:CF.,!z;|55vC&t=f,d_kW0[CMmeRNZ2mn@<;o5IL{]=֟^ѺFA8*,e֨L#vl&7\T'y!'[kI"Ot\M>ۋXVI+Zm͍f|lώKV箋NGDyzoDxkt_sZ]& dETtd|t`EI|g5|dtR%u	5q	z r@s	?:dwvv|4eA!R.-/^jBk#1T!l$_ixYcM	."3uy,P+27u\R9g*}<d/#(Bi
SN}C/'^mI%nO͘ݑY@@b^DK,3+1zw"O/Dgس?;;wwwEc[S[ͭZ]n,}n i\~C]]m]]q;2J-.$,4/N[9ut<q.CF[݃+SvqSWH'DTjdgzZ|7}Sxף-@Pc3e+X5#a-4ִ"193PbnX6ݍĝ,R~MVtch]E'գ?a61S(9rYJD-ҦXZ\VL~B!Y&e,WuWtTdu8~7aPjluoy8vxd@߫෽>@!DUkhqGX}\P_~rdӂm{Fi,,V)l)q4U    IDATmA&CDjCiI	
?SgU3-ɲãʺXQ֔u+hjXNefv@Fj*Apg8imtKm,o*+YtLiyYD)3k(L{ięAeȇE:>	e<Ic͗_-nxr]&J&QB07MKԁ7&gBwuEoO?ׅ}}KGƎV)	QKJ,3L`ȖSwc}i!n:9+-(OLӍd*Y<<W^e@gO`|踧Ҋ@=rgGE@֤n~)p(s˿I=W_Y,kdy
?07EĴPbHCnX79)M6czvI6ͤ^둧[96c/dORA89YF&*9l\rgjxۉvKBn6{Z5lA#unn#e9YeQ,ҤmN*vv[#CfiˤĄ##C)UF}ݵ	22M
3C8`y@r*	_]F,I|>y(ocrr)ת&cNMt-u\UٷNISRw[J-^wҖH~GnRaiK35nSsŝ@a6x$-gCWؕQ|*sX$n/p8Up
ԥNK$yI^B%C>x%HJ%a-o|kqQ:fIUpˢDx"˰
n.3wǕ{qcb>;4Y<斶hh>z2:Z*7DS+z\qg*WqZ>|+1v\t45mW7Zg`|Y&8ුJhwW083t:OJ֔ß&"J@`b sׁՋ(bDPdY.)mL,d>lanpɐ2;osX߬Y.nlN?ftz^|`auh ;j'rVVR搔s@E!yA<uρ,ȁo^+aRq4Nx=IYhV $dL>!z*w>>E=faCc|`ȡѯޥ5f]N=S*
܄B#F1<C<uҵZ^pfvS鰧zK
W[0 LfX̠oZe6[i52OKCO&dz3ZKչ1.MӆFqMMF>y=T@2'nybRhW(k~_^832&yj@3eJ":]^ç8fRkOg1Lۂf`F~3*+u8+z%^`̫15gpd5]Q[>Xͫʽ59+-ڄNţhʑ~`o/}6v?-<{ivLfމ;$,#}A=͠[y5z[[M껢{Ǯ̐#C*k-Ep3Թ,,zȐ[cxhHZ<Y0:]&Cv H>܋,rqCXFM{c</&o1ӫ~ Y\6d'@N
FҲX<31:ŚbyÇyߎoz(Ud%M-ro*{)iIS;eQ5'QMw@yvv^A=hqM>2O7(o*Dw*Mwۚ,Ps5Gv#Cnͱ)}gƶt4.lTBM]x$k[Ps CylvAŷnO;wDM:FSDS:4(Dy9iYY򜒬krwQ\
jHE#`Z<&63Xq,_Q7qp,/<,$'_PsmGLfCNlcT3p9cY>>,ڜ^w/^~x7Xbv&X,%7;qd\]*;!Ytg>L;ƶ}T7bOwoݘ[IkU4w4=-STf]KKܭ!_}deh6یӓ!}gkzI/1p낣!:J"]d[5,}KSG'+K*5~4)o%#S@}sRܺ;I='13OySR=}r	*}1wgz	grct$@:P1(gj.Ub;zڢ5,
֕z@5"lotԑW|yMY1äY9[lddL?/⧃̚appMWX#>47XP1ÂBL	5cS?]	LBһ2L![+՞^:r79m,MX:~Sq`(Y&81y0?i.PIwIT*2^i/X#lb+#vă"u9<d#7T_K0_ܬ_,( 2бcze`,(~C~7u=]ZEoe*8:uc*(뮬-ųwǕq}l2n,D[ꀬ	F:/K8;?_bg8.G-m_XuMkZ_	&tKHcRܧT{#4d롌'&,!#*'j5Nsd}!7~8M(&Qꁛ栶}R{ߨg+gc=fffb56.-iWbv.$2;YXY⡎Zee. hјhQW-^נQK4W)h$Sގhwߴ77kee[?TQpmh,d%jW$m'Δ?-/B{;dASod4n3uYѺg ]<jG%"ERը*u2# KTe),ƬS|UQK,2vAROj`4y{w;/^aA0'+NX	k[6eSiZθ9#u#˿&iqh)&SB>`cf-框"4OwCe4T:gٞR0y᠍@ 51]_'őǓ
eR>]ae/}eȔHdA.+1AsCX(7Bv{m^Tȏkg.ścqgf1:wJg1;9*UTbǾ]߾N\3#,sYS(_>L,ݹ&7\GOW4ƮeZ zsR6͉[oO3838CCxE<Ċe]rsk1e
"3䖝g	eMojđC^XYgъ-~'|	
ȸNK~.ffx-.4miQT0(ӦUPRXSE26/ =io<
tWLg$]rguhUEgd`nYfe $a	7lT:pƙrO\O/I\ݲDOt:%M\j~)hk|bli.rgXHJVO<
vL+?ҵԴ4E̤$gOmQvCu#Kx[7<|}*)dK`b[j̐,.ΎM15A6u-vu=Цs3H)IQ:NV9|O2[`zn2c\lqر8zh5Z^(Dxz%xePԐE Eܾ[_U.TEz>6fˏ+.w̢4;fMT}GIFVl8s;qul.֖ I8\bj6Es~dBbhG4,Č۟\\ޘZ3呡!aȏ?'{Kg=SU".8aWs_Fjoj0DY!JY'*2ӞX'Ss1uvܺ;-=ZWg_tLC^]v,3}Uz)$6k*na'JyişY0ya8v\}-'Y d3*m`;[F{+R=FI3
W3nu; ;+Nu3\Q2gǑ MqsѾ"#BA5'8)eMκGMϛTd!2T3aR`HSqezTs'zvzZ	u	yaQ+U<$ur xjgʅgx^/G+UsPSzySV3ExgѾ<0HLn{mS4y3s5,vi~h|m]6r.Bs	VCd%=R1Uvcc_˽XX4VU6WuTd	eD|qոxk,nN/ƁCS7c8xh#>l.k7Vb(8
YB}V	13z>Z[$Y4&e΋.{ ǐ,Pd&$">=tMQzDYPϖY=mYOŤQo[҂Ťzm4җb!~ur]uZ,r%[$𲟡3D0KNYܸ=&8RK+.Yih.R?wςJVlIMb)W$	y6-"-C[26.KxW<*aC3Mq7DSBPرMΙ^X35m|P_pmyG5m
ԓ9DH<)A`ZH"C 5P/D+Og,}@OT*i{^8Ze/*DE%G`<ť41(dXRv٩[xs͠+"`Dv\pڰI	gQk9`_
)Ҹ)+z\ѓ,orZ_	iSH (o2کlQ1l2̕Ac;;T]|!-5~ɗ_X$S'͸9{<(n(w}7qtE״kxD,GMҨՕXޢpRMq?A'\&RlӤ^VK0"9;tJ{LLH8.hIRaX\.7zzCCg/!'!^|1Y7!S[{ƚ-n݊wFsZ8A{KO~~5:-e0lԘv6I7Фa3Kъ{aԬNxCk&CU_tE[[)ʐk 673ٲlu1b{]A,d\gMN8!:iߋ@(tIvqbsjrsMOJ!x05@h8DN1cWwʅj#/T$[Vi.~xl.'~`l)Ah:h̴(	/6͙F/nq}NF7O9AcBOӧcvjRb+veTvwb8RcYp^ycc/ASPz50n{G)YTڬyp}=boiRK,|Kyӥ ՋG2sK3⛏=ׯ_sĵqAiB1T(7|'^$c.|G-5<]Vb}y1'ʭk ISTR%=\1+,X8ڀ<Y8G@'Cҡ@C6vg"=P#	6IE}hCn ?Kf0VF֬V=@B43ILܹq5ݸ-=SsC>Tzcs~O-f"tŞJd(%c;w/}xF,(t7cz~%/\׽^MΌJyNdȝήC{+soM{2% oEY|
Z[SےPF퍦O/ƭYwPNPGO+$1JmS@135R$m61!<3Mjxӿ*ujvu&YX]{TIjHJk~N-T)Re 52FF"@!h<E3QH6bv:>z>єegpVRЦm.,hˀWjU#:rPx1O%Bi0d<VWc޽x7=Dhݚ뱰b[l/]Xn3-gA |z;NE}*:Z|X`κ~ßĹWeM\7O?p_<CpwV7buv2gC5.,A8r`$o!9N;7lwgƧ`GO}qC ΪeQXe=Q`LmD6K&".^=O@h
ȬcG9Α+ꒅ3IVz}={Uq(K~snܸ}G22d^1zw`ȝ0W'( /ߞ>Mbm_,؋;c'NšZF ͘]Xox
T黧{;넀!n)pd?( 3"ڛ6$ Ic-d3ox5dH[3ЃCy}=ivٕ,5$#ƊD1اiV܁dN'Bŗ2uSCa1`տbuxag&a^bB
d\Sb+mGv>4dr\_XZr#sP|2GM`c<zm2g!\]0d)hl	klbGwJy|[1&)A'&;DQ_c=`^^07|o٩Fܹ%Ӌۛ'[Vxո|k,.ܞ~5/{{}:-ŧxDZ̜	MĘ$8;(iY>nzPR݌;t{L{ƽhҚ C
)M-?dN9)Ԫ٠I.qm#me=E?Bimdr:cG<C\E{k6D2IdWG3IF7:s1vxd|֥5`==Ҳ C5eҭݥjtwn1/t(5_G#F7t2.ukpqC6EUTѹy|,P>(!YVe69:YkDq!c$j#aY6{yO$<6²GitO_[w;zkʑKţP2cHժiמ|7.QgaԂ/0n {ίWTx`V"[k1t{    IDAT}p?6U{u;m(pRs:k9M@)EŇN+C.2$v0pI1+?D$hٕ̖#VjhVFshI>4"SJ{Ĳ*zBfN<[Ͳ-dOZ<±qpN\Y{
͡Nn˫㙧?d5[Tgyrmǹj<ɑHgwιT5놬ݍ<#䓟RAs 5^JQ-2滺1h]T<g_~!j?;C93dAҴ˾@D./ֿ77,sj\z=:r<2FGo_txZ+T t숞"Cj0 'N3zTKXx--BSdU	$b1Đ:S[Cd
91Ys7\4GKvEw$.$dY\`kbgo+̶Ϫ8H㭰:U^#\}$ȁ1鿈F{5`:qa%Bk!	V阓s2TN ͛FMrڳ .ta]x;/LR*%A$(Végo+ȅ.'M>eHXPpJ͇?75F1fN̦xQ\r@@q`*Y%&1Qo:2dX*`8ߊGOu۬J#&9۸e1	
i2߳p/tlo\p)dѾ7	MpP}ԙCЇu]8v8>'ɣzfurܹz9
[B%xlBxS	N\ΐz hƙ3<iY66ǹulہ
-R)ֺu0pA.O^;bfjowv?񄮓g:;6y:X]c>@=Mڴ7CY{vkqsaExT!w|LOby~&ZLKXyew}^du$842<szN$k6\ll-yWKɀXE/n{0^dG,!s#.
R<%lLX+9yj|jz8K7Cvذz\`ZqY:ѭo*:`!;vy]UC2rW0Sjx1൥<^$B5QSJ`0ЙsreDKp$OڛE訕ldgI|i'}8ҹ2]*J7R`ʐb#>WGM#fߛWm2FZ5.E8{/Xl[_9?^܋hݵORƦXY鳗x-G<z8̧$gXijvJG;74vkbL]<,uoo8Φ53'R2,fOhJ"lUʚůSoIE9PWߍ10 (  ޳'>9Փ6ᬾ#@Ejݻz轐Aب*KgQinW&knh>NOOE=Ln'Ieczð&/i,d-y.ZyPY8P:5
g!_kIFĂ_fsOYp%2(ʅ_ޏ?DMqDB
7g4vC]Eq\x_@!R_~־{5	7g1AJ<0l~Sa9*	[mkٶ́WkaVqcmTR=:T/yQ%7,1L7(̠_\6irx!PF4PZSczޯd+eMWTrmieiRE䍅UP{r\-
ڼc'Rs@\d濱ַ_4,yY&-{o۳A{qV|䁸vJ\=W'磡wxqͲ_]S{X]*b<th|hom}hljz
ָ=)3q2kmJWç!?' ͐	0RVյ-?SqX[C^Y^JS;vg;!Uؤp"Cvuo`Gܹ}S5,'|^Lܼz).]єXXp=??XڄGVkS89슔¤#(gk$N4,rB.VB)=+gᨳ!S	CZ$A`5d!E
tvD,*졛Ɛ/M5<bE3
݌a&#O
>)q$P;ɴ+ m(wn ,RSt˼\HBFdMni1Cqe7e̐JڙۑK%Ua2oWl>MN] DPhX^ 9A#m&`VV4
;7/M)^8͔J95xz: ){s,3g\[$8IA4dE:jȫ191/r`<p*Isa&E/\}{6ѓ±=q];$ڃ	\UIoV9/#qK_y-v@˂&׹8D{c}%z+?F7]ZwyҲ(m?g%rV@>a>~ڠ<EftxB.HEY+I-$ˋ5LOSs'Ō{?gKaYh+a
ekO*xC^^iOܾFG=zL56FWOw4)e<>s/)n)$E|s1F&53S7g
Gg2^-HA5ڛpqxS{%|Veo( _`^;d1R:*޼tquyF.Y*r♩L
$XoņҵNMd0ר
&kҤaOvoEO_خ+2@5)(iEH 'X i>t3	&`d4'e;H+#9ie$aUWb(|/,ș31?=>VEz \S8mj@P̈́'{Ѡm .e;IC/vm>'~Xnb_͵Kb}]z$@l,DR9y&忭Ldn6d<@\x).OMǵ{sػK:<yF+||^ɀC㗞2MMYF4tP@Ww숃ǘRÆZy@bYc]o$e@ 0̙s*&7NCPLlPֲy,ȔacB޵K7Į=ճX\MzibJ?zB?|^GU!]G#ےsu<?X[CC5X	l4CFV+|lWTȨF]&zYtn2BH~fE9sV(ǐ6qkb8倄Ko!y0/R8l;_q*q+Cԛn+Q >+ٯxeN\>_ K)U	7\*HL5T	 {Wsޥ)$P'k縻O̈́di3YEfC?,2},r62<Sr9bwKA>D}N$$
ơx~zRҲP,mYyjfNn`MZ#$AEz`
8z$jX&|ٴͪNűc>K@ׂѪ8][s16{WYd=779RLqᇎLܹ#ZOnW{{b{My[#]_"mTxfಔ)7<Xcqxgֺe0YC c-BRRxCinK_J޽Kꬃ7ߋ>V碾&̩/Vk5D Tep8{jԵt(	ڬ^2j|Ǳ`d\򪠆Dk: Ob ܐu	f/&Ћ0M$s`bL+1;`~|Y Y_!hJ|U]f;י_E1vfv캭.~q|~p_v{×=PJASk0;E@SO[>)F:p X;Ɯgֱɱ_jf@<n]x"-=_,f̙ZՆz97hyR&w$t= )`:VpUST+"E,M%L9Ź	r0B!͹]ȥ7',xf1UGrvm}bdZXTXþ$,lL{6?'x7aۣ^ͮr6JK6~+&g0l̍ƕqsj.nO/FǮDokm ZK_s|8N?폶Ɗ\#4PiS1Fs%4sq't:1N`6Q@{9	C>}Jz/|鹨Pm̬W_֝䬯mڛ퍘S)wl*,͔ ~&̧fnKʔ" 58m7李{]9?_JsL:@@4|*#ր=DɽQ@NuE3~ Ujkhz}]~)%fÖkFsúME	ȅk[Y:]E +)iˉ5!1[Vq`m%@`ޞ𕸓zLs3QJm(6oxVmR~K͒)^AI*`?77i<eTgQO
iP7Ϫ,"IRh e2}QntTyЉ4e@̜deVCԀ`Z`GkיlI;Ge#=dho'_i1o2CYMj1笹d3b,Zi.lJ7s<"f5DR`2򛯽kՀStnRc9ՒnodiKqkj.fc}bY+ei!>p8Ξ$yFOe٧AcjeNC~N5z_9p޶JZdsҒWia֌Z+2eQeÃqxzi$'g۫rb;UF*_a/8 4yƮ];z)fIK-8#Bd6`8dEQU#+qjho[hREΝ
AKu3Y57ykc]
Ia<2Zw3֦-!増RѶ	X81:sbT~݌z.4P>bY3
n93PP:C.'vVGR@8>OS\2s8pSz1hQr#ڮX2TĲX̕SiW]=M4B̏J0ҊvP L	{Ƥcpęy[z&ʀtÝl.xpϤ9eijYRP6Ggdx$&ĺXv4Y4\,ZWxF88òbw@~e}=s'uaYҋkY\z/,چY[MN廭X-!3ͥ{qCg.l[\E8QZY>8{J̯*VBĉыW+H<2˧>Bac`_9HཛjY3PK@|SL)	LŅ/<c199!~RX*6Les Û?V@޳g2db޽ԧ?@A].y
Ȱ,$ki=p=d7SrqũQmjSfYywOX!֓Đ[*/65KA:JH<Efd܀P+ޤTrކ[(;.`t*Hɐ{Ϭ+ʦSga<d,C$9ٴg?hȢ-;~zuPɹYI&uiMtb8eiAɽD'&6c{KtW7y)3-MhP,2~LDt+#:;)g*VGbhOkyIuD4pydlqS36t䐵$Hi!ZJy<	l:L%^]yzdi=y<Rp=f6<iݻH2e_58,VUiuIݡ7PXFb)@MD[(k9-{q)>`P~zsIAfsl*@k+Kc97+kʴ$8~p|OI[n5QաO}]R8|x(	(Pme;Dq6cm8L|gjʳ3sz-jUCr Cf}]u9-
Z[GWJ"^W;&(W5v'Ip!)@C6eFɐWpبo6cqWOΝԛɟ	ӮP`Uq(z,:Kbq{USTk6M?EW5}}y58-SV,`Ӛ= 	65+Sg$%F`pBy>!ߞ^i2EϾ/AZqV4B/鵩1iA*uc]g09CAQo!	OeW_*VSiͱB7 ue8liiieHDa$5y]Tn\)I{z%.R0&0"m+0|>K23
00}i24c̽ j3VMD"YC^pKÑlkz|o.llV
"WKeQx	IW&WxS4ϭnǙk>Z^Uחsqe}iH.>~X	ܶG7;`ȗΞ*CƜtkW>y5qljzxx_s0Ӄqܙꗿ`5G43LY/nyQfK54h_կ=$3{SO4tu%7|ӯ< ,u4ceq>n\G#Dc! tLO4`25h`qqV+Cݜ)ո/ɴT0ѺuzmM	Cm{5C֢e\pT3)#Y{&\1ęֲ򊇷G/{Ų3[&>f=Ekcf4)zsnf3Zo&<Ɣ$P.z8
P#U^MS@K9L    IDATDF6e4uǉ"l}مtyhC٥?(%:_K`flXkc
")hY:._14|F"\ Hiص,Ktr_.xR$/s3RUEmq~GtGqG]^V/'^kzP;vtI>!gr,vsYbuq"5ٸ:6끣
nLqp/.rR7g8{<1i`XpM8,ĥs#1sbP]ҳ;|TAQ"g][TQv% s#:|T\8w6^x'I=<zlM	% fcs.:^Op{?}w}1;M\*C~uKC@Y:ņN8Ivnkq̥AuUYa2{WLLc}߇8<0h0*;x X$TLd~T5rza5z:o_I^T5>o,!gUgX#k6@ZI_xJn2(]:jow'g{ͰI/<ݟQgP	BE{pyo:lErI2^Qd7ř4qYw~ˋsQ4>oi?CtyY:4')
VM,}y05(y=n2L7vv\&_#nẛqyN7Ӹ#ÕNf.,6.u"EX^:'~D$ȬW<GVς饗^w~Gn(W@;aA{!q(Hnb`dXG눋CTܜZl&xe5Ư]1(l,'GGcv>oj]$h2ݸ|1nߊouur8.w9PuN(M95K*0(4l"ӧ<͍@,8nXxo=+=/gbuhwXY?b=173Ʀ˸ox駵qfȖ@3:ըkh-+%x,6<yCYыnߵ
92n=iWgf/"eϥ
TF4P-}]=q4̂kSVUZESKMikp)
Έ:dU%W*%<`'B1o'՟>z0hܝۺD,dPU료Jא; OxШJ'eFfrZ+^6"$Dȿ_76Ƨ]'su6(HB*UQ$K'fђpS5ȸ`uhY(@	f00߱N#,ZnGpscfb<Os	goٔ݆3]Ba:Cp2ia~C2'-|4CX|N,}{\3<\G6j]C-GCuą~o^,ήdz F&8=)=˅5>&u+4ƖI^t!6EO6tƑE2Xtz!XsLe2SXFęx||_LnFLΕ<v&jNUk?oXk_Ʈݻɧ:XZiiuUKƭ	ԶhekB/Njs*S^LO__zJz+H&dڜ\A-sfQ4~_Oҳm3[SP;<;[<SX:d'TTt:ƫKPj f	lL8
=_CxoJO)ݽ_y+*O)@/B%A?vKGa5HmP&!PEU3H̨X	WqƩήRn*@1q)SEQd<!Ă)WK"G(=PK	-̕"bO*-HewR6p,u_JXgQ*Kuө`2JPftK<tGk)Y9.n:C~%-3K)#߮iQMf*b)|}n|bwg\<w!.{}Ye<K|}ߏwyGd64/|)sSGޕ+1~J,߽-0GrNCuQ_\[&"i]/'$ʎ	o^:>gRֳs(3`}ϸ\V6>fY[x]i?ؿX&s>-A{kffU5*tN 4bmoT0:?7^/DT j,/;cRjϮhz)e)NlH{!{h*a1a_GS8KP(>Puhep	e)HW%::Q\
l\UgL?"*\fQuz?k)ه/,.E|GFc|zNkI=f,p7WyzsJrdMRXlIRwUKoZ6X&297H\9#eV\BKXV3r5Zږ]at)4ÔaJ]U&-6;kGbinDz-tSNt(GK	B%9Rz˓zpyQArwn@rIl&`ȷ۲p~YP2鬨dȵN [R8jX[aD-/_ 2E<?@ 'tTc}{c߾z>Tjit4GJID-nvRk8zn.貏_dPbYky~R)9\xC1zb|Fk#cG:3(CJ*"O9ݛW/}3KsSr?{@<gd|H2:MÞA O.NŕGG]+F_pЖ@юh:tLObsu)iX[c4ٿc0gTR]lidm"㱒Ό{4:OIvY>c<=J3:Wz=lc8([_E'V-W"bR:;:sW4~g`oh Mli7_(C-0E,jFS%IIV2:R^W*lirrJ`r0*v@¦nie*V9CÀ&D.e'N0ih"x#j`Д
6)mOФjUY0i'2L4l!.Cq)8Q%ޒQ{ E^=v$}qc9mdS{+ondKo(K% ӸAW<".,
r^jJ
fzyv,-h4XGHGrC{#޻{;^ե%A*K%ٻ@<ppA˚\r$#GQo{2YoVs4XsPZDN6	^RoCC1z|>-hT"f&Umr](x`NJI=|Ed'}>YL8`N'4jN4	.bY4 j҅ř~lވ7-.O!O,֗sqnn2IN6k!Թ-ihf9iXJ{|#z;byE*ke>8Jr2EU/`8E	fD%7mf!ghfx:⃳Wb|ƚ=]ё.򦬹Z(jZek-2̚4N3e[ࢼ>KO_aSZBCHM=]?wtce*,G5v9&H9ZL}"q-	>Iiv!Ww-btM@ɆU	btY2)nx6j%+̾	VDK><9kHKhT;5u|Hcp$\yCpF/%&\&&o={d!+K;@]srE%uݽz1^8y_ܾ~=.ݹWNv튱:,E&(Tf2(/hoYфtS65Xso<'~Yd_x!Br-[FS3-MZ+Y\x1/I|fh`7'Viy96x󱰼ŋ)?+۷/y*I&ǒKR:U ?Ϝ{֢nF&`0dP3ѓuҲݴ9ޏ46pMjozM$ǿ ݍ E#SjOx~VORI* L^5j̀:RIGo}C ;'+nm4ɐq!\(3{gGcR|%{lV^öͪX: 2K`bd?iqy׬9")PP@9Ȥ!?߬)dN*Ek*b0`&`}#":d7My9R.2xϒsӋ'%KT+8榰hP׉N*7bdd$g\?=8?ɾ(B+N:eSV z[ǰA #D 1ѡX#d33,8P&&h}#~m}SƆ2ta x?*Tu87v-}p FGGͱʴxd9ٳabjrF><pd&<+:Jgon"7em}q'Pj6"6kC90VOU`ImҤVQd#CCqxZ a1ǻ(Fda#PCKrL.&jqa)Ww~/}ߞX]bO>87`7M mT9A2źFS3qoJz^첾hOtLObc=g,ې~)CUt֕SL\dC%q9dwjkq-e?%3d>xPc;CEWN YH+]yktz^^њ)LCC! /( brZ`rHLފC8(T\_I=M*~$|\ࠫ18E
-9#Wl'.*vYP,E}nU$2.]R3Ne ̕Hv"*1&Ky[xJX%1dnXb̶)Q[u)񒤫-ff_OtO^i	Hۜi:!wt	f!tdǐxo;o%vIWV IB3VԭK̃Kq֘,7TO.?/\;6DyD}Zl܊vE]a9<YWsmqO9+{XJ]+(<{tUeڑPTwn\K/k6bOčՆ+?plAPb$Z
pڍxMVϢ;N<tBdzRAP!ڼvE]t)_Ұwƕb[,Dbӷs@3?s!7sC	uqVӔf"4viH$>mR?V!i u/'l>v!wҽp=LDyK}(e5Vf3Oxc E,9'A]f8 OŘ^PhfvuZ9*eKC7\K09ܟ*TfVxnkbP]V9.T,T`0E1x"M:ZD,0Z7$1&q/7G	܄j
9oy*W'&bkqyeRۗĺON+ht}ZJjZ%1XFUN*<09Lŗ!x>p@:
wZǵuX,,,yAxbwG^clf^>v^qvs=M׊\Q_/\3rz~~Iߟc6YN9z[[b8{|4jp>FEothvL@URr)ll/|ص_t:Y^WpzzVvP^jQ#"bA55#ͼn3ͭ4"R͍19CMy/ͺA*jU[Ŕu@*sm
f, p깧F%$i^2;ڢmIٔ|d߹g|Nk^h@N6yiB7]TL@vlAM7f[nln#{OyܥT^O!yeK2A&ƪ~u,15%qqoMns|:h*{Usx	A0IN$suyIf.³.5f!.-<iMgA^#$(gz 0a~JR<ŀE,@۫ؾ~cRǪrPt&Cv:d(B!n+%OB&|/qlzaNò@@)T9lnX7Rp]'C^&gw.g3I<ΪB]0{x_K\|EzYQ.n[9|O5*S!7KccҚjҊƺhFÃ>:4Lv>Q3t{=,j2R-7;9Zc֍:Ay߹;e EjdQRO\XɗHOI*U)+A,Y&)hlU\*[ I@ m}nvNS{}{s9{NWƆ}\gH*Pk]"WZhݓϿуQ][~BwGL|dV[4)9e7	DF=mX! v]T!Ȑck?&IujvS~EJS#Z&B6Jh/Vʐ{z5y]{3D9sKv̷"_Yv":C{sF@8n7|7޾Һѡ~]&Liϭ_K9֩D?ՕFAɾ&M/;OFWEWTU-|dcgԤH5;Ia2nss,Dz)lQdBl&#(5y'5)XQ8q#St>yR,cco* C_ea\E.,<Ijk4= 	!'Oa몇,pAST D! sx޾7T;{Zٙ٨ʸkKVX>ywivȼ<y5w~|apٿ"+%9GTX:2%&T{O't3m)lE>h{]3lqxRtwucSoCT&Bq7+KfDʬRZzbC5ďaMQAWo|4Ξ:5JS'TUvyTH`䋲 s}]	!-NFy%6sOrȁh;X~KrwFoq|yִs2    IDATi.$\zTBaǨGz  w){OC?6;4F]i	*X70Mɔ̷VgdC1_l7rд8+:b*$ŜYu\9|MeΓs$Zp<kE,qSa^(mj\ȿE%jdiVÉuL
ZSGjjdL	kxb.D";#XpfDSkmGԐe^
zZ,ͤ{3Hb~ժ0d nUi)FZܲSL;*T7M=35©yhHXX\}Ϲ0 ޷
=+nlk)g>b2Q;W⡣q^Kyb	0;Z:!{V++:l4Gt05M!EGoO#O)@iT֢QjL}-2nocWHyAQBкP
βSrXځ4VZ\]Y_㱵5/|YpӓO=ͻ{ ʰNx4@s[lhN{^4	C-0.ԧI`yyB_>t_M[DI<`Jo
S)G8}=sK)1lP=<T YU0!f2 79<SeRr;A޼t#N;90d kը%gJ2e?GS_ZpPRhɜ+$Jp:=XyP25>ȦFNuN}&Ri޼V1OAQA\0(yS8IX(gyA*+REUPʕk4rQIbNjf6B֨E)=ƌH*NaX`KNc8sL.GF困{]anv6~#!Pr{.&'d˹2PuMj!@q!/ܹcBL.Zl& S[M^ %Tt6GSS%	]}Q:xBٞ %Ē!`m`5|'`4Z;c4&3.i`䠳3B`pp?i8%껱羷GIsGA{HTTb=??m?öz{
0dHhm)) ؕK_~pj{"Xd{o,h^6	ڧ{FB	޸~ nLdFRt@Tq5:EN!OebX$~̯nC)>/*ݽ^=$KBС[#'ˢ@$w.0WpG߸<ʌGܜfXgª0&Iɐu~%GhUJj<C_Jyd.dDgVӟKb.F*)cEAƞ*5L^0@)$1_0hA\_LP/rEu'Yg1x&j'[b)5x_|96<WjC'2{4>uԱ`e#)áA>}qp	=8<8^{߉y=;58`xh|IB}}f,N=RXAaQ%GY 孾7%ܤc1
l'GͲ(Zɐ%:&0-867Ĳ|#f&ϾA +[ #42JS:qoxhjحyi7jUH9sR?~!FF{36_]aџMKv+P]&@0 Yv5"ږͱx˱֭k܎UՓFCna5N:Ufd{zi8^^q'P!ADclc)iq#椪|]'OkepH7y{lT*6J&`*s!51IޛIr
,8A}zI?Qd$GXqr?59CXPSl6`i"V|xQz_,..~Ģ2'M6xq%K~cZk4&@	*J.2rC
C승Jth(NTř'6n(wBf\R牫S#.e;>SEesɌ_i2
6}§^:u*O&(C!>)pSnlaQI,!1mt󴚌B;k1Ska9mM(>̔:^J]ņNR	Svws8}ڊ	
s@8Ʈ.V6[trRMMO<"n~sphAP%ٚcQ7X[Y/Ͽg(
#Gzcc՜zڭބVW7L4!.<!]^^ațz,"`MA{ٓN6"ьr	@뿸,?e%g`5iْ9S4Lvpk11QvEɌ/{-~{^;0dϽwA򞙈kпqhǛ% Ɓ~gzQM2!+Z<G,:̓^]2{<)8:=eirV0rT}
,ʷ^e@gmXpP3QA=n #2I.=%|Gtt $jR$WȪ	07pNs</겂8~x(=uD]~=޼|+fYAFB$xjl7XYQ
DH~aq;zXk*aTԃesϋCb΄6cfN3/.GV|r舋J-&+:<B&Hib4<WS/=mbY4C_pjk#ۗF2;aKdYvrYFcos3}nUDǺ+cln-Zz@fV#vvwV/|?gWTWy>`tb	<P&0}"VjQEAi(Tpa)L܊߾!J5Y eqh'9[yF':ft0\S+ջjQkUɇ*\+Y';`Wwu3؀Uldr"wv; `UU@l1TT0v3.ۂ]Ȑߺ2&2qР!Qo}elRQ^ji'mث9^`fO!t2DanT?ۏ0^A":FsT7io[aiƐw2#W:ql=w TeǁD PL+Y%4/x5jUq?} i5I<dI`wwOS&oƫoť[2V7*MEQj31E6͔ӧŲ8vӳ
	)>[o~[z=xܸq3fQkm*yDB(Լ\kq5^{_݈M~
zd^L4/dF-JMS"3ha|ޞ9=n3?.52``F4ׯ^Hyvn%CeQbD[	bv;+^^A|cs{g?}Ce\~3LNxGzY4ORovrRזc[cyK~#lL,52YMmٞGg䉁,lK b!~rfPz/2t+xߝ̐"'vj B(JҭY1i1td0dW`[㵋Cʦ& s>0@*ٛ:KC8JٳeЋ"}C0l~O|8Q5 8uͫGO^nhm|R0aUfu ^S?ٔlr'o6=z#	P5$7MT3)IW:hn<65@wCtr-;pTvWٕ9SSҖ5g{)2N+7+ S'}icGiqrɐo|KGoP}	\nRc	5-
Ne uar;4qi[4e>k2hTa:Ef܆|?wlRFm?A^1)"f,cp;6=q3؅~<<JA.]3uD6KaŘs^|M{IdaȟLL6VѲfKYxfX@Ed=VEp>X^\c˫Lʶ  %Z@L`hM<ba@Po<HmSB~WCrO
@)IjmCdh91]ϓsPwЄV]eNAPZaHl,/׮ũ#՛15:4l3G7OX~T%rND2-HtfP`;1r?8$:8tDudd,>/hx˨r R8~Pot3M^ÇH p=HԇM0fmNK܄KCݍ3GeZv/ju'VŲ(J2P6,vW|mYM9Gɔj`gΜ{/:w&bjzV|QK~7][17=d9pݸ3T6IN[Ms@[=; kgZД`	M"{%.m,ٜ6ZA;r4>0d-xa: MA8([o"Ԑr9gƅh;kE	n]ag4MZh.3 C^.̅C܊raTD׍ҿTtO09j
`dȶWxȔDѢ:qӫ1{w<^yFWic	k3M<p zο/V~he0gR߁(EFbF2>'C.jZh yУ¯kZASdg`O+'6զʃ3u`6ǿ?-.s"cB
]?A <䖖x8}÷ݎAXS?*<P*jgHi%D9qN=M	Slm F{??#bnviLn˿piprER׀ƪydd
y  %8Ѧ"03BvmZf5ws离>իDxAM~5uyII!2&3&En캰J(鍫Qv( {ϟWL|ı	Ap"CЇo~sx䑇cƍ_X4V{rYf[͕s5F{Zwzo*|8rq
Ú3Sʢ	rd4¿rEラ^ێ8qTQe{%K]&w->|6/fn
mcׯD<r|uz]1Sd$RF-;Ǿ>Lc[Զ^s/?)T_x^յhn[\ H;#!Iklg Lܽ}3~ƍXx|֮FJZ7<=/eT׌7jY%vsX;3M}5Rʎ=٦86"cTxLa17%{:%ݞYЁ5zlɟ]4eU	v<OXsqͦqmKb4Uoĉã1)G-ƽ&0 ؂ x礢s`Q9zr<4in[`Z0ه+*S\	d]tqfa`m@)[
NY*=Lиp|=.`->\0Z"2@pQKtmѬ.-31'i[V%<hU}v*z*,/Dt$(QsB(;~X',C16vC_!Cc7CYHs+#kJ6P款isQ[s["R}4TqwĞWn|Uf8*P+4X:Mň1kdlؒ=s:Μ:mR0IZ[۶IpσJ)(nhzM	k0TFSK%Zb'61W>8E@ZS?+GǞ|LNq@ͭ0CŲhR:ljQu'!rSL!NM3wKo݈Śn96jS0=#j̯KʔlBSJQπ[_RS|J|tI>s!Uދ]g~n,*fj9&JWe)nC2ߨF{ѠS&#Ĳ8<C
ȳKk9-Xu!S*`gc&Y4#:-T=IY%=1sc,Uqkii>8:S48,EfALwS&EɫqGv-azdOL@cQhєH*~Lpfdã4(ft]%pK֦{~i
&,6>S]C tf|CiOMɨV?>zN8o7]3^`.\x nގ陙_|4mpjMw-AuA:{/Nc&dpP,j g |T_
.'.)b3:bne:5})A= [>6>lJn|w.9yB-8>`*ݠۿ^:Z%#v-C5E#+6bywW?8~lP5_gw` Sv/X+F@V"[+JECzdŅ<[uZPDK\kgEˉ'c-
I 2'_YxLlP%{f3S}0r?ɕk^HvYoM3`R07{fـndea25$Ԝ,	[`!:u2uG8a`=K{{U\$Y[=uVqK̘Фq~=7d"0禁j{2U01_Աd Y &L5҄du;fWC>0$;jC22D$i5gWy`LgoĵWcvjT$MoGZ| 6s2s%\;;̳g.<
7(=^wM<pqV,,,_|ubsH:`RhSC5s#ǫWLՙIu32.٤|ƌ:OcnR3f[U"*sSh@I6I-r3'OҠ3^|'6'`ޒ}vBmȮ    IDATa3\!4]}b[,lw^^ĉS'b{k==拟x'/
PTL5)25vcc}S2Avya.˷cbMa7Cn=X{k$8)0-̛խ+
H9vRe'I`fz/S^Ba4	HF lYqe}m|ċkib]Y6H1|M5!c,Yŉ#1ҪZ`I˖M,CE5rNӂOMOƊ1jhs_y&nԺg΄]bd|VgL*1m#]X\.$Vf#qdJ9`ZZceuE+UcgCc)ePI!ӼBKEQtU$UI3O3ɹ^|-&ލᡁxwţ="-.,>~V9ˈ(x +'ZcFWw^ǏUzZ,.cxߌ_|Q7?s\,Zh4?dR>#!\\: i;GA=?soZ=]5cR6fթuYDlSմ	f,/
گ]|'jSaDp@GSCV;w 6r^W_y#GOWV
_}kKJ
>fxϵhXDqQ }0,3d?xxY'H^`+p{|SŖ VPMJt$TQٍͪ)ELӥ(L3/2R=`_R3xFKlf!p ^UȂ,/KeZ("rJn<>K1CǶ,`\M5@`F%l!ǏZN0O+7!;7Hl&` C/#RzĂPAbc [)D{\dɈ>ag%[*~pglPx\TiF@)7 ̇&%
LBn^[Bi81Oi07Zn-3򝝸rjLOOwEOG1ԟY\1eQor:Hui4'j[O.]ӧL{ǎ0foLUSo}[;7nV￬F52QWkig6Lx
lMM]ҳ#Ow1*%[ɠnYјh',vLv^572#׭h<)ܰg'L}/Lw|	-2  LX٣4Uvb
CRj\|R<cGŲ`=E@O{~K6ޕ2zT}' 'H>`,L7ƝmK֣9VWizD=ꏾ[ j(5Wϓ90ސ0$9	QW9Ŷ·[R bua^dS'l(~@RlTM(ʬh$&'ƿyV?4"7ƅ!S xKof'AlB3
X2v.)Á3Sq'`Dj9e*iD+_|bJs*3*hkimn̲SXզOʅ,-/kQ^j$3A&t Wx2ΤONehڠl {cqCӛ[qڵ}$o{װt|Oۦ%69vJ{VeK.[4H-4L1<2W\EXd.-|:7uZ8++ʸ^js7*,VF#`#k]%vv;k1IO\GOo(lMX=I9]MPA6d(]a`-*d.mek.!.^sh_Ȧs`\/ںnhrʠ LwZ܌˯~qحq?p_pH[I6tk2Y:
g`x`Ho@(c$9TFƵMg1Nx뱳*/dQ21C\1;XGGBR7035fzIˢ]#\Y&mwíEUM~|%Q:ed듳w
Ct_k.J޼Jl;7cni]`_O#CW.MǗ*Mްm% ii7'>i_1)&b%h}ٺ36˞G0G:9rHW3qhPJHoPٰ4|Z&A(S>`ǦX7n5Eb_,	s-d׮]xG`QsG׭BͫۛM2U2j=J}d{CM<ڧNG%E8?sP:0<+kk߸xen%pߡkldFot5\<LYw~j%Ԛ7)ȢEb7L/qG-H2
'#;S0AEzm^4]&q4Wbxp z7^b;Zs^^X.=R˫B	g*,tV2E!֕qSQȫD7ݣ&Q7s=EĐca$(;%8䥅3'fҔ<e}֑#}ݱ_F-| 6=TvxCe}gɥ$/F_KlO@-͌ډ}I;ބBi)u+cO@.wO:	7dX;`.1PA"3o[Wo12a+T5-%y]zhIeSOaRMu+1	EamðL	-J\Ɛʗ?gu[U
䂇ӡ%fW-Pb@(w-$h|n070ӁM,ٱ0KL74Ff`LLs*k^?O>a-	4yOߦܤ".Jl)/ckZtGg<|P͛1.qa~>~7~-^xʨ$*Y7
|@=>iqP;P,g2؅E H>ٔ&Q7`j~"8h61W^aϭH-i{[wk1PY{=^@G[A/ȻC,9Ɇ(Y&:^eڴ3b(a+n]\~%#7^ѡ8tj:,4	}SNi.mxl2qcb.޺C^o2kjС/qYbv敥Qmwg+2gƈ [qKl7Oc41vL.l:0T(2f̸Tİaf2ș%caYSJh%\GP_w\1!Q	zkNw^TąN"\vVfۆXe
m8\(h#)"hE@Nhgec^i}dvNOg,7ִ䝼f }>< )0.+'ƪ>[HeK0Ȇ2i̝ɦhdY(CNk._sSO??$pco?2(-e3dW[l4H1L#T 8rp͛`Մȿk?wuzn߹ld%((lsybm5}/WAfkePl](ݽL]!j@2NG a;܌[p~Fpx'eZ6%v`ԛ;L2r}ys愖2YFR]9(hss&SoW7cfv):G*@jḙу6HXI%A)GSWl^c2eX6S1>9ߥ	+6-1|`1/+ h(PKf]Ƭ/^LA*tZ!D*uj$jeJ@nZܝXhcjp>Z" dF!)ַ9!5© qfLw%;/UwK)0 [I+s%)ZݮRS8{jejj§X#QpѕeXl7ht
&^ELF`tE݀1"(*L#I_bn3^oHx$`6fO9LTcŌ2c~v:zד?Qzqx?gqgbҙ24I]9G
&X	jlH(JſX3gġG:yBko*{,M7 |{Ilx<s2<ﻻRd6L-K?icuҰ#Pm5+āY>8bky`,v3I]9(;XPC"|)8i$g[\ZTUAofMx擓?5fӮUwFNcGhϕk@]V%:J*.o'8߰CXZX^Ҽ0;1r` :zp@Z ta66z֢m:eW,0S319]hXů]}1/;UW/ axv!+um~JT`N
02QtV[)n5z;b}3K.=vGw0Y9H,3  \u {aAoލU'dΌm)*a57EL>=Tg`/kr,8Yb7abO]i䔐^k_L}zN:rXxdw);5uNL=z<ԤimmE>e2ɩ8rl05niѦ0.!E3v֣V8x83BY_XeR3S,X{,|E3XSS@NY'xIǷ]Ȃ3;tKvϵ:}2;w	/]"vH_~995K?
G՜
$9>̐3[L+Qu%{˟i6ӗ\XY^-yi|J$oeW-I&u\bl'y0]̌<8:pDt4/VI`wLiP74=&ՍG[@]a~
VN=@8?Pe.{}:0L<sJdp+;&HlW=lt۩yFU׵-wRR$<05Z{cmr<,=ͥdmؓ4L4l8<vz=#e],i-R0̌U.vx/Wuh ]w	e(CAqN^[ *%c=3]s%!ף}g/nű,X\S;q+6
:zl4xB#<1@4u4D}sS CWƆ]As.x{a_^R6 6^٬8)k
j2v~pE{rRMER4Ar
$&R>~睋8=P/&'_?Wh_qNӖ3+4CfVHNU;rH^dl:wY/r7:="ӥ]۷$Ap3DR54%[PP$Ѯ*hbfN?M
Ja`ҵaT>du9tcO?#v4@<*F[GcyVC);IR9.N`LwT7
N9}4ܫq֔"w?sӓsDcիPޛf($gf3J)jMAYe[9a4-'%a3s»9A|@N	34K%95Z3`	_M( geK*#7x"b-'/!7vRWoǱCΐ/߼gØVsIB=i	e?赋WIl,}dȔTXR
vĀI>	J}?1zY䁳0p)x>C$y3%%/"#wlwRVBHSK7_YtN.!ЪV7q4O&33xR,Ń?W,wnn!޹x)+_Q̒ȱX%'DJ3` <G(,hN#Ǐ©%aoT@<ҽǶq5}/r80"ܜ{n1˟B+xJE0in&z_wk^Z^k
eR\ȈeoBo~SVx|@C0Ѿ2@9AÕ5T,|oX''&b#Ne8@ut{Swb{)5BF
He$yHo݌uܟ{,5q^-ظ&ҸXlοIQ.h/VE#6 XҔ|=bIlS{9X3/ElX,.HYX2U̐npb&y-V-p\`/32tK+)WS2yJc/TUXXF`^hwvoB`⍑zf>|
DS"b_8\vKzߨYBSG#GCĤMbJer=*h
Zq:en0ccYM~i_$
ʇ[7LB4b1]4ضȂ
:2D섀G0rj=?&ɼ队_}U?'_筚[L,33v#C6d\qƵͭ$oXRyc,L*K?|HNprc6
h`ƿp`/؈6)X3	$\s!kE)C.Cy8g`'2Xs23LkSHM]lEl$-NݨRv^ŭNGAvCx~[4Zۢ]J22*iM\Ƕbj\'CuUpOYݫgÀ7WԜ|l;YpJ4(̰b W@SSM+,	zvIL2dl`JHw	Bi+Yd	ANg*,Ͻ8zd1(-,I\o61͊H{ZފŢCc`*隘p/TIg?nnn!Xܨj^Yp5f&'[ڎ.{tfzeY=}}PjMaii9z{ze(NI7M`Uf)4"X-ɔRVz;fĩۙϼO?~]unVUJ`92>J/JwRyZ
d:%9[[9	N+he/Pc3?8#Cj(,-<Ev\'GM'Y+eX
`_ZA57	ϛY払e)x&-7Y5%aPձ䦞ܪ)COMރ_TcT=+1~vtXxydJfL*q;(H1Kj  mIDATjߨA1o4Q}1<:-meElWF]*IӞBiHd%wL?įgw2U(իe٥.Fֵ{ eb.&I*Y1II}.q,#lEM//1Xᆊ9+cu7di*Y,8MSE~Æ'p`OE$xm<R2dϚ$*<dq5ٸgSʹ+qI#剬$6C''UL=[ETe(YV募zƔ4P8}X'DJCf`^ϴ<EK
q+5e'ЁSiNNl2L3\2Ά:@eP:[6,LfTh&;;q՘;N/fU$~1Y&޺q-ZY#vw82bbL-ʙȣCQLư-l<:i{'^k115TC xQGF*KoNlUw=wKn%AijEg詔e(?poſTkUc19R&f|$CUvcn@HW*HrC=aqr<6sr&K]FpLƍF%qyoqj(u{s)Y?c(AM3ZUl>oQ8Źߒ]$?b#<4%x6YN)k6Mм>2;*''Xvև~7Ttl8̿YRȒuԙ'Sϻ۶idY#$DW+&ciOC.kڇ1wOB'Lo}H4r3w%f:	nA2S{/5,UURy};:9%p[cBʛήT|Ue1R|zw0`ɩMPsjttҒJp960O!Y0&ۨRoOW]ŋyMiZAB
{JLOލёk=bnz:ABi(3QۜR1!r?ĹGjHݭ`ʟdb4ڏy!sБ!ɾ)ff%fSiWzF4&,=+U
O?.807dY2dZ2o{)RIb0YbO@lke3P^W\e{%]z0G7@03SSgTvd*5s$)7r)ŏόLGTJ('k^%blf&@},5ԳY힟TQ]*)N&X7<4삗rzlܲ]B(l`/z6y?J7c4΄E
T!HOځnȐEiu/&ȁ!k'ci&Qd՚IH?c9˘wR=Q9Z4F葐
H[e9Ui ŕ?QW+-Oi^|}5Gi3-2)ꊶ"cU7@F?,8͸ad`Qj
h=`w@$O@E&ŋ1;5%86g,{@O27,+
2RV7(񋰅71s:bttTdpj>_zE1Grj'դ$p]>h\vU3{l>VSs">0G^^txBFDoNU2Bs4&l4;A[P1M4TdI2??g
UB3^H%آTg˫+
܆ܔ+xozt\94Ƈ33WsyibI{26=88leԔUc_x!$I-t٤5p2Q1n$`w	,8+h׫M^U3U)j&3hUCޡp݃u%1 B&>GR}%sYlLDh~?346 Ytۦq(;.h=0LP8-@I3){\	{Xc@Wݚ|RΎޯnlVK\|p;qơң'z#4)Hȧ	V9Y%Ɍ7m#م&I:D%xVJ6ax&Nj7&9}=.)pGl9c^7<Afj)qR	X,:,Y8XfCbdj+ׇM:dnͦ&^F=zDRxܫUe!hGt8FGUkŃrV  
s
DY)M(Q`6\uנLHG/h~vG&FDTr2|QŔmVz?'>joϏu'ܞ(|`2L0w^5J^ϪAd~wLq>rK| 3L/p.^	uEJQSFYX砗`s.J2 XP{
61D㯺8ؼaD
(p6
U7̔&cq%Koxe45Ǖq2MheJϺaڟK
81pl!HO2EZ	I6K;b%υgTJS+M񫷧uȔ߯joni~MaUJ;Mw	jFs2Ojtv+B0PS'6;62#2C.3n;Y6ټ[ trL%'c"fG	VIt5%)9SUo=SiJvG^,6);+)8zk^!.J	*)ެOMP*ZEPϜs葘;_9g{p8=3gt=k]@f2]ݲYt5Yٴ,UWޣ|@GSXE,#ospɺ\gq՗3,|o5Owjgez_)eI-%\JQ>W1V&:ٳY~qlhGG=+s@C$.7	RWJVz4)Lrae{Vn.o@LZaf^(z|,]YE7dxWIS<d[DqCq4!P)Fb^e0[e~8	"Վ½uA+,BG,fZGhLJFS4}(ӹ     IENDB`!{%xTPNG

   IHDR   @   @   iq   sRGB   IDATx^Q0D7ހ-5Ei|N׆4$_PH~	k/<B1N%&E@?,K|ަM 1^anXOb>cM act=k9R\KНQ(SNêSy(u2l J]L=:%7RW(SNêSy(u2l J]L=:%7RW(SNêSy(u2l J]L=:%7RW(SNêSy(u2l J]L=:%7RW(SNêSy(u2lRl5tf
:=yO6 ٦tmG`ȍ>osk ;Ͽw qy=~ZmY!WhjTrn~h
i{K|Jqwf77_p    IENDB`^xp100644 appointment.png /Mreqc\DZ100644 appointment_HL.png " 2
bهR100644 index.png ^ewj[˛^TD'Vk100644 index_HL.png cTHqƐP?d100644 mine.png f%D	O*s.5Y100644 mine_HL.png L+Yy?CΆe-5ns100644 order.png 8(aJ3dD\GK 100644 order_HL.png Rsڔ"`;-s^T100644 xiaofei.png ?C;4n(>|/8񏠇s100644 xiaofei_HL.png ٓ7Kν0#02zq鷖xgPNG

   IHDR         \rf   sRGB   !IDATx^kvۺFXˣH3d2IfV꺶R;z	$MT@
z(+ @@` @:
  r +  Q  (X 8 @
 u   
V  >   P   pq  9  (    |\G @@` @:
  r +  Q  (X 8l!"5S`^%p8[ԟp Hn_Ή@G($	#(__`4 (QEſxmMgZ3ShMbs{
4f ɌOΤ@3pfh1+0랎JRӮo3R]7qI ?n/v
n; ()agZ9+K@fBYCQrʵn<h˟
 93?_\GKWy [(8
䟧A hU|i/h1E)+
cu7= פ5~`c_ft&@[6\j& Z^-,OPi]||2Z
h&*]I hDe毕gʗLNVVpLԱ>@↠9 0,X io^ ZI] )#
xs. hI.j Kf  O-'2+ u6 sy K% <l-Qsti p +yKFƻ^&  iIbZ   d G.: 9 xee# v	 P[  ʨ=ҎPऀ6x %9
xl@nTG @)*-U
|+    BaJx% /y{  PR(\)   J0s  P (̕ @. 
3W
  e R(\)   J0s  P (̕ @. 
3W
  e R(\)   J0s  P (̕ @. 
3W
  e R(\)   J0s  P (̕ @. 
3W
  e R(\)   J0s  P (̕ @. 
3W
  e R(\)   J0s  P (̕ @. 
3W
  e,)lNGR# J- v}WѪYuK  (3" vW> 5 HS!<ZJ!Ao$8CyP
5Rsu il>  ܏O6 rK̶t X aKTق
) (sx@a1(|DW&e8* u &`)gs*  j[P3  P& P
+ 2\ @)f  p PR  ( BaJL%J)M[]@z9i=[ XchZs'^,V=@өs(X @@` @:
  r +  Q  (X 8 @
 u   
V  >   P   pq  9  (    |\G @@` @:
  r +  Q  (X 8 AH_4s&}q+  lO2%I pCh?5S~   #R= pCm[]ϭg#3 {1kBb"QXd3KVHƆo6i7]/ItQ NgԜ*BRžn_]Ҧh JTj
Obj ~o a]􏖗wa  HC2T  V!R6ZBim(
?$ @kUg
 @4Oqop8+x  T}9:x~@  FdV`N?>sWMA  Pţ(m98fypF. Fq%dnŏ %q*h,~x @1g+[>$?  0
 )~o-!r  Ci!  ִs  .G}u:  ~P;mҷ^= @ָ-~O3oF'e)  hor/]` R^9,ڍQK ,a&gjt0@_TRYx>ͥw \9YvN]  3S<K3Eoè1 E9˕i  1oJ K  )~/eY?N]  T#Swrׁ[>?M`m  g;3@6R`m3   [mK\%Ak   h>sQgbT`z+  XYn[=  _r i3R ٿG H c( ^Z,U]zL0Mzz $]`  7:@X{  .%4ŭ>{K Z5J^e# 4Z Fr ut`aꡈJ.I  p_ r4WJ' "to kzyG  (l *zu;  (l *zu;I_ ,@R	8.<t J BU6JrLY @!  t  e Pͤ/j1"{ 5ٽ$ Xx_]*Z +	  jeXNjk>7 ,V8u H}$硻 }vaH55&VN񘫯%R^% LQ%ڜ!Prk:_Uoz  ^ZiUwi \hn}Z?=Q  Ώ@@Z槂+2Yt7 /%/	;NI ' /se^Qo5 I4f }ZzJ}:)-,Hϐ0 ]$ZfMt  @\SZI1HϦ{iQ HJ37e	<*'H@| @tʩLm c)OΜ+Y8+L=z3 H. lu,{柹@`)+ܫ$?j$ 4]@n9kV|M[MmiNt~Nq)u42DP.`!~K\b:}kLp/| 95hHv/5A ֊4 ~heh5	& ]@5r.: Zr˾@JU4ntY9]EK˳y h-%]YysUn/}?)54v О
\82R,^:kYvݳKcɜ  )e}f'H
f}~=7 0Y0oҗȻ@	T}z
oG~şpw¥*8on>x SiB9S}`<K LŐsFB`)A_tr1*BoΌ=]ҿGyDSF;Ԛ&ګ+r"QQ\*_lup̔IWsnz{YmS­SKsZS;5xs4nhhe:.nQsݢ9|V,%j7xKԆ4ێ.9<%@IeGJL%BuP'洞u^&^BқCz+@Hl63!6sy<8E	 Y",P] @3  D@
 vcg( *  D0@v  P@T  a*  ڍ-  % U  [<CQ  J
  h7x @hW nlD ((Ю 

  Q"P] @3  D@
 vcg( *  D0@v  P@T  a*  ڍ-Am2    IENDB`O{xBPNG

   IHDR         \rf   sRGB   IDATx^Qv8E%QvqV	])G#M qӞd(VCXqP` $
V  >   P   pq  9  (    |\G @@` @:
  r +  Q  (X 8 @
 u   
V  >   P   pq  9  ( eYK;~S\:,t<\~' Rp
=j;$! +z
>RvWzXҡ`05 (
f x<^sfT `o` }Md/
V`&@Y?E4'@ ZWSжKתُ4-*C- (o@2~+<C% *2GkmRʭ+boZ"1NVy+u<|xR 
g~
S&ka] 7 ( }S$<-\ `V0_
̘0Ҟ(y>+)qNb+~`c_ix0]cҖ!(( ((?8o9]CTX@i=6;NeHq2"*o
Ey8j0%jZ \;X0orB`s5 f&yI)p fAeeu @/FP Kf  OFsaV Xt Ye.df Bχ}p + 7 "~0O3?
 L  baB2ʤwJ̾@ ȵK     D!13<?b0.  =*  Ĩ=j얊`?
  1 (f޶e~	@*N  (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b (f  b,+zN4j @T" Rៗײ,Gfe  fE .F \D03. G#t^z#Is3ET`Kfsy  _10s  $:;yN `Aq+C1(YZ;@=*pZg(Pg*搑
N  Ȅ(@ @>f(pS  & ̕ @ ̕ @ ̕ @ ̕ @ ̕'Jo>Q:[$b  Q`S+>H>_6{SP A
 u   
V  >   P   pq  9  (    |\G @@` @:
  r +  Q  (X 8 @
 u   
V  >   P   pq ȽcM2kW  Rh2S+B pCeaY>N5W  ?P  @zͷ"(^u}  _ǃUq1Lo,bdyo݆'iw1$Z @FMV'VeSO{8M^ @jLTk(ve\ G* 6MP7ǟTa  6'{¿5ƈ+t K\DKJ E<~T kυ k);y'.ynmj޺ǿ{^r7a}Nɝ  ^v~ܳߞ=_P   UA{֖q?,f  RR#}f_S9 	aT¿z?jr Ԩ1KEј+ - b.V+s-M 8cPXg{,W\}IQxo	QoLǍA PTqKaGw  qkZ>lſT @W  r5|m{U"B@.^nwKB< $l=Ի
=K KUZOn9[ H2{H^S7F ^J'DR  8.^C~9k rweVJal  x]eF_kX  wf`4 Owd C  ӕqC, x.  TGZ_n}~J`m LUXoͬV\`m3 4GZu&֊)%@ 0M;bt&i@  u3͑V x$K <cye  )'=Ӹe\ ёe}  'nj=Qw . R3POutr V6@rsV3  ߣ ܔjzHR ҽ u o< g /Et/7XӸ;8 W_  V?%f   P @cAN D}(Tc3 XЫ4 { }ss	ja6 諯O @K Qf    Ą P̈́?L럳XLj:P sE  י*&[n%kQ (Ul2{ S
G[r+ yr3l¨7z12,T^Gqh
1pp]X]t Z0Y#I,KjA16/ @I>u  KJXв<|,|yy=7^ p,gN P'Zbä,XZVz,s: r1	Xki֪	<ʽV ~^N@- @ji7	H%WO+!Ss?Sgϝ-BD@$߳?>	u
 x]~]@}9 >@}~Gf1rۗȁchXGx6㕙8_GE3k: e'_-,tⷸ7	 b'Z*K%Vg46SK zrpG캶 7N:F P5hW !;2K\lbڿ+(I3bH	%
mAQHbnYF'kpR f+~[~@>?3
40-f; __ f̾ Q)\Na\QM}_< ԥLInMy]+T3tl۴[S2{x\  *6/ER:{Q@~׶^QrrLj
_}nYt]R0vjw	>A{
B`T!=S)β;G]-<t ׋!_D{"ɢaAVcpNZDw AV5 e<bO^%{IB@RܖY;˕V#ң<]79Uclc98}q76$\tM7.h|Rկx-dO;xKp%wO݉Ij- Č?`bL}|:dO.钆܎˥K.MNr	H]ҹ+-sr+˝W~zN*KI ۽-߯bs/>?@^",P`^ 3*  a*  -@V W 0ol
 D
 ycg(U  d% U  [<C  +(0 `
d  Y0@y  P   J
̫  7xY @V"P`^ 3*  a*  -@V W 0ol
 D
 ycg(U?94j    IENDB`8>(xpPNG

   IHDR   @   @   iq   sRGB   IIDATx^Q0)l22bS0z`ҝ0LnWIIPWm6e L'`)qX$@unY=i~mg0>_'
<4/@C@\.0sq*J`d8V <,@O aU r@X 0QI	Z% I0C۶7L]5)MӠbCJ,A\XfMM@ Rv1 *3 J)͔tsCu
`Tt:VR ΝM-~
뺾rP!L5`TtUŤT
p@Qs}Q
jy4^g' ,{` BS@ "GPs Z;&0pm'|AM
i0A@E ynO@ ņ 6mu4HZ .ds_`}d ᜳ3wQi "5V x4qQQaLp:x2QeХ%H
E tU&M3UIn8    IENDB`A\)xiPNG

   IHDR   @   @   iq   sRGB   PIDATx^땄 q:V+s.A|01Fzw| nN,psX$Yw+zzsm_c %OQ=eᆒ  ZV?*\6.tX /(Dv 2 JA. @XKTk<ԁ$r@K*`6_a'4*`BxhnP# rjӏ ;@gM`?Ώ6$O$cKi!%l=tqC(+mk +fuC*U( MCPk:`Sw@ͭ[Ki9 KIA̦3RxemyP$ ?9˝@F


@~-gd &<ib'A;	_a2t79 ~ɕ Em]`mE\yR,unW  2K]{aK͔;	!0m|m6)^tD~TZ/ta<H^Y Rbu4Tw	bӓгDb
8QMzH~Ȣ_
    IENDB`xqPNG

   IHDR         \rf   sRGB   HIDATx^mR#98\SpJφn[%#N@ -}Z1! @ ;! HL H|L @@ 1 1 1 t   @ ;! HL H|L  ~yssY}:~_c8//	6%K?N~p3}}@ |cjJ(~m P%{Zሤ_@e0Q0szI|C4~˴9!1m1ܫfc! c9$i#"0ʒ gy||,n'A9p	wɖN_ &?#L5 NHuD`p! 	&?ğ<"0(y
`egx<D[?Q&a#$[  4Wz||<Nr*nC xsԳm OW@jlgh%ʲ7y,f|0''Xki P32}}}hY?X;	\
V[c3\M7K%Z+F	"Pmmm6n$Ylm hFyG1Kkة"nD \aTKQBp8Wx0P]M/,( |@Exgef4* AΚYn5n́7
yb+װi U# l% ϽZ"P <FB \@OP. G_aH D@ :1*$W>c@gr! 3lGKPn<
P0;<iD OA  @<lƳGw i*\jMk=T (I'*Fv#)41@;8)5@{S4J' ǀlTch$)) h<n@P]$E6  $ Uhd.۠I>@ NڼF
 ҏo]$+[~@=w ?h')^@ ("  h£  @h4Q@4@(@PI)S .K6h|u/p
 . | 4p2}(pC	wA >~RFK"5s! %ϯ1! @%8FxFgL#Tch$)- )Jc tP>dQ;BK@	x
)"
1,e*@!2@U
 } ~jf4ݿ3x6`?@cU}s!L	PPƜIvnb30! !җ˲"(&?P" B θa/5F.\_(n !ɀ6	-O@4(ޚeQ;0_AsW@Ex|:`POqW@Q`Y(?g`E /Pp8?ic܊ (5:
\D$>Ra EFwNE¼eRr3}$Zc  D/3>
|fISeePgܯT pF]ؿ?Kɢ_rހ
E)H^
HMMIM# 6DUd! 2Gdzqro ˋd` tO(Ӓ# #c?D~C7P'A}sF ?P;93#AxÏvb§PC7L gX h;PĀ&]	/{͡ M
c{
601e#M=?4Ưsy jhl ˦U-b`@c(@.gƛ)^2>ÿ@ $i:ky2I5BǗX y  K   0`_b	6@ 6#! K,ffdt<y|%L ، 0/	  @ ||[F4e{x|J? tr]$v'ЕJSwGG |\o A胊 T[ؠf P9 I_D[=pT;q:-W8C!+PoYK}nV H|l
<Z  x:hT?CېJR 4MF_y-BǄB0 p7I'Z Js־⻻ﶳ6 PNY JiikT"0 Y|iD`
 ;kΗ8VgҢNͫw]x- I׷0~O'aK_$=	o0\"@H$mvl<O⯥ߏw`sCtb}P.ܶ"nvMx/|nZ؈=p0~Ǯߔf;YVQ +O`SfZ ?D2d* HݫS _n2+`|  t"u* j?}ɳ56y	8LJ `P	orj2GB@[Š+'oG7<l^W65Y{Z"
$ gOIx\r3<Z>E w(Z6(UpP˹?vι[QCA wJw~AZGѱ:T E*4u1`:2"ҟT}- ?gIiiQ`d0L 4)vT;tR nU椩қc
@g7́R iC?t;0 guL膀ec(w,d za=;H
@YƈJּ>3t1`D, n'ʨHV# 	3ْ%9 ???YBE3G`]њW 0-@Y.`6JD"ojD1HXWaJSUu\
RZR M@R +۰`]*PJ@ntP	fJĒG 祕&,)'SW RJ! I3ͩQc *$1ǲ b)q	  
4$'5 .@ *8FTaMT e  B0&	Dm*䁋2
Q!UF6@|@Ǩ*LIrQc
 ybcTH$9M<p1_ P1*
h@ئH/C Ri4IN jlS$\̗! Tp
4$'5 .@ *8FTaMT e  B0&	Dm*䁋2
Q!UF6@|@Ǩ*LIrQc;lP:p|Gnnncw/
lƁ77@ a3@ y@ `  # CLo oa=0$ f*x# x끀!6SAGX	  
  <z `H 0TF C!l77V ^d);ݙ̔"A UD4y}eX% "% [,*` 0/`^bV	  h y	   J XEDK ׷XU*"@`^2@ V yY    IENDB`kn<\xoPNG

   IHDR         \rf   sRGB   )IDATx^Qv#)E+K`zv2OH'Ĕxn~iEz?@ -CZ1  	  ! HL H< @b@t   @ >C   x1 > ă@ li.pL'bs|ǋH_ۢDҕmoikG %6cQ`QӧAAm/A@G64lWJ!("R4>{@,{f=[A <60A8WG [_!F,^ЧЇsSOvE(7J$cڬi黁 L+%8?Bd |3XXtQ ' ?D :?o/^zľn tM߇g, (iitb9qNYe/ U$Q]DLUB ]zs뽮UaÏ'yO` FV_ap_\aۯX;6RP3`ӯ\u?6JJ3C jro%C|@Tu  ݭ3@zWóyw@ G?2G	+@@{̊3_Y
ρ@{b=^u~7i@~둞̻Mys`CT@ Q\s1忇SѯwՏ% e"r7Y3 7η' 	5GLo/ ,@d +aHv&FJ2yYg6 .LP8{.h`ra 4Sʳc2xlŵ-pkp:qUTa:`Ĝ7 ǂN- Y,@#)0Sؒ)wZ  F?F Y@-2_ #I dt^xj(kvRD	`&W>
o|0@   1Z0pS
@@.Q0C nTcK+k h[A @ 4@M
`  ! hV P d;1`դ_L]0?ݨ h8 ! h@aA e`U`  F8ܹ"OU0@,Fj, #AVƓ O\0;pxjzk6uχ@F'V`;8 dZ ){I@QȒ(2|݉ ;rm~lhk/Qmއ 4sXl+g/C 480{ mJmu:^ 0@?eYG37:/@;@eY~	pX.-!1# ^B96 :e_d :kK":\t_O<sKd "^ƛG"%Ё<~3S#	xg!d-YN&Èw{ f#f<@B X
?⏢n
k" z&uK6Pb|Nznpbc)0Bz>/؞K/x-IpTXYsڶ.W{^_O
;hod ^s)%L_V^z8]vF v#WRwANpUgX|C :դ"r#~;=5="zV%V;#a)K  JmxcYY0`?pTD8?$^!Ȝ	Dh ȑL&uiUeqjLD\NG0x\S+Ĭ/nPR6Z_  PMF}' pI|5 ixb!`3䮭" x?xA?|W#Q#\կĠʱf_vz1×xqg=gA o-\yduXg,	  Q@ K,nndT:uK   `& FFC Xg,	  Q@ K,nndT: |_>gBϩÛtE=W=:  \/~u1N}_Zu0%	x8*BWU3W2T]# ?p"hRv7B !g~qUm~`Qj#G* QBW bZ AJuQ~gT>N&)wIs^C1B 'K?duXR H__O#eb6 ^& +xJ" eo@xxx>#Y|ǕW\o}oXujS
"Z &K_At]j]mL3  LheVAD@H 	ӊ?# r  ~ՕQB	8ǩ{:a`ĀuN4s)	! ^%՟9wmĆSYgt*9q20 t4f@lj/E#L&S@0PVm}k|:y;0Mx18Q6j5ziy)_#XCfl ԟ;(ٹΧMSf	r~!	̸4]0xaD<:TS	OdYZ
L# _d?pi`uWRf<G&F ӀBd`%ॴ[\: ٟԟ@Vf\_s! ٟԟUZ
աvS$Cъ逴=C:t0T 0Y{8L <)fo&aˀaUe#82a) 뾘3<6 2YzY" CeqvfePO, "鿅uPv ݡ)6P/ OQEF@t_t He~LCFJ޶-  RMF@ю _4d! S)XF`@|}ȧ1u> P	%(PNlk VJ~ݵy@ >	, l x'e	.m w@ *GX}^Zi"Œ,@ Fڤf`۽ L  B0"	Dm2䎋@Ǩ*LHrQ} b P1*
(@T&H! Tp
4$'շ ;.k  B0"	Dm2䎋@Ǩ*LHrQ} b P1*
(@T&H! Tp
4$'շ ;.k  B0"	Dm2䎋@Ǩ*LHrQ} b P1*
(@T&H! Tp
4$'շ ;.k  B0"	Dm2䎋@G%ö=U<"BmUU$i	  .C@E P$ 4@Ev  p2T Iځ@@@AP@ T$i	  .C@E P$ 4@Ev  p2T Iځ@@@AP@ T$i	  .C@E`e]M;ˡuw]/4@v@vÏ	  = S@ R?g' d OM H= ?5 c|v@vÏ	  = S@ R?g' d OM?WYjr&:    IENDB`@AӼ'x|PNG

   IHDR   @   @   iq   sRGB   6IDATx^mn08ˀ8)\`
$Kl_ȇI&q )	(qCJes'MjS}T$ eY眫$y` t۶,%l @ik#>)%
( (zE iB,Q,˷E6(M %'ko9g$D:<a1U ~F  ^> l
RG dNTM Hom¦LS|8tYwY\Q۶gq_1SҦ '%9 ]`툅o``jԠq9\̝|4: 1 :^9GTC=8i5 
[*lh*|Dbdp4V~c&%G* = n~uF#`H9)d   U~JPs G,Ê#:l 0BgnpBb_    IENDB`h'xuPNG

   IHDR   @   @   iq   sRGB   /IDATx^m dy-]:8C]$IA4בB7
@ps:('?zcbRW5;fV0Ot `3y,2dS_~[cn .J0D{>T`OPv^֪`-kpr6X)JT{ DJjw,
[Ԫ# '@X: Fu ,u|"
6: S#.PN 6J
`svP8B.S@{B ]	ËN.m~%7A0wu ŃR*7qd2l_֔48 no 4@&K#A+GGWmHd)+`/-Z hx*@hS@HnLݍ*@P8CI0Ionb* Z@T(OX||և뷳gp
xA܏}Iz,CR@B6+ տ>Z-_4E    IENDB`R4xLPNG

   IHDR   @   @   iq   sRGB   IDATx^mr 9X)ڜ"c.`v[pw-3
>i; R[v;w:ryO)Sr~Spkgi_3m~?ϩ 5i5~wkH|m7̵: Rj lsU \bX,P Aݠ}'hĹxyIH` R<`x<$\'xM<YCQ&`@@  `ABbC]>Q S>bL<8q|M,=H0h#H> 5v| $?;,@eL-P@\ʢ| @jjVhPgP-gӥ k/cM]q, mrKSBY}d`Aj(0mjۚKfqIׅ +F!ͷsQQ Pw|Q.ei*`9>>+_X Q/
BhۖXR{fiq,#h V]$; \@Cko@<t#CW [ۅi?y4hRAs>D	l^@EQ"_1`AЮ+=$nE~Slΰn5$E$WUF( {r? l
 h:m:ld+
iI(-n`<    IENDB`j 2x)PNG

   IHDR   @   @   iq   sRGB   IDATx^u @a8y&x:!\U$Q^>&1E/}q Py6켓_+TJך2Uۼm1RV{-+
 k>o%aT`}(i"s]*tb @x V|}ysYO!V# oQ߃Mu*-c+Z  !}!.ks 5>ԭ*"f(x57Ylɚ U=O
@(ZmF/DC,F(Lp
 F9)3QyQ-:l q֏Y2eMTs%{9v7Ic|-̻z `: T @5:c )2PsH5weKȥ| (Ω| ,Cv0ߣ6@%*`cIARkn .t|#=-ns kN۽ TYK{ |ć} 8CKMHisJ0t~i%= FpKB1w< c1GȒϜ" 	[	ңyj	79}D<v+\AF&B`)/ ;7<5{Е 2<.o?0n=b    IENDB`8YxF 100644 index.js <.ޏMImϵ40000 modules ~GpdZ{}^6ҧŏ-x 1import { createPinia } from "pinia";

const store = createPinia();

export function setupStore(app) {
  app.use(store);
}

export { store };

export * from "./modules/user";
export * from "./modules/auth";
DExF 100644 auth.js ~=iAuO\4S܃100644 user.js O!8Z4`]u]x0import AuthAPI from "@/api/modules/auth";
import { store } from "@/store";
import { cache } from "@/utils/cache";
import { defineStore } from "pinia";
import { computed, ref, watch } from "vue";

export const useAuthStore = defineStore("auth", () => {
  const ACCESS_TOKEN_KEY = "accessToken";
  const REFRESH_TOKEN_KEY = "refreshToken";
  const accessToken = ref(cache(ACCESS_TOKEN_KEY) ?? "");
  const refreshToken = ref(cache(REFRESH_TOKEN_KEY) ?? "");
  const isLoggedIn = computed(() => !!accessToken.value);

  watch(accessToken, (newValue) => cache(ACCESS_TOKEN_KEY, newValue || null));
  watch(refreshToken, (newValue) => cache(REFRESH_TOKEN_KEY, newValue || null));

  // 注册
  async function signUp(payload) {
    const response = await AuthAPI.signUp(payload);
    const prefix = response.tokenType ? `${response.tokenType} ` : "";
    accessToken.value = prefix + response.accessToken;
    refreshToken.value = prefix + response.refreshToken;
    return response;
  }

  // 登录
  async function signIn(payload) {
    const response = await AuthAPI.signIn(payload);
    const prefix = response.tokenType ? `${response.tokenType} ` : "";
    accessToken.value = prefix + response.accessToken;
    refreshToken.value = prefix + response.refreshToken;
    return response;
  }

  // 登出
  function signOut() {
    accessToken.value = "";
    refreshToken.value = "";
  }

  // 刷新token
  async function refresh(payload) {
    const response = await AuthAPI.refreshToken(payload);
    const prefix = response.tokenType ? `${response.tokenType} ` : "";
    accessToken.value = prefix + response.accessToken;
    return response;
  }
  
  function setAccessToken(payload) {
    accessToken.value = payload;
  }

  return {
    accessToken,
    refreshToken,
    isLoggedIn,
    signUp,
    signIn,
    signOut,
    refresh,
	setAccessToken
  };
});

// 手动提供给 useStore() 函数 pinia 实例
// https://pinia.vuejs.org/zh/core-concepts/outside-component-usage.html#using-a-store-outside-of-a-component
export function useAuthStoreHook() {
  return useAuthStore(store);
}
r3x>import { defineStore } from "pinia";
import { ref, watch } from "vue";
import { cache } from "@/utils/cache";

export const useUserStore = defineStore("user", () => {
  const userInfo = ref(cache('USERINFO_KEY') ? JSON.parse(cache('USERINFO_KEY')) : {
    username: "",
  });
  
const adressInfo = ref(cache('ADRESS_KEY') ? JSON.parse(cache('ADRESS_KEY')) : {
    latitude: "",
    longitude: "",
    adress: "",
  });
  
watch(userInfo, (newValue) => cache('USERINFO_KEY', newValue ? JSON.stringify(newValue) : null));
watch(adressInfo, (newValue) => cache('ADRESS_KEY', newValue ? JSON.stringify(newValue) : null));
  
function setUserInfo(payload) {
    userInfo.value = payload;
}
function setAdressInfo(payload) {
    adressInfo.value = payload;
}

  return {
    userInfo,
	setUserInfo,
	adressInfo,
	setAdressInfo
  };
});
#:5x\{
  "compilerOptions": {
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": ".",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "importHelpers": true,
    "jsx": "preserve",
    "jsxFactory": "h",
    "jsxFragmentFactory": "Fragment",
    "jsxImportSource": "vue",
    "lib": ["esnext", "dom"],
    "module": "esnext",
    "moduleResolution": "bundler",
    "noEmit": true,
    "noImplicitThis": true,
    "noLib": false,
    "paths": {
      "@/*": ["./*"]
    },
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "target": "esnext",
    "types": ["@dcloudio/types"],
    "useDefineForClassFields": true,
    "verbatimModuleSyntax": true
  },
  "exclude": ["node_modules", "uni_modules", "unpackage", "**/*.js"],
  "include": ["**/*.{ts,vue}"]
}
x	/**
 * 这里是uni-app内置的常用样式变量
 *
 * uni-app 官方扩展插件及插件市场（https://ext.dcloud.net.cn）上很多三方插件均使用了这些样式变量
 * 如果你是插件开发者，建议你使用scss预处理，并在插件代码中直接使用这些变量（无需 import 这个文件），方便用户通过搭积木的方式开发整体风格一致的App
 *
 */

/**
 * 如果你是App开发者（插件使用者），你可以通过修改这些变量来定制自己的插件主题，实现自定义主题功能
 *
 * 如果你的项目同样使用了scss预处理，你也可以直接在你的 scss 代码中使用如下变量，同时无需 import 这个文件
 */

/* 颜色变量 */

/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;

/* 文字基本颜色 */
$uni-text-color: #333; //基本色
$uni-text-color-inverse: #fff; //反色
$uni-text-color-grey: #999; //辅助灰色，如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;

/* 背景颜色 */
$uni-bg-color: #ffffff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; //点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); //遮罩颜色

/* 边框颜色 */
$uni-border-color: #c8c7cc;

/* 尺寸变量 */

/* 文字尺寸 */
$uni-font-size-sm: 12px;
$uni-font-size-base: 14px;
$uni-font-size-lg: 16px;

/* 图片尺寸 */
$uni-img-size-sm: 20px;
$uni-img-size-base: 26px;
$uni-img-size-lg: 40px;

/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;

/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;

/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;

/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度

/* 文章场景相关 */
$uni-color-title: #2c405a; // 文章标题颜色
$uni-font-size-title: 20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle: 26px;
$uni-color-paragraph: #3f536e; // 文章段落颜色
$uni-font-size-paragraph: 15px;

/* uv-ui主题 */
@import "@/uni_modules/uv-ui-tools/theme.scss";
*:ëxK40000 uv-action-sheet k' Kqe40000 uv-album KR[0)ӷ40000 uv-alert w_BHZJ{Iʇ40000 uv-avatar DGpQa[s40000 uv-back-top d,f,r/40000 uv-badge kqiUwKC~ֿ40000 uv-button bvr>^ُD~+40000 uv-calendar Le_1V	w40000 uv-calendars QTO2M̭mbZE40000 uv-cell SriUL8-^40000 uv-checkbox DNJ:2IT]Ib40000 uv-code-input >	_9hLbL40000 uv-code wBƏ=..%Y40000 uv-collapse ؼBIYS/E40000 uv-count-down b6%cQy40000 uv-count-to 5c`ȱ1d'Hjo40000 uv-datetime-picker ږ"$]blƁxS40000 uv-divider 5etJCx&/40000 uv-drop-down (q׆wE740000 uv-empty Y,+Z+}|S40000 uv-form ;24׌BD40000 uv-gap fQii@"Q3W_<e40000 uv-grid Tĕt 1fruf40000 uv-icon \9L"/8z40000 uv-image o	*N]40000 uv-index-list jQ3?b|㎞40000 uv-input :G2 ]e0*U40000 uv-keyboard [6/xWu/,40000 uv-line-progress B2+`Z{C40000 uv-line t8.A( w40000 uv-link ~;t\"HO i40000 uv-list j\e1
O;40000 uv-load-more [CW(#40000 uv-loading-icon [!|}	H+-40000 uv-loading-page lz|T=<& f40000 uv-modal J w\Uee40000 uv-navbar C(TC.QP40000 uv-no-network |m$ha1I<40000 uv-notice-bar xۓf{T{40000 uv-notify p)7FqN.640000 uv-number-box 
Н{Yt^K240000 uv-overlay ]ŋ`f1b Fe40000 uv-parse ЎMb&>w%40000 uv-pick-color 1	:' +w:40000 uv-picker E T͖}BTk?x?40000 uv-popup @̐1=0fDV40000 uv-qrcode yUƴ١%WS40000 uv-radio Y!%t5}x%]	640000 uv-rate (2!r-Z
140000 uv-read-more 'R@LdKa40000 uv-row t8I"|/d440000 uv-safe-bottom Sa'
v|5K'0 40000 uv-scroll-list oP	M+1g40000 uv-search sTbV 6)a݀m40000 uv-skeleton ;$+NnD@40000 uv-skeletons ĄՃac,n40000 uv-slider +pL5AXOU$'40000 uv-status-bar QVo3	>*t'k40000 uv-steps MP+m6%CO($.40000 uv-sticky gHWHzW~%40000 uv-subsection yGۥ)c?40000 uv-swipe-action TRl,X40000 uv-swiper xoy(>+q40000 uv-switch <[*.qy7I,40000 uv-tabbar 	pܰbVm=H40000 uv-tabs 
0r/W {I$40000 uv-tags ykP"VxJڧ40000 uv-text #oBWd%րS40000 uv-textarea Z&wڝDu<إcq"˷40000 uv-toast r4QP+bu40000 uv-toolbar #K۹e|'[40000 uv-tooltip KFxU$w:F(40000 uv-transition %ge/]eHzI}40000 uv-ui-tools dn:c,c40000 uv-ui j Dr ~<40000 uv-upload kY.qɠ߯>FAp40000 uv-vtabs ɇ8E
KaRzn`^荪40000 uv-waterfall ,?Q!8O׷n]t`ª	x e100644 changelog.md 5Ephm b$L
P40000 components n8.Ty׎tӇˁ100644 package.json < 44T~&	100644 readme.md H~R|:=3m>ƲFxb## 1.0.12（2023-11-27）
1. 增加round圆角属性
## 1.0.11（2023-10-11）
1. 修复设置minDate出现选择错乱的BUG
## 1.0.10（2023-09-01）
1. 增加clearDate参数，是否清除上次选择，默认false
## 1.0.9（2023-08-31）
1. 增加mode="year"，方便只选择年
## 1.0.8（2023-07-17）
1. 优化文档
2. 优化其他
## 1.0.7（2023-07-13）
1. 修复 uv-datetime-picker 设置value属性不生效的BUG 
## 1.0.6（2023-07-05）
修复vue3模式下，动态修改v-model绑定的值无效的BUG
## 1.0.5（2023-07-02）
uv-datetime-picker  由于弹出层uv-popup的修改，打开和关闭方法更改，详情参考文档：https://www.uvui.cn/components/datetimePicker.html
## 1.0.4（2023-06-29）
1. 修复抖音小程序报错的BUG
## 1.0.3（2023-06-07）
1.  取消defaultIndex参数，传该值没实际意义，后续更新文档
## 1.0.2（2023-06-02）
1. 修复v-model重新赋值不更新的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-datetime-picker 时间选择器
}8oxX ## 1.0.2action-sheet4wactionSheet.html action-sheet 底部操作菜单
2#x* 40000 uv-action-sheet $J_j&zl^FBƌ!xS 100644 props.js .0:T!100644 uv-action-sheet.vue lNI}T#
:x^export default {
	props: {
		// 标题，有值则显示，同时会显示关闭按钮
		title: {
			type: String,
			default: ''
		},
		// 选项上方的描述信息
		description: {
			type: String,
			default: ''
		},
		// 数据
		actions: {
			type: Array,
			default: () => []
		},
		// 取消按钮的文字，不为空时显示按钮
		cancelText: {
			type: String,
			default: ''
		},
		// 点击某个菜单项时是否关闭弹窗
		closeOnClickAction: {
			type: Boolean,
			default: true
		},
		// 处理底部安全区（默认true）
		safeAreaInsetBottom: {
			type: Boolean,
			default: true
		},
		// 小程序的打开方式
		openType: {
			type: String,
			default: ''
		},
		// 点击遮罩是否允许关闭 (默认true)
		closeOnClickOverlay: {
			type: Boolean,
			default: true
		},
		// 圆角值
		round: {
			type: [Boolean, String, Number],
			default: 0
		},
		...uni.$uv?.props?.actionSheet
	}
}xx4'
<template>
	<uv-popup
	  ref="popup"
	  mode="bottom"
	  :safeAreaInsetBottom="safeAreaInsetBottom"
	  :round="round"
		:close-on-click-overlay="closeOnClickOverlay"
		@change="popupChange"
	>
		<view class="uv-action-sheet">
			<view
			  class="uv-action-sheet__header"
			  v-if="title"
			>
				<text class="uv-action-sheet__header__title uv-line-1">{{title}}</text>
				<view
				  class="uv-action-sheet__header__icon-wrap"
				  @tap.stop="cancel"
				>
					<uv-icon
					  name="close"
					  size="17"
					  color="#c8c9cc"
					  bold
					></uv-icon>
				</view>
			</view>
			<text
			  class="uv-action-sheet__description"
				:style="[{
					marginTop: `${title && description ? 0 : '18px'}`
				}]"
			  v-if="description"
			>{{description}}</text>
			<slot>
				<uv-line v-if="description"></uv-line>
				<view class="uv-action-sheet__item-wrap">
					<view v-for="(item, index) in actions" :key="index">
						<!-- #ifdef MP -->
						<button
						  class="uv-reset-button"
						  :openType="item.openType"
						  @getuserinfo="onGetUserInfo"
						  @contact="onContact"
						  @getphonenumber="onGetPhoneNumber"
						  @error="onError"
						  @launchapp="onLaunchApp"
						  @opensetting="onOpenSetting"
						  :lang="lang"
						  :session-from="sessionFrom"
						  :send-message-title="sendMessageTitle"
						  :send-message-path="sendMessagePath"
						  :send-message-img="sendMessageImg"
						  :show-message-card="showMessageCard"
						  :app-parameter="appParameter"
						  @tap="selectHandler(index)"
						  :hover-class="!item.disabled && !item.loading ? 'uv-action-sheet--hover' : ''"
						>
							<!-- #endif -->
							<view
							  class="uv-action-sheet__item-wrap__item"
							  @tap.stop="selectHandler(index)"
							  :hover-class="!item.disabled && !item.loading ? 'uv-action-sheet--hover' : ''"
							  :hover-stay-time="150"
							>
								<template v-if="!item.loading">
									<text
									  class="uv-action-sheet__item-wrap__item__name"
									  :style="[itemStyle(index)]"
									>{{ item.name }}</text>
									<text
									  v-if="item.subname"
									  class="uv-action-sheet__item-wrap__item__subname"
									>{{ item.subname }}</text>
								</template>
								<uv-loading-icon
								  v-else
								  custom-class="van-action-sheet__loading"
								  size="18"
								  mode="circle"
								/>
							</view>
							<!-- #ifdef MP -->
						</button>
						<!-- #endif -->
						<uv-line v-if="index !== actions.length - 1"></uv-line>
					</view>
				</view>
			</slot>
			<uv-gap
			  bgColor="#eaeaec"
			  height="6"
			  v-if="cancelText"
			></uv-gap>
			<view hover-class="uv-action-sheet--hover">
				<text
				  @touchmove.stop.prevent
				  :hover-stay-time="150"
				  v-if="cancelText"
				  class="uv-action-sheet__cancel-text"
				  @tap="cancel"
				>{{cancelText}}</text>
			</view>
		</view>
	</uv-popup>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import button from '@/uni_modules/uv-ui-tools/libs/mixin/button.js'
	import openType from '@/uni_modules/uv-ui-tools/libs/mixin/openType.js'
	import props from './props.js';
	/**
	 * ActionSheet 操作菜单
	 * @description 本组件用于从底部弹出一个操作菜单，供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI，配置更加灵活，所有平台都表现一致。
	 * @tutorial https://www.uvui.cn/components/actionSheet.html
	 * @property {Boolean}			show				操作菜单是否展示 （默认 false ）
	 * @property {String}			title				操作菜单标题
	 * @property {String}			description			选项上方的描述信息
	 * @property {Array<Object>}	actions				按钮的文字数组，见官方文档示例
	 * @property {String}			cancelText			取消按钮的提示文字,不为空时显示按钮
	 * @property {Boolean}			closeOnClickAction	点击某个菜单项时是否关闭弹窗 （默认 true ）
	 * @property {Boolean}			safeAreaInsetBottom	处理底部安全区 （默认 true ）
	 * @property {String}			openType			小程序的打开方式 (contact | launchApp | getUserInfo | openSetting ｜getPhoneNumber ｜error )
	 * @property {Boolean}			closeOnClickOverlay	点击遮罩是否允许关闭  (默认 true )
	 * @property {String}			lang				指定返回用户信息的语言，zh_CN 简体中文，zh_TW 繁体中文，en 英文
	 * @property {String}			sessionFrom			会话来源，openType="contact"时有效
	 * @property {String}			sendMessageTitle	会话内消息卡片标题，openType="contact"时有效
	 * @property {String}			sendMessagePath		会话内消息卡片点击跳转小程序路径，openType="contact"时有效
	 * @property {String}			sendMessageImg		会话内消息卡片图片，openType="contact"时有效
	 * @property {Boolean}			showMessageCard		是否显示会话内消息卡片，设置此参数为 true，用户进入客服会话会在右下角显示"可能要发送的小程序"提示，用户点击后可以快速发送小程序消息，openType="contact"时有效 （默认 false ）
	 * @property {String}			appParameter		打开 APP 时，向 APP 传递的参数，openType=launchApp 时有效
	 * 
	 * @event {Function} select			点击ActionSheet列表项时触发 
	 * @event {Function} close			点击取消按钮时触发
	 * @event {Function} getuserinfo	用户点击该按钮时，会返回获取到的用户信息，回调的 detail 数据与 wx.getUserInfo 返回的一致，openType="getUserInfo"时有效
	 * @event {Function} contact		客服消息回调，openType="contact"时有效
	 * @event {Function} getphonenumber	获取用户手机号回调，openType="getPhoneNumber"时有效
	 * @event {Function} error			当使用开放能力时，发生错误的回调，openType="error"时有效
	 * @event {Function} launchapp		打开 APP 成功的回调，openType="launchApp"时有效
	 * @event {Function} opensetting	在打开授权设置页后回调，openType="openSetting"时有效
	 * @example <uv-action-sheet ref="actionSheet" :actions="list" :title="title" ></uv-action-sheet>
	 */
	export default {
		name: "uv-action-sheet",
		mixins: [openType, button, mpMixin , mixin, props],
		emits: ['close', 'select'],
		computed: {
			// 操作项目的样式
			itemStyle() {
				return (index) => {
					let style = {};
					if (this.actions[index].color) style.color = this.actions[index].color
					if (this.actions[index].fontSize) style.fontSize = this.$uv.addUnit(this.actions[index].fontSize)
					// 选项被禁用的样式
					if (this.actions[index].disabled) style.color = '#c0c4cc'
					return style;
				}
			},
		},
		methods: {
			open() {
				this.$refs.popup.open();
			},
			close() {
				this.$refs.popup.close();
			},
			popupChange(e) {
				if(!e.show) this.$emit('close');
			},
			// 点击取消按钮
			cancel() {
				this.close();
			},
			selectHandler(index) {
				const item = this.actions[index]
				if (item && !item.disabled && !item.loading) {
					this.$emit('select', item)
					if (this.closeOnClickAction) {
						this.close();
					}
				}
			},
		}
	}
</script>

<style lang="scss" scoped>
	$show-lines: 1;
	$show-reset-button: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-action-sheet-reset-button-width:100% !default;
	$uv-action-sheet-title-font-size: 16px !default;
	$uv-action-sheet-title-padding: 12px 30px !default;
	$uv-action-sheet-title-color: $uv-main-color !default;
	$uv-action-sheet-header-icon-wrap-right:15px !default;
	$uv-action-sheet-header-icon-wrap-top:15px !default;
	$uv-action-sheet-description-font-size:13px !default;
	$uv-action-sheet-description-color:14px !default;
	$uv-action-sheet-description-margin: 18px 15px !default;
	$uv-action-sheet-item-wrap-item-padding:15px !default;
	$uv-action-sheet-item-wrap-name-font-size:16px !default;
	$uv-action-sheet-item-wrap-subname-font-size:13px !default;
	$uv-action-sheet-item-wrap-subname-color: #c0c4cc !default;
	$uv-action-sheet-item-wrap-subname-margin-top:10px !default;
	$uv-action-sheet-cancel-text-font-size:16px !default;
	$uv-action-sheet-cancel-text-color:$uv-content-color !default;
	$uv-action-sheet-cancel-text-font-size:15px !default;
	$uv-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;

	.uv-reset-button {
		width: $uv-action-sheet-reset-button-width;
	}

	.uv-action-sheet {
		text-align: center;
		&__header {
			position: relative;
			padding: $uv-action-sheet-title-padding;
			&__title {
				font-size: $uv-action-sheet-title-font-size;
				color: $uv-action-sheet-title-color;
				font-weight: bold;
				text-align: center;
			}

			&__icon-wrap {
				position: absolute;
				right: $uv-action-sheet-header-icon-wrap-right;
				top: $uv-action-sheet-header-icon-wrap-top;
			}
		}

		&__description {
			font-size: $uv-action-sheet-description-font-size;
			color: $uv-tips-color;
			margin: $uv-action-sheet-description-margin;
			text-align: center;
		}

		&__item-wrap {

			&__item {
				padding: $uv-action-sheet-item-wrap-item-padding;
				@include flex;
				align-items: center;
				justify-content: center;
				flex-direction: column;

				&__name {
					font-size: $uv-action-sheet-item-wrap-name-font-size;
					color: $uv-main-color;
					text-align: center;
				}

				&__subname {
					font-size: $uv-action-sheet-item-wrap-subname-font-size;
					color: $uv-action-sheet-item-wrap-subname-color;
					margin-top: $uv-action-sheet-item-wrap-subname-margin-top;
					text-align: center;
				}
			}
		}

		&__cancel-text {
			font-size: $uv-action-sheet-cancel-text-font-size;
			color: $uv-action-sheet-cancel-text-color;
			text-align: center;
			padding: $uv-action-sheet-cancel-text-font-size;
		}

		&--hover {
			background-color: $uv-action-sheet-cancel-text-hover-background-color;
		}
	}
</style>
Qn{|x4{
  "id": "uv-action-sheet",
  "displayName": "uv-action-sheet 底部操作菜单 全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.2",
  "description": "该组件用于从底部弹出一个操作菜单，供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheet API，配置更加灵活，所有平台都表现一致。",
  "keywords": [
    "action-sheet",
    "uvui",
    "uv-ui",
    "操作菜单",
    "菜单选择"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "插件不采集任何数据",
      "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
			"uv-ui-tools",
			"uv-popup",
			"uv-icon",
			"uv-line",
			"uv-loading-icon",
			"uv-gap"
		],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "Vue": {
          "vue2": "y",
          "vue3": "y"
        },
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y",
          "钉钉": "u",
          "快手": "u",
          "飞书": "u",
          "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        }
      }
    }
  }
}zzW.x## Sticky 吸顶

> **组件名：uv-sticky**

该组件与CSS中position: sticky属性实现的效果一致，当组件达到预设的到顶部距离时， 就会固定在指定位置，组件位置大于预设的顶部距离时，会重新按照正常的布局排列。

### <a href="https://www.uvui.cn/components/sticky.html" target="_blank">查看文档</a>

### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)

#### 如使用过程中有任何问题，或者您对uv-ui有一些好的建议，欢迎加入 uv-ui 交流群：<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
t*ux## ActionSheet 操作菜单action-sheet**

本组件用于从底部弹出一个操作菜单，供用户选择并返回结果。

本组件功能类似于uOni的uni.showActionSheet API，配置更加灵活，所有平台都表现一致1actionSheetZ[ت	x e100644 changelog.md B^#i4\ʳy40000 components UfKYڽsɡJ100644 package.json p	3s[100644 readme.md ,fM>I ?x5## 1.0.4（2023-12-06）
1. 阻止事件冒泡处理
## 1.0.3（2023-10-23）
1. 修复报错的BUG
## 1.0.2（2023-10-23）
1. 修复设置singleSize、multipleSize、space等值带单位，存在不显示的BUG
## 1.0.1（2023-09-13）
1. 添加依赖
## 1.0.0（2023-08-30）
1. 新增uv-album相册组件
_x# 40000 uv-album >h+$MҤGx( 100644 uv-album.vue ]y(Fd	%Y=x~%<template>
  <view class="uv-album">
    <view
      class="uv-album__row"
      ref="uv-album__row"
      v-for="(arr, index) in showUrls"
      :forComputedUse="albumWidth"
      :key="index"
    >
      <view
        class="uv-album__row__wrapper"
        v-for="(item, index1) in arr"
        :key="index1"
        :style="[imageStyle(index + 1, index1 + 1)]"
        @tap.stop="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
      >
        <image
          :src="getSrc(item)"
          :mode="
            urls.length === 1
              ? imageHeight > 0
                ? singleMode
                  : 'widthFix'
                  : multipleMode
          "
          :style="[
            {
              width: imageWidth,
              height: imageHeight
            }
          ]"
        ></image>
        <view
          v-if="
            showMore &&
            urls.length > rowCount * showUrls.length &&
            index === showUrls.length - 1 &&
            index1 === showUrls[showUrls.length - 1].length - 1
          "
          class="uv-album__row__wrapper__text"
        >
          <uv-text
            :text="`+${urls.length - maxCount}`"
            color="#fff"
            :size="$uv.getPx(multipleSize) * 0.3"
            align="center"
            customStyle="justify-content: center"
          ></uv-text>
        </view>
      </view>
    </view>
  </view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	// 由于weex为阿里的KPI业绩考核的产物，所以不支持百分比单位，这里需要通过dom查询组件的宽度
	const dom = uni.requireNativePlugin('dom')
	// #endif

	/**
	 * Album 相册
	 * @description 本组件提供一个类似相册的功能，让开发者开发起来更加得心应手。减少重复的模板代码
	 * @tutorial https://www.uvui.cn/components/album.html
	 * @property {Array}           urls             图片地址列表 Array<String>|Array<Object>形式
	 * @property {String}          keyName          指定从数组的对象元素中读取哪个属性作为图片地址
	 * @property {String | Number} singleSize       单图时，图片长边的长度  （默认 180 ）
	 * @property {String | Number} multipleSize     多图时，图片边长 （默认 70 ）
	 * @property {String | Number} space            多图时，图片水平和垂直之间的间隔 （默认 6 ）
	 * @property {String}          singleMode       单图时，图片缩放裁剪的模式 （默认 'scaleToFill' ）
	 * @property {String}          multipleMode     多图时，图片缩放裁剪的模式 （默认 'aspectFill' ）
	 * @property {String | Number} maxCount         取消按钮的提示文字 （默认 9 ）
	 * @property {Boolean}         previewFullImage 是否可以预览图片 （默认 true ）
	 * @property {String | Number} rowCount         每行展示图片数量，如设置，singleSize和multipleSize将会无效	（默认 3 ）
	 * @property {Boolean}         showMore         超出maxCount时是否显示查看更多的提示 （默认 true ）
	 *
	 * @event    {Function}        albumWidth       某些特殊的情况下，需要让文字与相册的宽度相等，这里事件的形式对外发送  （回调参数 width ）
	 * @example <uv-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></uv-album>
	 */
	export default {
		name: 'uv-album',
		mixins: [mpMixin, mixin],
		emits: ['albumWidth'],
		props: {
			// 图片地址，Array<String>|Array<Object>形式
			urls: {
				type: Array,
				default: () => []
			},
			// 指定从数组的对象元素中读取哪个属性作为图片地址
			keyName: {
				type: String,
				default: ''
			},
			// 单图时，图片长边的长度
			singleSize: {
				type: [String, Number],
				default: 180
			},
			// 多图时，图片边长
			multipleSize: {
				type: [String, Number],
				default: 70
			},
			// 多图时，图片水平和垂直之间的间隔
			space: {
				type: [String, Number],
				default: 6
			},
			// 单图时，图片缩放裁剪的模式
			singleMode: {
				type: String,
				default: 'scaleToFill'
			},
			// 多图时，图片缩放裁剪的模式
			multipleMode: {
				type: String,
				default: 'aspectFill'
			},
			// 最多展示的图片数量，超出时最后一个位置将会显示剩余图片数量
			maxCount: {
				type: [String, Number],
				default: 9
			},
			// 是否可以预览图片
			previewFullImage: {
				type: Boolean,
				default: true
			},
			// 每行展示图片数量，如设置，singleSize和multipleSize将会无效
			rowCount: {
				type: [String, Number],
				default: 3
			},
			// 超出maxCount时是否显示查看更多的提示
			showMore: {
				type: Boolean,
				default: true
			},
			...uni.$uv?.props?.album
		},
		data() {
			return {
				// 单图的宽度
				singleWidth: 0,
				// 单图的高度
				singleHeight: 0,
				// 单图时，如果无法获取图片的尺寸信息，让图片宽度默认为容器的一定百分比
				singlePercent: 0.6
			}
		},
		watch: {
			urls: {
				immediate: true,
				handler(newVal) {
					if (newVal.length === 1) {
						this.getImageRect()
					}
				}
			}
		},
		computed: {
			imageStyle() {
				return (index1, index2) => {
					const { space, rowCount, multipleSize, urls } = this;
					const rowLen = this.showUrls.length;
					const allLen = this.urls.length;
					const style = {
						marginRight: this.$uv.addUnit(space),
						marginBottom: this.$uv.addUnit(space)
					}
					// 如果为最后一行，则每个图片都无需下边框
					if (index1 === rowLen) style.marginBottom = 0
					// 每行的最右边一张和总长度的最后一张无需右边框
					if (
						index2 === rowCount ||
						(index1 === rowLen &&
							index2 === this.showUrls[index1 - 1].length)
					)
						style.marginRight = 0
					return style
				}
			},
			// 将数组划分为二维数组
			showUrls() {
				const arr = []
				this.urls.map((item, index) => {
					// 限制最大展示数量
					if (index + 1 <= this.maxCount) {
						// 计算该元素为第几个素组内
						const itemIndex = Math.floor(index / this.rowCount)
						// 判断对应的索引是否存在
						if (!arr[itemIndex]) {
							arr[itemIndex] = []
						}
						arr[itemIndex].push(item)
					}
				})
				return arr
			},
			imageWidth() {
				return this.$uv.addUnit(
					this.urls.length === 1 ? this.singleWidth : this.multipleSize
				)
			},
			imageHeight() {
				return this.$uv.addUnit(
					this.urls.length === 1 ? this.singleHeight : this.multipleSize
				)
			},
			// 此变量无实际用途，仅仅是为了利用computed特性，让其在urls长度等变化时，重新计算图片的宽度
			// 因为用户在某些特殊的情况下，需要让文字与相册的宽度相等，所以这里事件的形式对外发送
			albumWidth() {
				let width = 0
				if (this.urls.length === 1) {
					width = this.singleWidth
				} else {
					width =
						this.showUrls[0].length * this.$uv.getPx(this.multipleSize) +
						this.$uv.getPx(this.space) * (this.showUrls[0].length - 1)
				}
				this.$emit('albumWidth', width)
				return width
			}
		},
		methods: {
			// 预览图片
			onPreviewTap(url) {
				const urls = this.urls.map((item) => {
					return this.getSrc(item)
				})
				uni.previewImage({
					current: url,
					urls
				})
			},
			// 获取图片的路径
			getSrc(item) {
				return this.$uv.test.object(item) ?
					(this.keyName && item[this.keyName]) || item.src :
					item
			},
			// 单图时，获取图片的尺寸
			// 在小程序中，需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
			// 在没有添加的情况下，让单图宽度默认为盒子的一定宽度(singlePercent)
			getImageRect() {
				const src = this.getSrc(this.urls[0])
				uni.getImageInfo({
					src,
					success: (res) => {
						// 判断图片横向还是竖向展示方式
						const isHorizotal = res.width >= res.height
						this.singleWidth = isHorizotal ?
							this.singleSize :
							(res.width / res.height) * this.$uv.getPx(this.singleSize)
						this.singleHeight = !isHorizotal ?
							this.singleSize :
							(res.height / res.width) * this.singleWidth
					},
					fail: () => {
						this.getComponentWidth()
					}
				})
			},
			// 获取组件的宽度
			async getComponentWidth() {
				// 延时一定时间，以获取dom尺寸
				await this.$uv.sleep(30)
				// #ifndef APP-NVUE
				this.$uGetRect('.uv-album__row').then((size) => {
					this.singleWidth = size.width * this.singlePercent
				})
				// #endif

				// #ifdef APP-NVUE
				// 这里ref="uv-album__row"所在的标签为通过for循环出来，导致this.$refs['uv-album__row']是一个数组
				const ref = this.$refs['uv-album__row'][0]
				ref &&
					dom.getComponentRect(ref, (res) => {
						this.singleWidth = res.size.width * this.singlePercent
					})
				// #endif
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-album {
		@include flex(column);
		&__row {
			@include flex(row);
			flex-wrap: wrap;
			&__wrapper {
				position: relative;
				&__text {
					position: absolute;
					top: 0;
					left: 0;
					right: 0;
					bottom: 0;
					background-color: rgba(0, 0, 0, 0.3);
					@include flex(row);
					justify-content: center;
					align-items: center;
				}
			}
		}
	}
</style>WkxE{
  "id": "uv-sticky",
  "displayName": "uv-sticky 吸顶  全面兼容小程序、nvue、vue2、vue3等多端",
  "version": "1.0.4",
  "description": "吸顶组件与CSS中position: sticky属性实现的效果一致，当组件达到预设的到顶部距离时， 就会固定在指定位置，组件位置大于预设的顶部距离时，会重新按照正常的布局排列。",
  "keywords": [
    "uv-sticky",
    "uvui",
    "uv-ui",
    "sticky",
    "吸顶"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
    	"ads": "无",
    	"data": "插件不采集任何数据",
    	"permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
			"uv-ui-tools"
		],
    "encrypt": [],
    "platforms": {
			"cloud": {
				"tcb": "y",
				"aliyun": "y"
			},
			"client": {
				"Vue": {
					"vue2": "y",
					"vue3": "y"
				},
				"App": {
					"app-vue": "y",
					"app-nvue": "y"
				},
				"H5-mobile": {
					"Safari": "y",
					"Android Browser": "y",
					"微信浏览器(Android)": "y",
					"QQ浏览器(Android)": "y"
				},
				"H5-pc": {
					"Chrome": "y",
					"IE": "y",
					"Edge": "y",
					"Firefox": "y",
					"Safari": "y"
				},
				"小程序": {
					"微信": "y",
					"阿里": "y",
					"百度": "y",
					"字节跳动": "y",
					"QQ": "y",
					"钉钉": "u",
					"快手": "u",
					"飞书": "u",
					"京东": "u"
				},
				"快应用": {
					"华为": "u",
					"联盟": "u"
				}
			}
		}
  }
} BGxf{
  "id": "uv-empty",
  "displayName": "uv-empty 内容为空 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.5",
  "description": "该组件用于需要加载内容，但是加载的第一页数据就为空，提示一个 没有Q容 的场景， 我们精心挑选了十几个场景的图标，方便您使用yempt"空数据",
    "暂无数据,
			"uv-icon
ya(x3T{
  "id": "uv-datetime-picker",
  "displayName": "uv-datetime-picker 时间选择器=H12",
  "description": "时间选择器组件用于时间日期，主要用于年月日时分的选择，具体选择的精确由参数控制Odatetime-pickero!datetime",
    "时间选择picker
kBx{
  "id": "uv-albumalbum 相册TH4组件提供一个类似相册的功能，让开发者开发起来更加得心应手，功能齐全，灵活配置可以，(箱即用。减少重复的模板代码.albuma uvui",
    "相册",
    "图片text
exY## uv-ui-tools 工具集

> **组件名：uv-ui-tools**

uv-ui工具集成，包括网络Http请求、便捷工具、节流防抖、对象操作、时间格式化、路由跳转、全局唯一标识符、规则校验等等。

该组件推荐配合[uv-ui组件库](https://www.uvui.cn/components/intro.html)使用，单独下载也可以在自己项目中使用，需要做相应的配置，可查看文档。强烈推荐使用[uv-ui组件库](https://www.uvui.cn/components/intro.html)，导入组件都会自动导入`uv-ui-tools`。需要在自己的项目中使用请参考[扩展配置](https://www.uvui.cn/components/setting.html)。

uv-ui破釜沉舟之兼容vue3+2、app、h5、多端小程序的uni-app生态框架，大部分组件基于uView2.x，在经过改进后全面支持vue3，部分组件做了进一步的优化，修复大量BUG，支持单独导入，方便开发者选择导入需要的组件。开箱即用，灵活配置。

# <a href="https://www.uvui.cn/js/intro.html" target="_blank">查看文档</a>

## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>（请不要 下载插件ZIP）</small>

### [更多插件，请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)

<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">

![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)

</a>

#### 如使用过程中有任何问题反馈，或者您对uv-ui有一些好的建议，欢迎加入uv-ui官方交流群：<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>Wfx @## PickColor 颜色选择器

> **组件名：uv-pick-color**

该组件为颜色选择器，支持预制颜色，初始化颜'，简单配置，开箱即用。

# (	pickColor{Km,Nx 
## Picker "er**

此选择器用于单列，多列，多列联动的选择场景。

`uv-datetime-picker`等组件也用到了该组件，N功能完善，需要特别注意的是`columns`参数的形式是数组嵌套3e|yx ## Button 按钮

> **组件名：uv-button**

该组件内部实现以`uni-app`的`button`组件为基础，进行二次封装g，灵活配置，功能齐全，兼容全端。灵活配置，内置状态设置，开箱即用。

# Q(button.{x &# Album 相册album**

本组件提供一个类似相册的功能，让开发者开发起来更加得心应手。

功能齐全，灵活配4可以，开箱即用。减少重复的模板代码/album{oz	x e100644 changelog.md q̠0awO40000 components 'q7TdLy100644 package.json 4 9 p""aҺ100644 readme.md cݧjM:	,pb]4ÉݷJ?'xy## 1.0.7（2023-11-07）
1. 修复sticky属性不生效的BUG
## 1.0.6（2023-09-01）
1. 修复设置customNavHeight导致定位不准确的BUG
## 1.0.5（2023-08-23）
1. 修复ios端快速滑动+点击右侧导航会出现白屏的BUG
## 1.0.4（2023-07-25）
1. 修复全局设置成rpx存在的高度BUG
2. 修复其他BUG
## 1.0.3（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.2（2023-05-27）
1. select事件修复
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-index-list 索引列表
Jx^ <## 1.0.2（2023-07-13）
1. 修复  uv-number-box设置value(number-box 步进器
(mx\ :## 1.0.2（2023-06-01）
1. 修复点击触发两次实践Kalert 警告提示组件
0x# 40000 uv-alert DLv* P|~$TxL 100644 props.js ̎wǅ|SnS_100644 uv-alert.vue 9e,tsR>NJ|"0xexport default {
	props: {
		// 到顶部的距离
		top: {
			type: [String, Number],
			default: 0
		},
		// type主题，primary，success，warning，error
		type: {
			type: String,
			default: 'primary'
		},
		// 字体颜色
		color: {
			type: String,
			default: '#ffffff'
		},
		// 背景颜色
		bgColor: {
			type: String,
			default: ''
		},
		// 展示的文字内容
		message: {
			type: String,
			default: ''
		},
		// 展示时长，为0时不消失，单位ms
		duration: {
			type: [String, Number],
			default: 3000
		},
		// 字体大小
		fontSize: {
			type: [String, Number],
			default: 15
		},
		// 是否留出顶部安全距离（状态栏高度）
		safeAreaInsetTop: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.notify
	}
}&xB 显示文字
		title"\主题，success/warning/info/.0warning'
		},
		// 辅助性文字
		description"\是否可关闭
		closable/ // 是否显示图标
		showIcon/8// 浅或深色调，light-浅色，dark-深色
		effect",light'
		},
		// 文字是否居中
		center/!F4
alert
	}
}I9x-<template>
	<uv-transition
	    mode="fade"
	    :show="show"
	>
		<view
		    class="uv-alert"
		    :class="[`uv-alert--${type}--${effect}`]"
		    @tap.stop="clickHandler"
		    :style="[$uv.addStyle(customStyle)]"
		>
			<view
			    class="uv-alert__icon"
			    v-if="showIcon"
			>
				<uv-icon
				    :name="iconName"
				    size="18"
				    :color="iconColor"
				></uv-icon>
			</view>
			<view
			    class="uv-alert__content"
			    :style="[{
					paddingRight: closable ? '20px' : 0
				}]"
			>
				<text
				    class="uv-alert__content__title"
				    v-if="title"
					:style="[{
						fontSize: $uv.addUnit(fontSize),
						textAlign: center ? 'center' : 'left'
					}]"
				    :class="[effect === 'dark' ? 'uv-alert__text--dark' : `uv-alert__text--${type}--light`]"
				>{{ title }}</text>
				<text
				    class="uv-alert__content__desc"
					v-if="description"
					:style="[{
						fontSize: $uv.addUnit(fontSize),
						textAlign: center ? 'center' : 'left'
					}]"
				    :class="[effect === 'dark' ? 'uv-alert__text--dark' : `uv-alert__text--${type}--light`]"
				>{{ description }}</text>
			</view>
			<view
			    class="uv-alert__close"
			    v-if="closable"
			    @tap.stop="closeHandler"
			>
				<uv-icon
				    name="close"
				    :color="iconColor"
				    size="15"
				></uv-icon>
			</view>
		</view>
	</uv-transition>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Alert  警告提示
	 * @description 警告提示，展现需要关注的信息。
	 * @tutorial https://www.uvui.cn/components/alertTips.html
	 * 
	 * @property {String}			title       显示的文字 
	 * @property {String}			type        使用预设的颜色  （默认 'warning' ）
	 * @property {String}			description 辅助性文字，颜色比title浅一点，字号也小一点，可选  
	 * @property {Boolean}			closable    关闭按钮(默认为叉号icon图标)  （默认 false ）
	 * @property {Boolean}			showIcon    是否显示左边的辅助图标   （ 默认 false ）
	 * @property {String}			effect      多图时，图片缩放裁剪的模式  （默认 'light' ）
	 * @property {Boolean}			center		文字是否居中  （默认 false ）
	 * @property {String | Number}	fontSize    字体大小  （默认 14 ）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * @event    {Function}        click       点击组件时触发
	 * @example  <uv-alert :title="title"  type = "warning" :closable="closable" :description = "description"></uv-alert>
	 */
	export default {
		name: 'uv-alert',
		mixins: [mpMixin, mixin, props],
		emits: ['click'],
		data() {
			return {
				show: true
			}
		},
		computed: {
			iconColor() {
				return this.effect === 'light' ? this.type : '#fff'
			},
			// 不同主题对应不同的图标
			iconName() {
				switch (this.type) {
					case 'success':
						return 'checkmark-circle-fill';
						break;
					case 'error':
						return 'close-circle-fill';
						break;
					case 'warning':
						return 'error-circle-fill';
						break;
					case 'info':
						return 'info-circle-fill';
						break;
					case 'primary':
						return 'more-circle-fill';
						break;
					default: 
						return 'error-circle-fill';
				}
			}
		},
		methods: {
			// 点击内容
			clickHandler() {
				this.$emit('click')
			},
			// 点击关闭按钮
			closeHandler() {
				this.show = false
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-alert {
		position: relative;
		background-color: $uv-primary;
		padding: 8px 10px;
		@include flex(row);
		align-items: center;
		border-top-left-radius: 4px;
		border-top-right-radius: 4px;
		border-bottom-left-radius: 4px;
		border-bottom-right-radius: 4px;

		&--primary--dark {
			background-color: $uv-primary;
		}

		&--primary--light {
			background-color: #ecf5ff;
		}

		&--error--dark {
			background-color: $uv-error;
		}

		&--error--light {
			background-color: #FEF0F0;
		}

		&--success--dark {
			background-color: $uv-success;
		}

		&--success--light {
			background-color: #f5fff0;
		}

		&--warning--dark {
			background-color: $uv-warning;
		}

		&--warning--light {
			background-color: #FDF6EC;
		}

		&--info--dark {
			background-color: $uv-info;
		}

		&--info--light {
			background-color: #f4f4f5;
		}

		&__icon {
			margin-right: 5px;
		}

		&__content {
			@include flex(column);
			flex: 1;

			&__title {
				color: $uv-main-color;
				font-size: 14px;
				font-weight: bold;
				color: #fff;
				margin-bottom: 2px;
			}

			&__desc {
				color: $uv-main-color;
				font-size: 14px;
				flex-wrap: wrap;
				color: #fff;
			}
		}

		&__title--dark,
		&__desc--dark {
			color: #FFFFFF;
		}

		&__text--primary--light,
		&__text--primary--light {
			color: $uv-primary;
		}

		&__text--success--light,
		&__text--success--light {
			color: $uv-success;
		}

		&__text--warning--light,
		&__text--warning--light {
			color: $uv-warning;
		}

		&__text--error--light,
		&__text--error--light {
			color: $uv-error;
		}

		&__text--info--light,
		&__text--info--light {
			color: $uv-info;
		}

		&__close {
			position: absolute;
			top: 11px;
			right: 10px;
		}
	}
</style>
hx{
	"id": "uv-scroll-list",
	"displayName": "uv-scroll-list 横向滚动列表 全面兼容vue3+2、app、h5、小程序等多端",
	"version": "1.0.5",
	"description": "该组件一般用于同时展示多个商品、分类的场景，也可以完成左右滑动的列表，往往数量不确定，数量较多支持左右滚动。灵活配置，开箱即用。",
	"keywords": [
        "uv-scroll-list",
        "uvui",
        "uv-ui",
        "横向滚动列表",
        "scroll-view"
    ],
	"repository": "",
	"engines": {
		"HBuilderX": "^3.1.0"
	},
	"dcloudext": {
		"type": "component-vue",
		"sale": {
			"regular": {
				"price": "0.00"
			},
			"sourcecode": {
				"price": "0.00"
			}
		},
		"contact": {
			"qq": ""
		},
		"declaration": {
			"ads": "无",
			"data": "无",
			"permissions": "无"
		},
		"npmurl": ""
	},
	"uni_modules": {
		"dependencies": [
			"uv-ui-tools"
		],
		"encrypt": [],
		"platforms": {
			"cloud": {
				"tcb": "y",
				"aliyun": "y"
			},
			"client": {
				"Vue": {
					"vue2": "y",
					"vue3": "y"
				},
				"App": {
					"app-vue": "y",
					"app-nvue": "y"
				},
				"H5-mobile": {
					"Safari": "y",
					"Android Browser": "y",
					"微信浏览器(Android)": "y",
					"QQ浏览器(Android)": "y"
				},
				"H5-pc": {
					"Chrome": "y",
					"IE": "y",
					"Edge": "y",
					"Firefox": "y",
					"Safari": "y"
				},
				"小程序": {
					"微信": "y",
					"阿里": "y",
					"百度": "y",
					"字节跳动": "y",
					"QQ": "y",
					"钉钉": "u",
					"快手": "u",
					"飞书": "u",
					"京东": "u"
				},
				"快应用": {
					"华为": "u",
					"联盟": "u"
				}
			}
		}
	}
}k)?xl{
	"id": "uv-alert",
	"displayName": "uv-alert 警告提示 全面兼容小程序、nvue、vue2、vue3等多端",
	"version": "2",
	"description": "uv-alert 警告提示，展现需要关注的信息。灵活配置，功能齐全，兼容全端",
	"keywosaler.警告提示)件不采集任何数据i!,
			"uv-transition",
			"uv-icon{o*x## Alert 警告提示alert**

警告提示，展现需要关注的信息。

当某个页面需要向用户显示警告的信息时。

非浮层的Q静态展现形式，始终展现，不会自动消失，用户可以点击关闭1alertZ:	x e100644 changelog.md 1oilp,v240000 components F	rL~<!1l100644 package.json z5'G}Gh100644 readme.md بw6xY1ˑ:2=۳xs## 1.0.5（2023-12-06）
1. 优化
## 1.0.4（2023-12-06）
1. 优化
## 1.0.3（2023-12-06）
1. 阻止事件冒泡处理，单个头像模式
## 1.0.2（2023-12-06）
1. 阻止事件冒泡处理
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-avatar 头像组件
#xN 40000 uv-avatar-group 6(fWiY\Y40000 uv-avatar 4[zPȼϵ޲Pĥ57!xS 100644 props.js H/Nܧj0v	100644 uv-avatar-group.vue YHo@vMN W)Ʈ:xVexport default {
	props: {
		// 头像图片组
		urls: {
			type: Array,
			default: () => []
		},
		// 最多展示的头像数量
		maxCount: {
			type: [String, Number],
			default: 5
		},
		// 头像形状
		shape: {
			type: String,
			default: 'circle'
		},
		// 图片裁剪模式
		mode: {
			type: String,
			default: 'scaleToFill'
		},
		// 超出maxCount时是否显示查看更多的提示
		showMore: {
			type: Boolean,
			default: true
		},
		// 头像大小
		size: {
			type: [String, Number],
			default: 40
		},
		// 指定从数组的对象元素中读取哪个属性作为图片地址
		keyName: {
			type: String,
			default: ''
		},
		// 头像之间的遮挡比例
		gap: {
			type: [String, Number],
			validator(value) {
				return value >= 0 && value <= 1
			},
			default: 0.5
		},
		// 需额外显示的值
		extraValue: {
			type: [Number, String],
			default: 0
		},
		...uni.$uv?.props?.avatarGroup
	}
}fxL<template>
	<view class="uv-avatar-group">
		<view
		    class="uv-avatar-group__item"
		    v-for="(item, index) in showUrl"
		    :key="index"
		    :style="{
				marginLeft: index === 0 ? 0 : $uv.addUnit(-size * gap)
			}"
		>
			<uv-avatar
			    :size="size"
			    :shape="shape"
			    :mode="mode"
			    :src="$uv.test.object(item) ? keyName && item[keyName] || item.url : item"
			></uv-avatar>
			<view
			    class="uv-avatar-group__item__show-more"
			    v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
				@tap="clickHandler"
			>
				<uv-text
				    color="#ffffff"
				    :size="size * 0.4"
				    :text="`+${extraValue || urls.length - showUrl.length}`"
					align="center"
					customStyle="justify-content: center"
				></uv-text>
			</view>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * AvatarGroup  头像组
	 * @description 本组件一般用于展示头像的地方，如个人中心，或者评论列表页的用户头像展示等场所。
	 * @tutorial https://www.uvui.cn/components/avatar.html
	 * 
	 * @property {Array}           urls     头像图片组 （默认 [] ）
	 * @property {String | Number} maxCount 最多展示的头像数量 （ 默认 5 ）
	 * @property {String}          shape    头像形状（ 'circle' (默认) | 'square' ）
	 * @property {String}          mode     图片裁剪模式（默认 'scaleToFill' ）
	 * @property {Boolean}         showMore 超出maxCount时是否显示查看更多的提示 （默认 true ）
	 * @property {String | Number} size      头像大小 （默认 40 ）
	 * @property {String}          keyName  指定从数组的对象元素中读取哪个属性作为图片地址 
	 * @property {String | Number} gap      头像之间的遮挡比例（0.4代表遮挡40%）  （默认 0.5 ）
	 * @property {String | Number} extraValue  需额外显示的值
	 * @event    {Function}        showMore 头像组更多点击
	 * @example  <uv-avatar-group:urls="urls" size="35" gap="0.4" ></uv-avatar-group:urls=>
	 */
	export default {
		name: 'uv-avatar-group',
		mixins: [mpMixin, mixin, props],
		data() {
			return {

			}
		},
		computed: {
			showUrl() {
				return this.urls.slice(0, this.maxCount)
			}
		},
		methods: {
			clickHandler() {
				this.$emit('showMore')
			}
		},
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';

	.uv-avatar-group {
		@include flex;

		&__item {
			margin-left: -10px;
			position: relative;

			&--no-indent {
				// 如果你想质疑作者不会使用:first-child，说明你太年轻，因为nvue不支持
				margin-left: 0;
			}

			&__show-more {
				position: absolute;
				top: 0;
				bottom: 0;
				left: 0;
				right: 0;
				background-color: rgba(0, 0, 0, 0.3);
				@include flex;
				align-items: center;
				justify-content: center;
				border-radius: 100px;
			}
		}
	}
</style>
m2xM 100644 props.js lrYc$죁100644 uv-avatar.vue 	Y֯B{G6 Y	I했ϸaximport { range } from '@/uni_modules/uv-ui-tools/libs/function/test.js'
export default {
	props: {
		// 头像图片路径(不能为相对路径)
		src: {
			type: String,
			default: ''
		},
		// 头像形状，circle-圆形，square-方形
		shape: {
			type: String,
			default: 'circle'
		},
		// 头像尺寸
		size: {
			type: [String, Number],
			default: 40
		},
		// 裁剪模式
		mode: {
			type: String,
			default: 'scaleToFill'
		},
		// 显示的文字
		text: {
			type: String,
			default: ''
		},
		// 背景色
		bgColor: {
			type: String,
			default: '#c0c4cc'
		},
		// 文字颜色
		color: {
			type: String,
			default: '#fff'
		},
		// 文字大小
		fontSize: {
			type: [String, Number],
			default: 18
		},
		// 显示的图标
		icon: {
			type: String,
			default: ''
		},
		// 显示小程序头像，只对百度，微信，QQ小程序有效
		mpAvatar: {
			type: Boolean,
			default: false
		},
		// 是否使用随机背景色
		randomBgColor: {
			type: Boolean,
			default: false
		},
		// 加载失败的默认头像(组件有内置默认图片)
		defaultUrl: {
			type: String,
			default: ''
		},
		// 如果配置了randomBgColor为true，且配置了此值，则从默认的背景色数组中取出对应索引的颜色值，取值0-19之间
		colorIndex: {
			type: [String, Number],
			// 校验参数规则，索引在0-19之间
			validator(n) {
				return range(n, [0, 19]) || n === ''
			},
			default: ''
		},
		// 组件标识符
		name: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.avatar
	}
}%w0x?$<template>
	<view
		class="uv-avatar"
		:class="[`uv-avatar--${shape}`]"
		:style="[{
			backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $uv.random(0, 19)] : bgColor) : 'transparent',
			width: $uv.addUnit(size),
			height: $uv.addUnit(size),
		}, $uv.addStyle(customStyle)]"
		@tap="clickHandler"
	>
		<slot>
			<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU  -->
			<open-data
				v-if="mpAvatar && allowMp"
				type="userAvatarUrl"
				:style="[{
					width: $uv.addUnit(size),
					height: $uv.addUnit(size)
				}]"
			/>
			<!-- #endif -->
			<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU  -->
			<template v-if="mpAvatar && allowMp"></template>
			<!-- #endif -->
			<uv-icon
				v-else-if="icon"
				:name="icon"
				:size="fontSize"
				:color="color"
			></uv-icon>
			<uv-text
				v-else-if="text"
				:text="text"
				:size="fontSize"
				:color="color"
				align="center"
				customStyle="justify-content: center"
			></uv-text>
			<image
				class="uv-avatar__image"
				v-else
				:class="[`uv-avatar__image--${shape}`]"
				:src="avatarUrl || defaultUrl"
				:mode="mode"
				@error="errorHandler"
				:style="[{
					width: $uv.addUnit(size),
					height: $uv.addUnit(size)
				}]"
			></image>
		</slot>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	const base64Avatar =
		"data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
	/**
	 * Avatar  头像
	 * @description 本组件一般用于展示头像的地方，如个人中心，或者评论列表页的用户头像展示等场所。
	 * @tutorial https://www.uvui.cn/components/avatar.html
	 *
	 * @property {String}			src				头像路径，如加载失败，将会显示默认头像(不能为相对路径)
	 * @property {String}			shape			头像形状  （ circle (默认) | square）
	 * @property {String | Number}	size			头像尺寸，可以为指定字符串(large, default, mini)，或者数值 （默认 40 ）
	 * @property {String}			mode			头像图片的裁剪类型，与uni的image组件的mode参数一致，如效果达不到需求，可尝试传widthFix值 （默认 'scaleToFill' ）
	 * @property {String}			text			用文字替代图片，级别优先于src
	 * @property {String}			bgColor			背景颜色，一般显示文字时用 （默认 '#c0c4cc' ）
	 * @property {String}			color			文字颜色 （默认 '#ffffff' ）
	 * @property {String | Number}	fontSize		文字大小  （默认 18 ）
	 * @property {String}			icon			显示的图标
	 * @property {Boolean}			mpAvatar		显示小程序头像，只对百度，微信，QQ小程序有效  （默认 false ）
	 * @property {Boolean}			randomBgColor	是否使用随机背景色  （默认 false ）
	 * @property {String}			defaultUrl		加载失败的默认头像(组件有内置默认图片)
	 * @property {String | Number}	colorIndex		如果配置了randomBgColor为true，且配置了此值，则从默认的背景色数组中取出对应索引的颜色值，取值0-19之间
	 * @property {String}			name			组件标识符  （默认 'level' ）
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 *
	 * @event    {Function}        click       点击组件时触发   index: 用户传递的标识符
	 * @example  <uv-avatar :src="src" mode="square"></uv-avatar>
	 */
	export default {
		name: 'uv-avatar',
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 如果配置randomBgColor参数为true，在图标或者文字的模式下，会随机从中取出一个颜色值当做背景色
				colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
					'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
					'#73d1f1',
					'#80a7dc'
				],
				avatarUrl: this.src,
				allowMp: false
			}
		},
		watch: {
			// 监听头像src的变化，赋值给内部的avatarUrl变量，因为图片加载失败时，需要修改图片的src为默认值
			// 而组件内部不能直接修改props的值，所以需要一个中间变量
			src: {
				immediate: true,
				handler(newVal) {
					this.avatarUrl = newVal
					// 如果没有传src，则主动触发error事件，用于显示默认的头像，否则src为''空字符等的时候，会无内容展示
					if(!newVal) {
						this.errorHandler()
					}
				}
			}
		},
		computed: {
			imageStyle() {
				const style = {}
				return style
			}
		},
		created() {
			this.init()
		},
		methods: {
			init() {
				// 目前只有这几个小程序平台具有open-data标签
				// 其他平台可以通过uni.getUserInfo类似接口获取信息，但是需要弹窗授权(首次)，不合符组件逻辑
				// 故目前自动获取小程序头像只支持这几个平台
				// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
				this.allowMp = true
				// #endif
			},
			// 判断传入的name属性，是否图片路径，只要带有"/"均认为是图片形式
			isImg() {
				return this.src.indexOf('/') !== -1
			},
			// 图片加载时失败时触发
			errorHandler() {
				this.avatarUrl = this.defaultUrl || base64Avatar
			},
			clickHandler() {
				this.$emit('click', this.name)
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-avatar {
		@include flex;
		align-items: center;
		justify-content: center;

		&--circle {
			border-radius: 100px;
		}

		&--square {
			border-radius: 4px;
		}

		&__image {
			&--circle {
				border-radius: 100px;
			}

			&--square {
				border-radius: 4px;
			}
		}
	}
</style>
jxW{
	"id": "uv-calendar",
	"displayName": "uv-calendar 日历 全面兼容vue3+2、app、h5、小程序等多端",
	"version": "1.0.6",
	"description": "日历组件用于单个选择日期，范围选择日期等，日历被包裹在底部弹起的容器中，灵活配置，功能齐全，兼容全端。强烈推荐使用最新版日历组件，在下方跳入。",
	"keywords": [
        "uv-calendar",
        "uvui",
        "uv-ui",
        "calendar",
        "日历"
    ],
	"repository": "",
	"engines": {
		"HBuilderX": "^3.1.0"
	},
	"dcloudext": {
		"type": "component-vue",
		"sale": {
			"regular": {
				"price": "0.00"
			},
			"sourcecode": {
				"price": "0.00"
			}
		},
		"contact": {
			"qq": ""
		},
		"declaration": {
			"ads": "无",
			"data": "插件不采集任何数据",
			"permissions": "无"
		},
		"npmurl": ""
	},
	"uni_modules": {
		"dependencies": [
			"uv-ui-tools",
			"uv-button",
			"uv-popup"
		],
		"encrypt": [],
		"platforms": {
			"cloud": {
				"tcb": "y",
				"aliyun": "y"
			},
			"client": {
				"Vue": {
					"vue2": "y",
					"vue3": "y"
				},
				"App": {
					"app-vue": "y",
					"app-nvue": "y"
				},
				"H5-mobile": {
					"Safari": "y",
					"Android Browser": "y",
					"微信浏览器(Android)": "y",
					"QQ浏览器(Android)": "y"
				},
				"H5-pc": {
					"Chrome": "y",
					"IE": "y",
					"Edge": "y",
					"Firefox": "y",
					"Safari": "y"
				},
				"小程序": {
					"微信": "y",
					"阿里": "y",
					"百度": "y",
					"字节跳动": "y",
					"QQ": "y",
					"钉钉": "u",
					"快手": "u",
					"飞书": "u",
					"京东": "u"
				},
				"快应用": {
					"华为": "u",
					"联盟": "u"
				}
			}
		}
	}
}-;5x 
7{
	"id": "uv-button",
	"displayName": "uv-button 按钮;Ge15",
	"description": "按钮组件内部实现以uni-app的button组件为基础，进行二次封装0lbutton-button",
        "按钮loading-icon",
			"uv-iconq{k{x2b{
	"id": "uv-avatar",
	"displayName": "uv-avatar 头像 全面兼容小程序、nvue、vue2、vue3auv-avatar 本组件一般用于展示头像的地方，如个人中心，或者评论列表页的用户头像展示等场所。avatar7-avatar",
        "头像|icon",
			"uv-textK9㝱
_x S## Avatar 头像avatar**

本组件一般用于展示头像的地方，如个人中心，或者评论列表页的用户头像展示等场所。.avatarZQgI	x e100644 changelog.md r&/'4ŝz:/u40000 components l8?TYSz1ZDn100644 package.json Z_5G[XHOS!*100644 readme.md ֢3dFV`8yxi H3）
1. 优化插槽自定义内容部分
2. 增加backToTop方法说明back-top 返回顶部
#;ox& 40000 uv-back-top |?%Vv>c?b׵j5UxO 100644 props.js tN$_np(100644 uv-back-top.vue =J/u(pːYv@xexport default {
	props: {
		// 返回顶部的形状，circle-圆形，square-方形
		mode: {
			type: String,
			default: 'circle'
		},
		// 自定义图标
		icon: {
			type: String,
			default: 'arrow-upward'
		},
		// 提示文字
		text: {
			type: String,
			default: ''
		},
		// 返回顶部滚动时间
		duration: {
			type: [String, Number],
			default: 100
		},
		// 滚动距离
		scrollTop: {
			type: [String, Number],
			default: 0
		},
		// 距离顶部多少距离显示，单位px
		top: {
			type: [String, Number],
			default: 400
		},
		// 返回顶部按钮到底部的距离，单位px
		bottom: {
			type: [String, Number],
			default: 100
		},
		// 返回顶部按钮到右边的距离，单位px
		right: {
			type: [String, Number],
			default: 20
		},
		// 层级
		zIndex: {
			type: [String, Number],
			default: 9
		},
		// 图标的样式，对象形式
		iconStyle: {
			type: Object,
			default: () => ({
				color: '#909399',
				fontSize: '19px'
			})
		},
		...uni.$uv?.props?.backtop
	}
}#^x<template>
	<uv-transition mode="fade" :customStyle="backTopStyle" :show="show">
		<slot>
			<view class="uv-back-top" :style="[contentStyle]" @click="backToTop">
				<uv-icon :name="icon" :custom-style="iconStyle"></uv-icon>
				<text v-if="text" class="uv-back-top__text">{{text}}</text>
			</view>
		</slot>
	</uv-transition>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const dom = weex.requireModule('dom')
	// #endif
	/**
	 * backTop 返回顶部
	 * @description 本组件一个用于长页面，滑动一定距离后，出现返回顶部按钮，方便快速返回顶部的场景。
	 * @tutorial https://www.uvui.cn/components/backTop.html
	 * @property {String}			mode  		返回顶部的形状，circle-圆形，square-方形 （默认 'circle' ）
	 * @property {String} 			icon 		自定义图标 （默认 'arrow-upward' ） 见官方文档示例
	 * @property {String} 			text 		提示文字 
	 * @property {String | Number}  duration	返回顶部滚动时间 （默认 100）
	 * @property {String | Number}  scrollTop	滚动距离 （默认 0 ）
	 * @property {String | Number}  top  		距离顶部多少距离显示，单位px （默认 400 ）
	 * @property {String | Number}  bottom  	返回顶部按钮到底部的距离，单位px （默认 100 ）
	 * @property {String | Number}  right  		返回顶部按钮到右边的距离，单位px （默认 20 ）
	 * @property {String | Number}  zIndex 		层级   （默认 9 ）
	 * @property {Object<Object>}  	iconStyle 	图标的样式，对象形式   （默认 {color: '#909399',fontSize: '19px'}）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * 
	 * @example <uv-back-top :scrollTop="scrollTop"></uv-back-top>
	 */
	export default {
		name: 'uv-back-top',
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		computed: {
			backTopStyle() {
				// 动画组件样式
				const style = {
					bottom: this.$uv.addUnit(this.bottom),
					right: this.$uv.addUnit(this.right),
					width: '40px',
					height: '40px',
					position: 'fixed',
					zIndex: 10,
				}
				return style
			},
			show() {
				return this.$uv.getPx(this.scrollTop) > this.$uv.getPx(this.top)
			},
			contentStyle() {
				const style = {}
				let radius = 0
				// 是否圆形
				if (this.mode === 'circle') {
					radius = '100px'
				} else {
					radius = '4px'
				}
				// 为了兼容安卓nvue，只能这么分开写
				style.borderTopLeftRadius = radius
				style.borderTopRightRadius = radius
				style.borderBottomLeftRadius = radius
				style.borderBottomRightRadius = radius
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		methods: {
			backToTop() {
				// #ifdef APP-NVUE
				if (!this.$parent.$refs['uv-back-top']) {
					this.$uv.error(`nvue页面需要给页面最外层元素设置"ref='uv-back-top'`)
				}
				dom.scrollToElement(this.$parent.$refs['uv-back-top'], {
					offset: 0
				})
				// #endif

				// #ifndef APP-NVUE
				uni.pageScrollTo({
					scrollTop: 0,
					duration: this.duration
				});
				// #endif
				this.$emit('click')
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	$uv-back-top-flex: 1 !default;
	$uv-back-top-height: 100% !default;
	$uv-back-top-background-color: #E1E1E1 !default;
	$uv-back-top-tips-font-size: 12px !default;
	.uv-back-top {
		@include flex;
		flex-direction: column;
		align-items: center;
		flex: $uv-back-top-flex;
		height: $uv-back-top-height;
		justify-content: center;
		background-color: $uv-back-top-background-color;
		&__tips {
			font-size: $uv-back-top-tips-font-size;
			transform: scale(0.8);
		}
	}
</style>E/=xC{
	"id": "uv-drop-down",
	"displayName": "uv-drop-down 下拉筛选=6	"version": "1.0.5",
	主要提供筛选下拉筛选框，内置基础筛选功能，可以根据自己的需求自定义筛选项",
	"keywords": [
        "uv-drop-down",
        "uvui",
        "uv-ui",
        "下拉筛选",
        "筛选"
    ],
	"repository": "",
	"engines": {
		"HBuilderX": "^3.1.0"
	},
	"dcloudext": {
		"type": "component-vue",
		"sale": {
			"regular": {
				"price": "0.00"
			},
			"sourcecode": {
				"price": "0.00"
			}
		},
		"contact": {
			"qq": ""
		},
		"declaration": {
			"ads": "无",
		(		 ,		},
		"npmurl": ""
	},
	"uni_modules": {
		j0K,
			"uv-text",
			"uv-transition",
			"uv-sticky"
		],
		"encrypt": [],
			}
})x}{
	"id": "uv-back-top",
	"displayName": "uv-back-top 返回顶部  全面兼容小程序、nvue、vue2、vue3等多端",
	"vers2",
	"description": "返回顶部 组件一个用于长页面，滑动一定距离后，出现返回顶部按钮，方便快速>返回顶部的场景。",
	"keywords": [
        "uv-back-top;-avatar",
        "返回顶部	ransitionq~x I## BackTop 返回顶部back-top**

该组件一个用于长页面，滑动一定距离后，出现返回顶部按钮，方便快速返回顶部的场1backToZEm>	x e100644 changelog.md LSz|v40000 components ;ąCbڦV!2_100644 package.json Z8d0zj?J100644 readme.md Y~3 A0?~x## 1.0.2（2023-06-04）
1. 修复type等属性为null的时候不显示徽标的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-badge 徽标数，数字角标
Oʣx# 40000 uv-badge /0|e*=t`4xL 100644 props.js 69_}|ebKP100644 uv-badge.vue ӑ:чǻF8 ixhexport default {
	props: {
		// 是否显示圆点
		isDot: {
			type: Boolean,
			default: false
		},
		// 显示的内容
		value: {
			type: [Number, String],
			default: ''
		},
		// 是否显示
		show: {
			type: Boolean,
			default: true
		},
		// 最大值，超过最大值会显示 '{max}+'
		max: {
			type: [Number, String],
			default: 999
		},
		// 主题类型，error|warning|success|primary
		type: {
			type: [String,undefined,null],
			default: 'error'
		},
		// 当数值为 0 时，是否展示 Badge
		showZero: {
			type: Boolean,
			default: false
		},
		// 背景颜色，优先级比type高，如设置，type参数会失效
		bgColor: {
			type: [String, null],
			default: null
		},
		// 字体颜色
		color: {
			type: [String, null],
			default: null
		},
		// 徽标形状，circle-四角均为圆角，horn-左下角为直角
		shape: {
			type: [String,undefined,null],
			default: 'circle'
		},
		// 设置数字的显示方式，overflow|ellipsis|limit
		// overflow会根据max字段判断，超出显示`${max}+`
		// ellipsis会根据max判断，超出显示`${max}...`
		// limit会依据1000作为判断条件，超出1000，显示`${value/1000}K`，比如2.2k、3.34w，最多保留2位小数
		numberType: {
			type: [String,undefined,null],
			default: 'overflow'
		},
		// 设置badge的位置偏移，格式为 [x, y]，也即设置的为top和right的值，absolute为true时有效
		offset: {
			type: Array,
			default: () => []
		},
		// 是否反转背景和字体颜色
		inverted: {
			type: Boolean,
			default: false
		},
		// 是否绝对定位
		absolute: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.badge
	}
})9ٳxd<template>
	<text
		v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
		:class="[isDot ? 'uv-badge--dot' : 'uv-badge--not-dot', inverted && 'uv-badge--inverted', shape === 'horn' && 'uv-badge--horn', `uv-badge--${propsType}${inverted ? '--inverted' : ''}`]"
		:style="[$uv.addStyle(customStyle), badgeStyle]"
		class="uv-badge"
	>{{ isDot ? '' :showValue }}</text>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * badge 徽标数
	 * @description 该组件一般用于图标右上角显示未读的消息数量，提示用户点击，有圆点和圆包含文字两种形式。
	 * @tutorial https://www.uvui.cn/components/badge.html
	 * 
	 * @property {Boolean} 			isDot 		是否显示圆点 （默认 false ）
	 * @property {String | Number} 	value 		显示的内容
	 * @property {Boolean} 			show 		是否显示 （默认 true ）
	 * @property {String | Number} 	max 		最大值，超过最大值会显示 '{max}+'  （默认999）
	 * @property {String} 			type 		主题类型，error|warning|success|primary （默认 'error' ）
	 * @property {Boolean} 			showZero	当数值为 0 时，是否展示 Badge （默认 false ）
	 * @property {String} 			bgColor 	背景颜色，优先级比type高，如设置，type参数会失效
	 * @property {String} 			color 		字体颜色 （默认 '#ffffff' ）
	 * @property {String} 			shape 		徽标形状，circle-四角均为圆角，horn-左下角为直角 （默认 'circle' ）
	 * @property {String} 			numberType	设置数字的显示方式，overflow|ellipsis|limit  （默认 'overflow' ）
	 * @property {Array}} 			offset		设置badge的位置偏移，格式为 [x, y]，也即设置的为top和right的值，absolute为true时有效
	 * @property {Boolean} 			inverted	是否反转背景和字体颜色（默认 false ）
	 * @property {Boolean} 			absolute	是否绝对定位（默认 false ）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * @example <uv-badge :type="type" :count="count"></uv-badge>
	 */
	export default {
		name: 'uv-badge',
		mixins: [mpMixin, mixin, props],
		computed: {
			// 是否将badge中心与父组件右上角重合
			boxStyle() {
				let style = {};
				return style;
			},
			// 整个组件的样式
			badgeStyle() {
				const style = {}
				if(this.color) {
					style.color = this.color
				}
				if (this.bgColor && !this.inverted) {
					style.backgroundColor = this.bgColor
				}
				if (this.absolute) {
					style.position = 'absolute'
					// 如果有设置offset参数
					if(this.offset.length) {
						// top和right分为为offset的第一个和第二个值，如果没有第二个值，则right等于top
						const top = this.offset[0]
						const right = this.offset[1] || top
						style.top = this.$uv.addUnit(top)
						style.right = this.$uv.addUnit(right)
					}
				}
				return style
			},
			showValue() {
				switch (this.numberType) {
					case "overflow":
						return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
						break;
					case "ellipsis":
						return Number(this.value) > Number(this.max) ? "..." : this.value
						break;
					case "limit":
						return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
							Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
								1e3 * 100) / 100 + "k" : this.value
						break;
					default:
						return Number(this.value)
				}
			},
			propsType(){
				return this.type || 'error'
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-badge-primary: $uv-primary !default;
	$uv-badge-error: $uv-error !default;
	$uv-badge-success: $uv-success !default;
	$uv-badge-info: $uv-info !default;
	$uv-badge-warning: $uv-warning !default;
	$uv-badge-dot-radius: 100px !default;
	$uv-badge-dot-size: 8px !default;
	$uv-badge-dot-right: 4px !default;
	$uv-badge-dot-top: 0 !default;
	$uv-badge-text-font-size: 11px !default;
	$uv-badge-text-right: 10px !default;
	$uv-badge-text-padding: 2px 5px !default;
	$uv-badge-text-align: center !default;
	$uv-badge-text-color: #FFFFFF !default;

	.uv-badge {
		border-top-right-radius: $uv-badge-dot-radius;
		border-top-left-radius: $uv-badge-dot-radius;
		border-bottom-left-radius: $uv-badge-dot-radius;
		border-bottom-right-radius: $uv-badge-dot-radius;
		@include flex;
		line-height: $uv-badge-text-font-size;
		text-align: $uv-badge-text-align;
		font-size: $uv-badge-text-font-size;
		color: $uv-badge-text-color;

		&--dot {
			height: $uv-badge-dot-size;
			width: $uv-badge-dot-size;
		}
		
		&--inverted {
			font-size: 13px;
		}
		
		&--not-dot {
			padding: $uv-badge-text-padding;
		}

		&--horn {
			border-bottom-left-radius: 0;
		}

		&--primary {
			background-color: $uv-badge-primary;
		}
		
		&--primary--inverted {
			color: $uv-badge-primary;
		}

		&--error {
			background-color: $uv-badge-error;
		}
		
		&--error--inverted {
			color: $uv-badge-error;
		}

		&--success {
			background-color: $uv-badge-success;
		}
		
		&--success--inverted {
			color: $uv-badge-success;
		}

		&--info {
			background-color: $uv-badge-info;
		}
		
		&--info--inverted {
			color: $uv-badge-info;
		}

		&--warning {
			background-color: $uv-badge-warning;
		}
		
		&--warning--inverted {
			color: $uv-badge-warning;
		}
	}
</style>
RddxF{
	"id": "uv-badge",
	"displayName": "uv-badge 徽标数，数字角标 全面兼容小程序、nvue、vue2、vue3等多端",
	"version": "1.0.2",
	"description": "徽标数一般用于图标右上角显示未读的消息数量，提示用户点击，有圆点和圆包含文字两种形式。",
	"keywords": [
        "uv-badge",
        "uvui",
        "uv-ui",
        "徽标数",
        "数字角标"
    ],
	"repository": "",
	"engines": {
		"HBuilderX": "^3.1.0"
	},
	"dcloudext": {
		"type": "component-vue",
		"sale": {
			"regular": {
				"price": "0.00"
			},
			"sourcecode": {
				"price": "0.00"
			}
		},
		"contact": {
			"qq": ""
		},
		"declaration": {
			"ads": "无",
			"data": "插件不采集任何数据",
			"permissions": "无"
		},
		"npmurl": ""
	},
	"uni_modules": {
		"dependencies": [
			"uv-ui-tools"
		],
		"encrypt": [],
		"platforms": {
			"cloud": {
				"tcb": "y",
				"aliyun": "y"
			},
			"client": {
				"Vue": {
					"vue2": "y",
					"vue3": "y"
				},
				"App": {
					"app-vue": "y",
					"app-nvue": "y"
				},
				"H5-mobile": {
					"Safari": "y",
					"Android Browser": "y",
					"微信浏览器(Android)": "y",
					"QQ浏览器(Android)": "y"
				},
				"H5-pc": {
					"Chrome": "y",
					"IE": "y",
					"Edge": "y",
					"Firefox": "y",
					"Safari": "y"
				},
				"小程序": {
					"微信": "y",
					"阿里": "y",
					"百度": "y",
					"字节跳动": "y",
					"QQ": "y",
					"钉钉": "u",
					"快手": "u",
					"飞书": "u",
					"京东": "u"
				},
				"快应用": {
					"华为": "u",
					"联盟": "u"
				}
			}
		}
	}
}	9)xo## LoadMore 加载更多

> **组件名：uv-load-more**

此组件一般用于标识页面底部加载数据时的状态，共有三种状态：加载前、加载中、加载后。

### <a href="https://www.uvui.cn/components/loadMore.html" target="_blank">查看文档</a>

### [完整示例项目下载 | 关注更多组件](https://ext.dcloud.net.cn/plugin?name=uv-ui)

#### 如使用过程中有任何问题，或者您对uv-ui有一些好的建议，欢迎加入 uv-ui 交流群：<a href="https://ext.dcloud.net.cn/plugin?id=12287" target="_blank">uv-ui</a>、<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
P
x Q## ReadMore 展开阅读更多 

> **组件名：uv-read-more**

该组件一般用于内容较长，预先收起一部分，击展开全部内容的场景1reghS	=x h## Badge 徽标数badg<h标右上角显示未读的消息数量，提示用户点击，有圆点和圆包含文字两种形式1badg֦:?]-	x e100644 changelog.md T4񿊖VG;؀?40000 components FR
';3U100644 package.json ¤|Rt#nv100644 readme.md JGDfr%+w/)}?Hxt## 1.0.15（2023-12-20）
1. 优化
## 1.0.14（2023-12-06）
1. 优化
## 1.0.13（2023-12-06）
1. 阻止事件冒泡处理
## 1.0.12（2023-10-19）
1. 增加后置插槽
## 1.0.11（2023-09-21）
1. 修复通过customStyle修改按钮宽度，组件中最外层节点不改变的问题
## 1.0.10（2023-09-15）
1. 按钮支持open-type="agreePrivacyAuthorization"
## 1.0.9（2023-09-11）
1. 增加参数iconSize，用于控制图标的大小
## 1.0.8（2023-09-10）
1. 修复多个按钮在一行宽度不正常的BUG
## 1.0.7（2023-09-07）
1. 修复warning颜色对应错误的BUG
## 1.0.6（2023-07-25）
1. 增加customTextStyle属性，方便自定义文字样式
## 1.0.5（2023-07-20）
1. 解决微信小程序动态设置hover-class点击态不消失的BUG
## 1.0.4（2023-06-29）
1. 修改上次更新出现nvue报错异常
## 1.0.3（2023-06-28）
 修复：设置open-type="chooseAvatar"等值不生效的BUG
## 1.0.2（2023-06-01）
1. 修复按钮点击触发两次的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-button 按钮
;GǤx$ 40000 uv-button &=ΦJ%ger3s]	x i100644 nvue.scss l(R?hF&100644 props.js buVŸQ(1#K=R100644 uv-button.vue :$p`| Y` !{u3100644 vue.scss zLA55"Gg:Bx#$uv-button-active-opacity:0.75 !default;
$uv-button-loading-text-margin-left:4px !default;
$uv-button-text-color: #FFFFFF !default;
$uv-button-text-plain-error-color:$uv-error !default;
$uv-button-text-plain-warning-color:$uv-warning !default;
$uv-button-text-plain-success-color:$uv-success !default;
$uv-button-text-plain-info-color:$uv-info !default;
$uv-button-text-plain-primary-color:$uv-primary !default;
.uv-button {
	&--active {
		opacity: $uv-button-active-opacity;
	}
	
	&--active--plain {
		background-color: rgb(217, 217, 217);
	}
	
	&__loading-text {
		margin-left:$uv-button-loading-text-margin-left;
	}
	
	&__text,
	&__loading-text {
		color:$uv-button-text-color;
	}
	
	&__text--plain--error {
		color:$uv-button-text-plain-error-color;
	}
	
	&__text--plain--warning {
		color:$uv-button-text-plain-warning-color;
	}
	
	&__text--plain--success{
		color:$uv-button-text-plain-success-color;
	}
	
	&__text--plain--info {
		color:$uv-button-text-plain-info-color;
	}
	
	&__text--plain--primary {
		color:$uv-button-text-plain-primary-color;
	}
}Igxkexport default {
	props: {
		// 是否细边框
		hairline: {
			type: Boolean,
			default: true
		},
		// 按钮的预置样式，info，primary，error，warning，success
		type: {
			type: String,
			default: 'info'
		},
		// 按钮尺寸，large，normal，small，mini
		size: {
			type: String,
			default: 'normal'
		},
		// 按钮形状，circle（两边为半圆），square（带圆角）
		shape: {
			type: String,
			default: 'square'
		},
		// 按钮是否镂空
		plain: {
			type: Boolean,
			default: false
		},
		// 是否禁止状态
		disabled: {
			type: Boolean,
			default: false
		},
		// 是否加载中
		loading: {
			type: Boolean,
			default: false
		},
		// 加载中提示文字
		loadingText: {
			type: [String, Number],
			default: ''
		},
		// 加载状态图标类型
		loadingMode: {
			type: String,
			default: 'spinner'
		},
		// 加载图标大小
		loadingSize: {
			type: [String, Number],
			default: 14
		},
		// 开放能力，具体请看uniapp稳定关于button组件部分说明
		// https://uniapp.dcloud.io/component/button
		openType: {
			type: String,
			default: ''
		},
		// 用于 <form> 组件，点击分别会触发 <form> 组件的 submit/reset 事件
		// 取值为submit（提交表单），reset（重置表单）
		formType: {
			type: String,
			default: ''
		},
		// 打开 APP 时，向 APP 传递的参数，open-type=launchApp时有效
		// 只微信小程序、QQ小程序有效
		appParameter: {
			type: String,
			default: ''
		},
		// 指定是否阻止本节点的祖先节点出现点击态，微信小程序有效
		hoverStopPropagation: {
			type: Boolean,
			default: true
		},
		// 指定返回用户信息的语言，zh_CN 简体中文，zh_TW 繁体中文，en 英文。只微信小程序有效
		lang: {
			type: String,
			default: 'en'
		},
		// 会话来源，open-type="contact"时有效。只微信小程序有效
		sessionFrom: {
			type: String,
			default: ''
		},
		// 会话内消息卡片标题，open-type="contact"时有效
		// 默认当前标题，只微信小程序有效
		sendMessageTitle: {
			type: String,
			default: ''
		},
		// 会话内消息卡片点击跳转小程序路径，open-type="contact"时有效
		// 默认当前分享路径，只微信小程序有效
		sendMessagePath: {
			type: String,
			default: ''
		},
		// 会话内消息卡片图片，open-type="contact"时有效
		// 默认当前页面截图，只微信小程序有效
		sendMessageImg: {
			type: String,
			default: ''
		},
		// 是否显示会话内消息卡片，设置此参数为 true，用户进入客服会话会在右下角显示"可能要发送的小程序"提示，
		// 用户点击后可以快速发送小程序消息，open-type="contact"时有效
		showMessageCard: {
			type: Boolean,
			default: true
		},
		// 额外传参参数，用于小程序的data-xxx属性，通过target.dataset.name获取
		dataName: {
			type: String,
			default: ''
		},
		// 节流，一定时间内只能触发一次
		throttleTime: {
			type: [String, Number],
			default: 0
		},
		// 按住后多久出现点击态，单位毫秒
		hoverStartTime: {
			type: [String, Number],
			default: 0
		},
		// 手指松开后点击态保留时间，单位毫秒
		hoverStayTime: {
			type: [String, Number],
			default: 200
		},
		// 按钮文字，之所以通过props传入，是因为slot传入的话
		// nvue中无法控制文字的样式
		text: {
			type: [String, Number],
			default: ''
		},
		// 按钮图标
		icon: {
			type: String,
			default: ''
		},
		// 按钮图标大小
		iconSize: {
			type: [String, Number],
			default: ''
		},
		// 按钮图标颜色
		iconColor: {
			type: String,
			default: '#000000'
		},
		// 按钮颜色，支持传入linear-gradient渐变色
		color: {
			type: String,
			default: ''
		},
		// 自定义按钮文本样式
		customTextStyle: {
			type: [Object,String],
			default: ''
		},
		...uni.$uv?.props?.button
	}
}
	xGM<template>
	<view 
		class="uv-button-wrapper"
		:style="[btnWrapperStyle]"
	>
    <!-- #ifndef APP-NVUE -->
		<!-- #ifdef MP -->
		<!-- 为了解决微信小程序动态设置hover-class点击态不消失的BUG -->
		<view class="uv-button-wrapper--dis" v-if="disabled || loading"></view>
		<button
		  :hover-start-time="Number(hoverStartTime)"
		  :hover-stay-time="Number(hoverStayTime)"
		  :form-type="formType"
		  :open-type="openType"
		  :app-parameter="appParameter"
		  :hover-stop-propagation="hoverStopPropagation"
		  :send-message-title="sendMessageTitle"
		  :send-message-path="sendMessagePath"
		  :lang="lang"
		  :data-name="dataName"
		  :session-from="sessionFrom"
		  :send-message-img="sendMessageImg"
		  :show-message-card="showMessageCard"
		  @getphonenumber="onGetPhoneNumber"
		  @getuserinfo="onGetUserInfo"
		  @error="onError"
		  @opensetting="onOpenSetting"
		  @launchapp="onLaunchApp"
			@contact="onContact"
			@chooseavatar="onChooseavatar"
			@agreeprivacyauthorization="onAgreeprivacyauthorization"
			@addgroupapp="onAddgroupapp"
			@chooseaddress="onChooseaddress"
			@subscribe="onSubscribe"
			@login="onLogin"
			@im="onIm"
		  hover-class="uv-button--active"
		  class="uv-button uv-reset-button"
		  :style="[baseColor, $uv.addStyle(customStyle)]"
		  @tap="clickHandler"
		  :class="bemClass"
		>
		<!-- #endif -->
    <!-- #ifndef MP -->
    <button
      :hover-start-time="Number(hoverStartTime)"
      :hover-stay-time="Number(hoverStayTime)"
      :form-type="formType"
      :open-type="openType"
      :app-parameter="appParameter"
      :hover-stop-propagation="hoverStopPropagation"
      :send-message-title="sendMessageTitle"
      :send-message-path="sendMessagePath"
      :lang="lang"
      :data-name="dataName"
      :session-from="sessionFrom"
      :send-message-img="sendMessageImg"
      :show-message-card="showMessageCard"
      :hover-class="!disabled && !loading ? 'uv-button--active' : ''"
      class="uv-button uv-reset-button"
      :style="[baseColor, $uv.addStyle(customStyle)]"
      @tap="clickHandler"
      :class="bemClass"
    >
    <!-- #endif -->
      <template v-if="loading">
        <uv-loading-icon
          :mode="loadingMode"
          :size="loadingSize * 1.15"
          :color="loadingColor"
        ></uv-loading-icon>
          <text
            class="uv-button__loading-text"
            :style="[
							{ fontSize: textSize + 'px' },
							$uv.addStyle(customTextStyle)
						]"
          >{{ loadingText || text }}</text>
      </template>
      <template v-else>
        <uv-icon
          v-if="icon"
          :name="icon"
          :color="iconColorCom"
          :size="getIconSize"
          :customStyle="{ marginRight: '2px' }"
        ></uv-icon>
        <slot>
          <text
            class="uv-button__text"
            :style="[
							{ fontSize: textSize + 'px' },
							$uv.addStyle(customTextStyle)
						]"
            >{{ text }}</text>
        </slot>
				<slot name="suffix"></slot>
      </template>
    </button>
    <!-- #endif -->
    <!-- #ifdef APP-NVUE -->
    <view
      :hover-start-time="Number(hoverStartTime)"
      :hover-stay-time="Number(hoverStayTime)"
      class="uv-button"
      :hover-class="
        !disabled && !loading && !color && (plain || type === 'info')
          ? 'uv-button--active--plain'
          : !disabled && !loading && !plain
          ? 'uv-button--active'
          : ''
      "
      @tap="clickHandler"
      :class="bemClass"
      :style="[baseColor, $uv.addStyle(customStyle)]"
    >
      <template v-if="loading">
        <uv-loading-icon
          :mode="loadingMode"
          :size="loadingSize * 1.15"
          :color="loadingColor"
        ></uv-loading-icon>
        <text
          class="uv-button__loading-text"
          :style="[nvueTextStyle,$uv.addStyle(customTextStyle)]"
          :class="[plain && `uv-button__text--plain--${type}`]"
          >{{ loadingText || text }}</text>
      </template>
      <template v-else>
        <uv-icon
          v-if="icon"
          :name="icon"
          :color="iconColorCom"
          :size="getIconSize"
        ></uv-icon>
        <text
          class="uv-button__text"
          :style="[
            {
              marginLeft: icon ? '2px' : 0,
            },
            nvueTextStyle,
						$uv.addStyle(customTextStyle)
          ]"
          :class="[plain && `uv-button__text--plain--${type}`]"
          >{{ text }}</text>
				<slot name="suffix"></slot>
      </template>
    </view>
    <!-- #endif -->
	</view>
</template>

<script>
import throttle from '@/uni_modules/uv-ui-tools/libs/function/throttle.js';
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import button from '@/uni_modules/uv-ui-tools/libs/mixin/button.js'
import openType from '@/uni_modules/uv-ui-tools/libs/mixin/openType.js'
import props from "./props.js";
/**
 * button 按钮
 * @description Button 按钮
 * @tutorial https://www.uvui.cn/components/button.html
 * @property {Boolean}			hairline				是否显示按钮的细边框 (默认 true )
 * @property {String}			type					按钮的预置样式，info，primary，error，warning，success (默认 'info' )
 * @property {String}			size					按钮尺寸，large，normal，mini （默认 normal）
 * @property {String}			shape					按钮形状，circle（两边为半圆），square（带圆角） （默认 'square' ）
 * @property {Boolean}			plain					按钮是否镂空，背景色透明 （默认 false）
 * @property {Boolean}			disabled				是否禁用 （默认 false）
 * @property {Boolean}			loading					按钮名称前是否带 loading 图标(App-nvue 平台，在 ios 上为雪花，Android上为圆圈) （默认 false）
 * @property {String | Number}	loadingText				加载中提示文字
 * @property {String}			loadingMode				加载状态图标类型 （默认 'spinner' ）
 * @property {String | Number}	loadingSize				加载图标大小 （默认 15 ）
 * @property {String}			openType				开放能力，具体请看uniapp稳定关于button组件部分说明
 * @property {String}			formType				用于 <form> 组件，点击分别会触发 <form> 组件的 submit/reset 事件
 * @property {String}			appParameter			打开 APP 时，向 APP 传递的参数，open-type=launchApp时有效 （注：只微信小程序、QQ小程序有效）
 * @property {Boolean}			hoverStopPropagation	指定是否阻止本节点的祖先节点出现点击态，微信小程序有效（默认 true ）
 * @property {String}			lang					指定返回用户信息的语言，zh_CN 简体中文，zh_TW 繁体中文，en 英文（默认 en ）
 * @property {String}			sessionFrom				会话来源，openType="contact"时有效
 * @property {String}			sendMessageTitle		会话内消息卡片标题，openType="contact"时有效
 * @property {String}			sendMessagePath			会话内消息卡片点击跳转小程序路径，openType="contact"时有效
 * @property {String}			sendMessageImg			会话内消息卡片图片，openType="contact"时有效
 * @property {Boolean}			showMessageCard			是否显示会话内消息卡片，设置此参数为 true，用户进入客服会话会在右下角显示"可能要发送的小程序"提示，用户点击后可以快速发送小程序消息，openType="contact"时有效（默认false）
 * @property {String}			dataName				额外传参参数，用于小程序的data-xxx属性，通过target.dataset.name获取
 * @property {String | Number}	throttleTime			节流，一定时间内只能触发一次 （默认 0 )
 * @property {String | Number}	hoverStartTime			按住后多久出现点击态，单位毫秒 （默认 0 )
 * @property {String | Number}	hoverStayTime			手指松开后点击态保留时间，单位毫秒 （默认 200 )
 * @property {String | Number}	text					按钮文字，之所以通过props传入，是因为slot传入的话（注：nvue中无法控制文字的样式）
 * @property {String}			icon					按钮图标
 * @property {String}			iconColor				按钮图标颜色
 * @property {String}			color					按钮颜色，支持传入linear-gradient渐变色
 * @property {Object}			customStyle				定义需要用到的外部样式
 * @event {Function}	click			非禁止并且非加载中，才能点击
 * @event {Function}	getphonenumber	open-type="getPhoneNumber"时有效
 * @event {Function}	getuserinfo		用户点击该按钮时，会返回获取到的用户信息，从返回参数的detail中获取到的值同uni.getUserInfo
 * @event {Function}	error			当使用开放能力时，发生错误的回调
 * @event {Function}	opensetting		在打开授权设置页并关闭后回调
 * @event {Function}	launchapp		打开 APP 成功的回调
 * @example <uv-button>月落</uv-button>
 */
export default {
		name: "uv-button",
		// #ifdef MP
		mixins: [mpMixin, mixin, button, openType, props],
		// #endif
		// #ifndef MP
		mixins: [mpMixin, mixin, props],
		// #endif
		emits: ['click'],
		data() {
			return {};
		},
		computed: {
			// 生成bem风格的类名
			bemClass() {
				// this.bem为一个computed变量，在mixin中
				if (!this.color) {
					return this.bem("button",
						["type", "shape", "size"],
						["disabled", "plain", "hairline"]);
				} else {
					// 由于nvue的原因，在有color参数时，不需要传入type，否则会生成type相关的类型，影响最终的样式
					return this.bem("button",
						["shape", "size"],
						["disabled", "plain", "hairline"]);
				}
			},
			loadingColor() {
				if (this.plain) {
					// 如果有设置color值，则用color值，否则使用type主题颜色
					return this.color ? this.color : '#3c9cff';
				}
				if (this.type === "info") {
					return "#c9c9c9";
				}
				return "rgb(200, 200, 200)";
			},
			iconColorCom() {
				// 如果是镂空状态，设置了color就用color值，否则使用主题颜色，
				// uv-icon的color能接受一个主题颜色的值
				if (this.iconColor) return this.iconColor;
				if (this.plain) {
					return this.color ? this.color : this.type;
				} else {
					return this.type === "info" ? "#000000" : "#ffffff";
				}
			},
			baseColor() {
				let style = {};
				if (this.color) {
					// 针对自定义了color颜色的情况，镂空状态下，就是用自定义的颜色
					style.color = this.plain ? this.color : "white";
					if (!this.plain) {
						// 非镂空，背景色使用自定义的颜色
						style["background-color"] = this.color;
					}
					if (this.color.indexOf("gradient") !== -1) {
						// 如果自定义的颜色为渐变色，不显示边框，以及通过backgroundImage设置渐变色
						// weex文档说明可以写borderWidth的形式，为什么这里需要分开写？
						// 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西，所以需要这么写才有效
						style.borderTopWidth = 0;
						style.borderRightWidth = 0;
						style.borderBottomWidth = 0;
						style.borderLeftWidth = 0;
						if (!this.plain) {
							style.backgroundImage = this.color;
						}
					} else {
						// 非渐变色，则设置边框相关的属性
						style.borderColor = this.color;
						style.borderWidth = "1px";
						style.borderStyle = "solid";
					}
				}
				return style;
			},
			// nvue版本按钮的字体不会继承父组件的颜色，需要对每一个text组件进行单独的设置
			nvueTextStyle() {
				let style = {};
				// 针对自定义了color颜色的情况，镂空状态下，就是用自定义的颜色
				if (this.type === "info") {
					style.color = "#323233";
				}
				if (this.color) {
					style.color = this.plain ? this.color : "white";
				}
				style.fontSize = this.textSize + "px";
				return style;
			},
			// 字体大小
			textSize() {
				let fontSize = 14,
					{ size } = this;
				if (size === "large") fontSize = 16;
				if (size === "normal") fontSize = 14;
				if (size === "small") fontSize = 12;
				if (size === "mini") fontSize = 10;
				return fontSize;
			},
			// 设置图标大小
			getIconSize() {
				const size = this.iconSize ? this.iconSize : this.textSize * 1.35;
				return this.$uv.addUnit(size);
			},
			// 设置外层盒子的宽度，其他样式不需要
			btnWrapperStyle() {
				const style = {};
				const customStyle = this.$uv.addStyle(this.customStyle);
				if(customStyle.width) style.width = customStyle.width;
				return style;
			}
		},
		methods: {
			clickHandler() {
				// 非禁止并且非加载中，才能点击
				if (!this.disabled && !this.loading) {
					// 进行节流控制，每this.throttle毫秒内，只在开始处执行
					throttle(() => {
						this.$emit("click");
					}, this.throttleTime);
				}
			}
		}
	}
</script>

<style lang="scss" scoped>
$show-reset-button: 1;
@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';

/* #ifndef APP-NVUE */
@import "./vue.scss";
/* #endif */

/* #ifdef APP-NVUE */
@import "./nvue.scss";
/* #endif */

$uv-button-uv-button-height: 40px !default;
$uv-button-text-font-size: 15px !default;
$uv-button-loading-text-font-size: 15px !default;
$uv-button-loading-text-margin-left: 4px !default;
$uv-button-large-width: 100% !default;
$uv-button-large-height: 50px !default;
$uv-button-normal-padding: 0 12px !default;
$uv-button-large-padding: 0 15px !default;
$uv-button-normal-font-size: 14px !default;
$uv-button-small-min-width: 60px !default;
$uv-button-small-height: 30px !default;
$uv-button-small-padding: 0px 8px !default;
$uv-button-mini-padding: 0px 8px !default;
$uv-button-small-font-size: 12px !default;
$uv-button-mini-height: 22px !default;
$uv-button-mini-font-size: 10px !default;
$uv-button-mini-min-width: 50px !default;
$uv-button-disabled-opacity: 0.5 !default;
$uv-button-info-color: #323233 !default;
$uv-button-info-background-color: #fff !default;
$uv-button-info-border-color: #ebedf0 !default;
$uv-button-info-border-width: 1px !default;
$uv-button-info-border-style: solid !default;
$uv-button-success-color: #fff !default;
$uv-button-success-background-color: $uv-success !default;
$uv-button-success-border-color: $uv-button-success-background-color !default;
$uv-button-success-border-width: 1px !default;
$uv-button-success-border-style: solid !default;
$uv-button-primary-color: #fff !default;
$uv-button-primary-background-color: $uv-primary !default;
$uv-button-primary-border-color: $uv-button-primary-background-color !default;
$uv-button-primary-border-width: 1px !default;
$uv-button-primary-border-style: solid !default;
$uv-button-error-color: #fff !default;
$uv-button-error-background-color: $uv-error !default;
$uv-button-error-border-color: $uv-button-error-background-color !default;
$uv-button-error-border-width: 1px !default;
$uv-button-error-border-style: solid !default;
$uv-button-warning-color: #fff !default;
$uv-button-warning-background-color: $uv-warning !default;
$uv-button-warning-border-color: $uv-button-warning-background-color !default;
$uv-button-warning-border-width: 1px !default;
$uv-button-warning-border-style: solid !default;
$uv-button-block-width: 100% !default;
$uv-button-circle-border-top-right-radius: 100px !default;
$uv-button-circle-border-top-left-radius: 100px !default;
$uv-button-circle-border-bottom-left-radius: 100px !default;
$uv-button-circle-border-bottom-right-radius: 100px !default;
$uv-button-square-border-top-right-radius: 3px !default;
$uv-button-square-border-top-left-radius: 3px !default;
$uv-button-square-border-bottom-left-radius: 3px !default;
$uv-button-square-border-bottom-right-radius: 3px !default;
$uv-button-icon-min-width: 1em !default;
$uv-button-plain-background-color: #fff !default;
$uv-button-hairline-border-width: 0.5px !default;

.uv-button {
    height: $uv-button-uv-button-height;
    position: relative;
    align-items: center;
    justify-content: center;
    @include flex;
    /* #ifndef APP-NVUE */
    box-sizing: border-box;
    /* #endif */
    flex-direction: row;

    &__text {
        font-size: $uv-button-text-font-size;
    }

    &__loading-text {
        font-size: $uv-button-loading-text-font-size;
        margin-left: $uv-button-loading-text-margin-left;
    }

    &--large {
        /* #ifndef APP-NVUE */
        width: $uv-button-large-width;
        /* #endif */
        height: $uv-button-large-height;
        padding: $uv-button-large-padding;
    }

    &--normal {
        padding: $uv-button-normal-padding;
        font-size: $uv-button-normal-font-size;
    }

    &--small {
        /* #ifndef APP-NVUE */
        min-width: $uv-button-small-min-width;
        /* #endif */
        height: $uv-button-small-height;
        padding: $uv-button-small-padding;
        font-size: $uv-button-small-font-size;
    }

    &--mini {
        height: $uv-button-mini-height;
        font-size: $uv-button-mini-font-size;
        /* #ifndef APP-NVUE */
        min-width: $uv-button-mini-min-width;
        /* #endif */
        padding: $uv-button-mini-padding;
    }

    &--disabled {
        opacity: $uv-button-disabled-opacity;
    }

    &--info {
        color: $uv-button-info-color;
        background-color: $uv-button-info-background-color;
        border-color: $uv-button-info-border-color;
        border-width: $uv-button-info-border-width;
        border-style: $uv-button-info-border-style;
    }

    &--success {
        color: $uv-button-success-color;
        background-color: $uv-button-success-background-color;
        border-color: $uv-button-success-border-color;
        border-width: $uv-button-success-border-width;
        border-style: $uv-button-success-border-style;
    }

    &--primary {
        color: $uv-button-primary-color;
        background-color: $uv-button-primary-background-color;
        border-color: $uv-button-primary-border-color;
        border-width: $uv-button-primary-border-width;
        border-style: $uv-button-primary-border-style;
    }

    &--error {
        color: $uv-button-error-color;
        background-color: $uv-button-error-background-color;
        border-color: $uv-button-error-border-color;
        border-width: $uv-button-error-border-width;
        border-style: $uv-button-error-border-style;
    }

    &--warning {
        color: $uv-button-warning-color;
        background-color: $uv-button-warning-background-color;
        border-color: $uv-button-warning-border-color;
        border-width: $uv-button-warning-border-width;
        border-style: $uv-button-warning-border-style;
    }

    &--block {
        @include flex;
        width: $uv-button-block-width;
    }

    &--circle {
        border-top-right-radius: $uv-button-circle-border-top-right-radius;
        border-top-left-radius: $uv-button-circle-border-top-left-radius;
        border-bottom-left-radius: $uv-button-circle-border-bottom-left-radius;
        border-bottom-right-radius: $uv-button-circle-border-bottom-right-radius;
    }

    &--square {
        border-bottom-left-radius: $uv-button-square-border-top-right-radius;
        border-bottom-right-radius: $uv-button-square-border-top-left-radius;
        border-top-left-radius: $uv-button-square-border-bottom-left-radius;
        border-top-right-radius: $uv-button-square-border-bottom-right-radius;
    }

    &__icon {
        /* #ifndef APP-NVUE */
        min-width: $uv-button-icon-min-width;
        line-height: inherit !important;
        vertical-align: top;
        /* #endif */
    }

    &--plain {
        background-color: $uv-button-plain-background-color;
    }

    &--hairline {
        border-width: $uv-button-hairline-border-width !important;
    }
}
</style>
4zx[@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
// nvue下hover-class无效
$uv-button-before-top:50% !default;
$uv-button-before-left:50% !default;
$uv-button-before-width:100% !default;
$uv-button-before-height:100% !default;
$uv-button-before-transform:translate(-50%, -50%) !default;
$uv-button-before-opacity:0 !default;
$uv-button-before-background-color:#000 !default;
$uv-button-before-border-color:#000 !default;
$uv-button-active-before-opacity:.15 !default;
$uv-button-icon-margin-left:4px !default;
$uv-button-plain-uv-button-info-color:$uv-info;
$uv-button-plain-uv-button-success-color:$uv-success;
$uv-button-plain-uv-button-error-color:$uv-error;
$uv-button-plain-uv-button-warning-color:$uv-warning;

.uv-button-wrapper {
	position: relative;
	&--dis {
		position: absolute;
		left: 0;
		top: 0;
		right: 0;
		bottom: 0;
		z-index: 9;
	}
}

.uv-button {
	width: 100%;
	
	&__text {
		white-space: nowrap;
		line-height: 1;
	}
	
	&:before {
		position: absolute;
		top:$uv-button-before-top;
		left:$uv-button-before-left;
		width:$uv-button-before-width;
		height:$uv-button-before-height;
		border: inherit;
		border-radius: inherit;
		transform:$uv-button-before-transform;
		opacity:$uv-button-before-opacity;
		content: " ";
		background-color:$uv-button-before-background-color;
		border-color:$uv-button-before-border-color;
	}
	
	&--active {
		&:before {
			opacity: .15
		}
	}
	
	&__icon+&__text:not(:empty),
	&__loading-text {
		margin-left:$uv-button-icon-margin-left;
	}
	
	&--plain {
		&.uv-button--primary {
			color: $uv-primary;
		}
	}
	
	&--plain {
		&.uv-button--info {
			color:$uv-button-plain-uv-button-info-color;
		}
	}
	
	&--plain {
		&.uv-button--success {
			color:$uv-button-plain-uv-button-success-color;
		}
	}
	
	&--plain {
		&.uv-button--error {
			color:$uv-button-plain-uv-button-error-color;
		}
	}
	
	&--plain {
		&.uv-button--warning {
			color:$uv-button-plain-uv-button-warning-color;
		}
	}
}
[ˈE	x e100644 changelog.md Xbg\ZGZ	ńk40000 components q6Hو#100644 package.json ؁ [5$c_HfWC<100644 readme.md <-D22"Z+`8e.x## 1.0.6（2023-11-03）
1. **该版本不再维护**，推荐使用新版本[https://ext.dcloud.net.cn/plugin?name=uv-calendars](https://ext.dcloud.net.cn/plugin?name=uv-calendars)
## 1.0.5（2023-07-02）
uv-calendar  由于弹出层uv-popup的修改，打开和关闭方法更改，详情参考文档：https://www.uvui.cn/components/calendar.html
## 1.0.4（2023-06-15）
1. formatter格式化中增加topInfo参数
## 1.0.3（2023-06-08）
1. 增加点击日期change回调
2. 优化
## 1.0.2（2023-06-05）
1. 修改多个时间选择的时候存在反选的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-calendar 日历
{o)x& 40000 uv-calendar <ﺭ];(x >100644 calendar.js ޥv+0,=!v100644 header.vue ڧ*_p&\48H100644 month.vue dӂ{Jy{100644 props.js Y)<% u4:>a100644 uv-calendar.vue bn7#Pu'U54*WKVxa/**
* @1900-2100区间内的公历、农历互转
* @charset UTF-8
* @github  https://github.com/jjonline/calendar.js
* @Author  Jea杨(JJonline@JJonline.Cn)
* @Time    2014-7-21
* @Time    2016-8-13 Fixed 2033hex、Attribution Annals
* @Time    2016-9-25 Fixed lunar LeapMonth Param Bug
* @Time    2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
* @Version 1.0.3
* @公历转农历：calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
* @农历转公历：calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
*/
/* eslint-disable */
var calendar = {

  /**
      * 农历1900-2100的润大小信息表
      * @Array Of Property
      * @return Hex
      */
  lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
    0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
    0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
    0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
    0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
    0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
    0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
    0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
    0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
    0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
    0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
    0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
    0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
    0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
    0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
    /** Add By JJonline@JJonline.Cn**/
    0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
    0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
    0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
    0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
    0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
    0x0d520], // 2100

  /**
      * 公历每个月份的天数普通表
      * @Array Of Property
      * @return Number
      */
  solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],

  /**
      * 天干地支之天干速查表
      * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
      * @return Cn string
      */
  Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],

  /**
      * 天干地支之地支速查表
      * @Array Of Property
      * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
      * @return Cn string
      */
  Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],

  /**
      * 天干地支之地支速查表<=>生肖
      * @Array Of Property
      * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
      * @return Cn string
      */
  Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],

  /**
      * 24节气速查表
      * @Array Of Property
      * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
      * @return Cn string
      */
  solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],

  /**
      * 1900-2100各年的24节气日期速查表
      * @Array Of Property
      * @return 0x string For splice
      */
  sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
    '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
    'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
    '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
    '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
    '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
    '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
    '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
    '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
    '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
    '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
    '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
    '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
    '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
    '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
    '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
    '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
    '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
    '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
    '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
    '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
    '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
    '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
    '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
    '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],

  /**
      * 数字转中文速查表
      * @Array Of Property
      * @trans ['日','一','二','三','四','五','六','七','八','九','十']
      * @return Cn string
      */
  nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],

  /**
      * 日期转农历称呼速查表
      * @Array Of Property
      * @trans ['初','十','廿','卅']
      * @return Cn string
      */
  nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],

  /**
      * 月份转农历称呼速查表
      * @Array Of Property
      * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
      * @return Cn string
      */
  nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],

  /**
      * 返回农历y年一整年的总天数
      * @param lunar Year
      * @return Number
      * @eg:var count = calendar.lYearDays(1987) ;//count=387
      */
  lYearDays: function (y) {
    var i; var sum = 348
    for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
    return (sum + this.leapDays(y))
  },

  /**
      * 返回农历y年闰月是哪个月；若y年没有闰月 则返回0
      * @param lunar Year
      * @return Number (0-12)
      * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
      */
  leapMonth: function (y) { // 闰字编码 \u95f0
    return (this.lunarInfo[y - 1900] & 0xf)
  },

  /**
      * 返回农历y年闰月的天数 若该年没有闰月则返回0
      * @param lunar Year
      * @return Number (0、29、30)
      * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
      */
  leapDays: function (y) {
    if (this.leapMonth(y)) {
      return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
    }
    return (0)
  },

  /**
      * 返回农历y年m月（非闰月）的总天数，计算m为闰月时的天数请使用leapDays方法
      * @param lunar Year
      * @return Number (-1、29、30)
      * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
      */
  monthDays: function (y, m) {
    if (m > 12 || m < 1) { return -1 }// 月份参数从1至12，参数错误返回-1
    return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
  },

  /**
      * 返回公历(!)y年m月的天数
      * @param solar Year
      * @return Number (-1、28、29、30、31)
      * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
      */
  solarDays: function (y, m) {
    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
    var ms = m - 1
    if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
      return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
    } else {
      return (this.solarMonth[ms])
    }
  },

  /**
     * 农历年份转换为干支纪年
     * @param  lYear 农历年的年份数
     * @return Cn string
     */
  toGanZhiYear: function (lYear) {
    var ganKey = (lYear - 3) % 10
    var zhiKey = (lYear - 3) % 12
    if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
    if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
    return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
  },

  /**
     * 公历月、日判断所属星座
     * @param  cMonth [description]
     * @param  cDay [description]
     * @return Cn string
     */
  toAstro: function (cMonth, cDay) {
    var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
    var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
    return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
  },

  /**
      * 传入offset偏移量返回干支
      * @param offset 相对甲子的偏移量
      * @return Cn string
      */
  toGanZhi: function (offset) {
    return this.Gan[offset % 10] + this.Zhi[offset % 12]
  },

  /**
      * 传入公历(!)y年获得该年第n个节气的公历日期
      * @param y公历年(1900-2100)；n二十四节气中的第几个节气(1~24)；从n=1(小寒)算起
      * @return day Number
      * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
      */
  getTerm: function (y, n) {
    if (y < 1900 || y > 2100) { return -1 }
    if (n < 1 || n > 24) { return -1 }
    var _table = this.sTermInfo[y - 1900]
    var _info = [
      parseInt('0x' + _table.substr(0, 5)).toString(),
      parseInt('0x' + _table.substr(5, 5)).toString(),
      parseInt('0x' + _table.substr(10, 5)).toString(),
      parseInt('0x' + _table.substr(15, 5)).toString(),
      parseInt('0x' + _table.substr(20, 5)).toString(),
      parseInt('0x' + _table.substr(25, 5)).toString()
    ]
    var _calday = [
      _info[0].substr(0, 1),
      _info[0].substr(1, 2),
      _info[0].substr(3, 1),
      _info[0].substr(4, 2),

      _info[1].substr(0, 1),
      _info[1].substr(1, 2),
      _info[1].substr(3, 1),
      _info[1].substr(4, 2),

      _info[2].substr(0, 1),
      _info[2].substr(1, 2),
      _info[2].substr(3, 1),
      _info[2].substr(4, 2),

      _info[3].substr(0, 1),
      _info[3].substr(1, 2),
      _info[3].substr(3, 1),
      _info[3].substr(4, 2),

      _info[4].substr(0, 1),
      _info[4].substr(1, 2),
      _info[4].substr(3, 1),
      _info[4].substr(4, 2),

      _info[5].substr(0, 1),
      _info[5].substr(1, 2),
      _info[5].substr(3, 1),
      _info[5].substr(4, 2)
    ]
    return parseInt(_calday[n - 1])
  },

  /**
      * 传入农历数字月份返回汉语通俗表示法
      * @param lunar month
      * @return Cn string
      * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
      */
  toChinaMonth: function (m) { // 月 => \u6708
    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
    var s = this.nStr3[m - 1]
    s += '\u6708'// 加上月字
    return s
  },

  /**
      * 传入农历日期数字返回汉字表示法
      * @param lunar day
      * @return Cn string
      * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
      */
  toChinaDay: function (d) { // 日 => \u65e5
    var s
    switch (d) {
      case 10:
        s = '\u521d\u5341'; break
      case 20:
        s = '\u4e8c\u5341'; break
        break
      case 30:
        s = '\u4e09\u5341'; break
        break
      default :
        s = this.nStr2[Math.floor(d / 10)]
        s += this.nStr1[d % 10]
    }
    return (s)
  },

  /**
      * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
      * @param y year
      * @return Cn string
      * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
      */
  getAnimal: function (y) {
    return this.Animals[(y - 4) % 12]
  },

  /**
      * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
      * @param y  solar year
      * @param m  solar month
      * @param d  solar day
      * @return JSON object
      * @eg:console.log(calendar.solar2lunar(1987,11,01));
      */
  solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
    // 年份限定、上限
    if (y < 1900 || y > 2100) {
      return -1// undefined转换为数字变为NaN
    }
    // 公历传参最下限
    if (y == 1900 && m == 1 && d < 31) {
      return -1
    }
    // 未传参  获得当天
    if (!y) {
      var objDate = new Date()
    } else {
      var objDate = new Date(y, parseInt(m) - 1, d)
    }
    var i; var leap = 0; var temp = 0
    // 修正ymd参数
    var y = objDate.getFullYear()
    var m = objDate.getMonth() + 1
    var d = objDate.getDate()
    var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
    for (i = 1900; i < 2101 && offset > 0; i++) {
      temp = this.lYearDays(i)
      offset -= temp
    }
    if (offset < 0) {
      offset += temp; i--
    }

    // 是否今天
    var isTodayObj = new Date()
    var isToday = false
    if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
      isToday = true
    }
    // 星期几
    var nWeek = objDate.getDay()
    var cWeek = this.nStr1[nWeek]
    // 数字表示周几顺应天朝周一开始的惯例
    if (nWeek == 0) {
      nWeek = 7
    }
    // 农历年
    var year = i
    var leap = this.leapMonth(i) // 闰哪个月
    var isLeap = false

    // 效验闰月
    for (i = 1; i < 13 && offset > 0; i++) {
      // 闰月
      if (leap > 0 && i == (leap + 1) && isLeap == false) {
        --i
        isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
      } else {
        temp = this.monthDays(year, i)// 计算农历普通月天数
      }
      // 解除闰月
      if (isLeap == true && i == (leap + 1)) { isLeap = false }
      offset -= temp
    }
    // 闰月导致数组下标重叠取反
    if (offset == 0 && leap > 0 && i == leap + 1) {
      if (isLeap) {
        isLeap = false
      } else {
        isLeap = true; --i
      }
    }
    if (offset < 0) {
      offset += temp; --i
    }
    // 农历月
    var month = i
    // 农历日
    var day = offset + 1
    // 天干地支处理
    var sm = m - 1
    var gzY = this.toGanZhiYear(year)

    // 当月的两个节气
    // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
    var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
    var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始

    // 依据12节气修正干支月
    var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
    if (d >= firstNode) {
      gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
    }

    // 传入的日期的节气与否
    var isTerm = false
    var Term = null
    if (firstNode == d) {
      isTerm = true
      Term = this.solarTerm[m * 2 - 2]
    }
    if (secondNode == d) {
      isTerm = true
      Term = this.solarTerm[m * 2 - 1]
    }
    // 日柱 当月一日与 1900/1/1 相差天数
    var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
    var gzD = this.toGanZhi(dayCyclical + d - 1)
    // 该日期所属的星座
    var astro = this.toAstro(m, d)

    return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
  },

  /**
      * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
      * @param y  lunar year
      * @param m  lunar month
      * @param d  lunar day
      * @param isLeapMonth  lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
      * @return JSON object
      * @eg:console.log(calendar.lunar2solar(1987,9,10));
      */
  lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
    var isLeapMonth = !!isLeapMonth
    var leapOffset = 0
    var leapMonth = this.leapMonth(y)
    var leapDay = this.leapDays(y)
    if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
    if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
    var day = this.monthDays(y, m)
    var _day = day
    // bugFix 2016-9-25
    // if month is leap, _day use leapDays method
    if (isLeapMonth) {
      _day = this.leapDays(y, m)
    }
    if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验

    // 计算农历的时间差
    var offset = 0
    for (var i = 1900; i < y; i++) {
      offset += this.lYearDays(i)
    }
    var leap = 0; var isAdd = false
    for (var i = 1; i < m; i++) {
      leap = this.leapMonth(y)
      if (!isAdd) { // 处理闰月
        if (leap <= i && leap > 0) {
          offset += this.leapDays(y); isAdd = true
        }
      }
      offset += this.monthDays(y, i)
    }
    // 转换闰月农历 需补充该年闰月的前一个月的时差
    if (isLeapMonth) { offset += day }
    // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
    var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
    var calObj = new Date((offset + d - 31) * 86400000 + stmap)
    var cY = calObj.getUTCFullYear()
    var cM = calObj.getUTCMonth() + 1
    var cD = calObj.getUTCDate()

    return this.solar2lunar(cY, cM, cD)
  }
}

export default calendar
xm  /**
  q3  * @return Hex
        */
  yKoo!oooboo8oooyooOoo%	+L	o	o"
o
o
o!    0x0d520], // 2100

    /**
  3c8  */
  C  /**
  GpJF  */
  p  /**
  &
  !ZF  */
    /**
  6ZF  */
  V$  /**
        * 24节气速查表
  !F  */
  "  /**
  8	'  */
  3xnna4:   &EOnaX8o"nnan!O1
       D",>'a4\"na?P=nQ!.[na,B!O Q!NO-naM!"n%,/   (@VWQ!8
    '7f0e2d} n!+0%"P!Q!n$1^#'   @"S,!&'%2',
    %,&
*'.)#nQ!&B$n'" L   &"~$"0%"P!%n$1^#$ A+8]"6'n%5'9'n. #$(*   )p-Q/)n'" ,?(n)
    .hO!m*n$,++'A+n.9'+8m*5J,9',,B. #$(
7- 	    '665f@,(F-n'" 
S.B.n  /**
  /'C/UF  */
  /|  /**
  50-{0+F  */
  06  /**
  0-C1aF  */
  1  /**
  3c25E4c82@  */
  2 3&3]3&  },

    /**
  3R5E4c8-474F  */
  474.  },

    /**
  3	505E4c8e5v5L  */
  55#5B+    }
        return (0)
    },

    /**
  3t6\5E4c8
9、30)
  
7K  */
  X7#w7Z5(7  },

    /**
  8/I8c828N  */
    solar_7EG    var ms = m - 1
    Y9O9P#Q9%    }
    },

    /**
  0:.\:-F */
  :':&:&;PX;P;9  },

    /**
  ;.<&7<$F */
  w<)<G=C=Y  },

    /**
  =0>1F  */
  e>$>;  },

    /**
  >J?l|??V  */
  ?!@09@+`@.    var _info = [
      @=@$@@$.A@$fA@$A@$A
    ]
    A BB B# BB BpBBBBBBBB$B#
C#'C#DC$CBC#CBCCDCD
DD#DZCLD#iD#D#*      _info[5].substr(4, 2)
        ]
    D&  },

    /**
  DB5EFjEJ  */
  E4EG*F"HF%    return s
    },

    /**
  F<5EF
FFF  */
  8G2    var s
    pGGG(      case 20:
        G*        break
      GH*+        break
            default:
        @H3kH$+    }
        return (s)
    },

    /**
  Ha  * @param y year
  F ;ID  */
    getAnimal5I(  },

    /**
  IV$JAJ _J!Z=ZJ	  */
  JLK!@
      \K8
    }
    K!    if (\ %
            return -1
        }
    K#LL##Q!LhL
    }
    L*L    var y = @M
    L'M"%MM82QM#      offset -= temp
        }
    R^0emp; i--
        }

        // 是否今天
    YN$yNNn      isToday^  // 星期几
    %O%FO&hO?:    if (nWeek == 0) {
            nWeek = 7
        }
    OOO54    var isLeap = false

        // 效验闰月
    NP3      // 闰月
      PD        --i
        PT!Q0QK      }
      }QQF#      offset -= temp
        }
    Q0R:NR        isLeap = false
      !QR!      }
        }
    R^RJ    }
        // 农历月
        var month = i
        // 农历日
    S    // 天干地支处理
    NSaS+S!SIS\BTZT)T:     if (d >= firstNode) {
      U8    }

    HU*nU    var Term = null
    U VU+
    }
    U!VU$1]
        }
    PV8VQV5W$"W(FW  },

    /**
  Xw\YyY YYp!Z=Z<  */
  |ZXZ(    var leapOffset = 0
    [*1['T[[uT\'    var _day = day
    \\6    if (isLeapMonth) {
      \%
    }
    @.]9c]$    var offset = 0
    ]+^M  }
    ](^()^%H^,l^/^;        }
            }
  ^^
    }
    _LI_+p__3`D]`)`*`&`*  }
}

export default calendar
Tx@<template>
	<view class="uv-calendar-header uv-border-bottom">
		<text
			class="uv-calendar-header__title"
			v-if="showTitle"
		>{{ title }}</text>
		<text
			class="uv-calendar-header__subtitle"
			v-if="showSubtitle"
		>{{ subtitle }}</text>
		<view class="uv-calendar-header__weekdays">
			<text class="uv-calendar-header__weekdays__weekday">一</text>
			<text class="uv-calendar-header__weekdays__weekday">二</text>
			<text class="uv-calendar-header__weekdays__weekday">三</text>
			<text class="uv-calendar-header__weekdays__weekday">四</text>
			<text class="uv-calendar-header__weekdays__weekday">五</text>
			<text class="uv-calendar-header__weekdays__weekday">六</text>
			<text class="uv-calendar-header__weekdays__weekday">日</text>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	export default {
		name: 'uv-calendar-header',
		mixins: [mpMixin, mixin],
		props: {
			// 标题
			title: {
				type: String,
				default: ''
			},
			// 副标题
			subtitle: {
				type: [String,null],
				default: ''
			},
			// 是否显示标题
			showTitle: {
				type: Boolean,
				default: true
			},
			// 是否显示副标题
			showSubtitle: {
				type: Boolean,
				default: true
			},
		},
		data() {
			return {

			}
		},
		methods: {
			name() {

			}
		},
	}
</script>

<style lang="scss" scoped>
	$show-border: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-calendar-header {
		padding-bottom: 4px;

		&__title {
			font-size: 16px;
			color: $uv-main-color;
			text-align: center;
			height: 42px;
			line-height: 42px;
			font-weight: bold;
		}

		&__subtitle {
			font-size: 14px;
			color: $uv-main-color;
			height: 40px;
			text-align: center;
			line-height: 40px;
			font-weight: bold;
		}

		&__weekdays {
			@include flex;
			justify-content: space-between;

			&__weekday {
				font-size: 13px;
				color: $uv-main-color;
				line-height: 30px;
				flex: 1;
				text-align: center;
			}
		}
	}
</style>
t|	xO<template>
	<view class="uv-calendar-month-wrapper" ref="uv-calendar-month-wrapper">
		<view v-for="(item, index) in months" :key="index" :class="[`uv-calendar-month-${index}`]"
			:ref="`uv-calendar-month-${index}`" :id="`month-${index}`">
			<text v-if="index !== 0" class="uv-calendar-month__title">{{ item.year }}年{{ item.month }}月</text>
			<view class="uv-calendar-month__days">
				<view v-if="showMark" class="uv-calendar-month__days__month-mark-wrapper">
					<text class="uv-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
				</view>
				<view class="uv-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1"
					:style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)"
					:class="[item1.selected && 'uv-calendar-month__days__day__select--selected']">
					<view class="uv-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]">
						<text v-if="getTopInfo(index, index1, item1)"
						class="uv-calendar-month__days__day__select__top-info"
						:class="[item1.disabled && 'uv-calendar-month__days__day__select__top-info--disabled']"
						:style="[textStyle(item1)]"
						>{{ getTopInfo(index, index1, item1) }}</text>
						<text class="uv-calendar-month__days__day__select__info"
							:class="[item1.disabled && 'uv-calendar-month__days__day__select__info--disabled']"
							:style="[textStyle(item1)]">{{ item1.day }}</text>
						<text v-if="getBottomInfo(index, index1, item1)"
							class="uv-calendar-month__days__day__select__buttom-info"
							:class="[item1.disabled && 'uv-calendar-month__days__day__select__buttom-info--disabled']"
							:style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text>
						<text v-if="item1.dot" class="uv-calendar-month__days__day__select__dot"></text>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	// #ifdef APP-NVUE
	// 由于nvue不支持百分比单位，需要查询宽度来计算每个日期的宽度
	const dom = uni.requireNativePlugin('dom')
	// #endif
	import { colorGradient } from '@/uni_modules/uv-ui-tools/libs/function/colorGradient.js';
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import dayjs from '@/uni_modules/uv-ui-tools/libs/util/dayjs.js'
	export default {
		name: 'uv-calendar-month',
		emits:['monthSelected','updateMonthTop','change'],
		mixins: [mpMixin, mixin],
		props: {
			// 是否显示月份背景色
			showMark: {
				type: Boolean,
				default: true
			},
			// 主题色，对底部按钮和选中日期有效
			color: {
				type: String,
				default: '#3c9cff'
			},
			// 月份数据
			months: {
				type: Array,
				default: () => []
			},
			// 日期选择类型
			mode: {
				type: String,
				default: 'single'
			},
			// 日期行高
			rowHeight: {
				type: [String, Number],
				default: 58
			},
			// mode=multiple时，最多可选多少个日期
			maxCount: {
				type: [String, Number],
				default: Infinity
			},
			// mode=range时，第一个日期底部的提示文字
			startText: {
				type: String,
				default: '开始'
			},
			// mode=range时，最后一个日期底部的提示文字
			endText: {
				type: String,
				default: '结束'
			},
			// 默认选中的日期，mode为multiple或range是必须为数组格式
			defaultDate: {
				type: [Array, String, Date],
				default: null
			},
			// 最小的可选日期
			minDate: {
				type: [String, Number],
				default: 0
			},
			// 最大可选日期
			maxDate: {
				type: [String, Number],
				default: 0
			},
			// 如果没有设置maxDate，则往后推多少个月
			maxMonth: {
				type: [String, Number],
				default: 2
			},
			// 是否为只读状态，只读状态下禁止选择日期
			readonly: {
				type: Boolean,
				default: false
			},
			// 日期区间最多可选天数，默认无限制，mode = range时有效
			maxRange: {
				type: [Number, String],
				default: Infinity
			},
			// 范围选择超过最多可选天数时的提示文案，mode = range时有效
			rangePrompt: {
				type: String,
				default: ''
			},
			// 范围选择超过最多可选天数时，是否展示提示文案，mode = range时有效
			showRangePrompt: {
				type: Boolean,
				default: true
			},
			// 是否允许日期范围的起止时间为同一天，mode = range时有效
			allowSameDay: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				// 每个日期的宽度
				width: 0,
				// 当前选中的日期item
				item: {},
				selected: []
			}
		},
		watch: {
			selectedChange: {
				immediate: true,
				handler(n) {
					this.setDefaultDate()
				}
			}
		},
		computed: {
			// 多个条件的变化，会引起选中日期的变化，这里统一管理监听
			selectedChange() {
				return [this.minDate, this.maxDate, this.defaultDate]
			},
			dayStyle(index1, index2, item) {
				return (index1, index2, item) => {
					const style = {}
					let week = item.week
					// 不进行四舍五入的形式保留2位小数
					const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
					// 得出每个日期的宽度
					// #ifdef APP-NVUE
					style.width = this.$uv.addUnit(dayWidth)
					// #endif
					style.height = this.$uv.addUnit(this.rowHeight)
					if (index2 === 0) {
						// 获取当前为星期几，如果为0，则为星期天，减一为每月第一天时，需要向左偏移的item个数
						week = (week === 0 ? 7 : week) - 1
						style.marginLeft = this.$uv.addUnit(week * dayWidth)
					}
					if (this.mode === 'range') {
						// 之所以需要这么写，是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
						style.paddingLeft = 0
						style.paddingRight = 0
						style.paddingBottom = 0
						style.paddingTop = 0
					}
					return style
				}
			},
			daySelectStyle() {
				return (index1, index2, item) => {
					let date = dayjs(item.date).format("YYYY-MM-DD"),
						style = {}
					// 判断date是否在selected数组中，因为月份可能会需要补0，所以使用dateSame判断，而不用数组的includes判断
					if (this.selected.some(item => this.dateSame(item, date))) {
						style.backgroundColor = this.color
					}
					if (this.mode === 'single') {
						if (date === this.selected[0]) {
							// 因为需要对nvue的兼容，只能这么写，无法缩写，也无法通过类名控制等等
							style.borderTopLeftRadius = '3px'
							style.borderBottomLeftRadius = '3px'
							style.borderTopRightRadius = '3px'
							style.borderBottomRightRadius = '3px'
						}
					} else if (this.mode === 'range') {
						if (this.selected.length >= 2) {
							const len = this.selected.length - 1
							// 第一个日期设置左上角和左下角的圆角
							if (this.dateSame(date, this.selected[0])) {
								style.borderTopLeftRadius = '3px'
								style.borderBottomLeftRadius = '3px'
							}
							// 最后一个日期设置右上角和右下角的圆角
							if (this.dateSame(date, this.selected[len])) {
								style.borderTopRightRadius = '3px'
								style.borderBottomRightRadius = '3px'
							}
							// 处于第一和最后一个之间的日期，背景色设置为浅色，通过将对应颜色进行等分，再取其尾部的颜色值
							if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
									.selected[len]))) {
								style.backgroundColor = colorGradient(this.color, '#ffffff', 100)[90]
								// 增加一个透明度，让范围区间的背景色也能看到底部的mark水印字符
								style.opacity = 0.7
							}
						} else if (this.selected.length === 1) {
							// 之所以需要这么写，是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
							// 进行还原操作，否则在nvue的iOS，uni-app有bug，会导致诡异的表现
							style.borderTopLeftRadius = '3px'
							style.borderBottomLeftRadius = '3px'
						}
					} else {
						if (this.selected.some(item => this.dateSame(item, date))) {
							style.borderTopLeftRadius = '3px'
							style.borderBottomLeftRadius = '3px'
							style.borderTopRightRadius = '3px'
							style.borderBottomRightRadius = '3px'
						}
					}
					return style
				}
			},
			// 某个日期是否被选中
			textStyle() {
				return (item) => {
					const date = dayjs(item.date).format("YYYY-MM-DD"),
						style = {}
					// 选中的日期，提示文字设置白色
					if (this.selected.some(item => this.dateSame(item, date))) {
						style.color = '#ffffff'
					}
					if (this.mode === 'range') {
						const len = this.selected.length - 1
						// 如果是范围选择模式，第一个和最后一个之间的日期，文字颜色设置为高亮的主题色
						if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
								.selected[len]))) {
							style.color = this.color
						}
					}
					return style
				}
			},
			// 获取顶部的提示文字
			getTopInfo() {
				return (index1, index2, item) => {
					return item.topInfo;
				}
			},
			// 获取底部的提示文字
			getBottomInfo() {
				return (index1, index2, item) => {
					const date = dayjs(item.date).format("YYYY-MM-DD")
					const bottomInfo = item.bottomInfo
					// 当为日期范围模式时，且选择的日期个数大于0时
					if (this.mode === 'range' && this.selected.length > 0) {
						if (this.selected.length === 1) {
							// 选择了一个日期时，如果当前日期为数组中的第一个日期，则显示底部文字为“开始”
							if (this.dateSame(date, this.selected[0])) return this.startText
							else return bottomInfo
						} else {
							const len = this.selected.length - 1
							// 如果数组中的日期大于2个时，第一个和最后一个显示为开始和结束日期
							if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) &&
								len === 1) {
								// 如果长度为2，且第一个等于第二个日期，则提示语放在同一个item中
								return `${this.startText}/${this.endText}`
							} else if (this.dateSame(date, this.selected[0])) {
								return this.startText
							} else if (this.dateSame(date, this.selected[len])) {
								return this.endText
							} else {
								return bottomInfo
							}
						}
					} else {
						return bottomInfo
					}
				}
			}
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				// 初始化默认选中
				this.$emit('monthSelected', this.selected)
				this.$nextTick(() => {
					// 这里需要另一个延时，因为获取宽度后，会进行月份数据渲染，只有渲染完成之后，才有真正的高度
					// 因为nvue下，$nextTick并不是100%可靠的
					this.$uv.sleep(10).then(() => {
						this.getWrapperWidth()
						this.getMonthRect()
					})
				})
			},
			// 判断两个日期是否相等
			dateSame(date1, date2) {
				return dayjs(date1).isSame(dayjs(date2))
			},
			// 获取月份数据区域的宽度，因为nvue不支持百分比，所以无法通过css设置每个日期item的宽度
			getWrapperWidth() {
				// #ifdef APP-NVUE
				dom.getComponentRect(this.$refs['uv-calendar-month-wrapper'], res => {
					this.width = res.size.width
				})
				// #endif
				// #ifndef APP-NVUE
				this.$uvGetRect('.uv-calendar-month-wrapper').then(size => {
					this.width = size.width
				})
				// #endif
			},
			getMonthRect() {
				// 获取每个月份数据的尺寸，用于父组件在scroll-view滚动事件中，监听当前滚动到了第几个月份
				const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise(
					`uv-calendar-month-${index}`))
				// 一次性返回
				Promise.all(promiseAllArr).then(
					sizes => {
						let height = 1
						const topArr = []
						for (let i = 0; i < this.months.length; i++) {
							// 添加到months数组中，供scroll-view滚动事件中，判断当前滚动到哪个月份
							topArr[i] = height
							height += sizes[i].height
						}
						// 由于微信下，无法通过this.months[i].top的形式(引用类型)去修改父组件的month的top值，所以使用事件形式对外发出
						this.$emit('updateMonthTop', topArr)
					})
			},
			// 获取每个月份区域的尺寸
			getMonthRectByPromise(el) {
				// #ifndef APP-NVUE
				// $uvGetRect为uvui自带的节点查询简化方法，详见文档介绍：https://www.uvui.cn/js/getRect.html
				// 组件内部一般用this.$uvGetRect，对外的为getRect，二者功能一致，名称不同
				return new Promise(resolve => {
					this.$uvGetRect(`.${el}`).then(size => {
						resolve(size)
					})
				})
				// #endif

				// #ifdef APP-NVUE
				// nvue下，使用dom模块查询元素高度
				// 返回一个promise，让调用此方法的主体能使用then回调
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs[el][0], res => {
						resolve(res.size)
					})
				})
				// #endif
			},
			// 点击某一个日期
			clickHandler(index1, index2, item) {
				if (this.readonly) {
					return;
				}
				this.item = item
				const date = dayjs(item.date).format("YYYY-MM-DD")
				if (item.disabled) return
				// 对上一次选择的日期数组进行深度克隆
				let selected = this.$uv.deepClone(this.selected)
				if (this.mode === 'single') {
					// 单选情况下，让数组中的元素为当前点击的日期
					selected = [date]
				} else if (this.mode === 'multiple') {
					if (selected.some(item => this.dateSame(item, date))) {
						// 如果点击的日期已在数组中，则进行移除操作，也就是达到反选的效果
						const itemIndex = selected.findIndex(item => dayjs(item).format("YYYY-MM-DD") === dayjs(date).format("YYYY-MM-DD"))
						selected.splice(itemIndex, 1)
					} else {
						// 如果点击的日期不在数组中，且已有的长度小于总可选长度时，则添加到数组中去
						if (selected.length < this.maxCount) selected.push(date)
					}
				} else {
					// 选择区间形式
					if (selected.length === 0 || selected.length >= 2) {
						// 如果原来就为0或者大于2的长度，则当前点击的日期，就是开始日期
						selected = [date]
					} else if (selected.length === 1) {
						// 如果已经选择了开始日期
						const existsDate = selected[0]
						// 如果当前选择的日期小于上一次选择的日期，则当前的日期定为开始日期
						if (dayjs(date).isBefore(existsDate)) {
							selected = [date]
						} else if (dayjs(date).isAfter(existsDate)) {
							// 当前日期减去最大可选的日期天数，如果大于起始时间，则进行提示
							if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) {
								if(this.rangePrompt) {
									this.$uv.toast(this.rangePrompt)
								} else {
									this.$uv.toast(`选择天数不能超过 ${this.maxRange} 天`)
								}
								return
							}
							// 如果当前日期大于已有日期，将当前的添加到数组尾部
							selected.push(date)
							const startDate = selected[0]
							const endDate = selected[1]
							const arr = []
							let i = 0
							do {
								// 将开始和结束日期之间的日期添加到数组中
								arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD"))
								i++
								// 累加的日期小于结束日期时，继续下一次的循环
							} while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate)))
							// 为了一次性修改数组，避免computed中多次触发，这里才用arr变量一次性赋值的方式，同时将最后一个日期添加近来
							arr.push(endDate)
							selected = arr
						} else {
							// 选择区间时，只有一个日期的情况下，且不允许选择起止为同一天的话，不允许选择自己
							if (selected[0] === date && !this.allowSameDay) return
							selected.push(date)
						}
					}
				}
				this.setSelected(selected)
				this.$emit('change',{
					day: date,
					selected: selected
				});
			},
			// 设置默认日期
			setDefaultDate() {
				if (!this.defaultDate) {
					// 如果没有设置默认日期，则将当天日期设置为默认选中的日期
					const selected = [dayjs().format("YYYY-MM-DD")]
					return this.setSelected(selected, false)
				}
				let defaultDate = []
				const minDate = this.minDate || dayjs().format("YYYY-MM-DD")
				const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD")
				if (this.mode === 'single') {
					// 单选模式，可以是字符串或数组，Date对象等
					if (!this.$uv.test.array(this.defaultDate)) {
						defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")]
					} else {
						defaultDate = [this.defaultDate[0]]
					}
				} else {
					// 如果为非数组，则不执行
					if (!this.$uv.test.array(this.defaultDate)) return
					defaultDate = this.defaultDate
				}
				// 过滤用户传递的默认数组，取出只在可允许最大值与最小值之间的元素
				defaultDate = defaultDate.filter(item => {
					return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs(
						maxDate).add(1, 'day'))
				})
				this.setSelected(defaultDate, false)
			},
			setSelected(selected, event = true) {
				this.selected = selected
				event && this.$emit('monthSelected', this.selected)
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-calendar-month-wrapper {
		margin-top: 4px;
	}

	.uv-calendar-month {

		&__title {
			font-size: 14px;
			line-height: 42px;
			height: 42px;
			color: $uv-main-color;
			text-align: center;
			font-weight: bold;
		}

		&__days {
			position: relative;
			@include flex;
			flex-wrap: wrap;

			&__month-mark-wrapper {
				position: absolute;
				top: 0;
				bottom: 0;
				left: 0;
				right: 0;
				@include flex;
				justify-content: center;
				align-items: center;

				&__text {
					font-size: 155px;
					color: rgba(231, 232, 234, 0.83);
				}
			}

			&__day {
				@include flex;
				padding: 2px;
				/* #ifndef APP-NVUE */
				// vue下使用css进行宽度计算，因为某些安卓机会无法进行js获取父元素宽度进行计算得出，会有偏移
				width: calc(100% / 7);
				box-sizing: border-box;
				/* #endif */

				&__select {
					flex: 1;
					@include flex;
					align-items: center;
					justify-content: center;
					position: relative;

					&__dot {
						width: 7px;
						height: 7px;
						border-radius: 100px;
						background-color: $uv-error;
						position: absolute;
						top: 12px;
						right: 7px;
					}
					
					&__top-info {
						color: $uv-content-color;
						text-align: center;
						position: absolute;
						top: 2px;
						font-size: 10px;
						text-align: center;
						left: 0;
						right: 0;
						&--selected {
							color: #ffffff;
						}
						
						&--disabled {
							color: #cacbcd;
						}
					}
					
					&__buttom-info {
						color: $uv-content-color;
						text-align: center;
						position: absolute;
						bottom: 5px;
						font-size: 10px;
						text-align: center;
						left: 0;
						right: 0;

						&--selected {
							color: #ffffff;
						}

						&--disabled {
							color: #cacbcd;
						}
					}

					&__info {
						text-align: center;
						font-size: 16px;

						&--selected {
							color: #ffffff;
						}

						&--disabled {
							color: #cacbcd;
						}
					}

					&--selected {
						background-color: $uv-primary;
						@include flex;
						justify-content: center;
						align-items: center;
						flex: 1;
						border-radius: 3px;
					}

					&--range-selected {
						opacity: 0.3;
						border-radius: 0;
					}

					&--range-start-selected {
						border-top-right-radius: 0;
						border-bottom-right-radius: 0;
					}

					&--range-end-selected {
						border-top-left-radius: 0;
						border-bottom-left-radius: 0;
					}
				}
			}
		}
	}
</style>
xexport default {
	props: {
		// 日历顶部标题
		title: {
			type: String,
			default: '日期选择'
		},
		// 是否显示标题
		showTitle: {
			type: Boolean,
			default: true
		},
		// 是否显示副标题
		showSubtitle: {
			type: Boolean,
			default: true
		},
		// 日期类型选择，single-选择单个日期，multiple-可以选择多个日期，range-选择日期范围
		mode: {
			type: String,
			default: 'single'
		},
		// mode=range时，第一个日期底部的提示文字
		startText: {
			type: String,
			default: '开始'
		},
		// mode=range时，最后一个日期底部的提示文字
		endText: {
			type: String,
			default: '结束'
		},
		// 自定义列表
		customList: {
			type: Array,
			default: () => []
		},
		// 主题色，对底部按钮和选中日期有效
		color: {
			type: String,
			default: '#3c9cff'
		},
		// 最小的可选日期
		minDate: {
			type: [String, Number],
			default: 0
		},
		// 最大可选日期
		maxDate: {
			type: [String, Number],
			default: 0
		},
		// 默认选中的日期，mode为multiple或range是必须为数组格式
		defaultDate: {
			type: [Array, String, Date, null],
			default: null
		},
		// mode=multiple时，最多可选多少个日期
		maxCount: {
			type: [String, Number],
			default: Number.MAX_SAFE_INTEGER
		},
		// 日期行高
		rowHeight: {
			type: [String, Number],
			default: 56
		},
		// 日期格式化函数
		formatter: {
			type: [Function, null],
			default: null
		},
		// 是否显示农历
		showLunar: {
			type: Boolean,
			default: false
		},
		// 是否显示月份背景色
		showMark: {
			type: Boolean,
			default: true
		},
		// 确定按钮的文字
		confirmText: {
			type: String,
			default: '确定'
		},
		// 确认按钮处于禁用状态时的文字
		confirmDisabledText: {
			type: String,
			default: '确定'
		},
		// 是否允许点击遮罩关闭日历
		closeOnClickOverlay: {
			type: Boolean,
			default: false
		},
		// 是否允许点击确认按钮关闭日历
		closeOnClickConfirm: {
			type: Boolean,
			default: true
		},
		// 是否为只读状态，只读状态下禁止选择日期
		readonly: {
			type: Boolean,
			default: false
		},
		// 	是否展示确认按钮
		showConfirm: {
			type: Boolean,
			default: true
		},
		// 日期区间最多可选天数，默认无限制，mode = range时有效 Infinity
		maxRange: {
			type: [Number, String],
			default: Number.MAX_SAFE_INTEGER
		},
		// 范围选择超过最多可选天数时的提示文案，mode = range时有效
		rangePrompt: {
			type: String,
			default: ''
		},
		// 范围选择超过最多可选天数时，是否展示提示文案，mode = range时有效
		showRangePrompt: {
			type: Boolean,
			default: true
		},
		// 是否允许日期范围的起止时间为同一天，mode = range时有效
		allowSameDay: {
			type: Boolean,
			default: false
		},
		// 圆角值
		round: {
			type: [Boolean, String, Number],
			default: 0
		},
		// 最多展示月份数量
		monthNum: {
			type: [Number, String],
			default: 3
		},
		...uni.$uv?.props?.calendar
	}
}?#Gx1 <template>
	<uv-popup
		ref="calendarPopup"
		mode="bottom"
		closeable
		:round="round"
		:closeOnClickOverlay="closeOnClickOverlay"
		@change="popupChange"
	>
		<view class="uv-calendar">
			<uvHeader
				:title="title"
				:subtitle="subtitle"
				:showSubtitle="showSubtitle"
				:showTitle="showTitle"
			></uvHeader>
			<scroll-view
				:style="{ height: $uv.addUnit(listHeight) }"
				scroll-y
				@scroll="onScroll"
				:scroll-top="scrollTop"
				:scrollIntoView="scrollIntoView"
			>
				<uvMonth
					:color="color"
					:rowHeight="rowHeight"
					:showMark="showMark"
					:months="months"
					:mode="mode"
					:maxCount="maxCount"
					:startText="startText"
					:endText="endText"
					:defaultDate="defaultDate"
					:minDate="innerMinDate"
					:maxDate="innerMaxDate"
					:maxMonth="monthNum"
					:readonly="readonly"
					:maxRange="maxRange"
					:rangePrompt="rangePrompt"
					:showRangePrompt="showRangePrompt"
					:allowSameDay="allowSameDay"
					ref="month"
					@monthSelected="monthSelected"
					@updateMonthTop="updateMonthTop"
					@change="changeDay"
				></uvMonth>
			</scroll-view>
			<slot name="footer" v-if="showConfirm">
				<view class="uv-calendar__confirm">
					<uv-button
						shape="circle"
						:text="buttonDisabled ? confirmDisabledText : confirmText"
						:color="color"
						@click="confirm"
						:disabled="buttonDisabled"
					></uv-button>
				</view>
			</slot>
		</view>
	</uv-popup>
</template>

<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import uvHeader from './header.vue'
import uvMonth from './month.vue'
import props from './props.js'
import dayjs from '@/uni_modules/uv-ui-tools/libs/util/dayjs.js'
import Calendar from './calendar.js'
/**
 * Calendar 日历
 * @description  此组件用于单个选择日期，范围选择日期等，日历被包裹在底部弹起的容器中.
 * @tutorial https://www.uvui.cn/components/calendar.html
 *
 * @property {String}				title				标题内容 (默认 日期选择 )
 * @property {Boolean}				showTitle			是否显示标题  (默认 true )
 * @property {Boolean}				showSubtitle		是否显示副标题	(默认 true )
 * @property {String}				mode				日期类型选择  single-选择单个日期，multiple-可以选择多个日期，range-选择日期范围 （ 默认 'single' )
 * @property {String}				startText			mode=range时，第一个日期底部的提示文字  (默认 '开始' )
 * @property {String}				endText				mode=range时，最后一个日期底部的提示文字 (默认 '结束' )
 * @property {Array}				customList			自定义列表
 * @property {String}				color				主题色，对底部按钮和选中日期有效  (默认 ‘#3c9cff' )
 * @property {String | Number}		minDate				最小的可选日期	 (默认 0 )
 * @property {String | Number}		maxDate				最大可选日期  (默认 0 )
 * @property {Array | String| Date}	defaultDate			默认选中的日期，mode为multiple或range是必须为数组格式
 * @property {String | Number}		maxCount			mode=multiple时，最多可选多少个日期  (默认 	Number.MAX_SAFE_INTEGER  )
 * @property {String | Number}		rowHeight			日期行高 (默认 56 )
 * @property {Function}				formatter			日期格式化函数
 * @property {Boolean}				showLunar			是否显示农历  (默认 false )
 * @property {Boolean}				showMark			是否显示月份背景色 (默认 true )
 * @property {String}				confirmText			确定按钮的文字 (默认 '确定' )
 * @property {String}				confirmDisabledText	确认按钮处于禁用状态时的文字 (默认 '确定' )
 * @property {Boolean}				show				是否显示日历弹窗 (默认 false )
 * @property {Boolean}				closeOnClickOverlay	是否允许点击遮罩关闭日历 (默认 false )
 * @property {Boolean}				closeOnClickConfirm	是否允许点击确认按钮关闭日历，设置为false不影响confirm事件返回 (默认 true )
 * @property {Boolean}				readonly	        是否为只读状态，只读状态下禁止选择日期 (默认 false )
 * @property {String | Number}		maxRange	        日期区间最多可选天数，默认无限制，mode = range时有效
 * @property {String}				rangePrompt	        范围选择超过最多可选天数时的提示文案，mode = range时有效
 * @property {Boolean}				showRangePrompt	    范围选择超过最多可选天数时，是否展示提示文案，mode = range时有效 (默认 true )
 * @property {Boolean}				allowSameDay	    是否允许日期范围的起止时间为同一天，mode = range时有效 (默认 false )
 * @property {Number|String}	    round				圆角值，默认无圆角  (默认 0 )
 * @property {Number|String}	    monthNum			最多展示的月份数量  (默认 3 )
 *
 * @event {Function()} confirm 		点击确定按钮时触发		选择日期相关的返回参数
 * @event {Function()} close 		日历关闭时触发			可定义页面关闭时的回调事件
 * @example <uv-calendar ref="calendar" :defaultDate="defaultDateMultiple" mode="multiple" @confirm="confirm">
	</uv-calendar>
 * */
export default {
	name: 'uv-calendar',
	emits:['confirm','close','change'],
	mixins: [mpMixin, mixin, props],
	components: {
		uvHeader,
		uvMonth
	},
	data() {
		return {
			// 需要显示的月份的数组
			months: [],
			// 在月份滚动区域中，当前视图中月份的index索引
			monthIndex: 0,
			// 月份滚动区域的高度
			listHeight: 0,
			// month组件中选择的日期数组
			selected: [],
			scrollIntoView: '',
			scrollTop:0,
			// 过滤处理方法
			innerFormatter: (value) => value
		}
	},
	watch: {
		selectedChange: {
			immediate: true,
			handler(n) {
				this.setMonth()
			}
		}
	},
	computed: {
		// 由于maxDate和minDate可以为字符串(2021-10-10)，或者数值(时间戳)，但是dayjs如果接受字符串形式的时间戳会有问题，这里进行处理
		innerMaxDate() {
			return this.$uv.test.number(this.maxDate)
				? Number(this.maxDate)
				: this.maxDate
		},
		innerMinDate() {
			return this.$uv.test.number(this.minDate)
				? Number(this.minDate)
				: this.minDate
		},
		// 多个条件的变化，会引起选中日期的变化，这里统一管理监听
		selectedChange() {
			return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
		},
		subtitle() {
			// 初始化时，this.months为空数组，所以需要特别判断处理
			if (this.months.length) {
				return `${this.months[this.monthIndex].year}年${
					this.months[this.monthIndex].month
				}月`
			} else {
				return ''
			}
		},
		buttonDisabled() {
			// 如果为range类型，且选择的日期个数不足1个时，让底部的按钮出于disabled状态
			if (this.mode === 'range') {
				if (this.selected.length <= 1) {
					return true
				} else {
					return false
				}
			} else {
				return false
			}
		}
	},
	mounted() {
		this.start = Date.now()
		this.init()
	},
	methods: {
		// 在微信小程序中，不支持将函数当做props参数，故只能通过ref形式调用
		setFormatter(e) {
			this.innerFormatter = e
		},
		// 点击日期框触发
		changeDay(e) {
			this.$emit('change',e);
		},
		// month组件内部选择日期后，通过事件通知给父组件
		monthSelected(e) {
			this.selected = e
			if (!this.showConfirm) {
				// 在不需要确认按钮的情况下，如果为单选，或者范围多选且已选长度大于2，则直接进行返还
				if (
					this.mode === 'multiple' ||
					this.mode === 'single' ||
					(this.mode === 'range' && this.selected.length >= 2)
				) {
					this.$emit('confirm', this.selected)
				}
			}
		},
		init() {
			// 校验maxDate，不能小于minDate
			if (
				this.innerMaxDate &&
				this.innerMinDate &&
				new Date(this.innerMaxDate).getTime() < new Date(this.innerMinDate).getTime()
			) {
				return this.$uv.error('maxDate不能小于minDate')
			}
			// 滚动区域的高度
			this.listHeight = this.rowHeight * 5 + 30
			this.setMonth()
		},
		open() {
			this.setMonth()
			this.$refs.calendarPopup.open();
		},
		popupChange(e) {
			if(!e.show) {
				this.$emit('close');
			}
		},
		// 点击确定按钮
		confirm() {
			if (!this.buttonDisabled) {
				this.$emit('confirm', this.selected)
			}
			if (this.closeOnClickConfirm) {
				this.$refs.calendarPopup.close();
			}
		},
		// 获得两个日期之间的月份数
		getMonths(minDate, maxDate) {
			const minYear = dayjs(minDate).year()
			const minMonth = dayjs(minDate).month() + 1
			const maxYear = dayjs(maxDate).year()
			const maxMonth = dayjs(maxDate).month() + 1
			return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1
		},
		// 设置月份数据
		setMonth() {
			// 最小日期的毫秒数
			const minDate = this.innerMinDate || dayjs().valueOf()
			// 如果没有指定最大日期，则往后推3个月
			const maxDate =
				this.innerMaxDate ||
				dayjs(minDate)
					.add(this.monthNum - 1, 'month')
					.valueOf()
			// 最大最小月份之间的共有多少个月份，
			const months = this.$uv.range(
				1,
				this.monthNum,
				this.getMonths(minDate, maxDate)
			)
			// 先清空数组
			this.months = []
			for (let i = 0; i < months; i++) {
				this.months.push({
					date: new Array(
						dayjs(minDate).add(i, 'month').daysInMonth()
					)
						.fill(1)
						.map((item, index) => {
							// 日期，取值1-31
							let day = index + 1
							// 星期，0-6，0为周日
							const week = dayjs(minDate)
								.add(i, 'month')
								.date(day)
								.day()
							const date = dayjs(minDate)
								.add(i, 'month')
								.date(day)
								.format('YYYY-MM-DD')
							let topInfo = ''
							let bottomInfo = ''
							if (this.showLunar) {
								// 将日期转为农历格式
								const lunar = Calendar.solar2lunar(
									dayjs(date).year(),
									dayjs(date).month() + 1,
									dayjs(date).date()
								)
								bottomInfo = lunar.IDayCn
							}
							let config = {
								day,
								week,
								// 小于最小允许的日期，或者大于最大的日期，则设置为disabled状态
								disabled:
									dayjs(date).isBefore(
										dayjs(minDate).format('YYYY-MM-DD')
									) ||
									dayjs(date).isAfter(
										dayjs(maxDate).format('YYYY-MM-DD')
									),
								// 返回一个日期对象，供外部的formatter获取当前日期的年月日等信息，进行加工处理
								date: new Date(date),
								topInfo,
								bottomInfo,
								dot: false,
								month:
									dayjs(minDate).add(i, 'month').month() + 1
							}
							const formatter =
								this.formatter || this.innerFormatter
							return formatter(config)
						}),
					// 当前所属的月份
					month: dayjs(minDate).add(i, 'month').month() + 1,
					// 当前年份
					year: dayjs(minDate).add(i, 'month').year()
				})
			}

		},
		// 滚动到默认设置的月份
		scrollIntoDefaultMonth(selected) {
			// 查询默认日期在可选列表的下标
			const _index = this.months.findIndex(({
				  year,
				  month
			  }) => {
				month = this.$uv.padZero(month)
				return `${year}-${month}` === selected
			})
			if (_index !== -1) {
				// #ifndef MP-WEIXIN
				this.$nextTick(() => {
					this.scrollIntoView = `month-${_index}`
				})
				// #endif
				// #ifdef MP-WEIXIN
				this.scrollTop = this.months[_index].top || 0;
				// #endif
			}
		},
		// scroll-view滚动监听
		onScroll(event) {
			// 不允许小于0的滚动值，如果scroll-view到顶了，继续下拉，会出现负数值
			const scrollTop = Math.max(0, event.detail.scrollTop)
			// 将当前滚动条数值，除以滚动区域的高度，可以得出当前滚动到了哪一个月份的索引
			for (let i = 0; i < this.months.length; i++) {
				if (scrollTop >= (this.months[i].top || this.listHeight)) {
					this.monthIndex = i
				}
			}
		},
		// 更新月份的top值
		updateMonthTop(topArr = []) {
			// 设置对应月份的top值，用于onScroll方法更新月份
			topArr.map((item, index) => {
				this.months[index].top = item
			})

			// 获取默认日期的下标
			if (!this.defaultDate) {
				// 如果没有设置默认日期，则将当天日期设置为默认选中的日期
				const selected = dayjs().format("YYYY-MM")
				this.scrollIntoDefaultMonth(selected)
				return
			}
			let selected = dayjs().format("YYYY-MM");
			// 单选模式，可以是字符串或数组，Date对象等
			if (!this.$uv.test.array(this.defaultDate)) {
				selected = dayjs(this.defaultDate).format("YYYY-MM")
			} else {
				selected = dayjs(this.defaultDate[0]).format("YYYY-MM");
			}
			this.scrollIntoDefaultMonth(selected)
		}
	}
}
</script>

<style lang="scss" scoped>
.uv-calendar {
	&__confirm {
		padding: 7px 18px;
	}
}
</style>
3"x 
## Calendar 日历 calendar**

此组件用于单个选择日期，范围选择日期等，日历被包裹在底部弹起的容器中。灵活配瑌#W

## 温馨提示：该组件不再更新，强烈推荐使用最新版日历组件：[@calendars.html](@calendars.html)。基于 `uv-ui` 插件市场首款多功能日历组件，不仅可以查看、选择日期，还可以选择意范围内的日期、打点操作、自定义主题颜色、自定义文案、农历显示等。追求的就是完美。

*calendar{&'U֪	x e100644 changelog.md ㍬pdxs^40000 components 	
_{100644 package.json qSQ"\nGhi0OK5100644 readme.md ن*)2~~,/73] <qx## 1.0.15（2023-11-08）
1. 增加readonly属性，是否为只读状态，只读状态下禁止选择日期
## 1.0.14（2023-10-12）
1. 修复selected没有设置了info或者info设置为空字符串后，文本则无法恢复BUG
## 1.0.13（2023-09-19）
1. 修复range模式下，selected设置了info后选中后，导致文本不恢复的问题
2. 修复multiple模式下，selected自定义信息的颜色没变，依然是白色
## 1.0.12（2023-09-14）
1. 优化
## 1.0.11（2023-09-14）
1. 增加allowSameDay参数，是否允许日期范围的起止时间为同一天，mode = range时有效
2. 修复在vue2+小程序渲染时闪烁的问题
## 1.0.10（2023-09-07）
1. 修复国际化失效的BUG
## 1.0.9（2023-09-01）
1. 修复在pages.json中设置easycom会报错的BUG
## 1.0.8（2023-08-29）
1. 修复mainjs中设置setConfig修改属性不生效的问题，出自评论区：https://ext.dcloud.net.cn/plugin?id=12287
## 1.0.7（2023-08-26）
1. 去除range参数，由mode="range"替换
2. 新增mode参数，不传 / multiple / range，分别为单日期， 多个日期，选择日期范围
3. 与uv-calendar选择日期的功能保持一致
## 1.0.6（2023-08-25）
1. 修复点击返回今天按钮时，monthSwitch方法回调参数返回月份不是当天对应月份：https://github.com/climblee/uv-ui/issues/7
## 1.0.5（2023-08-13）
1. 修复选择月份弹窗层级的问题
## 1.0.4（2023-08-06）
1. 优化
## 1.0.3（2023-08-06）
1. 修复高度不对的BUG
2. 修复文案在小屏幕的BUG
## 1.0.2（2023-08-05）
1. 增加startText参数
2. 增加endText参数
3. 增加selected中的参数
4. 优化日历范围选择
## 1.0.1（2023-08-04）
1. 修复 自定义主题时 颜色错误的BUG
## 1.0.0（2023-08-03）
1. 新增 uv-calendars 新版日历发布
x' 40000 uv-calendars St_t˱CyW-=x 100644 calendar-body.vue u4]ejX*e100644 calendar-item.vue -wӼvi100644 calendar.js DzG+SvEu40000 i18n pגT\m)SX100644 util.js mk6aćJ֤100644 uv-calendars.vue [7pv+ӘT usf'xN"<template>
	<view class="uv-calendar-body">
		<view class="uv-calendar__header">
			<view class="uv-calendar__header-btn-box" @click.stop="pre">
				<view class="uv-calendar__header-btn uv-calendar--left"></view>
			</view>
			<picker mode="date" :value="getDate" fields="month" @change="bindDateChange">
				<text class="uv-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
			</picker>
			<view class="uv-calendar__header-btn-box" @click.stop="next">
				<view class="uv-calendar__header-btn uv-calendar--right"></view>
			</view>
			<text class="uv-calendar__backtoday" @click="backToday">{{todayText}}</text>
		</view>
		<view class="uv-calendar__box">
			<view v-if="showMonth" class="uv-calendar__box-bg">
				<text class="uv-calendar__box-bg-text">{{nowDate.month}}</text>
			</view>
			<view class="uv-calendar__weeks uv-calendar__weeks-week">
				<view class="uv-calendar__weeks-day">
					<text class="uv-calendar__weeks-day-text">{{SUNText}}</text>
				</view>
				<view class="uv-calendar__weeks-day">
					<text class="uv-calendar__weeks-day-text">{{monText}}</text>
				</view>
				<view class="uv-calendar__weeks-day">
					<text class="uv-calendar__weeks-day-text">{{TUEText}}</text>
				</view>
				<view class="uv-calendar__weeks-day">
					<text class="uv-calendar__weeks-day-text">{{WEDText}}</text>
				</view>
				<view class="uv-calendar__weeks-day">
					<text class="uv-calendar__weeks-day-text">{{THUText}}</text>
				</view>
				<view class="uv-calendar__weeks-day">
					<text class="uv-calendar__weeks-day-text">{{FRIText}}</text>
				</view>
				<view class="uv-calendar__weeks-day">
					<text class="uv-calendar__weeks-day-text">{{SATText}}</text>
				</view>
			</view>
			<view class="uv-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
				<view class="uv-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
					<calendar-item class="uv-calendar-item--hook" :weeks="weeks" :rangeInfoText="rangeInfoText(weeks)" :multiple="multiple" :range="range" :calendar="calendar" :selected="selected" :lunar="lunar" :color="color" @change="choiceDate"></calendar-item>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';

	import CalendarItem from './calendar-item.vue';

	import { initVueI18n } from '@dcloudio/uni-i18n';
	import i18nMessages from './i18n/index.js';
	const { t } = initVueI18n(i18nMessages);
	export default {
		mixins: [mpMixin, mixin],
		components: {
			CalendarItem
		},
		props: {
			date: {
				type: [String,Array],
				default: ''
			},
			nowDate: {
				type: [String, Object],
				default: ''
			},
			weeks: {
				type: [Array, Object],
				default () {
					return []
				}
			},
			calendar: {
				type: Object,
				default () {
					return {}
				}
			},
			selected: {
				type: Array,
				default () {
					return []
				}
			},
			lunar: {
				type: Boolean,
				default: false
			},
			showMonth: {
				type: Boolean,
				default: true
			},
			color: {
				type: String,
				default: '#3c9cff'
			},
			startText: {
				type: String,
				default: '开始'
			},
			endText: {
				type: String,
				default: '结束'
			},
			range: {
				type: Boolean,
				default: false
			},
			multiple: {
				type: Boolean,
				default: false
			},
			// 是否允许日期范围的起止时间为同一天，mode = range时有效
			allowSameDay: {
				type: Boolean,
				default: false
			}
		},
		computed: {
			getDate() {
				return Array.isArray(this.date) ? this.date[0] : this.date;
			},
			/**
			 * for i18n
			 */
			todayText() {
				return t("uv-calender.today")
			},
			monText() {
				return t("uv-calender.MON")
			},
			TUEText() {
				return t("uv-calender.TUE")
			},
			WEDText() {
				return t("uv-calender.WED")
			},
			THUText() {
				return t("uv-calender.THU")
			},
			FRIText() {
				return t("uv-calender.FRI")
			},
			SATText() {
				return t("uv-calender.SAT")
			},
			SUNText() {
				return t("uv-calender.SUN")
			},
			rangeInfoText(weeks) {
				return weeks=> {
					if(this.allowSameDay && weeks.beforeRange && weeks.afterRange && weeks.dateEqual) {
						return this.setInfo(weeks,`${this.startText}/${this.endText}`);
					} 
					if(weeks.beforeRange) {
						return this.setInfo(weeks,this.startText);
					}
					if(weeks.afterRange) {
						return this.setInfo(weeks,this.endText);
					}
					if(weeks.extraInfo?.info_old == ' ') {
						weeks.extraInfo.info = null;
					}else if(weeks.extraInfo?.info_old) {
						weeks.extraInfo.info = weeks.extraInfo.info_old;
					} 
				}
			}
		},
		methods: {
			setInfo(weeks,text) {
				this.setInfoOld(weeks);
				if(weeks.extraInfo) {
					weeks.extraInfo.info = text;
				}else {
					weeks.extraInfo = {
						info: text
					}
				}
			},
			setInfoOld(weeks) {
				if(weeks.extraInfo) {
					weeks.extraInfo.info_old = weeks.extraInfo.info ? weeks.extraInfo.info_old || weeks.extraInfo.info : ' ';
				}
			},
			bindDateChange(e) {
				this.$emit('bindDateChange', e);
			},
			backToday() {
				this.$emit('backToday');
			},
			pre() {
				this.$emit('pre');
			},
			next() {
				this.$emit('next');
			},
			choiceDate(e) {
				this.$emit('choiceDate', e);
			}
		}
	}
</script>

<style scoped lang="scss">
	@mixin flex($direction: row) {
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		flex-direction: $direction;
	}
	$uv-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
	$uv-border-color: #EDEDED !default;
	$uv-text-color: #333;
	$uv-bg-color-hover: #f1f1f1;
	$uv-font-size-base: 14px;
	$uv-text-color-placeholder: #808080;
	$uv-color-subtitle: #555555;
	$uv-text-color-grey: #999;
	.uv-calendar {
		@include flex(column);
	}
	.uv-calendar__mask {
		position: fixed;
		bottom: 0;
		top: 0;
		left: 0;
		right: 0;
		background-color: $uv-bg-color-mask;
		transition-property: opacity;
		transition-duration: 0.3s;
		opacity: 0;
		/* #ifndef APP-NVUE */
		z-index: 99;
		/* #endif */
	}
	.uv-calendar--mask-show {
		opacity: 1
	}
	.uv-calendar--fixed {
		position: fixed;
		/* #ifdef APP-NVUE */
		bottom: 0;
		/* #endif */
		left: 0;
		right: 0;
		transition-property: transform;
		transition-duration: 0.3s;
		transform: translateY(460px);
		/* #ifndef APP-NVUE */
		bottom: calc(var(--window-bottom));
		z-index: 99;
		/* #endif */
	}
	.uv-calendar--ani-show {
		transform: translateY(0);
	}
	.uv-calendar__content {
		background-color: #fff;
	}
	.uv-calendar__header {
		position: relative;
		@include flex;
		justify-content: center;
		align-items: center;
		height: 50px;
		border-bottom-color: $uv-border-color;
		border-bottom-style: solid;
		border-bottom-width: 1px;
	}
	.uv-calendar--fixed-top {
		@include flex;
		justify-content: space-between;
		border-top-color: $uv-border-color;
		border-top-style: solid;
		border-top-width: 1px;
	}
	.uv-calendar--fixed-width {
		width: 50px;
	}
	.uv-calendar__backtoday {
		position: absolute;
		right: 0;
		top: 25rpx;
		padding: 0 5px;
		padding-left: 10px;
		height: 25px;
		line-height: 25px;
		font-size: 12px;
		border-top-left-radius: 25px;
		border-bottom-left-radius: 25px;
		color: $uv-text-color;
		background-color: $uv-bg-color-hover;
	}
	.uv-calendar__header-text {
		text-align: center;
		width: 100px;
		font-size: $uv-font-size-base;
		color: $uv-text-color;
	}
	.uv-calendar__header-btn-box {
		@include flex;
		align-items: center;
		justify-content: center;
		width: 50px;
		height: 50px;
	}
	.uv-calendar__header-btn {
		width: 10px;
		height: 10px;
		border-left-color: $uv-text-color-placeholder;
		border-left-style: solid;
		border-left-width: 2px;
		border-top-color: $uv-color-subtitle;
		border-top-style: solid;
		border-top-width: 2px;
	}
	.uv-calendar--left {
		transform: rotate(-45deg);
	}
	.uv-calendar--right {
		transform: rotate(135deg);
	}
	.uv-calendar__weeks {
		position: relative;
		@include flex;
	}
	.uv-calendar__weeks-week {
		padding: 0 0 2rpx;
	}
	.uv-calendar__weeks-item {
		flex: 1;
	}
	.uv-calendar__weeks-day {
		flex: 1;
		@include flex(column);
		justify-content: center;
		align-items: center;
		height: 45px;
		border-bottom-color: #F5F5F5;
		border-bottom-style: solid;
		border-bottom-width: 1px;
	}
	.uv-calendar__weeks-day-text {
		font-size: 14px;
	}
	.uv-calendar__box {
		position: relative;
	}
	.uv-calendar__box-bg {
		@include flex(column);
		justify-content: center;
		align-items: center;
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
	}
	.uv-calendar__box-bg-text {
		font-size: 200px;
		font-weight: bold;
		color: $uv-text-color-grey;
		opacity: 0.1;
		text-align: center;
		/* #ifndef APP-NVUE */
		line-height: 1;
		/* #endif */
	}
</style>x1<template>
	<view class="uv-calendar-item__weeks-box" :class="{
		'uv-calendar-item--disable':weeks.disable || (weeks.extraInfo&&weeks.extraInfo.disable),
		'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
		'uv-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple) ,
		'uv-calendar-item--before-checked':weeks.beforeRange,
		'uv-calendar-item--range': weeks.range,
		'uv-calendar-item--after-checked':weeks.afterRange,
		'uv-calendar-item--multiple':weeks.multiple
		}" :style="[itemBoxStyle]" @click="choiceDate(weeks)">
		<view class="uv-calendar-item__weeks-box-item">
			<text v-if="selected&&weeks.extraInfo&&weeks.extraInfo.badge" class="uv-calendar-item__weeks-box-circle"></text>
			<text class="uv-calendar-item__weeks-top-text" v-if="weeks.extraInfo&&weeks.extraInfo.topinfo" :style="[infoStyle('top')]">{{weeks.extraInfo&&weeks.extraInfo.topinfo}}</text>
			<text class="uv-calendar-item__weeks-box-text" :class="{
				'uv-calendar-item--isDay-text': weeks.isDay,
				'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
				'uv-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
				'uv-calendar-item--before-checked':weeks.beforeRange,
				'uv-calendar-item--range': weeks.range,
				'uv-calendar-item--after-checked':weeks.afterRange,
				'uv-calendar-item--multiple':weeks.multiple,
				'uv-calendar-item--disable':weeks.disable || (weeks.extraInfo&&weeks.extraInfo.disable)
				}" :style="[itemBoxStyle]">{{weeks.date}}</text>
			<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uv-calendar-item__weeks-lunar-text" :class="{
				'uv-calendar-item--isDay-text':weeks.isDay,
				'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
				'uv-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
				'uv-calendar-item--before-checked':weeks.beforeRange,
				'uv-calendar-item--range': weeks.range,
				'uv-calendar-item--after-checked':weeks.afterRange,
				'uv-calendar-item--multiple':weeks.multiple
				}" :style="[itemBoxStyle]">{{todayText}}</text>
			<text v-if="lunar&&!weeks.extraInfo" class="uv-calendar-item__weeks-lunar-text" :class="{
				'uv-calendar-item--isDay-text':weeks.isDay,
				'uv-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay && !multiple,
				'uv-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay && !multiple,
				'uv-calendar-item--before-checked':weeks.beforeRange,
				'uv-calendar-item--range': weeks.range,
				'uv-calendar-item--after-checked':weeks.afterRange,
				'uv-calendar-item--multiple':weeks.multiple,
				'uv-calendar-item--disable':weeks.disable || (weeks.extraInfo&&weeks.extraInfo.disable)
				}" :style="[itemBoxStyle]">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
			<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uv-calendar-item__weeks-lunar-text" :class="{
						'uv-calendar-item__weeks-lunar-text--equal': weeks.dateEqual
					}" :style="[infoStyle('bottom')]">{{weeks.extraInfo.info}}</text>
		</view>
	</view>
</template>
<script>
	import { colorGradient } from '@/uni_modules/uv-ui-tools/libs/function/colorGradient.js';
	import { initVueI18n } from '@dcloudio/uni-i18n'
	import i18nMessages from './i18n/index.js'
	const { t } = initVueI18n(i18nMessages)
	export default {
		emits: ['change'],
		props: {
			weeks: {
				type: Object,
				default () {
					return {}
				}
			},
			calendar: {
				type: Object,
				default: () => {
					return {}
				}
			},
			selected: {
				type: Array,
				default: () => {
					return []
				}
			},
			lunar: {
				type: Boolean,
				default: false
			},
			color: {
				type: String,
				default: '#3c9cff'
			},
			range: {
				type: Boolean,
				default: false
			},
			multiple: {
				type: Boolean,
				default: false
			}
		},
		computed: {
			todayText() {
				return t("uv-calender.today")
			},
			itemBoxStyle() {
				const style = {};
				if (this.multiple) { // 多选状态
					if (this.weeks.multiple) {
						style.backgroundColor = this.color;
						style.color = '#fff';
					} else if (this.weeks.isDay) {
						style.color = this.color;
					}
				} else if (this.range) { // 范围选择
					if (this.weeks.beforeRange || this.weeks.afterRange) {
						style.backgroundColor = this.color;
					} else if (this.weeks.range) {
						style.backgroundColor = colorGradient(this.color, '#ffffff', 100)[90]
						style.color = this.color;
						style.opacity = 0.8;
						style.borderRadius = 0;
					}
				} else {
					if (this.weeks.isDay) {
						style.color = this.color;
					}
					if (this.calendar.fullDate === this.weeks.fullDate) {
						style.backgroundColor = this.color;
						style.color = '#fff';
					}
				}
				return style;
			},
			infoStyle(val) {
				return val => {
					const style = {};
					if (!this.weeks.multiple) {
						if (val == 'top') {
							style.color = this.weeks.extraInfo.topinfoColor ? this.weeks.extraInfo.topinfoColor : '#606266';
						} else if (val == 'bottom') {
							style.color = this.weeks.extraInfo.infoColor ? this.weeks.extraInfo.infoColor : '#f56c6c';
						}
						if (this.weeks.range) {
							style.color = this.color;
						}
						if (this.calendar.fullDate === this.weeks.fullDate || this.weeks.beforeRange || this.weeks.afterRange) {
							style.color = this.multiple ? style.color : '#fff';
						}
					} else {
						style.color = '#fff';
					}
					return style;
				}
			}
		},
		methods: {
			choiceDate(weeks) {
				if (this.weeks.extraInfo && this.weeks.extraInfo.disable) return;
				this.$emit('change', weeks)
			}
		}
	}
</script>
<style lang="scss" scoped>
	@mixin flex($direction: row) {
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		flex-direction: $direction;
	}
	$uv-font-size-base: 14px;
	$uv-text-color: #333;
	$uv-font-size-sm: 24rpx;
	$uv-error: #f56c6c !default;
	$uv-opacity-disabled: 0.3;
	$uv-text-color-disable: #c0c0c0;
	$uv-primary: #3c9cff !default;
	$info-height: 32rpx;
	.uv-calendar-item__weeks-box {
		flex: 1;
		@include flex(column);
		justify-content: center;
		align-items: center;
		border-radius: 4px;
	}
	.uv-calendar-item__weeks-top-text {
		height: $info-height;
		line-height: $info-height;
		font-size: $uv-font-size-sm;
	}
	.uv-calendar-item__weeks-box-text {
		font-size: $uv-font-size-base;
		color: $uv-text-color;
	}
	.uv-calendar-item__weeks-lunar-text {
		height: $info-height;
		line-height: $info-height;
		font-size: $uv-font-size-sm;
		color: $uv-text-color;
	}
	.uv-calendar-item__weeks-lunar-text--equal {
		/* #ifdef H5 */
		white-space: nowrap;
		transform: scale(.8);
		/* #endif */
		/* #ifndef H5 */
		font-size: 20rpx;
		/* #endif */
	}
	.uv-calendar-item__weeks-box-item {
		position: relative;
		@include flex(column);
		justify-content: center;
		align-items: center;
		width: 106rpx;
		height: 56px;
	}
	.uv-calendar-item__weeks-box-circle {
		position: absolute;
		top: 5px;
		right: 5px;
		width: 8px;
		height: 8px;
		border-radius: 8px;
		background-color: $uv-error;
	}
	.uv-calendar-item--disable {
		background-color: rgba(249, 249, 249, $uv-opacity-disabled);
		color: $uv-text-color-disable;
	}
	.uv-calendar-item--isDay-text {
		color: $uv-primary;
	}
	.uv-calendar-item--isDay {
		background-color: $uv-primary;
		color: #fff;
	}
	.uv-calendar-item--checked {
		background-color: $uv-primary;
		color: #fff;
		border-radius: 4px;
	}
	// .uv-calendar-item--range {
	// 	background-color: $uv-primary;
	// 	color: #fff;
	// }
	.uv-calendar-item--before-checked {
		color: #fff;
	}
	.uv-calendar-item--after-checked {
		color: #fff;
	}
	.uv-calendar-item--multiple {
		background-color: $uv-primary;
		color: #fff;
	}
</style>o	x h100644 en.json >+/W?L100644 index.js u	{{] ʔUz100644 zh-Hans.json H`[K~4!\8\G100644 zh-Hant.json )fHaedOz>σ;Ux{
	"uv-calender.ok": "ok",
	"uv-calender.cancel": "cancel",
	"uv-calender.today": "today",
	"uv-calender.MON": "MON",
	"uv-calender.TUE": "TUE",
	"uv-calender.WED": "WED",
	"uv-calender.THU": "THU",
	"uv-calender.FRI": "FRI",
	"uv-calender.SAT": "SAT",
	"uv-calender.SUN": "SUN"
}
aP
x ]import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
	en,
	'zh-Hans': zhHans,
	'zh-Hant': zhHant
}
x5*x{
	"uv-calender.ok": "確定",
	"uv-calender.cancel": "取消",
	"uv-calender.today": "今日",
	"uv-calender.SUN": "日",
	"uv-calender.MON": "一",
	"uv-calender.TUE": "二",
	"uv-calender.WED": "三",
	"uv-calender.THU": "四",
	"uv-calender.FRI": "五",
	"uv-calender.SAT": "六"
}
J`m+x %	x~.import CALENDAR from './calendar.js'
class Calendar {
	constructor({
		date,
		selected,
		startDate,
		endDate,
		range,
		multiple,
		allowSameDay
	} = {}) {
		// 当前日期
		this.date = this.getDate(new Date()) // 当前初入日期
		// 打点信息
		this.selected = selected || [];
		// 范围开始
		this.startDate = startDate
		// 范围结束
		this.endDate = endDate
		this.range = range
		this.multiple = multiple
		this.allowSameDay = allowSameDay
		// 多选状态
		this.cleanRangeStatus()
		// 范围状态
		this.cleanMultipleStatus()
		// 每周日期
		this.weeks = {}
		// this._getWeek(this.date.fullDate)
	}
	/**
	 * 设置日期
	 * @param {Object} date
	 */
	setDate(date, status) {
		if (this.range && status == 'init') {
			this.cleanRangeStatus();
			if (Array.isArray(date)) {
				this.rangeStatus.before = date[0];
				this.rangeStatus.after = date.length > 1 ? date[date.length - 1] : '';
				if (this.rangeStatus.after && this.dateCompare(this.rangeStatus.before, this.rangeStatus.after)) {
					this.rangeStatus.data = this.geDateAll(this.rangeStatus.before, this.rangeStatus.after)
				}
				this.selectDate = this.getDate(date[0])
				this._getWeek(this.selectDate.fullDate)
			} else {
				this.selectDate = this.getDate(date)
				this.rangeStatus.before = this.selectDate.fullDate;
				this._getWeek(this.selectDate.fullDate)
			}
		} else if (this.multiple && status == 'init') {
			this.cleanMultipleStatus();
			if (Array.isArray(date)) {
				this.multipleStatus.data = date;
				this.selectDate = this.getDate(date[0])
				this._getWeek(this.selectDate.fullDate)
			} else {
				this.selectDate = this.getDate(date)
				this.multipleStatus.data = [this.selectDate.fullDate];
				this._getWeek(this.selectDate.fullDate)
			}
		} else {
			if (Array.isArray(date)) {
				this.selectDate = this.getDate(date[0])
				this._getWeek(this.selectDate.fullDate)
			} else {
				this.selectDate = this.getDate(date)
				this._getWeek(this.selectDate.fullDate)
			}
		}
	}
	/**
	 * 清理多选状态
	 */
	cleanRangeStatus() {
		this.rangeStatus = {
			before: '',
			after: '',
			data: []
		}
	}
	/**
	 * 清理多选状态
	 */
	cleanMultipleStatus() {
		this.multipleStatus = {
			data: []
		}
	}
	/**
	 * 重置开始日期
	 */
	resetSatrtDate(startDate) {
		// 范围开始
		this.startDate = startDate
	}
	/**
	 * 重置结束日期
	 */
	resetEndDate(endDate) {
		// 范围结束
		this.endDate = endDate
	}
	/**
	 * 获取任意时间
	 */
	getDate(date, AddDayCount = 0, str = 'day') {
		if (!date) {
			date = new Date()
		}
		if (typeof date !== 'object') {
			date = date.replace(/-/g, '/')
		}
		const dd = new Date(date)
		switch (str) {
			case 'day':
				dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
				break
			case 'month':
				if (dd.getDate() === 31 && AddDayCount > 0) {
					dd.setDate(dd.getDate() + AddDayCount)
				} else {
					const preMonth = dd.getMonth()
					dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
					const nextMonth = dd.getMonth()
					// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
					if (AddDayCount < 0 && preMonth !== 0 && nextMonth - preMonth > AddDayCount) {
						dd.setMonth(nextMonth + (nextMonth - preMonth + AddDayCount))
					}
					// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
					if (AddDayCount > 0 && nextMonth - preMonth > AddDayCount) {
						dd.setMonth(nextMonth - (nextMonth - preMonth - AddDayCount))
					}
				}
				break
			case 'year':
				dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
				break
		}
		const y = dd.getFullYear()
		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期，不足10补0
		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号，不足10补0
		return {
			fullDate: y + '-' + m + '-' + d,
			year: y,
			month: m,
			date: d,
			day: dd.getDay()
		}
	}
	/**
	 * 获取上月剩余天数
	 */
	_getLastMonthDays(firstDay, full) {
		let dateArr = []
		for (let i = firstDay; i > 0; i--) {
			const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
			dateArr.push({
				date: beforeDate,
				month: full.month - 1,
				lunar: this.getlunar(full.year, full.month - 1, beforeDate),
				disable: true
			})
		}
		return dateArr
	}
	/**
	 * 获取本月天数
	 */
	_currentMonthDys(dateData, full) {
		let dateArr = []
		let fullDate = this.date.fullDate
		for (let i = 1; i <= dateData; i++) {
			let nowDate = full.year + '-' + (full.month < 10 ? full.month : full.month) + '-' + (i < 10 ? '0' + i : i)
			// 是否今天
			let isDay = fullDate === nowDate
			// 获取打点信息
			let info = this.selected && this.selected.find((item) => {
				if (this.dateEqual(nowDate, item.date)) {
					return item
				}
			})
			// 日期禁用
			let disableBefore = true
			let disableAfter = true
			if (this.startDate) {
				// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
				// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
				disableBefore = this.dateCompare(this.startDate, nowDate)
			}
			if (this.endDate) {
				// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
				// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
				disableAfter = this.dateCompare(nowDate, this.endDate)
			}
			let ranges = this.rangeStatus.data
			let checked = false
			let rangesStatus = -1
			if (this.range) {
				if (ranges) {
					rangesStatus = ranges.findIndex((item) => {
						return this.dateEqual(item, nowDate)
					})
				}
				if (rangesStatus !== -1) {
					checked = true
				}
			}
			let multiples = this.multipleStatus.data
			let checked_multiple = false
			let multiplesStatus = -1
			if (this.multiple) {
				if (multiples) {
					multiplesStatus = multiples.findIndex((item) => {
						return this.dateEqual(item, nowDate)
					})
				}
				if (multiplesStatus !== -1) {
					checked_multiple = true
				}
			}
			let data = {
				fullDate: nowDate,
				year: full.year,
				date: i,
				range: this.range ? checked : false,
				multiple: this.multiple ? checked_multiple : false,
				beforeRange: this.dateEqual(this.rangeStatus.before, nowDate),
				afterRange: this.dateEqual(this.rangeStatus.after, nowDate),
				dateEqual: this.range && checked && this.dateEqual(this.rangeStatus.before, this.rangeStatus.after),
				month: full.month,
				lunar: this.getlunar(full.year, full.month, i),
				disable: !(disableBefore && disableAfter),
				isDay
			}
			if (info) {
				data.extraInfo = info
			}
			dateArr.push(data)
		}
		return dateArr
	}
	/**
	 * 获取下月天数
	 */
	_getNextMonthDays(surplus, full) {
		let dateArr = []
		for (let i = 1; i < surplus + 1; i++) {
			dateArr.push({
				date: i,
				month: Number(full.month) + 1,
				lunar: this.getlunar(full.year, Number(full.month) + 1, i),
				disable: true
			})
		}
		return dateArr
	}
	/**
	 * 获取当前日期详情
	 * @param {Object} date
	 */
	getInfo(date) {
		if (!date) {
			date = new Date()
		} else if (Array.isArray(date)) {
			date = date[0]
		}
		const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
		return dateInfo
	}
	/**
	 * 比较时间大小
	 */
	dateCompare(startDate, endDate) {
		// 计算截止时间
		startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
		// 计算详细项的截止时间
		endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
		if (startDate <= endDate) {
			return true
		} else {
			return false
		}
	}
	/**
	 * 比较时间是否相等
	 */
	dateEqual(before, after) {
		// 计算截止时间
		before = new Date(before.replace('-', '/').replace('-', '/'))
		// 计算详细项的截止时间
		after = new Date(after.replace('-', '/').replace('-', '/'))
		if (before.getTime() - after.getTime() === 0) {
			return true
		} else {
			return false
		}
	}
	/**
	 * 比较after时间是否大于before时间
	 */
	dateAfterLgBefore(before, after) {
		// 计算截止时间
		before = new Date(before.replace('-', '/').replace('-', '/'))
		// 计算详细项的截止时间
		after = new Date(after.replace('-', '/').replace('-', '/'))
		if (after.getTime() - before.getTime() > 0) {
			return true
		} else {
			return false
		}
	}
	/**
	 * 获取日期范围内所有日期
	 * @param {Object} begin
	 * @param {Object} end
	 */
	geDateAll(begin, end) {
		var arr = []
		var ab = begin.split('-')
		var ae = end.split('-')
		var db = new Date()
		db.setFullYear(ab[0], ab[1] - 1, ab[2])
		var de = new Date()
		de.setFullYear(ae[0], ae[1] - 1, ae[2])
		var unixDb = db.getTime() - 24 * 60 * 60 * 1000
		var unixDe = de.getTime() - 24 * 60 * 60 * 1000
		for (var k = unixDb; k <= unixDe;) {
			k = k + 24 * 60 * 60 * 1000
			arr.push(this.getDate(new Date(parseInt(k))).fullDate)
		}
		return arr
	}
	/**
	 * 计算阴历日期显示
	 */
	getlunar(year, month, date) {
		return CALENDAR.solar2lunar(year, month, date)
	}
	/**
	 * 设置打点
	 */
	setSelectInfo(data, value) {
		this.selected = value
		this._getWeek(data)
	}
	/**
	 * 获取多选状态
	 */
	setMultiple(fullDate) {
		if (!this.multiple) return
		let multiples = this.multipleStatus.data;
		const findIndex = multiples.findIndex(item => this.dateEqual(fullDate, item));
		if (findIndex < 0) {
			this.multipleStatus.data = this.multipleStatus.data.concat([fullDate]);
		} else {
			this.multipleStatus.data.splice(findIndex, 1);
		}
		this._getWeek(fullDate)
	}
	/**
	 *  获取范围状态
	 */
	setRange(fullDate) {
		let {
			before,
			after
		} = this.rangeStatus
		if (!this.range) return
		if (before && after) {
			this.cleanRangeStatus();
			this.rangeStatus.before = fullDate
		} else {
			if (!before) {
				this.rangeStatus.before = fullDate
			} else {
				if (this.allowSameDay && this.dateEqual(before, fullDate)) {
					this.rangeStatus.after = fullDate
				} else if (!this.dateAfterLgBefore(this.rangeStatus.before, fullDate)) {
					this.cleanRangeStatus();
					this.rangeStatus.before = fullDate
					this._getWeek(fullDate)
					return;
				}
				this.rangeStatus.after = fullDate
				if (this.dateCompare(this.rangeStatus.before, this.rangeStatus.after)) {
					this.rangeStatus.data = this.geDateAll(this.rangeStatus.before, this.rangeStatus.after);
				} else {
					this.rangeStatus.data = this.geDateAll(this.rangeStatus.after, this.rangeStatus.before);
				}
			}
		}
		this._getWeek(fullDate)
	}
	/**
	 * 获取每周数据
	 * @param {Object} dateData
	 */
	_getWeek(dateData) {
		const {
			year,
			month
		} = this.getDate(dateData)
		let firstDay = new Date(year, month - 1, 1).getDay()
		let currentDay = new Date(year, month, 0).getDate()
		let dates = {
			lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
			nextMonthDays: [], // 下个月开始几天
			weeks: []
		}
		let canlender = []
		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
		let weeks = {}
		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
		for (let i = 0; i < canlender.length; i++) {
			if (i % 7 === 0) {
				weeks[parseInt(i / 7)] = new Array(7)
			}
			weeks[parseInt(i / 7)][i % 7] = canlender[i]
		}
		this.canlender = canlender
		this.weeks = weeks
	}
	//静态方法
	// static init(date) {
	// 	if (!this.instance) {
	// 		this.instance = new Calendar(date);
	// 	}
	// 	return this.instance;
	// }
}
export default Calendarx+0<template>
	<view class="uv-calendar">
		<view class="uv-calendar__content" v-if="insert">
			<calendar-body
				:date="date"
				:nowDate="nowDate"
				:weeks="weeks"
				:calendar="calendar"
				:selected="selected"
				:lunar="lunar"
				:showMonth="showMonth"
				:color="color"
				:startText="startText"
				:endText="endText"
				:range="range"
				:multiple="multiple"
				:allowSameDay="allowSameDay"
				@bindDateChange="bindDateChange"
				@pre="pre"
				@next="next"
				@backToday="backToday"
				@choiceDate="choiceDate"
			></calendar-body>
		</view>
		<uv-popup ref="popup" mode="bottom" v-else :round="round" z-index="998" :close-on-click-overlay="closeOnClickOverlay" @maskClick="maskClick">
			<view style="min-height: 100px;">
				<uv-toolbar
					:show="true"
					:cancelColor="cancelColor"
					:confirmColor="getConfirmColor"
					:cancelText="cancelText"
					:confirmText="confirmText"
					:title="title"
					@cancel="close"
					@confirm="confirm"></uv-toolbar>
				<view class="line"></view>
				<calendar-body
					:nowDate="nowDate"
					:weeks="weeks"
					:calendar="calendar"
					:selected="selected"
					:lunar="lunar"
					:showMonth="showMonth"
					:color="color"
					:startText="startText"
					:endText="endText"
					:range="range"
					:multiple="multiple"
					:allowSameDay="allowSameDay"
					@bindDateChange="bindDateChange"
					@pre="pre"
					@next="next"
					@backToday="backToday"
					@choiceDate="choiceDate"
				></calendar-body>
			</view>
		</uv-popup>
	</view>
</template>
<script>
	/**
	 * Calendar 日历
	 * @description 日历组件可以查看日期，选择任意范围内的日期，打点操作。常用场景如：酒店日期预订、火车机票选择购买日期、上下班打卡等
	 * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-calendar
	 * @property {String} date 自定义当前时间，默认为今天
	 * @property {Boolean} lunar 显示农历
	 * @property {String} startDate 日期选择范围-开始日期
	 * @property {String} endDate 日期选择范围-结束日期
	 * @property {String} mode = [不传 | multiple | range ]  多个日期 | 选择日期范围 默认单日期
	 * @property {Boolean} insert = [true|false] 插入模式,默认为false
	 * 	@value true 弹窗模式
	 * 	@value false 插入模式
	 * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
	 * @property {Array} selected 打点，期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
	 * @property {String} cancelColor 取消按钮颜色
	 * @property {String} confirmColor  确认按钮颜色，默认#3c9cff
	 * @property {String} title 头部工具条中间的标题文字
	 * @property {String} color 主题色，默认#3c9cff
	 * @property {Number} round :insert="false"时的圆角
	 * @property {Boolean} closeOnClickOverlay 点击遮罩是否关闭
	 * @property {String} startText range为true时，第一个日期底部的提示文字
	 * @property {String} endText range为true时，最后一个日期底部的提示文字
	 * @property {String} readonly 是否为只读状态，只读状态下禁止选择日期，默认false
	 * 
	 * @event {Function} change 日期改变，`insert :ture` 时生效
	 * @event {Function} confirm 确认选择`insert :false` 时生效
	 * @event {Function} monthSwitch 切换月份时触发
	 * 
	 * @example <uv-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
	 */
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
	import Calendar from './util.js';
	import calendarBody from './calendar-body.vue';
	import { initVueI18n } from '@dcloudio/uni-i18n';
	import i18nMessages from './i18n/index.js';
	const { t } = initVueI18n(i18nMessages);
	export default {
		components: {
			calendarBody
		},
		mixins: [mpMixin, mixin],
		emits: ['close', 'confirm', 'change', 'monthSwitch'],
		props: {
			// 取消按钮颜色
			cancelColor: {
				type: String,
				default: ''
			},
			// 确认按钮颜色，range模式下未选全显示灰色
			confirmColor: {
				type: String,
				default: '#3c9cff'
			},
			// 标题
			title: {
				type: String,
				default: ''
			},
			// 主题色
			color: {
				type: String,
				default: '#3c9cff'
			},
			// 默认显示日期
			date: {
				type: [String,Array],
				default: ''
			},
			// 打点等设置
			selected: {
				type: Array,
				default () {
					return []
				}
			},
			// 是否显示农历
			lunar: {
				type: Boolean,
				default: false
			},
			// 可选择的起始日期
			startDate: {
				type: String,
				default: ''
			},
			// 可选择的结束日期
			endDate: {
				type: String,
				default: ''
			},
			// multiple - 选择多日期  range - 选择日期范围
			mode: {
				type: String,
				default: ''
			},
			// 是否插入模式
			insert: {
				type: Boolean,
				default: false
			},
			// 是否显示月份为背景
			showMonth: {
				type: Boolean,
				default: true
			},
			// 弹窗模式是否清空上次选择内容
			clearDate: {
				type: Boolean,
				default: true
			},
			// 弹窗圆角
			round: {
				type: [Number,String],
				default: 8
			},
			// 点击遮罩是否关闭弹窗
			closeOnClickOverlay: {
				type: Boolean,
				default: true
			},
			// range为true时，第一个日期底部的提示文字
			startText: {
				type: String,
				default: '开始'
			},
			// range为true时，最后一个日期底部的提示文字
			endText: {
				type: String,
				default: '结束'
			},
			// 是否允许日期范围的起止时间为同一天，mode = range时有效
			allowSameDay: {
				type: Boolean,
				default: false
			},
			// 是否禁用
			readonly: {
				type: Boolean,
				default: false
			},
			...uni.$uv?.props?.calendars
		},
		data(){
			return {
				weeks: [],
				calendar: {},
				nowDate: '',
				allowConfirm: false,
				multiple: false,
				range: false
			}
		},
		computed:{
			/**
			 * for i18n
			 */
			confirmText() {
				return t("uv-calender.ok")
			},
			cancelText() {
				return t("uv-calender.cancel")
			},
			getConfirmColor() {
				if(this.range || this.multiple || this.readonly) {
					return this.allowConfirm? this.confirmColor: '#999'
				}else {
					return this.confirmColor;
				}
			}
		},
		watch: {
			date(newVal) {
				this.init(newVal)
			},
			startDate(val) {
				this.cale.resetSatrtDate(val)
				this.cale.setDate(this.nowDate.fullDate)
				this.weeks = this.cale.weeks
			},
			endDate(val) {
				this.cale.resetEndDate(val)
				this.cale.setDate(this.nowDate.fullDate)
				this.weeks = this.cale.weeks
			},
			selected(newVal) {
				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
				this.weeks = this.cale.weeks
			}
		},
		created() {
			this.setMode();
			this.cale = new Calendar({
				selected: this.selected,
				startDate: this.startDate,
				endDate: this.endDate,
				range: this.range,
				multiple: this.multiple,
				allowSameDay: this.allowSameDay
			})
			this.init(this.date)
		},
		methods: {
			setMode() {
				switch (this.mode){
					case 'range':
						this.range = true;
						break;
					case 'multiple':
						this.multiple = true;
					default:
						break;
				}
			},
			async open() {
				if (this.clearDate && !this.insert) {
					this.cale.cleanRangeStatus()
					this.init(this.date)
				}
				if(!this.insert){
					this.$refs.popup.open();
				}
			},
			close() {
				this.$refs.popup.close();
				this.$emit('close');
			},
			confirm() {
				if(this.readonly) {
					return;
				} else if(this.range && !this.cale.rangeStatus.after) {
					return;
				} else if(this.multiple && this.cale.multipleStatus.data.length == 0){
					return;
				}
				this.setEmit('confirm');
				this.close()
			},
			maskClick() {
				if(this.closeOnClickOverlay) {
					this.$emit('close');
				}
			},
			bindDateChange(e) {
				const value = e.detail.value + '-1'
				this.setDate(value)
		
				const { year, month } = this.cale.getDate(value)
				this.$emit('monthSwitch', {
					year,
					month
				})
			},
			/**
			 * 初始化日期显示
			 * @param {Object} date
			 */
			init(date) {
				if(this.range) {
					// 重置范围选择状态
					this.cale.cleanRangeStatus();
				}else if(this.multiple){
					// 重置多选状态
					this.cale.cleanMultipleStatus();
				}
				this.cale.setDate(date,'init')
				this.weeks = this.cale.weeks
				this.nowDate = this.calendar = this.cale.getInfo(date)
				this.changeConfirmStatus();
			},
			/**
			 * 变化触发
			 */
			change() {
				this.changeConfirmStatus();
				if (!this.insert) return
				this.setEmit('change')
			},
			changeConfirmStatus() {
				if(this.readonly) {
					this.allowConfirm = false;
				} else if (this.range) {
					this.allowConfirm = this.cale.rangeStatus.after ? true : false;
				} else if(this.multiple) {
					this.allowConfirm = this.cale.multipleStatus.data.length > 0 ? true : false;
				}
			},
			/**
			 * 选择月份触发
			 */
			monthSwitch() {
				let {
					year,
					month
				} = this.nowDate
				this.$emit('monthSwitch', {
					year,
					month: Number(month)
				})
			},
			/**
			 * 派发事件
			 * @param {Object} name
			 */
			setEmit(name) {
				let {
					year,
					month,
					date,
					fullDate,
					lunar,
					extraInfo
				} = this.calendar
				this.$emit(name, {
					range: this.cale.rangeStatus,
					multiple: this.cale.multipleStatus,
					year,
					month,
					date,
					fulldate: fullDate,
					lunar,
					extraInfo: extraInfo || {}
				})
			},
			/**
			 * 选择天触发
			 * @param {Object} weeks
			 */
			choiceDate(weeks) {
				if (weeks.disable || this.readonly) return
				this.calendar = weeks
				// 设置范围选择
				this.cale.setRange(this.calendar.fullDate)
				// 设置多选
				this.cale.setMultiple(this.calendar.fullDate);
				this.weeks = this.cale.weeks
				this.change()
			},
			/**
			 * 回到今天
			 */
			backToday() {
				const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
				const date = this.cale.getDate(new Date())
				const todayYearMonth = `${date.year}-${date.month}`
				this.init(date.fullDate)
				if (nowYearMonth !== todayYearMonth) {
					this.monthSwitch()
				}
				this.change()
			},
			/**
			 * 上个月
			 */
			pre() {
				const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
				this.setDate(preDate)
				this.monthSwitch()
			},
			/**
			 * 下个月
			 */
			next() {
				const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
				this.setDate(nextDate)
				this.monthSwitch()
			},
			/**
			 * 设置日期
			 * @param {Object} date
			 */
			setDate(date) {
				this.cale.setDate(date)
				this.weeks = this.cale.weeks
				this.nowDate = this.cale.getInfo(date)
			}
		}
	}
</script>
<style scoped lang="scss">
	$uv-border-color: #EDEDED !default;
	.uv-calendar__content {
		background-color: #fff;
	}
	.line {
		width: 750rpx;
		height: 1px;
		border-bottom-color: $uv-border-color;
		border-bottom-style: solid;
		border-bottom-width: 1px;
	}
</style>DHhMx(E{
  "id": "uv-calendars",
  "displayName": "uv-calendars 最新日历=H15",
  "description": "新版本uv-calendars，不仅拥有老版本的所有功能，还增加了更加适用的插入页面强大功能，且更加简洁。查看日期、选择单个或多个或任意范围日期，打点操作，自定义文案，自定义主题等强大功能OAuv-ui",
    "uvui",
    "日历",
    "打卡",
    "日历选择-popup",
			"uv-toolbar
Ox## Calendars 全新日历

> **组件名：uv-calendars**

为了解决老版本`uv-calendar`性能问题，特别是对日期选择范围有很大限制，体验不友好等缺点。于是有了新版日历组件。

新版本`uv-calendars`，不仅拥有老版本的所有功能，还增加了更加适用的插入页面等强大功能，且更加简洁。查看日期、选择单个或多个或任意范围日期，打点操作，自定义文案，自定义主题等强大功能。

常用场景：酒店日期预订、火车机票选择购买日期、上下班打卡等。

# <a href="https://www.uvui.cn/components/calendars.html" target="_blank">查看文档</a>

## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>（请不要 下载插件ZIP）</small>

### [更多插件，请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)

<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">

![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)

</a>

#### 如使用过程中有任何问题反馈，或者您对uv-ui有一些好的建议，欢迎加入uv-ui官方交流群：<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>3˶2	x e100644 changelog.md Baͻ	C}Q+40000 components I.pHAeRr100644 package.json f_T>,$bt0100644 readme.md >sL2:>+oei!X=O x## 1.0.5（2023-12-06）
1. 修复uv-cell right-icon插槽编译到APP端不显示的BUG，问题来源：https://gitee.com/climblee/uv-ui/issues/I8LXZI
## 1.0.4（2023-09-19）
1. 增加cellStyle参数，方便自定义单元格的样式
## 1.0.3（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.2（2023-06-21）
1. 优化
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-cell 单元格
]xJ 40000 uv-cell-group ;*lo~-2FR_o40000 uv-cell !CM0u.>}xQ 100644 props.js W޴i'4>[7a)100644 uv-cell-group.vue SF3
LVT%	<R6UxF  分组标题,6X边框
		bord($truecellGroup
	}
}p˾xxq<template>
    <view :style="[$uv.addStyle(customStyle)]" :class="[customClass]" class="uv-cell-group">
        <view v-if="title" class="uv-cell-group__title">
            <slot name="title">
				<text class="uv-cell-group__title__text">{{ title }}</text>
			</slot>
        </view>
        <view class="uv-cell-group__wrapper">
			<uv-line v-if="border"></uv-line>
            <slot />
        </view>
    </view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * cellGroup  单元格
	 * @description cell单元格一般用于一组列表的情况，比如个人中心页，设置页等。
	 * @tutorial https://www.uvui.cn/components/cell.html
	 * 
	 * @property {String}	title		分组标题
	 * @property {Boolean}	border		是否显示外边框 (默认 true )
	 * @property {Object}	customStyle	定义需要用到的外部样式
	 * 
	 * @event {Function} click 	点击cell列表时触发
	 * @example <uv-cell-group title="设置喜好">
	 */
	export default {
		name: 'uv-cell-group',
		mixins: [mpMixin, mixin, props]
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-cell-group-title-padding: 16px 16px 8px !default;
	$uv-cell-group-title-font-size: 15px !default;
	$uv-cell-group-title-line-height: 16px !default;
	$uv-cell-group-title-color: $uv-main-color !default;

    .uv-cell-group {
		flex: 1;
		
        &__title {
            padding: $uv-cell-group-title-padding;

            &__text {
                font-size: $uv-cell-group-title-font-size;
                line-height: $uv-cell-group-title-line-height;
                color: $uv-cell-group-title-color;
            }
        }
		
		&__wrapper {
			position: relative;
		}
    }
</style>

fxK 100644 props.js eycafp?;3ԯ0100644 uv-cell.vue hsJAQbk!yx>export default {
	props: {
		// 标题
		title: {
			type: [String, Number],
			default: ''
		},
		// 标题下方的描述信息
		label: {
			type: [String, Number],
			default: ''
		},
		// 右侧的内容
		value: {
			type: [String, Number],
			default: ''
		},
		// 左侧图标名称，或者图片链接(本地文件建议使用绝对地址)
		icon: {
			type: String,
			default: ''
		},
		// 是否禁用cell
		disabled: {
			type: Boolean,
			default: false
		},
		// 是否显示下边框
		border: {
			type: Boolean,
			default: true
		},
		// 内容是否垂直居中(主要是针对右侧的value部分)
		center: {
			type: Boolean,
			default: true
		},
		// 点击后跳转的URL地址
		url: {
			type: String,
			default: ''
		},
		// 链接跳转的方式，内部使用的是uvui封装的route方法，可能会进行拦截操作
		linkType: {
			type: String,
			default: 'navigateTo'
		},
		// 是否开启点击反馈(表现为点击时加上灰色背景)
		clickable: {
			type: Boolean,
			default: false
		},
		// 是否展示右侧箭头并开启点击反馈
		isLink: {
			type: Boolean,
			default: false
		},
		// 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件)
		required: {
			type: Boolean,
			default: false
		},
		// 右侧的图标箭头
		rightIcon: {
			type: String,
			default: 'arrow-right'
		},
		// 右侧箭头的方向，可选值为：left，up，down
		arrowDirection: {
			type: String,
			default: ''
		},
		// 左侧图标样式
		iconStyle: {
			type: [Object, String],
			default: () => {
				return {}
			}
		},
		// 右侧箭头图标的样式
		rightIconStyle: {
			type: [Object, String],
			default: () => {
				return {}
			}
		},
		// 标题的样式
		titleStyle: {
			type: [Object, String],
			default: () => {
				return {}
			}
		},
		// 单位元的大小，可选值为large
		size: {
			type: String,
			default: ''
		},
		// 点击cell是否阻止事件传播
		stop: {
			type: Boolean,
			default: true
		},
		// 标识符，cell被点击时返回
		name: {
			type: [Number, String],
			default: ''
		},
		// 单元格自定义样式
		cellStyle: {
			type: [Object, String],
			default: () => {}
		},
		...uni.$uv?.props?.cell
	}
}x~<template>
	<view class="uv-cell" :class="[customClass]" :style="[$uv.addStyle(customStyle)]"
		:hover-class="(!disabled && (clickable || isLink)) ? 'uv-cell--clickable' : ''" :hover-stay-time="250"
		@click="clickHandler">
		<view class="uv-cell__body" 
			:class="[ center && 'uv-cell--center', size === 'large' && 'uv-cell__body--large']"
			:style="[cellStyle]"
		>
			<view class="uv-cell__body__content">
				<view class="uv-cell__left-icon-wrap">
					<slot name="icon">
						<uv-icon v-if="icon" :name="icon" :custom-style="iconStyle" :size="size === 'large' ? 22 : 18"></uv-icon>
					</slot>
				</view>
				<view class="uv-cell__title">
					<slot name="title">
						<text v-if="title" class="uv-cell__title-text" :style="[titleTextStyle]"
							:class="[disabled && 'uv-cell--disabled', size === 'large' && 'uv-cell__title-text--large']">{{ title }}</text>
					</slot>
					<slot name="label">
						<text class="uv-cell__label" v-if="label"
							:class="[disabled && 'uv-cell--disabled', size === 'large' && 'uv-cell__label--large']">{{ label }}</text>
					</slot>
				</view>
			</view>
			<slot name="value">
				<text class="uv-cell__value"
					:class="[disabled && 'uv-cell--disabled', size === 'large' && 'uv-cell__value--large']"
					v-if="!$uv.test.empty(value)">{{ value }}</text>
			</slot>
			<view class="uv-cell__right-icon-wrap"
				:class="[`uv-cell__right-icon-wrap--${arrowDirection}`]">
				<slot name="right-icon">
					<uv-icon v-if="isLink" :name="rightIcon" :custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'"
						:size="size === 'large' ? 18 : 16"></uv-icon>
				</slot>
			</view>
		</view>
		<uv-line v-if="border"></uv-line>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * cell  单元格
	 * @description cell单元格一般用于一组列表的情况，比如个人中心页，设置页等。
	 * @tutorial https://www.uvui.cn/components/cell.html
	 * @property {String | Number}	title			标题
	 * @property {String | Number}	label			标题下方的描述信息
	 * @property {String | Number}	value			右侧的内容
	 * @property {String}			icon			左侧图标名称，或者图片链接(本地文件建议使用绝对地址)
	 * @property {Boolean}			disabled		是否禁用cell	
	 * @property {Boolean}			border			是否显示下边框 (默认 true )
	 * @property {Boolean}			center			内容是否垂直居中(主要是针对右侧的value部分) (默认 false )
	 * @property {String}			url				点击后跳转的URL地址
	 * @property {String}			linkType		链接跳转的方式，内部使用的是uvui封装的route方法，可能会进行拦截操作 (默认 'navigateTo' )
	 * @property {Boolean}			clickable		是否开启点击反馈(表现为点击时加上灰色背景) （默认 false ） 
	 * @property {Boolean}			isLink			是否展示右侧箭头并开启点击反馈 （默认 false ）
	 * @property {Boolean}			required		是否显示表单状态下的必填星号(此组件可能会内嵌入input组件) （默认 false ）
	 * @property {String}			rightIcon		右侧的图标箭头 （默认 'arrow-right'）
	 * @property {String}			arrowDirection	右侧箭头的方向，可选值为：left，up，down
	 * @property {Object | String}			rightIconStyle	右侧箭头图标的样式
	 * @property {Object | String}			titleStyle		标题的样式
	 * @property {Object | String}			iconStyle		左侧图标样式
	 * @property {String}			size			单位元的大小，可选值为 large，normal，mini 
	 * @property {Boolean}			stop			点击cell是否阻止事件传播 (默认 true )
	 * @property {Object | String}  cellStyle 单元格自定义样式
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 * 
	 * @event {Function}			click			点击cell列表时触发
	 * @example 该组件需要搭配cell-group组件使用，见官方文档示例
	 */
	export default {
		name: 'uv-cell',
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		computed: {
			titleTextStyle() {
				return this.$uv.addStyle(this.titleStyle)
			}
		},
		methods: {
			// 点击cell
			clickHandler(e) {
				if (this.disabled) return
				this.$emit('click', {
					name: this.name
				})
				// 如果配置了url(此props参数通过mixin引入)参数，跳转页面
				this.openPage()
				// 是否阻止事件传播
				this.stop && this.preventEvent(e)
			},
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-cell-padding: 10px 15px !default;
	$uv-cell-font-size: 15px !default;
	$uv-cell-line-height: 24px !default;
	$uv-cell-color: $uv-main-color !default;
	$uv-cell-icon-size: 16px !default;
	$uv-cell-title-font-size: 15px !default;
	$uv-cell-title-line-height: 22px !default;
	$uv-cell-title-color: $uv-main-color !default;
	$uv-cell-label-font-size: 12px !default;
	$uv-cell-label-color: $uv-tips-color !default;
	$uv-cell-label-line-height: 18px !default;
	$uv-cell-value-font-size: 14px !default;
	$uv-cell-value-color: $uv-content-color !default;
	$uv-cell-clickable-color: $uv-bg-color !default;
	$uv-cell-disabled-color: #c8c9cc !default;
	$uv-cell-padding-top-large: 13px !default;
	$uv-cell-padding-bottom-large: 13px !default;
	$uv-cell-value-font-size-large: 15px !default;
	$uv-cell-label-font-size-large: 14px !default;
	$uv-cell-title-font-size-large: 16px !default;
	$uv-cell-left-icon-wrap-margin-right: 4px !default;
	$uv-cell-right-icon-wrap-margin-left: 4px !default;
	$uv-cell-title-flex: 1 !default;
	$uv-cell-label-margin-top: 5px !default;
	.uv-cell {
		&__body {
			@include flex();
			/* #ifndef APP-NVUE */
			box-sizing: border-box;
			/* #endif */
			padding: $uv-cell-padding;
			font-size: $uv-cell-font-size;
			color: $uv-cell-color;
			&__content {
				@include flex(row);
				align-items: center;
				flex: 1;
			}
			&--large {
				padding-top: $uv-cell-padding-top-large;
				padding-bottom: $uv-cell-padding-bottom-large;
			}
		}
		&__left-icon-wrap,
		&__right-icon-wrap {
			@include flex();
			align-items: center;
			// height: $uv-cell-line-height;
			font-size: $uv-cell-icon-size;
		}
		&__left-icon-wrap {
			margin-right: $uv-cell-left-icon-wrap-margin-right;
		}
		&__right-icon-wrap {
			margin-left: $uv-cell-right-icon-wrap-margin-left;
			transition: transform 0.3s;
			&--up {
				transform: rotate(-90deg);
			}
			&--down {
				transform: rotate(90deg);
			}
		}
		&__title {
			flex: $uv-cell-title-flex;
			&-text {
				font-size: $uv-cell-title-font-size;
				line-height: $uv-cell-title-line-height;
				color: $uv-cell-title-color;
				&--large {
					font-size: $uv-cell-title-font-size-large;
				}
			}
		}
		&__label {
			margin-top: $uv-cell-label-margin-top;
			font-size: $uv-cell-label-font-size;
			color: $uv-cell-label-color;
			line-height: $uv-cell-label-line-height;
			&--large {
				font-size: $uv-cell-label-font-size-large;
			}
		}
		&__value {
			text-align: right;
			font-size: $uv-cell-value-font-size;
			line-height: $uv-cell-line-height;
			color: $uv-cell-value-color;
			&--large {
				font-size: $uv-cell-value-font-size-large;
			}
		}
		&--clickable {
			background-color: $uv-cell-clickable-color;
		}
		&--disabled {
			color: $uv-cell-disabled-color;
			/* #ifndef APP-NVUE */
			cursor: not-allowed;
			/* #endif */
		}
		&--center {
			align-items: center;
		}
	}
</style>xJ={
  "id": "uv-toast",
  "displayName": "uv-toast 消息提示9J3",
  "description": "Toast 组件主要用于消息通知、加载提示、操作结果提示等醒目提示效果，我们为其提供了多种丰富的APIytoast!toast",
    "消息提示3,
			"uv-overlay",
			"uv-loading-icon",
			"uv-gap
9_Zx 2{
  "id": "uv-notify",
  "displayName": "uv-notify0muv-notify 该组件一般用于页面顶部向下滑出一个提示，后自动收起的场景。",
  "keywords": [
    "uv-notifyG!notifym
status-bar_
transition
po?|x 8{
  "id": "uv-cell",
  "displayName": "uv-cell 单元格@Ik5",
  "description": "cell单元格一般用于一组列表的情况，比如个人中心页，设置页等cell!!单元格",
    "设置页\icon",
			"uv-lines
;xt&Ox @## SwipeAction 滑动单元格 wipe-action**

该组件一般用于左滑唤出操作菜单的场景，用的最多的是左滑删除操作。

### <a href="h
wipeActionZng!Ox |## Cell 单元格]cell**

cell单元格一般用于一组列表的情况，比如个人中心页，设置页等1cellݥrM	x e100644 changelog.md *,~m5^u_k*40000 components L+s
xFD--l100644 package.json DMZ_wV CyR)100644 readme.md C%PF=dYyDT:
9Ox## 1.0.14（2023-11-04）
1. 修复label文字较多不分行的问题
## 1.0.13（2023-10-11）
1. 优化同类问题：https://gitee.com/climblee/uv-ui/issues/I872VD
## 1.0.12（2023-09-22）
1. 修复change回调中v-model值不更新的BUG
## 1.0.11（2023-09-01）
1. 修复点击空隙处无效的问题
2. label支持插槽下可点击
## 1.0.10（2023-08-27）
1. 修复label设置布尔值不生效的BUG
## 1.0.9（2023-08-16）
1. 解决数据多不换行的BUG
## 1.0.8（2023-07-13）
1. 修复  uv-checkbox设置value属性不生效的BUG
## 1.0.7（2023-07-05）
修复vue3模式下，动态修改v-model绑定的值无效的BUG
## 1.0.6（2023-06-29）
1. 增加label插槽，与radio保持一致
2. 优化文档
## 1.0.5（2023-06-12）
1. 修复1.0.4改出的问题
## 1.0.4（2023-06-08）
1. 复选框修复全局设置不生效的BUG
## 1.0.3（2023-06-06）
1. uv-checkbox-group 兼容自定义样式customStyle，方便通过样式调整整体位置等；
2. .uv-checkbox-group--row增加flex-wrap: wrap;允许换行
## 1.0.2（2023-05-30）
1. 修复error报错的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-checkbox 复选框
tv9xR 40000 uv-checkbox-group ~Qx!#"ĭ[40000 uv-checkbox i3T׫u)8-y_xU 100644 props.js G S oƧ;\H"100644 uv-checkbox-group.vue bB<ARCH4$!g`xexport default {
	props: {
		// 绑定的值
		value: {
			type: Array,
			default: () => []
		},
		modelValue: {
			type: Array,
			default: () => []
		},
		// 标识符
		name: {
			type: String,
			default: ''
		},
		// 形状，circle-圆形，square-方形
		shape: {
			type: String,
			default: 'square'
		},
		// 是否禁用全部checkbox
		disabled: {
			type: Boolean,
			default: false
		},
		// 选中状态下的颜色，如设置此值，将会覆盖parent的activeColor值
		activeColor: {
			type: String,
			default: '#2979ff'
		},
		// 未选中的颜色
		inactiveColor: {
			type: String,
			default: '#c8c9cc'
		},
		// 整个组件的尺寸，默认px
		size: {
			type: [String, Number],
			default: 18
		},
		// 布局方式，row-横向，column-纵向
		placement: {
			type: String,
			default: 'row'
		},
		// label的字体大小，px单位
		labelSize: {
			type: [String, Number],
			default: 14
		},
		// label的字体颜色
		labelColor: {
			type: [String],
			default: '#303133'
		},
		// 是否禁止点击文本操作
		labelDisabled: {
			type: Boolean,
			default: false
		},
		// 图标颜色
		iconColor: {
			type: String,
			default: '#fff'
		},
		// 图标的大小，单位px
		iconSize: {
			type: [String, Number],
			default: 12
		},
		// 勾选图标的对齐方式，left-左边，right-右边
		iconPlacement: {
			type: String,
			default: 'left'
		},
		// 竖向配列时，是否显示下划线
		borderBottom: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.checkboxGroup
	}
}VwxM<template>
	<view
	    class="uv-checkbox-group"
	    :class="bemClass"
			:style="[$uv.addStyle(this.customStyle)]"
	>
		<slot></slot>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * checkboxGroup 复选框组
	 * @description 复选框组件一般用于需要多个选择的场景，该组件功能完整，使用方便
	 * @tutorial https://www.uvui.cn/components/checkbox.html
	 * @property {String}			name			标识符 
	 * @property {Array}			value			绑定的值
	 * @property {String}			shape			形状，circle-圆形，square-方形 （默认 'square' ）
	 * @property {Boolean}			disabled		是否禁用全部checkbox （默认 false ）
	 * @property {String}			activeColor		选中状态下的颜色，如设置此值，将会覆盖parent的activeColor值 （默认 '#2979ff' ）
	 * @property {String}			inactiveColor	未选中的颜色 （默认 '#c8c9cc' ）
	 * @property {String | Number}	size			整个组件的尺寸 单位px （默认 18 ）
	 * @property {String}			placement		布局方式，row-横向，column-纵向 （默认 'row' ）
	 * @property {String | Number}	labelSize		label的字体大小，px单位  （默认 14 ）
	 * @property {String}			labelColor		label的字体颜色 （默认 '#303133' ）
	 * @property {Boolean}			labelDisabled	是否禁止点击文本操作 (默认 false )
	 * @property {String}			iconColor		图标颜色 （默认 '#ffffff' ）
	 * @property {String | Number}	iconSize		图标的大小，单位px （默认 12 ）
	 * @property {String}			iconPlacement	勾选图标的对齐方式，left-左边，right-右边  （默认 'left' ）
	 * @property {Boolean}			borderBottom	placement为row时，是否显示下边框 （默认 false ）
	 * @event {Function}	change	任一个checkbox状态发生变化时触发，回调为一个对象
	 * @event {Function}	input	修改通过v-model绑定的值时触发，回调为一个对象
	 * @example <uv-checkbox-group></uv-checkbox-group>
	 */
	export default {
		name: 'uv-checkbox-group',
		mixins: [mpMixin, mixin, props],
		computed: {
			// 这里computed的变量，都是子组件uv-checkbox需要用到的，由于头条小程序的兼容性差异，子组件无法实时监听父组件参数的变化
			// 所以需要手动通知子组件，这里返回一个parentData变量，供watch监听，在其中去通知每一个子组件重新从父组件(uv-checkbox-group)
			// 拉取父组件新的变化后的参数
			parentData() {
				let value = [];
				if(this.value.length) {
					value  = this.value;
				} else if (this.modelValue.length){
					value = this.modelValue;
				}
				return [value, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
					this.iconSize, this.borderBottom, this.placement, this.labelSize, this.labelColor]
			},
			bemClass() {
				// this.bem为一个computed变量，在mixin中
				return this.bem('checkbox-group', ['placement'])
			},
		},
		watch: {
			// 当父组件需要子组件需要共享的参数发生了变化，手动通知子组件
			parentData() {
				if (this.children.length) {
					this.children.map(child => {
						// 判断子组件(uv-checkbox)如果有init方法的话，就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
						typeof(child.init) === 'function' && child.init()
					})
				}
			},
		},
		data() {
			return {

			}
		},
		created() {
			this.children = []
		},
		methods: {
			// 将其他的checkbox设置为未选中的状态
			unCheckedOther(childInstance) {
				const values = []
				this.children.map(child => {
					// 将被选中的checkbox，放到数组中返回
					if (child.isChecked) {
						values.push(child.name)
					}
				})
				// 修改通过v-model绑定的值
				// #ifdef VUE2
				this.$emit('input', values)
				// #endif
				// #ifdef VUE3
				this.$emit('update:modelValue',values)
				// #endif
				// 发出事件
				this.$emit('change', values)
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';

	.uv-checkbox-group {
		flex: 1;
		
		&--row {
			@include flex;
			flex-wrap: wrap;
		}

		&--column {
			@include flex(column);
		}
	}
</style>
CxO 100644 props.js X6;/KtC100644 uv-checkbox.vue ё(|~#Zn$Wp0 _Sx3export default {
	props: {
		// checkbox的名称
		name: {
			type: [String, Number, Boolean],
			default: ''
		},
		// 形状，square为方形，circle为圆型
		shape: {
			type: String,
			default: ''
		},
		// 整体的大小
		size: {
			type: [String, Number],
			default: ''
		},
		// 是否默认选中
		checked: {
			type: Boolean,
			default: false
		},
		// 是否禁用
		disabled: {
			type: [String, Boolean],
			default: ''
		},
		// 选中状态下的颜色，如设置此值，将会覆盖parent的activeColor值
		activeColor: {
			type: String,
			default: ''
		},
		// 未选中的颜色
		inactiveColor: {
			type: String,
			default: ''
		},
		// 图标的大小，单位px
		iconSize: {
			type: [String, Number],
			default: ''
		},
		// 图标颜色
		iconColor: {
			type: String,
			default: ''
		},
		// label提示文字，因为nvue下，直接slot进来的文字，由于特殊的结构，无法修改样式
		label: {
			type: [String, Number, Boolean],
			default: ''
		},
		// label的字体大小，px单位
		labelSize: {
			type: [String, Number],
			default: ''
		},
		// label的颜色
		labelColor: {
			type: String,
			default: ''
		},
		// 是否禁止点击提示语选中复选框
		labelDisabled: {
			type: [String, Boolean],
			default: ''
		},
		...uni.$uv?.props?.checkbox
	}
}ܶx19<template>
	<view
	  class="uv-checkbox"
	  :style="[checkboxStyle]"
	  @tap.stop="wrapperClickHandler"
	  :class="[`uv-checkbox-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'uv-border-bottom']"
	>
		<view
		  class="uv-checkbox__icon-wrap"
		  @tap.stop="iconClickHandler"
		  :class="iconClasses"
		  :style="[iconWrapStyle]"
		>
			<slot name="icon">
				<uv-icon
				  class="uv-checkbox__icon-wrap__icon"
				  name="checkbox-mark"
				  :size="elIconSize"
				  :color="elIconColor"
				/>
			</slot>
		</view>
		<view 
			class="uv-checkbox__label-wrap" 
			@tap.stop="labelClickHandler">
			<slot>
				<text
				  :style="{
						color: elDisabled ? elInactiveColor : elLabelColor,
						fontSize: elLabelSize,
						lineHeight: elLabelSize
					}"
				>{{label}}</text>
			</slot>
		</view>
		
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * checkbox  复选框
	 * @description 复选框组件一般用于需要多个选择的场景，该组件功能完整，使用方便
	 * @tutorial https://www.uvui.cn/components/checkbox.html
	 * @property {String | Number | Boolean}	name			checkbox组件的标示符
	 * @property {String}						shape			形状，square为方形，circle为圆型
	 * @property {String | Number}				size			整体的大小
	 * @property {Boolean}						checked			是否默认选中
	 * @property {String | Boolean}				disabled		是否禁用
	 * @property {String}						activeColor		选中状态下的颜色，如设置此值，将会覆盖parent的activeColor值
	 * @property {String}						inactiveColor	未选中的颜色
	 * @property {String | Number}				iconSize		图标的大小，单位px
	 * @property {String}						iconColor		图标颜色
	 * @property {String | Number}				label			label提示文字，因为nvue下，直接slot进来的文字，由于特殊的结构，无法修改样式
	 * @property {String}						labelColor 		label的颜色
	 * @property {String | Number}				labelSize		label的字体大小，px单位
	 * @property {String | Boolean}				labelDisabled	是否禁止点击提示语选中复选框
	 * @property {Object}						customStyle		定义需要用到的外部样式
	 * 
	 * @event {Function}	change	任一个checkbox状态发生变化时触发，回调为一个对象
	 * @example <uv-checkbox v-model="checked" :disabled="false">天涯</uv-checkbox>
	 */
	export default {
		name: "uv-checkbox",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				isChecked: false,
				// 父组件的默认值，因为头条小程序不支持在computed中使用this.parent.shape的形式
				// 故只能使用如此方法
				parentData: {
					iconSize: 12,
					labelDisabled: null,
					disabled: null,
					shape: 'square',
					activeColor: null,
					inactiveColor: null,
					size: 18,
					value: null,
					modelValue: null,
					iconColor: null,
					placement: 'row',
					borderBottom: false,
					iconPlacement: 'left',
					labelSize: 14,
					labelColor: '#303133'
				}
			}
		},
		computed: {
			// 是否禁用，如果父组件uv-raios-group禁用的话，将会忽略子组件的配置
			elDisabled() {
				return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
			},
			// 是否禁用label点击
			elLabelDisabled() {
				return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
					false;
			},
			// 组件尺寸，对应size的值，默认值为21px
			elSize() {
				return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
			},
			// 组件的勾选图标的尺寸，默认12px
			elIconSize() {
				return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
			},
			// 组件选中激活时的颜色
			elActiveColor() {
				return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
			},
			// 组件选未中激活时的颜色
			elInactiveColor() {
				return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
					'#c8c9cc');
			},
			// label的颜色
			elLabelColor() {
				return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
			},
			// 组件的形状
			elShape() {
				return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
			},
			// label大小
			elLabelSize() {
				return this.$uv.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
					'15'))
			},
			elIconColor() {
				const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
					'#ffffff');
				// 图标的颜色
				if (this.elDisabled) {
					// disabled状态下，已勾选的checkbox图标改为elInactiveColor
					return this.isChecked ? this.elInactiveColor : 'transparent'
				} else {
					return this.isChecked ? iconColor : 'transparent'
				}
			},
			iconClasses() {
				let classes = []
				// 组件的形状
				classes.push('uv-checkbox__icon-wrap--' + this.elShape)
				if (this.elDisabled) {
					classes.push('uv-checkbox__icon-wrap--disabled')
				}
				if (this.isChecked && this.elDisabled) {
					classes.push('uv-checkbox__icon-wrap--disabled--checked')
				}
				// 支付宝，头条小程序无法动态绑定一个数组类名，否则解析出来的结果会带有","，而导致失效
				// #ifdef MP-ALIPAY || MP-TOUTIAO
				classes = classes.join(' ')
				// #endif
				return classes
			},
			iconWrapStyle() {
				// checkbox的整体样式
				const style = {}
				style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff'
				style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
				style.width = this.$uv.addUnit(this.elSize)
				style.height = this.$uv.addUnit(this.elSize)
				// 如果是图标在右边的话，移除它的右边距
				if (this.parentData.iconPlacement === 'right') {
					style.marginRight = 0
				}
				return style
			},
			checkboxStyle() {
				const style = {}
				if (this.parentData.borderBottom && this.parentData.placement === 'row') {
					this.$uv.error('检测到您将borderBottom设置为true，需要同时将uv-checkbox-group的placement设置为column才有效')
				}
				// 当父组件设置了显示下边框并且排列形式为纵向时，给内容和边框之间加上一定间隔
				if (this.parentData.borderBottom && this.parentData.placement === 'column') {
					style.paddingBottom = '8px'
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		created() {
			this.init()
		},
		methods: {
			init() {
				// 支付宝小程序不支持provide/inject，所以使用这个方法获取整个父组件，在created定义，避免循环引用
				this.updateParentData()
				if (!this.parent) {
					this.$uv.error('uv-checkbox必须搭配uv-checkbox-group组件使用')
				}
				this.$nextTick(()=>{
					let parentValue = [];
					if(this.parentData.value.length) {
						parentValue = this.parentData.value;
					} else if (this.parentData.modelValue.length){
						parentValue = this.parentData.modelValue;
					}
					// 设置初始化时，是否默认选中的状态，父组件uv-checkbox-group的value可能是array，所以额外判断
					if (this.checked) {
						this.isChecked = true
					} else if (this.$uv.test.array(parentValue)) {
						// 查找数组是是否存在this.name元素值
						this.isChecked = parentValue.some(item => {
							return item === this.name
						})
					}
				})
			},
			updateParentData() {
				this.getParentData('uv-checkbox-group')
			},
			// 横向两端排列时，点击组件即可触发选中事件
			wrapperClickHandler(e) {
				this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
			},
			// 点击图标
			iconClickHandler(e) {
				this.preventEvent(e)
				// 如果整体被禁用，不允许被点击
				if (!this.elDisabled) {
					this.setRadioCheckedStatus()
				}
			},
			// 点击label
			labelClickHandler(e) {
				this.preventEvent(e)
				// 如果按钮整体被禁用或者label被禁用，则不允许点击文字修改状态
				if (!this.elLabelDisabled && !this.elDisabled) {
					this.setRadioCheckedStatus()
				}
			},
			emitEvent() {
				this.$emit('change', this.isChecked)
				// 尝试调用uv-form的验证方法，进行一定延迟，否则微信小程序更新可能会不及时
				this.$nextTick(() => {
					this.$uv.formValidate(this, 'change')
				})
			},
			// 改变组件选中状态
			// 这里的改变的依据是，更改本组件的checked值为true，同时通过父组件遍历所有uv-checkbox实例
			// 将本组件外的其他uv-checkbox的checked都设置为false(都被取消选中状态)，因而只剩下一个为选中状态
			setRadioCheckedStatus() {
				// 将本组件标记为与原来相反的状态
				this.isChecked = !this.isChecked
				this.emitEvent()
				typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
			}
		},
		watch:{
			checked(){
				this.isChecked = this.checked
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-border: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-checkbox-label-wrap-padding-right:6px !default;
	$uv-checkbox-icon-wrap-font-size:6px !default;
	$uv-checkbox-icon-wrap-border-width:1px !default;
	$uv-checkbox-icon-wrap-border-color:#c8c9cc !default;
	$uv-checkbox-icon-wrap-icon-line-height:0 !default;
	$uv-checkbox-icon-wrap-circle-border-radius:100% !default;
	$uv-checkbox-icon-wrap-square-border-radius:3px !default;
	$uv-checkbox-icon-wrap-checked-color:#fff !default;
	$uv-checkbox-icon-wrap-checked-background-color:red !default;
	$uv-checkbox-icon-wrap-checked-border-color:#2979ff !default;
	$uv-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default;
	$uv-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
	$uv-checkbox-label-margin-left:5px !default;
	$uv-checkbox-label-margin-right:12px !default;
	$uv-checkbox-label-color:$uv-content-color !default;
	$uv-checkbox-label-font-size:15px !default;
	$uv-checkbox-label-disabled-color:#c8c9cc !default;

	.uv-checkbox {
		/* #ifndef APP-NVUE */
		@include flex(row);
		/* #endif */
		overflow: hidden;
		flex-direction: row;
		align-items: center;

		&-label--left {
			flex-direction: row
		}

		&-label--right {
			flex-direction: row-reverse;
			justify-content: space-between
		}

		&__icon-wrap {
			/* #ifndef APP-NVUE */
			box-sizing: border-box;
			// nvue下，border-color过渡有问题
			transition-property: border-color, background-color, color;
			transition-duration: 0.2s;
			/* #endif */
			color: $uv-content-color;
			@include flex;
			align-items: center;
			justify-content: center;
			color: transparent;
			text-align: center;
			font-size: $uv-checkbox-icon-wrap-font-size;
			border-width: $uv-checkbox-icon-wrap-border-width;
			border-color: $uv-checkbox-icon-wrap-border-color;
			border-style: solid;

			/* #ifdef MP-TOUTIAO */
			// 头条小程序兼容性问题，需要设置行高为0，否则图标偏下
			&__icon {
				line-height: $uv-checkbox-icon-wrap-icon-line-height;
			}

			/* #endif */

			&--circle {
				border-radius: $uv-checkbox-icon-wrap-circle-border-radius;
			}

			&--square {
				border-radius: $uv-checkbox-icon-wrap-square-border-radius;
			}

			&--checked {
				color: $uv-checkbox-icon-wrap-checked-color;
				background-color: $uv-checkbox-icon-wrap-checked-background-color;
				border-color: $uv-checkbox-icon-wrap-checked-border-color;
			}

			&--disabled {
				background-color: $uv-checkbox-icon-wrap-disabled-background-color !important;
			}

			&--disabled--checked {
				color: $uv-checkbox-icon-wrap-disabled-checked-color !important;
			}
		}

		&__label {
			/* #ifndef APP-NVUE */
			word-wrap: break-word;
			/* #endif */
			margin-left: $uv-checkbox-label-margin-left;
			margin-right: $uv-checkbox-label-margin-right;
			color: $uv-checkbox-label-color;
			font-size: $uv-checkbox-label-font-size;

			&--disabled {
				color: $uv-checkbox-label-disabled-color;
			}
		}
		
		&__label-wrap {
			flex: 1;
			padding-left: $uv-checkbox-label-wrap-padding-right;
		}
	}
</style>
UJx @{
  "id": "uv-checkbox",
  "displayName": "uv-checkbox 复选框=H14",
  "description": "复选框组件一般用于需要多个选择的场景，该组件功能完整，使用方便。",
  "keZuv-checkboxo!checkbox",
    "复选框zn9xi## Empty 内容为空

> **组件名：uv-empty**

该组件用于需要加载内容，但是加载的第一页数据就为空，提示一个"没有内容"的场景， 我们精心挑选了十几个场景的图标，方便您使用。

# <a href="https://www.uvui.cn/components/empty.html" target="_blank">查看文档</a>

## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>（请不要 下载插件ZIP）</small>

### [更多插件，请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)

<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">

![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)

</a>

#### 如使用过程中有任何问题反馈，或者您对uv-ui有一些好的建议，欢迎加入uv-ui官方交流群：<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
#x ## Checkbox 复选框

> **组件名：uv-checkbox**

复选框组件一般用于需要多个选择的场景，该组件功能V整，使用方便。可配合 `uv-form` 组件进行表单验证等场景使用。 ,checkboxp2d{Y	x e100644 changelog.md ?_VK:d40000 components IOe8;E100644 package.json bowkm9mH'e100644 readme.md [
k+RD,ǫyL=DxM## 1.0.13（2023-12-06）
1. 优化
## 1.0.12（2023-12-06）
1. 阻止事件冒泡问题
## 1.0.11（2023-11-10）
1. 调整清除按钮样式的marginLeft，避免微信上多数情况触发不了的BUG
## 1.0.10（2023-10-07）
1. 修复搜狗输入法下存在不可清空的情况
## 1.0.9（2023-09-14）
1. 修复H5等情况设置禁用或可读情况下，点击事件无效的问题
## 1.0.8（2023-08-22）
1. 修复无法@keyboardheightchange无法获取键盘高度的BUG
## 1.0.7（2023-08-18）
1. 修复ios端不能输入的BUG
## 1.0.6（2023-08-05）
1. 修复在vue2模式下，v-model设置为0时不生效的BUG
## 1.0.5（2023-07-18）
1. 修复在微信小程序端清除内容存在不能清除的BUG
## 1.0.4（2023-07-13）
1.  修复value/v-model更改不生效的BUG
## 1.0.3（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.2（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.1（2023-05-12）
1. 修复vue3双向绑定的BUG
## 1.0.0（2023-05-10）
uv-input 输入框
'9@Zx -## 1.0.5（2023-08-05）
A>:6-28）
修复：使用:disabledKeyboard="true"属性，事件全部失效的BUG
## 1.0.2（2023-06-23）
优化下边框
## 1.0.1r}(code-input 验证码输入
Q`x( 40000 uv-code-input )F~MYU7thڽ)ġxQ 100644 props.js J^FNl![D100644 uv-code-input.vue ' _(oӠi҆z[.xexport default {
	props: {
		value: {
			type: [String, Number],
			default: ''
		},
		modelValue: {
			type: [String, Number],
			default: ''
		},
		// 输入框类型
		// number-数字输入键盘，app-vue下可以输入浮点数，app-nvue和小程序平台下只能输入整数
		// idcard-身份证输入键盘，微信、支付宝、百度、QQ小程序
		// digit-带小数点的数字键盘，App的nvue页面、微信、支付宝、百度、头条、QQ小程序
		// text-文本输入键盘
		type: {
			type: String,
			default: 'text'
		},
		// 是否禁用输入框
		disabled: {
			type: Boolean,
			default: false
		},
		// 禁用状态时的背景色
		disabledColor: {
			type: String,
			default: '#f5f7fa'
		},
		// 是否显示清除控件
		clearable: {
			type: Boolean,
			default: false
		},
		// 是否密码类型
		password: {
			type: Boolean,
			default: false
		},
		// 最大输入长度，设置为 -1 的时候不限制最大长度
		maxlength: {
			type: [String, Number],
			default: -1
		},
		// 	输入框为空时的占位符
		placeholder: {
			type: String,
			default: null
		},
		// 指定placeholder的样式类，注意页面或组件的style中写了scoped时，需要在类名前写/deep/
		placeholderClass: {
			type: String,
			default: 'input-placeholder'
		},
		// 指定placeholder的样式
		placeholderStyle: {
			type: [String, Object],
			default: 'color: #c0c4cc'
		},
		// 设置右下角按钮的文字，有效值：send|search|next|go|done，兼容性详见uni-app文档
		// https://uniapp.dcloud.io/component/input
		// https://uniapp.dcloud.io/component/textarea
		confirmType: {
			type: String,
			default: 'done'
		},
		// 点击键盘右下角按钮时是否保持键盘不收起，H5无效
		confirmHold: {
			type: Boolean,
			default: false
		},
		// focus时，点击页面的时候不收起键盘，微信小程序有效
		holdKeyboard: {
			type: Boolean,
			default: false
		},
		// 自动获取焦点
		// 在 H5 平台能否聚焦以及软键盘是否跟随弹出，取决于当前浏览器本身的实现。nvue 页面不支持，需使用组件的 focus()、blur() 方法控制焦点
		focus: {
			type: Boolean,
			default: false
		},
		// 键盘收起时，是否自动失去焦点，目前仅App3.0.0+有效
		autoBlur: {
			type: Boolean,
			default: false
		},
		// 指定focus时光标的位置
		cursor: {
			type: [String, Number],
			default: -1
		},
		// 输入框聚焦时底部与键盘的距离
		cursorSpacing: {
			type: [String, Number],
			default: 30
		},
		// 光标起始位置，自动聚集时有效，需与selection-end搭配使用
		selectionStart: {
			type: [String, Number],
			default: -1
		},
		// 光标结束位置，自动聚集时有效，需与selection-start搭配使用
		selectionEnd: {
			type: [String, Number],
			default: -1
		},
		// 键盘弹起时，是否自动上推页面
		adjustPosition: {
			type: Boolean,
			default: true
		},
		// 输入框内容对齐方式，可选值为：left|center|right
		inputAlign: {
			type: String,
			default: 'left'
		},
		// 输入框字体的大小
		fontSize: {
			type: [String, Number],
			default: '14px'
		},
		// 输入框字体颜色
		color: {
			type: String,
			default: '#303133'
		},
		// 输入框前置图标
		prefixIcon: {
			type: String,
			default: ''
		},
		// 前置图标样式，对象或字符串
		prefixIconStyle: {
			type: [String, Object],
			default: ''
		},
		// 输入框后置图标
		suffixIcon: {
			type: String,
			default: ''
		},
		// 后置图标样式，对象或字符串
		suffixIconStyle: {
			type: [String, Object],
			default: ''
		},
		// 边框类型，surround-四周边框，bottom-底部边框，none-无边框
		border: {
			type: String,
			default: 'surround'
		},
		// 是否只读，与disabled不同之处在于disabled会置灰组件，而readonly则不会
		readonly: {
			type: Boolean,
			default: false
		},
		// 输入框形状，circle-圆形，square-方形
		shape: {
			type: String,
			default: 'square'
		},
		// 用于处理或者过滤输入框内容的方法
		formatter: {
			type: [Function, null],
			default: null
		},
		// 是否忽略组件内对文本合成系统事件的处理
		ignoreCompositionEvent: {
			type: Boolean,
			default: true
		},
		...uni.$uv?.props?.input
	}
}O&rxg!)l7'6
		},
		// 是否用圆点填充
		dotN2@显示模式，box-盒子模式，line-底部横线模式
		mode")box'
		},
		// 是否细边框
		hairlineN2字符间的距离
		spac!,10
		},
		// 是否自动获取m@字体是否加粗
		bolM3z7606266'
		},
		// 字体$<418
		},
		// 输入框的大小，宽等于高
		siz!,35
		},
		// 是否隐藏原生键盘，如果想用自定义键盘的话，需设置此参数为true
		disabledKeyboard: {
			|,"框和线条颜色
		borderColor"<#c9cacc'
		},
		// 是否禁止输入"."符号
		disabledDotN"codeInput
	}
}9)x!8<template>
	<view class="uv-code-input">
		<view
			class="uv-code-input__item"
			:style="[itemStyle(index)]"
			v-for="(item, index) in codeLength"
			:key="index"
		>
			<view
				class="uv-code-input__item__dot"
				v-if="dot && codeArray.length > index"
			></view>
			<text
				v-else
				:style="{
					fontSize: $uv.addUnit(fontSize),
					fontWeight: bold ? 'bold' : 'normal',
					color: color
				}"
			>{{codeArray[index]}}</text>
			<view
				class="uv-code-input__item__line"
				v-if="mode === 'line'"
				:style="[lineStyle]"
			></view>
			<!-- #ifndef APP-PLUS -->
			<view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: color}" class="uv-code-input__item__cursor"></view>
			<!-- #endif -->
		</view>
		<input
			:disabled="disabledKeyboard"
			type="number"
			:focus="focus"
			:value="inputValue"
			:maxlength="maxlength"
			:adjustPosition="adjustPosition"
			class="uv-code-input__input"
			@input="inputHandler"
			:style="{
				height: $uv.addUnit(size) 
			}"
			@focus="isFocus = true"
			@blur="isFocus = false"
		/>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * CodeInput 验证码输入
	 * @description 该组件一般用于验证用户短信验证码的场景，也可以结合uvui的键盘组件使用
	 * @tutorial https://www.uvui.cn/components/codeInput.html
	 * @property {String | Number}	value / v-model				预置值
	 * @property {String | Number}	maxlength			最大输入长度 （默认 6 ）
	 * @property {Boolean}			dot					是否用圆点填充 （默认 false ）
	 * @property {String}			mode				显示模式，box-盒子模式，line-底部横线模式 （默认 'box' ）
	 * @property {Boolean}			hairline			是否细边框 （默认 false ）
	 * @property {String | Number}	space				字符间的距离 （默认 10 ）
	 * @property {Boolean}			focus				是否自动获取焦点 （默认 false ）
	 * @property {Boolean}			bold				字体和输入横线是否加粗 （默认 false ）
	 * @property {String}			color				字体颜色 （默认 '#606266' ）
	 * @property {String | Number}	fontSize			字体大小，单位px （默认 18 ）
	 * @property {String | Number}	size				输入框的大小，宽等于高 （默认 35 ）
	 * @property {Boolean}			disabledKeyboard	是否隐藏原生键盘，如果想用自定义键盘的话，需设置此参数为true （默认 false ）
	 * @property {String}			borderColor			边框和线条颜色 （默认 '#c9cacc' ）
	 * @property {Boolean}			disabledDot			是否禁止输入"."符号 （默认 true ）
	 * 
	 * @event {Function}	change	输入内容发生改变时触发，具体见上方说明			value：当前输入的值
	 * @event {Function}	finish	输入字符个数达maxlength值时触发，见上方说明	value：当前输入的值
	 * @example	<uv-code-input v-model="value4" :focus="true"></uv-code-input>
	 */
	export default {
		name: 'uv-code-input',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				inputValue: '',
				isFocus: this.focus
			}
		},
		created() {
			const value = String(this.value) || String(this.modelValue);
			this.inputValue = String(value).substring(0, this.maxlength);
		},
		watch: {
			value(newVal) {
				// 转为字符串，超出部分截掉
				this.inputValue = String(newVal).substring(0, this.maxlength);
				if (this.disabledKeyboard) {
					this.customInput();
				}
			},
			modelValue(newVal) {
				// 转为字符串，超出部分截掉
				this.inputValue = String(newVal).substring(0, this.maxlength);
				if (this.disabledKeyboard) {
					this.customInput();
				}
			}
		},
		computed: {
			// 根据长度，循环输入框的个数，因为头条小程序数值不能用于v-for
			codeLength() {
				return new Array(Number(this.maxlength))
			},
			// 循环item的样式
			itemStyle() {
				return index => {
					const addUnit = this.$uv.addUnit
					const style = {
						width: addUnit(this.size),
						height: addUnit(this.size)
					}
					// 盒子模式下，需要额外进行处理
					if (this.mode === 'box') {
						// 设置盒子的边框，如果是细边框，则设置为0.5px宽度
						style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}`
						// 如果盒子间距为0的话
						if (this.$uv.getPx(this.space) === 0) {
							// 给第一和最后一个盒子设置圆角
							if (index === 0) {
								style.borderTopLeftRadius = '3px'
								style.borderBottomLeftRadius = '3px'
							}
							if (index === this.codeLength.length - 1) {
								style.borderTopRightRadius = '3px'
								style.borderBottomRightRadius = '3px'
							}
							// 最后一个盒子的右边框需要保留
							if (index !== this.codeLength.length - 1) {
								style.borderRight = 'none'
							}
						}
					}
					if (index !== this.codeLength.length - 1) {
						// 设置验证码字符之间的距离，通过margin-right设置，最后一个字符，无需右边框
						style.marginRight = addUnit(this.space)
					} else {
						// 最后一个盒子的有边框需要保留
						style.marginRight = 0
					}
					return style
				}
			},
			// 将输入的值，转为数组，给item历遍时，根据当前的索引显示数组的元素
			codeArray() {
				return String(this.inputValue).split('')
			},
			// 下划线模式下，横线的样式
			lineStyle() {
				const style = {}
				style.height = this.hairline ? '1px' : '4px'
				style.width = this.$uv.addUnit(this.size)
				// 线条模式下，背景色即为边框颜色
				style.backgroundColor = this.borderColor
				return style
			}
		},
		methods: {
			// 监听输入框的值发生变化
			inputHandler(e) {
				const value = e.detail.value
				this.inputValue = value
				// 是否允许输入“.”符号
				if (this.disabledDot) {
					this.$nextTick(() => {
						this.inputValue = value.replace('.', '')
					})
				}
				// 未达到maxlength之前，发送change事件，达到后发送finish事件
				this.$emit('change', value)
				// 修改通过v-model双向绑定的值
				this.$emit('input', value)
				this.$emit('update:modelValue', value)
				// 达到用户指定输入长度时，发出完成事件
				if (String(value).length >= Number(this.maxlength)) {
					this.$emit('finish', value)
				}
			},
			// 自定义键盘输入值监听
			customInput() {
				const value = this.inputValue;
				// 是否允许输入“.”符号
				if (this.disabledDot) {
					this.$nextTick(() => {
						this.inputValue = value.replace('.', '')
					})
				}
				// 未达到maxlength之前，发送change事件，达到后发送finish事件
				this.$emit('change', value)
				// 达到用户指定输入长度时，发出完成事件
				if (String(value).length >= Number(this.maxlength)) {
					this.$emit('finish', value)
				}
			}
		}
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-code-input-cursor-width: 1px;
	$uv-code-input-cursor-height: 40%;
	$uv-code-input-cursor-animation-duration: 1s;
	$uv-code-input-cursor-animation-name: uv-cursor-flicker;
	.uv-code-input {
		@include flex;
		position: relative;
		overflow: hidden;
		&__item {
			@include flex;
			justify-content: center;
			align-items: center;
			position: relative;
			&__text {
				font-size: 15px;
				color: $uv-content-color;
			}
			&__dot {
				width: 7px;
				height: 7px;
				border-radius: 100px;
				background-color: $uv-content-color;
			}
			&__line {
				position: absolute;
				bottom: 0;
				height: 4px;
				border-radius: 100px;
				width: 40px;
				background-color: $uv-content-color;
			}
			/* #ifndef APP-PLUS */
			&__cursor {
				position: absolute;
				top: 50%;
				left: 50%;
				transform: translate(-50%, -50%);
				width: $uv-code-input-cursor-width;
				height: $uv-code-input-cursor-height;
				animation: $uv-code-input-cursor-animation-duration uv-cursor-flicker infinite;
			}
			/* #endif */
		}
		&__input {
			// 之所以需要input输入框，是因为有它才能唤起键盘
			// 这里将它设置为两倍的屏幕宽度，再将左边的一半移出屏幕，为了不让用户看到输入的内容
			position: absolute;
			left: -750rpx;
			width: 1500rpx;
			top: 0;
			background-color: transparent;
			text-align: left;
		}
	}
	/* #ifndef APP-PLUS */
	@keyframes uv-cursor-flicker {
		0% {
			opacity: 0;
		}
		50% {
			opacity: 1;
		}
		100% {
			opacity: 0;
		}
	}
	/* #endif */
</style>N)x J{
  "id": "uv-code-input",
  "displayName": "uv-code-input 验证码输入=^l验证码输入组件一般用于验证用户短信验证码的场景，输入框或横线多种模式可选Ouv-code-inputo!code",
    "验证码输入	u_x## Input 输入框

> **组件名：uv-input**

此组件为一个输入框，默认没有边框和样式，是专门为配合单组件uv-form而设计的，利用它可以快速实现表单验证，输入内容，下拉选择等功能。

# <a href="inputp2d
&x S## CodeInput 验证码	code-input**

该组件一般用于验证用户短信验证码的场景，输入框或横线多种模式可选。

# <a href="hcodeI_`	x e100644 changelog.md pTReFJR˯Q40000 components iihÁܦΈ(U100644 package.json 9,95x5-?"100644 readme.md .;<SQmPNJ ԜP<"x&## 1.0.9（2023-12-06）
1. 优化
## 1.0.8（2023-12-06）
1. 阻止事件冒泡问题
## 1.0.7（2023-10-13）
1. unmounted兼容vue3
## 1.0.6（2023-08-14）
1. 修复初始的时候闪动的BUG
## 1.0.5（2023-06-22）
1. 优化修改
## 1.0.4（2023-06-21）
1. 修复BUG
## 1.0.3（2023-06-01）
1. 修复点击触发两次事件的BUG 
## 1.0.2（2023-05-23）
1. 优化
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-grid 宫格布局
d3x@ ## 1.0.3`优化
## 1.0.2`/code 验证码倒计时
x" 40000 uv-code "v;b#xlP]~rȫxK 100644 props.js Ə}}JN+100644 uv-code.vue =']F/90tZ,x4export default {
	props: {
		// 倒计时总秒数
		seconds: {
			type: [String, Number],
			default: 60
		},
		// 尚未开始时提示
		startText: {
			type: String,
			default: '获取验证码'
		},
		// 正在倒计时中的提示
		changeText: {
			type: String,
			default: 'X秒重新获取'
		},
		// 倒计时结束时的提示
		endText: {
			type: String,
			default: '重新获取'
		},
		// 是否在H5刷新或各端返回再进入时继续倒计时
		keepRunning: {
			type: Boolean,
			default: false
		},
		// 为了区分多个页面，或者一个页面多个倒计时组件本地存储的继续倒计时变了
		uniqueKey: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.code
	}
}hBx<template>
	<view class="uv-code">
		<!-- 此组件功能由js完成，无需写html逻辑 -->
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Code 验证码倒计时
	 * @description 考虑到用户实际发送验证码的场景，可能是一个按钮，也可能是一段文字，提示语各有不同，所以本组件不提供界面显示，只提供倒计时文本，由用户将文本嵌入到具体的场景
	 * @tutorial https://www.uvui.cn/components/code.html
	 * @property {String | Number}	seconds			倒计时所需的秒数（默认 60 ）
	 * @property {String}			startText		开始前的提示语，见官网说明（默认 '获取验证码' ）
	 * @property {String}			changeText		倒计时期间的提示语，必须带有字母"x"，见官网说明（默认 'X秒重新获取' ）
	 * @property {String}			endText			倒计结束的提示语，见官网说明（默认 '重新获取' ）
	 * @property {Boolean}			keepRunning		是否在H5刷新或各端返回再进入时继续倒计时（ 默认false ）
	 * @property {String}			uniqueKey		为了区分多个页面，或者一个页面多个倒计时组件本地存储的继续倒计时变了
	 *
	 * @event {Function}	change	倒计时期间，每秒触发一次
	 * @event {Function}	start	开始倒计时触发
	 * @event {Function}	end		结束倒计时触发
	 * @example <uv-code ref="uCode" @change="codeChange" seconds="20"></uv-code>
	 */
	export default {
		name: "uv-code",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				secNum: this.seconds,
				timer: null,
				canGetCode: true, // 是否可以执行验证码操作
			}
		},
		mounted() {
			this.checkKeepRunning()
		},
		watch: {
			seconds: {
				immediate: true,
				handler(n) {
					this.secNum = n
				}
			}
		},
		methods: {
			checkKeepRunning() {
				// 获取上一次退出页面(H5还包括刷新)时的时间戳，如果没有上次的保存，此值可能为空
				let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp'))
				if (!lastTimestamp) return this.changeEvent(this.startText)
				// 当前秒的时间戳
				let nowTimestamp = Math.floor((+new Date()) / 1000)
				// 判断当前的时间戳，是否小于上一次的本该按设定结束，却提前结束的时间戳
				if (this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
					// 剩余尚未执行完的倒计秒数
					this.secNum = lastTimestamp - nowTimestamp
					// 清除本地保存的变量
					uni.removeStorageSync(this.uniqueKey + '_$uCountDownTimestamp')
					// 开始倒计时
					this.start()
				} else {
					// 如果不存在需要继续上一次的倒计时，执行正常的逻辑
					this.changeEvent(this.startText)
				}
			},
			// 开始倒计时
			start() {
				// 防止快速点击获取验证码的按钮而导致内部产生多个定时器导致混乱
				if (this.timer) {
					clearInterval(this.timer)
					this.timer = null
				}
				this.$emit('start')
				this.canGetCode = false
				// 这里放这句，是为了一开始时就提示，否则要等setInterval的1秒后才会有提示
				this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
				this.timer = setInterval(() => {
					if (--this.secNum) {
						// 用当前倒计时的秒数替换提示字符串中的"x"字母
						this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
					} else {
						clearInterval(this.timer)
						this.timer = null
						this.changeEvent(this.endText)
						this.secNum = this.seconds
						this.$emit('end')
						this.canGetCode = true
					}
				}, 1000)
				this.setTimeToStorage()
			},
			// 重置，可以让用户再次获取验证码
			reset() {
				this.canGetCode = true
				clearInterval(this.timer)
				this.secNum = this.seconds
				this.changeEvent(this.endText)
			},
			changeEvent(text) {
				this.$emit('change', text)
			},
			// 保存时间戳，为了防止倒计时尚未结束，H5刷新或者各端的右上角返回上一页再进来
			setTimeToStorage() {
				if (!this.keepRunning || !this.timer) return
				// 记录当前的时间戳，为了下次进入页面，如果还在倒计时内的话，继续倒计时
				// 倒计时尚未结束，结果大于0；倒计时已经开始，就会小于初始值，如果等于初始值，说明没有开始倒计时，无需处理
				if (this.secNum > 0 && this.secNum <= this.seconds) {
					// 获取当前时间戳(+ new Date()为特殊写法)，除以1000变成秒，再去除小数部分
					let nowTimestamp = Math.floor((+new Date()) / 1000)
					// 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数
					uni.setStorage({
						key: this.uniqueKey + '_$uCountDownTimestamp',
						data: nowTimestamp + Number(this.secNum)
					})
				}
			}
		},
		// #ifdef VUE2
		// 组件销毁的时候，清除定时器，否则定时器会继续存在，系统不会自动清除
		beforeDestroy() {
			this.setTimeToStorage()
			clearTimeout(this.timer)
			this.timer = null
		},
		// #endif
		// #ifdef VUE3
		// 组件销毁，兼容vue3
		unmounted() {
			this.setTimeToStorage()
			clearTimeout(this.timer)
			this.timer = null
		}
		// #endif
	}
</script>f| x 6{
  "id": "uv-gap",
  "displayName": "uv-gap 间隔槽@I1",
  "description": "该组件一般用于内容块之间的用一个灰色块隔开的场景，方便用户风格统一，减少工作量gap!!间隔槽",
    "内容块\t	HbSx"{
  "id": "uv-load-moreload-more 加载更多 6I2uv-load-more 此组件一般用于标识页面底部加载数据时的状态，共有三种状态：加载前、加载中、加载后
uv-load-more(!more",
    "加载更多c#,
			"uv-line",
			"uv-loading-iconA
f]1x 5{
  "id": "uv-line",
  "displayName": "uv-line 线条EJ1in示一根线条，用于分隔内容块，有横向和竖向两种模式，且能设置0.5px线条，使用也很简单。",
0inP"line",
    "线条	'~)xR{
  "id": "uv-codcode 验证码倒计时6I3考虑到用户实际发送验证码的场景，可能是一个按钮，也可能是一段文字，提示语各有不同，所h本组件不提供界面显示，只提供倒计时文本，由用户将文本嵌入到具体的场景,codM"code",
    "验证码倒计时!x-## Code 验证码输入框code**

考虑到用户实际发送验证码的场景，可能是一个按钮，也可能是一段文字，提示语各有不，所以本组件不提供界面显示，只提供倒计时文本，由用户将文本嵌入到具体的场景。

### <a hre"cod֦	x e100644 changelog.md VIN:L40000 components 렜[F(1(	BM'HC100644 package.json ϕe/vY5z➙Bd100644 readme.md 4;̮#Ud<x
## 1.0.2（2023-09-13）
1. 修复全局设置rpx，导致展开高度不对的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-read-more 展开阅读更多
V3x Scollapse 折叠面板
!աxQ 40000 uv-collapse-item 1T6Ne/40000 uv-collapse ÐTaX-4X$ >."JxT 100644 props.js <!.QI100644 uv-collapse-item.vue (*g`e.,wwGP! >xexport default {
	props: {
		// 标题
		title: {
			type: String,
			default: ''
		},
		// 标题右侧内容
		value: {
			type: String,
			default: ''
		},
		// 标题下方的描述信息
		label: {
			type: String,
			default: ''
		},
		// 是否禁用折叠面板
		disabled: {
			type: Boolean,
			default: false
		},
		// 是否展示右侧箭头并开启点击反馈
		isLink: {
			type: Boolean,
			default: true
		},
		// 是否开启点击反馈
		clickable: {
			type: Boolean,
			default: true
		},
		// 是否显示内边框
		border: {
			type: Boolean,
			default: true
		},
		// 标题的对齐方式
		align: {
			type: String,
			default: 'left'
		},
		// 唯一标识符
		name: {
			type: [String, Number],
			default: ''
		},
		// 标题左侧图片，可为绝对路径的图片或内置图标
		icon: {
			type: String,
			default: ''
		},
		// 面板展开收起的过渡时间，单位ms
		duration: {
			type: Number,
			default: 300
		},
		...uni.$uv?.props?.collapseItem
	}
}pTx[<template>
	<view class="uv-collapse-item">
		<uv-cell
			:title="title"
			:value="value"
			:label="label"
			:icon="icon"
			:isLink="isLink"
			:clickable="clickable"
			:border="parentData.border && showBorder"
			@click="clickHandler"
			:arrowDirection="expanded ? 'up' : 'down'"
			:disabled="disabled"
		>
			<!-- #ifndef MP-WEIXIN -->
			<!-- 微信小程序不支持，因为微信中不支持 <slot name="title" slot="title" />的写法 -->
			<template slot="title">
				<slot name="title"></slot>
			</template>
			<template slot="icon">
				<slot name="icon"></slot>
			</template>
			<template slot="value">
				<slot name="value"></slot>
			</template>
			<template slot="right-icon">
				<slot name="right-icon"></slot>
			</template>
			<!-- #endif -->
		</uv-cell>
		<view
			class="uv-collapse-item__content"
			:animation="animationData"
			ref="animation"
		>
			<view
				class="uv-collapse-item__content__text content-class"
				:id="elId"
				:ref="elId"
			><slot /></view>
		</view>
		<uv-line v-if="parentData.border"></uv-line>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const animation = uni.requireNativePlugin('animation')
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * collapseItem 折叠面板Item
	 * @description 通过折叠面板收纳内容区域（搭配uv-collapse使用）
	 * @tutorial https://www.uvui.cn/components/collapse.html
	 * @property {String}			title 		标题
	 * @property {String}			value 		标题右侧内容
	 * @property {String}			label 		标题下方的描述信息
	 * @property {Boolean}			disbled 	是否禁用折叠面板 ( 默认 false )
	 * @property {Boolean}			isLink 		是否展示右侧箭头并开启点击反馈 ( 默认 true )
	 * @property {Boolean}			clickable	是否开启点击反馈 ( 默认 true )
	 * @property {Boolean}			border		是否显示内边框 ( 默认 true )
	 * @property {String}			align		标题的对齐方式 ( 默认 'left' )
	 * @property {String | Number}	name		唯一标识符
	 * @property {String}			icon		标题左侧图片，可为绝对路径的图片或内置图标
	 * @event {Function}			change 			某个item被打开或者收起时触发
	 * @example <uv-collapse-item :title="item.head" v-for="(item, index) in itemList" :key="index">{{item.body}}</uv-collapse-item>
	 */
	export default {
		name: "uv-collapse-item",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				elId: '',
				// uni.createAnimation的导出数据
				animationData: {},
				// 是否展开状态
				expanded: false,
				// 根据expanded确定是否显示border，为了控制展开时，cell的下划线更好的显示效果，进行一定时间的延时
				showBorder: false,
				// 是否动画中，如果是则不允许继续触发点击
				animating: false,
				// 父组件uv-collapse的参数
				parentData: {
					accordion: false,
					border: false
				}
			};
		},
		watch: {
			expanded(n) {
				clearTimeout(this.timer)
				this.timer = null
				// 这里根据expanded的值来进行一定的延时，是为了cell的下划线更好的显示效果
				this.timer = setTimeout(() => {
					this.showBorder = n
				}, n ? 10 : 290)
			}
		},
		created() {
			this.elId = this.$uv.guid();
		},
		mounted() {
			this.init()
		},
		methods: {
			// 异步获取内容，或者动态修改了内容时，需要重新初始化
			init() {
				// 初始化数据
				this.updateParentData()
				if (!this.parent) {
					return this.$uv.error('uv-collapse-item必须要搭配uv-collapse组件使用')
				}
				const {
					value,
					accordion,
					children = []
				} = this.parent

				if (accordion) {
					if (this.$uv.test.array(value)) {
						return this.$uv.error('手风琴模式下，uv-collapse组件的value参数不能为数组')
					}
					this.expanded = this.name == value
				} else {
					if (!this.$uv.test.array(value) && value !== null) {
						return this.$uv.error('非手风琴模式下，uv-collapse组件的value参数必须为数组')
					}
					this.expanded = (value || []).some(item => item == this.name)
				}
				// 设置组件的展开或收起状态
				this.$nextTick(function() {
					this.setContentAnimate()
				})
			},
			updateParentData() {
				// 此方法在mixin中
				this.getParentData('uv-collapse')
			},
			async setContentAnimate() {
				// 每次面板打开或者收起时，都查询元素尺寸
				// 好处是，父组件从服务端获取内容后，变更折叠面板后可以获得最新的高度
				const rect = await this.queryRect()
				const height = this.expanded ? rect.height : 0
				this.animating = true
				// #ifdef APP-NVUE
				const ref = this.$refs['animation'].ref
				animation.transition(ref, {
					styles: {
						height: height + 'px'
					},
					duration: this.duration,
					// 必须设置为true，否则会到面板收起或展开时，页面其他元素不会随之调整它们的布局
					needLayout: true,
					timingFunction: 'ease-in-out',
				}, () => {
					this.animating = false
				})
				// #endif

				// #ifndef APP-NVUE
				const animation = uni.createAnimation({
					timingFunction: 'ease-in-out',
				});
				animation
					.height(height)
					.step({
						duration: this.duration,
					})
					.step()
				// 导出动画数据给面板的animationData值
				this.animationData = animation.export()
				// 标识动画结束
				this.$uv.sleep(this.duration).then(() => {
					this.animating = false
				})
				// #endif
			},
			// 点击collapsehead头部
			clickHandler() {
				if (this.disabled && this.animating) return
				// 设置本组件为相反的状态
				this.parent && this.parent.onChange(this)
			},
			// 查询内容高度
			queryRect() {
				// #ifndef APP-NVUE
				// 组件内部一般用this.$uvGetRect，对外的为getRect，二者功能一致，名称不同
				return new Promise(resolve => {
					this.$uvGetRect(`#${this.elId}`).then(size => {
						resolve(size)
					})
				})
				// #endif

				// #ifdef APP-NVUE
				// nvue下，使用dom模块查询元素高度
				// 返回一个promise，让调用此方法的主体能使用then回调
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs[this.elId], res => {
						resolve(res.size)
					})
				})
				// #endif
			}
		},
	};
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-collapse-item {

		&__content {
			overflow: hidden;
			height: 0;

			&__text {
				padding: 12px 15px;
				color: $uv-content-color;
				font-size: 14px;
				line-height: 18px;
			}
		}
	}
</style>
mxO 100644 props.js pō]#feU100644 uv-collapse.vue ^\ڰ	'# xiexport default {
	props: {
		// 当前展开面板的name，非手风琴模式：[<string | number>]，手风琴模式：string | number
		value: {
			type: [String, Number, Array, null],
			default: null
		},
		// 是否手风琴模式
		accordion: {
			type: Boolean,
			default: false
		},
		// 是否显示外边框
		border: {
			type: Boolean,
			default: true
		},
		...uni.$uv?.props?.collapse
	}
}x<template>
	<view class="uv-collapse">
		<uv-line v-if="border"></uv-line>
		<slot />
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * collapse 折叠面板 
	 * @description 通过折叠面板收纳内容区域
	 * @tutorial https://www.uvui.cn/components/collapse.html
	 * @property {String | Number | Array}	value		当前展开面板的name，非手风琴模式：[<string | number>]，手风琴模式：string | number
	 * @property {Boolean}					accordion	是否手风琴模式（ 默认 false ）
	 * @property {Boolean}					border		是否显示外边框 ( 默认 true ）
	 * @event {Function}	change 		当前激活面板展开时触发(如果是手风琴模式，参数activeNames类型为String，否则为Array)
	 * @example <uv-collapse></uv-collapse>
	 */
	export default {
		name: "uv-collapse",
		mixins: [mpMixin, mixin, props],
		watch: {
			needInit() {
				this.init()
			},
			// 当父组件需要子组件需要共享的参数发生了变化，手动通知子组件
			parentData() {
				if (this.children.length) {
					this.children.map(child => {
						// 判断子组件(uv-checkbox)如果有updateParentData方法的话，就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
						typeof(child.updateParentData) === 'function' && child.updateParentData()
					})
				}
			}
		},
		created() {
			this.children = []
		},
		computed: {
			needInit() {
				// 通过computed，同时监听accordion和value值的变化
				// 再通过watch去执行init()方法，进行再一次的初始化
				return [this.accordion, this.value]
			}
		},
		methods: {
			// 重新初始化一次内部的所有子元素
			init() {
				this.children.map(child => {
					child.init()
				})
			},
			/**
			 * collapse-item被点击时触发，由collapse统一处理各子组件的状态
			 * @param {Object} target 被操作的面板的实例
			 */
			onChange(target) {
				let changeArr = []
				this.children.map((child, index) => {
					// 如果是手风琴模式，将其他的折叠面板收起来
					if (this.accordion) {
						child.expanded = child === target ? !target.expanded : false
						child.setContentAnimate()
					} else {
						if(child === target) {
							child.expanded = !child.expanded
							child.setContentAnimate()
						}
					}
					// 拼接change事件中，数组元素的状态
					changeArr.push({
						// 如果没有定义name属性，则默认返回组件的index索引
						name: child.name || index,
						status: child.expanded ? 'open' : 'close'
					})
				})

				this.$emit('change', changeArr)
				this.$emit(target.expanded ? 'open' : 'close', target.name)
			}
		}
	}
</script>
IߧWExC{
  "id": "uv-collapse",
  "displayName": "uv-collapse 折叠面板FI1折叠面板组件，通过折叠面板收纳内容区域，点击可展开收起，多功能参数可配置。",
  "keywords":=collapsP"collapse",
    "折叠面板cell
w6~	px k## Collapse 折叠面板ccollapse**

通过折叠面板收纳内容区域，点击可展开收起，多功能参数可配置1collapseݥW	x e100644 changelog.md D9,,xTSS7ɛ40000 components ˴@А,'28ݫ5100644 package.json P3/9jK[*Lt100644 readme.md 2jhNQ3ՍÑR<mx## 1.0.3（2023-10-13）
1. unmounted兼容vue3
## 1.0.2（2023-06-20）
1. 增加外部样式customStyle参数
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-count-down 倒计时
4֨x( 40000 uv-count-down Bt_ZCд=4ѥxu 100644 props.js ŵFiIi@8"宊100644 utils.js u PdӆYA0v	gh100644 uv-count-down.vue XF~fW
	c/'x:export default {
	props: {
		// 倒计时时长，单位ms
		time: {
			type: [String, Number],
			default: 0
		},
		// 时间格式，DD-日，HH-时，mm-分，ss-秒，SSS-毫秒
		format: {
			type: String,
			default: 'HH:mm:ss'
		},
		// 是否自动开始倒计时
		autoStart: {
			type: Boolean,
			default: true
		},
		// 是否展示毫秒倒计时
		millisecond: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.countDown
	}
}g@lx8// 补0，如1 -> 01
function padZero(num, targetLength = 2) {
    let str = `${num}`
    while (str.length < targetLength) {
        str = `0${str}`
    }
    return str
}
const SECOND = 1000
const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR
export function parseTimeData(time) {
    const days = Math.floor(time / DAY)
    const hours = Math.floor((time % DAY) / HOUR)
    const minutes = Math.floor((time % HOUR) / MINUTE)
    const seconds = Math.floor((time % MINUTE) / SECOND)
    const milliseconds = Math.floor(time % SECOND)
    return {
        days,
        hours,
        minutes,
        seconds,
        milliseconds
    }
}
export function parseFormat(format, timeData) {
    let {
        days,
        hours,
        minutes,
        seconds,
        milliseconds
    } = timeData
    // 如果格式化字符串中不存在DD(天)，则将天的时间转为小时中去
    if (format.indexOf('DD') === -1) {
        hours += days * 24
    } else {
        // 对天补0
        format = format.replace('DD', padZero(days))
    }
    // 其他同理于DD的格式化处理方式
    if (format.indexOf('HH') === -1) {
        minutes += hours * 60
    } else {
        format = format.replace('HH', padZero(hours))
    }
    if (format.indexOf('mm') === -1) {
        seconds += minutes * 60
    } else {
        format = format.replace('mm', padZero(minutes))
    }
    if (format.indexOf('ss') === -1) {
        milliseconds += seconds * 1000
    } else {
        format = format.replace('ss', padZero(seconds))
    }
    return format.replace('SSS', padZero(milliseconds, 3))
}
export function isSameSecond(time1, time2) {
    return Math.floor(time1 / 1000) === Math.floor(time2 / 1000)
}
q*x$<template>
	<view 
		class="uv-count-down"
		:style="[$uv.addStyle(customStyle)]">
		<slot>
			<text class="uv-count-down__text">{{ formattedTime }}</text>
		</slot>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	import {
		isSameSecond,
		parseFormat,
		parseTimeData
	} from './utils';
	/**
	 * uv-count-down 倒计时
	 * @description 该组件一般使用于某个活动的截止时间上，通过数字的变化，给用户明确的时间感受，提示用户进行某一个行为操作。
	 * @tutorial https://www.uvui.cn/components/countDown.html
	 * @property {String | Number}	time		倒计时时长，单位ms （默认 0 ）
	 * @property {String}			format		时间格式，DD-日，HH-时，mm-分，ss-秒，SSS-毫秒  （默认 'HH:mm:ss' ）
	 * @property {Boolean}			autoStart	是否自动开始倒计时 （默认 true ）
	 * @property {Boolean}			millisecond	是否展示毫秒倒计时 （默认 false ）
	 * @event {Function} finish 倒计时结束时触发 
	 * @event {Function} change 倒计时变化时触发 
	 * @event {Function} start	开始倒计时
	 * @event {Function} pause	暂停倒计时 
	 * @event {Function} reset	重设倒计时，若 auto-start 为 true，重设后会自动开始倒计时 
	 * @example <uv-count-down :time="time"></uv-count-down>
	 */
	export default {
		name: 'uv-count-down',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				timer: null,
				// 各单位(天，时，分等)剩余时间
				timeData: parseTimeData(0),
				// 格式化后的时间，如"03:23:21"
				formattedTime: '0',
				// 倒计时是否正在进行中
				runing: false,
				endTime: 0, // 结束的毫秒时间戳
				remainTime: 0, // 剩余的毫秒时间
			}
		},
		watch: {
			time(n) {
				this.reset()
			}
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				this.reset()
			},
			// 开始倒计时
			start() {
				if (this.runing) return
				// 标识为进行中
				this.runing = true
				// 结束时间戳 = 此刻时间戳 + 剩余的时间
				this.endTime = Date.now() + this.remainTime
				this.toTick()
			},
			// 根据是否展示毫秒，执行不同操作函数
			toTick() {
				if (this.millisecond) {
					this.microTick()
				} else {
					this.macroTick()
				}
			},
			macroTick() {
				this.clearTimeout()
				// 每隔一定时间，更新一遍定时器的值
				// 同时此定时器的作用也能带来毫秒级的更新
				this.timer = setTimeout(() => {
					// 获取剩余时间
					const remain = this.getRemainTime()
					// 重设剩余时间
					if (!isSameSecond(remain, this.remainTime) || remain === 0) {
						this.setRemainTime(remain)
					}
					// 如果剩余时间不为0，则继续检查更新倒计时
					if (this.remainTime !== 0) {
						this.macroTick()
					}
				}, 30)
			},
			microTick() {
				this.clearTimeout()
				this.timer = setTimeout(() => {
					this.setRemainTime(this.getRemainTime())
					if (this.remainTime !== 0) {
						this.microTick()
					}
				}, 50)
			},
			// 获取剩余的时间
			getRemainTime() {
				// 取最大值，防止出现小于0的剩余时间值
				return Math.max(this.endTime - Date.now(), 0)
			},
			// 设置剩余的时间
			setRemainTime(remain) {
				this.remainTime = remain
				// 根据剩余的毫秒时间，得出该有天，小时，分钟等的值，返回一个对象
				const timeData = parseTimeData(remain)
				this.$emit('change', timeData)
				// 得出格式化后的时间
				this.formattedTime = parseFormat(this.format, timeData)
				// 如果时间已到，停止倒计时
				if (remain <= 0) {
					this.pause()
					this.$emit('finish')
				}
			},
			// 重置倒计时
			reset() {
				this.pause()
				this.remainTime = this.time
				this.setRemainTime(this.remainTime)
				if (this.autoStart) {
					this.start()
				}
			},
			// 暂停倒计时
			pause() {
				this.runing = false;
				this.clearTimeout()
			},
			// 清空定时器
			clearTimeout() {
				clearTimeout(this.timer)
				this.timer = null
			}
		},
		// #ifdef VUE2
		beforeDestroy() {
			this.clearTimeout()
		},
		// #endif
		// #ifdef VUE3
		unmounted() {
			this.clearTimeout()
		}
		// #endif
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-count-down-text-color: $uv-content-color !default;
	$uv-count-down-text-font-size: 15px !default;
	$uv-count-down-text-line-height: 22px !default;
	.uv-count-down {
		&__text {
			color: $uv-count-down-text-color;
			font-size: $uv-count-down-text-font-size;
			line-height: $uv-count-down-text-line-height;
		}
	}
</style>:j(x'D{
  "id": "uv-count-down",
  "displayName": "uv-count-down 倒计时@_该倒计时组件一般使用于某个活动的截止时间上，通过数字的变化，给用户明确的时间感受，提#用户进行某一个行为操作
count-down!!countDown",
    "倒计时\t	3x "## CountDown 倒计旑count-down**

该组件一般使用于某个活动的截止时间上，通过数字的变化，给用户明确的时间感受(提示用户进行某一个行为操作1	countDownZ=ܪ	x e100644 changelog.md 2?^Y~_]c340000 components ĀpiZ99壡KE100644 package.json }/xʤ¦p1100644 readme.md ]_aj/|pQ݌MAxj## 1.0.4（2023-06-20）
1. 优化
## 1.0.3（2023-06-20）
1. 修复继续滚动的函数
2. 修复其他
## 1.0.2（2023-06-20）
1. 适配px和rpx的单位
2. 适配customStyle参数
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-count-to 数字滚动
̵ߦx& 40000 uv-count-to jqSl	a*yI|=xO 100644 props.js IqbPߠO\3_p2=100644 uv-count-to.vue _4z醏,j"*kOTHxwexport default {
	props: {
		// 开始的数值，默认从0增长到某一个数
		startVal: {
			type: [String, Number],
			default: 0
		},
		// 要滚动的目标数值，必须
		endVal: {
			type: [String, Number],
			default: 0
		},
		// 滚动到目标数值的动画持续时间，单位为毫秒（ms）
		duration: {
			type: [String, Number],
			default: 2000
		},
		// 设置数值后是否自动开始滚动
		autoplay: {
			type: Boolean,
			default: true
		},
		// 要显示的小数位数
		decimals: {
			type: [String, Number],
			default: 0
		},
		// 是否在即将到达目标数值的时候，使用缓慢滚动的效果
		useEasing: {
			type: Boolean,
			default: true
		},
		// 十进制分割
		decimal: {
			type: [String, Number],
			default: '.'
		},
		// 字体颜色
		color: {
			type: String,
			default: '#606266'
		},
		// 字体大小
		fontSize: {
			type: [String, Number],
			default: 22
		},
		// 是否加粗字体
		bold: {
			type: Boolean,
			default: false
		},
		// 千位分隔符，类似金额的分割(￥23,321.05中的",")
		separator: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.countTo
	}
}ix@<template>
	<text
		class="uv-count-num"
		:style="[{
			fontSize: $uv.addUnit(fontSize),
			fontWeight: bold ? 'bold' : 'normal',
			color: color
		},$uv.addStyle(customStyle)]"
	>{{ displayValue }}</text>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
/**
 * countTo 数字滚动
 * @description 该组件一般用于需要滚动数字到某一个值的场景，目标要求是一个递增的值。
 * @tutorial https://www.uvui.cn/components/countTo.html
 * @property {String | Number}	startVal	开始的数值，默认从0增长到某一个数（默认 0 ）
 * @property {String | Number}	endVal		要滚动的目标数值，必须 （默认 0 ）
 * @property {String | Number}	duration	滚动到目标数值的动画持续时间，单位为毫秒（ms） （默认 2000 ）
 * @property {Boolean}			autoplay	设置数值后是否自动开始滚动 （默认 true ）
 * @property {String | Number}	decimals	要显示的小数位数，见官网说明（默认 0 ）
 * @property {Boolean}			useEasing	滚动结束时，是否缓动结尾，见官网说明（默认 true ）
 * @property {String}			decimal		十进制分割 （ 默认 "." ）
 * @property {String}			color		字体颜色（ 默认 '#606266' )
 * @property {String | Number}	fontSize	字体大小，单位px（ 默认 22 ）
 * @property {Boolean}			bold		字体是否加粗（默认 false ）
 * @property {String}			separator	千位分隔符，见官网说明
 * @event {Function} end 数值滚动到目标值时触发
 * @example <uv-count-to ref="uCountTo" :end-val="endVal" :autoplay="autoplay"></uv-count-to>
 */
export default {
	name: 'uv-count-to',
	data() {
		return {
			localStartVal: this.startVal,
			displayValue: this.formatNumber(this.startVal),
			printVal: null,
			paused: false, // 是否暂停
			localDuration: Number(this.duration),
			startTime: null, // 开始的时间
			timestamp: null, // 时间戳
			remaining: null, // 停留的时间
			rAF: null,
			lastTime: 0 // 上一次的时间
		};
	},
	mixins: [mpMixin, mixin, props],
	computed: {
		countDown() {
			return this.startVal > this.endVal;
		}
	},
	watch: {
		startVal() {
			this.autoplay && this.start();
		},
		endVal() {
			this.autoplay && this.start();
		}
	},
	mounted() {
		this.autoplay && this.start();
	},
	methods: {
		easingFn(t, b, c, d) {
			return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b;
		},
		requestAnimationFrame(callback) {
			const currTime = new Date().getTime();
			// 为了使setTimteout的尽可能的接近每秒60帧的效果
			const timeToCall = Math.max(0, 16 - (currTime - this.lastTime));
			const id = setTimeout(() => {
				callback(currTime + timeToCall);
			}, timeToCall);
			this.lastTime = currTime + timeToCall;
			return id;
		},
		cancelAnimationFrame(id) {
			clearTimeout(id);
		},
		// 开始滚动数字
		start() {
			this.localStartVal = this.startVal;
			this.startTime = null;
			this.localDuration = this.duration;
			this.paused = false;
			this.rAF = this.requestAnimationFrame(this.count);
		},
		// 暂定状态，从暂停状态开始滚动；或者滚动状态下，暂停
		restart() {
			if (this.paused) {
				this.resume();
				this.paused = false;
			} else {
				this.stop();
				this.paused = true;
			}
		},
		// 暂停
		stop() {
			this.cancelAnimationFrame(this.rAF);
			this.paused = true;
		},
		// 重新开始(暂停的情况下)
		resume() {
			if (!this.remaining) return;
			this.startTime = 0;
			this.localDuration = this.remaining;
			this.localStartVal = this.printVal;
			this.requestAnimationFrame(this.count);
		},
		// 重置
		reset() {
			this.startTime = null;
			this.cancelAnimationFrame(this.rAF);
			this.displayValue = this.formatNumber(this.startVal);
		},
		count(timestamp) {
			if (!this.startTime) this.startTime = timestamp;
			this.timestamp = timestamp;
			const progress = timestamp - this.startTime;
			this.remaining = this.localDuration - progress;
			if (this.useEasing) {
				if (this.countDown) {
					this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration);
				} else {
					this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration);
				}
			} else {
				if (this.countDown) {
					this.printVal = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration);
				} else {
					this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration);
				}
			}
			if (this.countDown) {
				this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal;
			} else {
				this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal;
			}
			this.displayValue = this.formatNumber(this.printVal) || 0;
			if (progress < this.localDuration) {
				this.rAF = this.requestAnimationFrame(this.count);
			} else {
				this.$emit('end');
			}
		},
		// 判断是否数字
		isNumber(val) {
			return !isNaN(parseFloat(val));
		},
		formatNumber(num) {
			// 将num转为Number类型，因为其值可能为字符串数值，调用toFixed会报错
			num = Number(num);
			num = num.toFixed(Number(this.decimals));
			num += '';
			const x = num.split('.');
			let x1 = x[0];
			const x2 = x.length > 1 ? `${this.decimal}${x[1]}` : '';
			const rgx = /(\d+)(\d{3})/;
			if (this.separator && !this.isNumber(this.separator)) {
				while (rgx.test(x1)) {
					x1 = x1.replace(rgx, '$1' + this.separator + '$2');
				}
			}
			return x1 + x2;
		},
		destroyed() {
			this.cancelAnimationFrame(this.rAF);
		}
	}
};
</script>

<style lang="scss" scoped>
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

.uv-count-num {
	/* #ifndef APP-NVUE */
	display: inline-flex;
	/* #endif */
	text-align: center;
}
</style>
\x6C{
  "id": "uv-count-to",
  "displayName": "uv-count-to 数字滚动@I4",
  "description": "该数字滚动组件一般用于需要滚动数字到某一个值的场景，目标要求是一个递增0的值，一种数字上升的视觉冲击效果countTo!! 数字滚动",
    "数字变化\t	ժ'x v## CountTo 数字滚动count-to@N需要滚动数字到某一个值的场景，目标要求是一个递增的值1countToݥ{rP	x e100644 changelog.md DxLi@![>a"g0<;40000 components ߤKn2100644 package.json H.+#aEo100644 readme.md A7}{Rc<x- 40000 uv-datetime-picker uxը
M)Lm^[Z,,2e=?xV 100644 props.js `1LQNFũEG100644 uv-datetime-picker.vue E`NrMؐ-c_u"x	export default {
	props: {
		value: {
			type: [String, Number],
			default: ''
		},
		modelValue: {
			type: [String, Number],
			default: ''
		},
		// 是否打开组件
		show: {
			type: Boolean,
			default: false
		},
		// 是否展示顶部的操作栏
		showToolbar: {
			type: Boolean,
			default: true
		},
		// 顶部标题
		title: {
			type: String,
			default: ''
		},
		// 展示格式，mode=date为日期选择，mode=time为时间选择，mode=year-month为年月选择，mode=datetime为日期时间选择
		mode: {
			type: String,
			default: 'datetime'
		},
		// 可选的最大时间
		maxDate: {
			type: Number,
			// 最大默认值为后10年
			default: new Date(new Date().getFullYear() + 10, 0, 1).getTime()
		},
		// 可选的最小时间
		minDate: {
			type: Number,
			// 最小默认值为前10年
			default: new Date(new Date().getFullYear() - 10, 0, 1).getTime()
		},
		// 可选的最小小时，仅mode=time有效
		minHour: {
			type: Number,
			default: 0
		},
		// 可选的最大小时，仅mode=time有效
		maxHour: {
			type: Number,
			default: 23
		},
		// 可选的最小分钟，仅mode=time有效
		minMinute: {
			type: Number,
			default: 0
		},
		// 可选的最大分钟，仅mode=time有效
		maxMinute: {
			type: Number,
			default: 59
		},
		// 选项过滤函数
		filter: {
			type: [Function, null],
			default: null
		},
		// 选项格式化函数
		formatter: {
			type: [Function, null],
			default: null
		},
		// 是否显示加载中状态
		loading: {
			type: Boolean,
			default: false
		},
		// 各列中，单个选项的高度
		itemHeight: {
			type: [String, Number],
			default: 44
		},
		// 取消按钮的文字
		cancelText: {
			type: String,
			default: '取消'
		},
		// 确认按钮的文字
		confirmText: {
			type: String,
			default: '确认'
		},
		// 取消按钮的颜色
		cancelColor: {
			type: String,
			default: '#909193'
		},
		// 确认按钮的颜色
		confirmColor: {
			type: String,
			default: '#3c9cff'
		},
		// 每列中可见选项的数量
		visibleItemCount: {
			type: [String, Number],
			default: 5
		},
		// 是否允许点击遮罩关闭选择器
		closeOnClickOverlay: {
			type: Boolean,
			default: true
		},
		// 是否允许点击确认关闭选择器
		closeOnClickConfirm: {
			type: Boolean,
			default: true
		},
		// 是否清空上次选择内容
		clearDate: {
			type: Boolean,
			default: false
		},
		// 圆角
		round: {
			type: [String, Number],
			default: 0
		},
		...uni.$uv?.props?.datetimePicker
	}
}x3x<template>
	<uv-picker
		ref="picker"
		:closeOnClickOverlay="closeOnClickOverlay"
		:closeOnClickConfirm="closeOnClickConfirm"
		:columns="columns"
		:title="title"
		:itemHeight="itemHeight"
		:showToolbar="showToolbar"
		:visibleItemCount="visibleItemCount"
		:defaultIndex="innerDefaultIndex"
		:cancelText="cancelText"
		:confirmText="confirmText"
		:cancelColor="cancelColor"
		:confirmColor="confirmColor"
		@close="close"
		@cancel="cancel"
		@confirm="confirm"
		@change="change"
		:round="round"
	>
	</uv-picker>
</template>
<script>
	function times(n, iteratee) {
		let index = -1
		const result = Array(n < 0 ? 0 : n)
		while (++index < n) {
			result[index] = iteratee(index)
		}
		return result
	}
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	import dayjs from '@/uni_modules/uv-ui-tools/libs/util/dayjs.js'
	/**
	 * DatetimePicker 时间日期选择器
	 * @description 此选择器用于时间日期
	 * @tutorial https://www.uvui.cn/components/datetimePicker.html
	 * @property {Boolean}			showToolbar			是否显示顶部的操作栏  ( 默认 true )
	 * @property {String | Number}	value				绑定值
	 * @property {String}			title				顶部标题
	 * @property {String}			mode				展示格式 mode=date为日期选择，mode=time为时间选择，mode=year-month为年月选择，mode=datetime为日期时间选择  ( 默认 ‘datetime )
	 * @property {Number}			maxDate				可选的最大时间  默认值为后10年
	 * @property {Number}			minDate				可选的最小时间  默认值为前10年
	 * @property {Number}			minHour				可选的最小小时，仅mode=time有效   ( 默认 0 )
	 * @property {Number}			maxHour				可选的最大小时，仅mode=time有效	  ( 默认 23 )
	 * @property {Number}			minMinute			可选的最小分钟，仅mode=time有效	  ( 默认 0 )
	 * @property {Number}			maxMinute			可选的最大分钟，仅mode=time有效   ( 默认 59 )
	 * @property {Function}			filter				选项过滤函数
	 * @property {Function}			formatter			选项格式化函数
	 * @property {Boolean}			loading				是否显示加载中状态   ( 默认 false )
	 * @property {String | Number}	itemHeight			各列中，单个选项的高度   ( 默认 44 )
	 * @property {String}			cancelText			取消按钮的文字  ( 默认 '取消' )
	 * @property {String}			confirmText			确认按钮的文字  ( 默认 '确认' )
	 * @property {String}			cancelColor			取消按钮的颜色  ( 默认 '#909193' )
	 * @property {String}			confirmColor		确认按钮的颜色  ( 默认 '#3c9cff' )
	 * @property {String | Number}	visibleItemCount	每列中可见选项的数量  ( 默认 5 )
	 * @property {Boolean}			closeOnClickOverlay	是否允许点击遮罩关闭选择器  ( 默认 true )
	 * @property {String | Number}	round	圆角  ( 默认 0 )
	 * @event {Function} close 关闭选择器时触发
	 * @event {Function} confirm 点击确定按钮，返回当前选择的值
	 * @event {Function} change 当选择值变化时触发
	 * @event {Function} cancel 点击取消按钮
	 * @example  <uv-datetime-picker ref="datetimepicker" :value="value1"  mode="datetime" ></uv-datetime-picker>
	 */
	export default {
		name: 'uv-datetime-picker',
		emits: ['close', 'cancel', 'confirm', 'input', 'change', 'update:modelValue'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				columns: [],
				innerDefaultIndex: [],
				innerFormatter: (type, value) => value
			}
		},
		watch: {
			propsChange() {
				this.init()
			}
		},
		computed: {
			// 如果以下这些变量发生了变化，意味着需要重新初始化各列的值
			propsChange() {
				const propsValue = this.value || this.modelValue;
				return [this.mode, this.maxDate, this.minDate, this.minHour, this.maxHour, this.minMinute, this.maxMinute, this.filter, propsValue]
			}
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				this.getValue();
				this.updateColumnValue(this.innerValue)
			},
			getValue() {
				const propsValue = this.value || this.modelValue;
				this.innerValue = this.correctValue(propsValue)
			},
			// 在微信小程序中，不支持将函数当做props参数，故只能通过ref形式调用
			setFormatter(e) {
				this.innerFormatter = e
			},
			open() {
				this.$refs.picker.open();
				this.getValue();
				this.updateColumnValue(this.innerValue);
			},
			close() {
				this.$emit('close');
			},
			// 点击工具栏的取消按钮
			cancel() {
				this.$emit('cancel')
			},
			// 点击工具栏的确定按钮
			confirm() {
				this.$emit('confirm', {
					value: this.innerValue,
					mode: this.mode
				})
				if(!this.clearDate) {
					this.$emit('input', this.innerValue)
					this.$emit('update:modelValue', this.innerValue)
				}
			},
			//用正则截取输出值,当出现多组数字时,抛出错误
			intercept(e, type) {
				let judge = e.match(/\d+/g)
				//判断是否掺杂数字
				if (judge.length > 1) {
					this.$uv.error("请勿在过滤或格式化函数时添加数字")
					return 0
				} else if (type && judge[0].length == 4) { //判断是否是年份
					return judge[0]
				} else if (judge[0].length > 2) {
					this.$uv.error("请勿在过滤或格式化函数时添加数字")
					return 0
				} else {
					return judge[0]
				}
			},
			// 列发生变化时触发
			change(e) {
				const { indexs, values } = e
				let selectValue = ''
				if (this.mode === 'time') {
					// 根据value各列索引，从各列数组中，取出当前时间的选中值
					selectValue = `${this.intercept(values[0][indexs[0]])}:${this.intercept(values[1][indexs[1]])}`
				} else if (this.mode === 'year') {
					const year = parseInt(this.intercept(values[0][indexs[0]], 'year'));
					selectValue = Number(new Date(year, 0));
				} else {
					// 将选择的值转为数值，比如'03'转为数值的3，'2019'转为数值的2019
					const year = parseInt(this.intercept(values[0][indexs[0]], 'year'))
					const month = parseInt(this.intercept(values[1][indexs[1]]))
					let date = parseInt(values[2] ? this.intercept(values[2][indexs[2]]) : 1)
					let hour = 0,
						minute = 0
					// 此月份的最大天数
					const maxDate = dayjs(`${year}-${month}`).daysInMonth()
					// year-month模式下，date不会出现在列中，设置为1，为了符合后边需要减1的需求
					if (this.mode === 'year-month') {
						date = 1
					}
					// 不允许超过maxDate值
					date = Math.min(maxDate, date)
					if (this.mode === 'datetime') {
						hour = parseInt(this.intercept(values[3][indexs[3]]))
						minute = parseInt(this.intercept(values[4][indexs[4]]))
					}
					// 转为时间模式
					selectValue = Number(new Date(year, month - 1, date, hour, minute))
				}
				// 取出准确的合法值，防止超越边界的情况
				selectValue = this.correctValue(selectValue)
				this.innerValue = selectValue
				this.updateColumnValue(selectValue)
				// 发出change时间，value为当前选中的时间戳
				this.$emit('change', {
					value: selectValue,
					mode: this.mode
				})
			},
			// 更新各列的值，进行补0、格式化等操作
			updateColumnValue(value) {
				this.innerValue = value
				this.updateColumns()
				this.updateIndexs(value)
			},
			// 更新索引
			updateIndexs(value) {
				let values = []
				const formatter = this.formatter || this.innerFormatter;
				if (this.mode === 'time') {
					// 将time模式的时间用:分隔成数组
					const timeArr = value.split(':')
					// 使用formatter格式化方法进行管道处理
					values = [formatter('hour', timeArr[0]), formatter('minute', timeArr[1])]
				} else {
					const date = new Date(value)
					values = [
						formatter('year', `${dayjs(value).year()}`),
						// 月份补0
						formatter('month', this.$uv.padZero(dayjs(value).month() + 1))
					]
					if (this.mode === 'date') {
						// date模式，需要添加天列
						values.push(formatter('day', this.$uv.padZero(dayjs(value).date())))
					}
					if (this.mode === 'datetime') {
						// 数组的push方法，可以写入多个参数
						values.push(formatter('day', this.$uv.padZero(dayjs(value).date())), formatter('hour', this.$uv.padZero(dayjs(value).hour())), formatter('minute', this.$uv.padZero(dayjs(value).minute())))
					}
				}
				// 根据当前各列的所有值，从各列默认值中找到默认值在各列中的索引
				const indexs = this.columns.map((column, index) => {
					// 通过取大值，可以保证不会出现找不到索引的-1情况
					return Math.max(0, column.findIndex(item => item === values[index]))
				})
				this.$nextTick(()=>{
					this.$uv.sleep(100).then(res=>{
						this.$refs.picker.setIndexs(indexs,true);
					})
				})
			},
			// 更新各列的值
			updateColumns() {
				const formatter = this.formatter || this.innerFormatter
				// 获取各列的值，并且map后，对各列的具体值进行补0操作
				const results = this.getOriginColumns().map((column) => column.values.map((value) => formatter(column.type, value)))
				this.columns = results
			},
			getOriginColumns() {
				// 生成各列的值
				const results = this.getRanges().map(({ type, range }) => {
					let values = times(range[1] - range[0] + 1, (index) => {
						let value = range[0] + index
						value = type === 'year' ? `${value}` : this.$uv.padZero(value)
						return value
					})
					// 进行过滤
					if (this.filter) {
						values = this.filter(type, values)
					}
					return { type, values }
				})
				return results
			},
			// 通过最大值和最小值生成数组
			generateArray(start, end) {
				return Array.from(new Array(end + 1).keys()).slice(start)
			},
			// 得出合法的时间
			correctValue(value) {
				const isDateMode = this.mode !== 'time'
				if (isDateMode && !this.$uv.test.date(value)) {
					// 如果是日期类型，但是又没有设置合法的当前时间的话，使用最小时间为当前时间
					value = this.minDate
				} else if (!isDateMode && !value) {
					// 如果是时间类型，而又没有默认值的话，就用最小时间
					value = `${this.$uv.padZero(this.minHour)}:${this.$uv.padZero(this.minMinute)}`
				}
				// 时间类型
				if (!isDateMode) {
					if (String(value).indexOf(':') === -1) return this.$uv.error('时间错误，请传递如12:24的格式')
					let [hour, minute] = value.split(':')
					// 对时间补零，同时控制在最小值和最大值之间
					hour = this.$uv.padZero(this.$uv.range(this.minHour, this.maxHour, Number(hour)))
					minute = this.$uv.padZero(this.$uv.range(this.minMinute, this.maxMinute, Number(minute)))
					return `${ hour }:${ minute }`
				} else {
					// 如果是日期格式，控制在最小日期和最大日期之间
					value = dayjs(value).isBefore(dayjs(this.minDate)) ? this.minDate : value
					value = dayjs(value).isAfter(dayjs(this.maxDate)) ? this.maxDate : value
					return value
				}
			},
			// 获取每列的最大和最小值
			getRanges() {
				if (this.mode === 'time') {
					return [{
						type: 'hour',
						range: [this.minHour, this.maxHour],
					}, {
						type: 'minute',
						range: [this.minMinute, this.maxMinute],
					}, ];
				}
				const { maxYear, maxDate, maxMonth, maxHour, maxMinute, } = this.getBoundary('max', this.innerValue);
				const { minYear, minDate, minMonth, minHour, minMinute, } = this.getBoundary('min', this.innerValue);
				const result = [{
					type: 'year',
					range: [minYear, maxYear],
				}, {
					type: 'month',
					range: [minMonth, maxMonth],
				}, {
					type: 'day',
					range: [minDate, maxDate],
				}, {
					type: 'hour',
					range: [minHour, maxHour],
				}, {
					type: 'minute',
					range: [minMinute, maxMinute],
				}, ];
				if (this.mode === 'date') result.splice(3, 2);
				if (this.mode === 'year-month') result.splice(2, 3);
				if (this.mode === 'year') result.splice(1, 4);
				return result;
			},
			// 根据minDate、maxDate、minHour、maxHour等边界值，判断各列的开始和结束边界值
			getBoundary(type, innerValue) {
				const value = new Date(innerValue)
				const boundary = new Date(this[`${type}Date`])
				const year = dayjs(boundary).year()
				let month = 1
				let date = 1
				let hour = 0
				let minute = 0
				if (type === 'max') {
					month = 12
					// 月份的天数
					date = dayjs(value).daysInMonth()
					hour = 23
					minute = 59
				}
				// 获取边界值，逻辑是：当年达到了边界值(最大或最小年)，就检查月允许的最大和最小值，以此类推
				if (dayjs(value).year() === year) {
					month = dayjs(boundary).month() + 1
					if (dayjs(value).month() + 1 === month) {
						date = dayjs(boundary).date()
						if (dayjs(value).date() === date) {
							hour = dayjs(boundary).hour()
							if (dayjs(value).hour() === hour) {
								minute = dayjs(boundary).minute()
							}
						}
					}
				}
				return {
					[`${type}Year`]: year,
					[`${type}Month`]: month,
					[`${type}Date`]: date,
					[`${type}Hour`]: hour,
					[`${type}Minute`]: minute
				}
			},
		},
	}
</script>ZL
lx [## DatetimePicker 时间
datetime'd时间日期，主要用于年月日时分的选择，具体选择的精确度由参数控制。

# Q(	datetimeP)\	x e100644 changelog.md -ɿR$LVz\40000 components |SNntw\M100644 package.json KEaDmXO100644 readme.md #ˢ8Z
>/h|Q?nxe #QG问题
## 1.0.2（2023-06-01）
1. 修复点击触发两次事件的BUGědivider 分割线
3եx% 40000 uv-divider Gdc% Q}2>xN 100644 props.js {ALR+100644 uv-divider.vue yt͕^:*Y"/xexport default {
	props: {
		// 是否虚线
		dashed: {
			type: Boolean,
			default: false
		},
		// 是否细线
		hairline: {
			type: Boolean,
			default: true
		},
		// 是否以点替代文字，优先于text字段起作用
		dot: {
			type: Boolean,
			default: false
		},
		// 内容文本的位置，left-左边，center-中间，right-右边
		textPosition: {
			type: String,
			default: 'center'
		},
		// 文本内容
		text: {
			type: [String, Number],
			default: ''
		},
		// 文本大小
		textSize: {
			type: [String, Number],
			default: 14
		},
		// 文本颜色
		textColor: {
			type: String,
			default: '#909399'
		},
		// 线条颜色
		lineColor: {
			type: String,
			default: '#dcdfe6'
		},
		...uni.$uv?.props?.divider
	}
}:bxU<template>
	<view 
		class="uv-divider"
		:style="[$uv.addStyle(customStyle)]"
		@tap="click"
		>
		<uv-line 
			:color="lineColor"
			:customStyle="leftLineStyle"
			:hairline="hairline"
			:dashed="dashed"></uv-line>
		<text 
			v-if="dot"
			class="uv-divider__dot"
		>●</text>
		<text 
			v-else-if="text"
			class="uv-divider__text"
			:style="[textStyle]"
		>{{text}}</text>
		<uv-line 
			:color="lineColor"
			:customStyle="rightLineStyle"
			:hairline="hairline"
			:dashed="dashed"
		></uv-line>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * divider 分割线
	 * @description 区隔内容的分割线，一般用于页面底部"没有更多"的提示。
	 * @tutorial https://www.uvui.cn/components/divider.html
	 * @property {Boolean}			dashed			是否虚线 （默认 false ）
	 * @property {Boolean}			hairline		是否细线 （默认  true ）
	 * @property {Boolean}			dot				是否以点替代文字，优先于text字段起作用 （默认 false ）
	 * @property {String}			textPosition	内容文本的位置，left-左边，center-中间，right-右边 （默认 'center' ）
	 * @property {String | Number}	text			文本内容
	 * @property {String | Number}	textSize		文本大小 （默认 14）
	 * @property {String}			textColor		文本颜色 （默认 '#909399' ）
	 * @property {String}			lineColor		线条颜色 （默认 '#dcdfe6' ）
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 *
	 * @event {Function}	click	divider组件被点击时触发
	 * @example <uv-divider :color="color">锦瑟无端五十弦</uv-divider>
	 */
	export default {
		name: 'uv-divider',
		mixins: [mpMixin, mixin, props],
		emits: ['click'],
		computed: {
			textStyle() {
				const style = {}
				style.fontSize = this.$uv.addUnit(this.textSize)
				style.color = this.textColor
				return style
			},
			// 左边线条的的样式
			leftLineStyle() {
				const style = {}
				// 如果是在左边，设置左边的宽度为固定值
				if (this.textPosition === 'left') {
					style.width = '80rpx'
				} else {
					style.flex = 1
				}
				return style
			},
			// 右边线条的的样式
			rightLineStyle() {
				const style = {}
				// 如果是在右边，设置右边的宽度为固定值
				if (this.textPosition === 'right') {
					style.width = '80rpx'
				} else {
					style.flex = 1
				}
				return style
			}
		},
		methods: {
			// divider组件被点击时触发
			click() {
				this.$emit('click');
			}
		}
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	$uv-divider-margin: 15px 0 !default;
	$uv-divider-text-margin: 0 15px !default;
	$uv-divider-dot-font-size: 12px !default;
	$uv-divider-dot-margin: 0 12px !default;
	$uv-divider-dot-color: #c0c4cc !default;
	.uv-divider {
		@include flex;
		flex-direction: row;
		align-items: center;
		margin: $uv-divider-margin;
		&__text {
			margin: $uv-divider-text-margin;
		}
		&__dot {
			font-size: $uv-divider-dot-font-size;
			margin: $uv-divider-dot-margin;
			color: $uv-divider-dot-color;
		}
	}
</style>c"x >{
  "id": "uv-divider",
  "displayName": "uv-divider 分割线@I^4",
  "description": "区隔内容的分割线，一般用于页面底部没有更多的提示divider!!分割线",
    "没有更多\lines
n%gx x## Divider 分割线Udivider**

区隔内容的分割线，一般用于页面底部"没有更多"的提示1dividerZlJV	x e100644 changelog.md c|`Yp݇PtU%40000 components OuuDјO8100644 package.json h6 <wsG;s100644 readme.md 1O.t&ac<xG## 1.0.5（2024-01-02）
1. 修复parentData不变的BUG
## 1.0.4（2023-09-28）
1. 增加uv-sticky依赖
## 1.0.3（2023-08-29）
1. 修复自定义内容，点击自定义内容时会自动关闭弹窗的问题
## 1.0.2（2023-08-22）
1. 优化
## 1.0.1（2023-08-22）
1. 增加@change回调，返回弹窗关闭状态
2. 增加init方法，方便位置改变进行调整
## 1.0.0（2023-07-30）
新增uv-drop-down 下拉筛选组件
]x 40000 uv-drop-down-item (P+$Vx:eJ$40000 uv-drop-down-popup +^B^xknt,40000 uv-drop-down <CWl\3:k1x1 100644 uv-drop-down-item.vue 8zr٪,EJ.V&PkxS<template>
	<view class="uv-drop-down-item" @click="clickHandler">
		<uv-text :text="label" :size="getTextStyle.size" :color="getTextStyle.color" lines="1" :custom-style="{marginRight: '10rpx',maxWidth:'200rpx'}"></uv-text>
		<uv-icon :name="getDownIcon.name" :size="getDownIcon.size" :color="getDownIcon.color" v-if="[1,'1'].indexOf(type)==-1"></uv-icon>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
	/**
	 * DropDown 下拉框
	 * @description 下拉筛选
	 * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
	 * @property {String | Number} name 字段标识
	 * @property {String | Number} type 类型 1 没有筛选项，直接进行选中和不选中  2 有多个选项
	 * @property {String | Number} label 筛选项的文本
	 * @property {Boolean} isDrop 该项是否打开
	 */
	export default {
		name: 'uv-drop-down-item',
		mixins: [mpMixin, mixin],
		emits: ['click'],
		props: {
			name: {
				type: [String, Number],
				default: ''
			},
			// 类型 1 没有筛选项，直接进行选中和不选中  2 有多个选项
			type: {
				type: [String, Number],
				default: '2'
			},
			// 筛选的文本
			label: {
				type: [String],
				default: ''
			},
			// 筛选值
			value: {
				type: [String, Number, null],
				default: ''
			},
			// 是否下拉菜单打开
			isDrop: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				parentData: {
					defaultValue: [0, '0', 'all'],
					textSize: '30rpx',
					textColor: '#333',
					textActiveSize: '30rpx',
					textActiveColor: '#3c9cff',
					extraIcon: {},
					extraActiveIcon: {},
					sign: '',
					clickHandler: Function
				},
				active: false,
				isDroped: false,
				elId: ''
			}
		},
		watch: {
			isDrop: {
				handler(newVal) {
					this.isDroped = newVal;
				},
				immediate: true
			},
			value: {
				handler(newVal) {
					this.$nextTick(()=>{
						this.active = this.parentData.defaultValue.indexOf(newVal) == -1;
					})
				},
				immediate: true
			}
		},
		computed: {
			getDownIcon() {
				const style = {
					size: '30rpx',
					color: '#333',
					...this.parentData.extraIcon
				}
				if (this.active || this.isDroped) {
					style.color = this.parentData.extraActiveIcon?.color ? this.parentData.extraActiveIcon?.color : '#3c9cff';
					style.size = this.parentData.extraActiveIcon?.size ? this.parentData.extraActiveIcon?.size : '30rpx';
				}
				if (this.isDroped) {
					style.name = this.parentData.extraActiveIcon?.name;
				}
				return style;
			},
			getTextStyle() {
				const style = {
					size: this.parentData.textSize,
					color: this.parentData.textColor
				};
				if (this.active || this.isDroped) {
					style.size = this.parentData.textActiveSize;
					style.color = this.parentData.textActiveColor;
				}
				return style;
			}
		},
		created() {
			this.init();
		},
		methods: {
			init() {
				this.elId = this.$uv.guid();
				this.getParentData('uv-drop-down');
				if (!this.parent) {
					this.$uv.error('uv-drop-down必须搭配uv-drop-down-item组件使用');
				}
				uni.$on('HANDLE_DROPDOWN_ONE', id => {
					if (this.isDroped && this.elId != id) {
						this.isDroped = false;
					}
				})
				uni.$on(`${this.parentData.sign}_CLOSEPOPUP`, async () => {
					if (this.isDroped) {
						this.isDroped = false;
					}
				})
			},
			async clickHandler() {
				let data = {};
				uni.$emit('HANDLE_DROPDOWN_ONE', this.elId);
				switch (+this.type) {
					case 1:
						this.active = !this.active;
						data = {
							name: this.name,
							active: this.active,
							type: this.type
						};
						break;
					case 2:
						this.isDroped = !this.isDroped;
						data = {
							name: this.name,
							active: this.isDroped,
							type: this.type
						};
						break;
				}
				this.parentData.clickHandler(data);
				this.$emit('click', data);
				uni.$emit(`${this.parentData.sign}_CLICKMENU`, {
					show: +this.type > 1 && this.isDroped
				});
			}
		}
	}
</script>
<style scoped lang="scss">
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-drop-down-item {
		@include flex;
		align-items: center;
		padding: 20rpx;
	}
</style>Ox2 100644 uv-drop-down-popup.vue j[>_B*\uJ-t@x
<template>
	<view class="uv-drop-down-popup">
		<uv-transition :show="show" mode="fade" :duration="300" :custom-style="overlayStyle" @click="clickOverlay">
			<view class="uv-dp__container" ref="uvDPContainer" :style="{height: `${height}px`}" @click.stop="blockClick">
				<view class="uv-dp__container__list" ref="uvDPList">
					<slot>
						<view class="uv-dp__container__list--item" v-for="(item,index) in list" :key="index" @click="clickHandler(item,index)" :style="[itemCustomStyle(index)]">
							<uv-text :text="item[keyName]" :size="getTextSize(index)" :color="getTextColor(index)"></uv-text>
						</view>
					</slot>
				</view>
			</view>
		</uv-transition>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
	// #ifdef APP-NVUE
	const animation = uni.requireNativePlugin('animation');
	const dom = uni.requireNativePlugin('dom');
	// #endif
	/**
	 * DropDownPopup 下拉框
	 * @description 下拉筛选框
	 * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
	 * @property {String | Number} name 字段标识
	 * @property {String | Number} zIndex 弹出层的层级
	 * @property {String | Number} opacity 遮罩层的透明度
	 * @property {Boolean} clickOverlayOnClose 是否允许点击遮罩层关闭弹窗
	 * @property {Object} currentDropItem 当前下拉筛选菜单对象
	 * @property {String} keyName 指定从当前下拉筛选菜单对象元素中读取哪个属性作为文本展示
	 */
	export default {
		name: 'uv-drop-down-popup',
		mixins: [mpMixin, mixin],
		props: {
			sign: {
				type: [String, Number],
				default: 'UVDROPDOWN'
			},
			zIndex: {
				type: [Number, String],
				default: 999
			},
			opacity: {
				type: [Number, String],
				default: 0.5
			},
			clickOverlayOnClose: {
				type: Boolean,
				default: true
			},
			// 当前下拉选项对象
			currentDropItem: {
				type: Object,
				default () {
					return {
						activeIndex: 0,
						child: []
					}
				}
			},
			keyName: {
				type: String,
				default: 'label'
			}
		},
		data() {
			return {
				show: false,
				rect: {},
				height: 0
			}
		},
		computed: {
			overlayStyle() {
				let { height = 0, top = 0 } = this.rect;
				// #ifdef H5
				top += this.$uv.sys().windowTop;
				// #endif
				const style = {
					position: 'fixed',
					top: `${top+height}px`,
					left: 0,
					right: 0,
					zIndex: this.zIndex,
					bottom: 0,
					'background-color': `rgba(0, 0, 0, ${this.opacity})`
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			},
			list() {
				try {
					return Array.isArray(this.currentDropItem.child) ? this.currentDropItem.child : [];
				} catch (e) {
					return [];
				}
			},
			getTextColor(index) {
				return index => {
					const active = this.currentDropItem.activeIndex == index;
					const color = this.currentDropItem.color;
					const activeColor = this.currentDropItem.activeColor;
					if (active) {
						return activeColor ? activeColor : '#3c9cff';
					}
					return color ? color : '#333';
				}
			},
			getTextSize(index) {
				return index => {
					const active = this.currentDropItem.activeIndex == index;
					const size = this.currentDropItem.size;
					const activeSize = this.currentDropItem.activeSize;
					if (active) {
						return activeSize ? activeSize : '30rpx';
					}
					return size ? size : '30rpx';
				}
			},
			itemCustomStyle() {
				return index => {
					const active = this.currentDropItem.activeIndex == index;
					const style = {};
					if (active && this.currentDropItem.itemActiveCustomStyle) {
						return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemActiveCustomStyle));
					}
					if (this.currentDropItem.itemCustomStyle) {
						return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemCustomStyle))
					}
					return style;
				}
			}
		},
		created() {
			this.init();
		},
		methods: {
			blockClick() {},
			clickHandler(item, index) {
				this.currentDropItem.activeIndex = index;
				this.$emit('clickItem', item);
				this.close();
			},
			init() {
				uni.$off(`${this.sign}_GETRECT`);
				uni.$on(`${this.sign}_GETRECT`, rect => {
					this.rect = rect;
				})
				uni.$off(`${this.sign}_CLICKMENU`);
				uni.$on(`${this.sign}_CLICKMENU`, async res => {
					if (res.show) {
						this.open();
					} else {
						this.close();
					}
				})
			},
			open() {
				this.show = true;
				this.$nextTick(async () => {
					// #ifndef H5 || MP-WEIXIN
					await this.$uv.sleep(60);
					// #endif
					const res = await this.queryRect();
					// #ifndef APP-NVUE
					this.height = res.height;
					// #endif
					// #ifdef APP-NVUE
					this.animation(res.height);
					// #endif
					this.$emit('popupChange', { show: true });
				})
			},
			close() {
				if(!this.show) return;
				this.height = 0;
				// #ifndef APP-NVUE
				this.height = 0;
				// #endif
				// #ifdef APP-NVUE
				this.animation(0);
				// #endif
				this.show = false;
				uni.$emit(`${this.sign}_CLOSEPOPUP`);
				this.$emit('popupChange', { show: false });
			},
			clickOverlay() {
				if (this.clickOverlayOnClose) {
					this.close();
				}
			},
			// 查询内容高度
			queryRect() {
				// #ifndef APP-NVUE
				// 组件内部一般用this.$uvGetRect，对外的为getRect，二者功能一致，名称不同
				return new Promise(resolve => {
					this.$uvGetRect(`.uv-dp__container__list`).then(size => {
						resolve(size)
					})
				})
				// #endif
				// #ifdef APP-NVUE
				// nvue下，使用dom模块查询元素高度
				// 返回一个promise，让调用此方法的主体能使用then回调
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs.uvDPList, res => {
						resolve(res.size)
					})
				})
				// #endif
			},
			// nvue下设置高度
			animation(height, duration = 200) {
				// #ifdef APP-NVUE
				const ref = this.$refs['uvDPContainer'];
				animation.transition(ref, {
					styles: {
						height: `${height}px`
					},
					duration
				})
				// #endif
			}
		}
	}
</script>
<style scoped lang="scss">
	.uv-dp__container {
		/* #ifndef APP-NVUE */
		overflow: hidden;
		transition: all .15s;
		/* #endif */
		background-color: #fff;
	}
	.uv-dp__container__list {
		&--item {
			padding: 20rpx 60rpx;
		}
	}
</style>:Hx, 100644 uv-drop-down.vue x@1MQPbJ2K7GN+<x7<template>
	<uv-sticky :disabled="!isSticky">
		<view ref="dropDownRef" class="uv-drop-down" :style="[$uv.addStyle(customStyle)]">
			<slot></slot>
		</view>
	</uv-sticky>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom');
	// #endif
	/**
	 * DropDown 下拉框
	 * @description 下拉筛选
	 * @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
	 * @property {String | Number} sign 组件唯一标识，需要手动传
	 * @property {Boolean} is-sticky = [true|false] 是否吸顶
	 * @property {Array} default-value 默认值，表示参数value属于这里面的值，就说明是未选中即是默认展示的值。eg：上面示例中的{label: '全部',value: 'all'} 即是默认值。后续处理逻辑也可以根据是否是其中值进行过滤。
	 * @property {String} textSize 每项字体大小
	 * @property {String} textColor 每项文本颜色
	 * @property {String} textActiveSize 每项选中状态字体大小
	 * @property {String} textActiveColor 每项选中状态文本颜色
	 * @property {Object} extraIcon 每项右侧图标
	 * @property {Object} extraActiveIcon 每项选中后右侧图标
	 */
	export default {
		name: 'uv-drop-down',
		mixins: [mpMixin, mixin],
		emits: ['click'],
		props: {
			isSticky: {
				type: Boolean,
				default: true
			},
			sign: {
				type: [String, Number],
				default: 'UVDROPDOWN'
			},
			defaultValue: {
				type: Array,
				default: () => [0, '0', 'all']
			},
			textSize: {
				type: String,
				default: '30rpx'
			},
			textColor: {
				type: String,
				default: '#333'
			},
			textActiveSize: {
				type: String,
				default: '30rpx'
			},
			textActiveColor: {
				type: String,
				default: '#3c9cff'
			},
			extraIcon: {
				type: Object,
				default () {
					return {
						name: 'arrow-down',
						size: '30rpx',
						color: '#333'
					}
				}
			},
			extraActiveIcon: {
				type: Object,
				default () {
					return {
						name: 'arrow-up',
						size: '30rpx',
						color: '#3c9cff'
					}
				}
			}
		},
		computed: {
			parentData() {
				return [this.defaultValue, this.textSize, this.textColor, this.textActiveColor, this.textActiveSize, this.extraIcon, this.extraActiveIcon, this.sign, this.clickHandler];
			}
		},
		mounted() {
			this.init();
		},
		methods: {
			init() {
				uni.$emit(`${this.sign}_CLICKMENU`, {
					show: false
				});
				this.$nextTick(async () => {
					const rect = await this.queryRect();
					uni.$emit(`${this.sign}_GETRECT`, rect);
				})
			},
			// 查询内容高度
			queryRect() {
				// #ifndef APP-NVUE
				// 组件内部一般用this.$uvGetRect，对外的为getRect，二者功能一致，名称不同
				return new Promise(resolve => {
					this.$uvGetRect(`.uv-drop-down`).then(size => {
						resolve(size)
					})
				})
				// #endif
				// #ifdef APP-NVUE
				// nvue下，使用dom模块查询元素高度
				// 返回一个promise，让调用此方法的主体能使用then回调
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs.dropDownRef, res => {
						res.size.top = res.size.top <= 0 ? 0 : res.size.top;
						resolve(res.size)
					})
				})
				// #endif
			},
			clickHandler(data) {
				this.$emit('click', data);
			}
		}
	}
</script>
<style scoped lang="scss">
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-drop-down {
		@include flex;
		justify-content: space-between;
		background-color: #fff;
		border-bottom: 1px solid #dadbde;
	}
</style>7 nx	## DropDown 下拉筛选

> **组件名：uv-drop-down**

该组件主要提供筛选下拉筛选框，内置基础筛选功能，可以根据自己的需求自定义筛选项。

为了兼容app-nvue，需要内置三个组件进行配合使用，uv-drop-down属于菜单项（其实还包括子组件uv-drop-down-item），uv-drop-down-popup属于筛选框。

只需要做简单j的约定式配置，即可使用该功能，兼容性良好，已经在多端进行了多次测试。

# (dropDown{Y9?	x e100644 changelog.md *ڋO錗zn%L*40000 components 
S(Cd;&/ݓF100644 package.json EQTfمFI](100644 readme.md ק8<M%!L^c<ѶxY## 1.0.5（2023-12-20）
1. 优化
## 1.0.4（2023-08-04）
1. icon支持base64图片
## 1.0.3（2023-07-17）
1. 修复  uv-empty 恢复设置mode属性的内置图标
## 1.0.2（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-empty 内容为空
x# 40000 uv-empty PU3Tn{OدmxL 100644 props.js &ֺhlIz100644 uv-empty.vue "&KyxnW읲/<ڽ ?x
export default {
	props: {
		// 内置图标名称，或图片路径，建议绝对路径
		icon: {
			type: String,
			default: ''
		},
		// 提示文字
		text: {
			type: String,
			default: ''
		},
		// 文字颜色
		textColor: {
			type: String,
			default: '#c0c4cc'
		},
		// 文字大小
		textSize: {
			type: [String, Number],
			default: 14
		},
		// 图标的颜色
		iconColor: {
			type: String,
			default: '#c0c4cc'
		},
		// 图标的大小
		iconSize: {
			type: [String, Number],
			default: 90
		},
		// 选择预置的图标类型
		mode: {
			type: String,
			default: 'data'
		},
		//  图标宽度，单位px
		width: {
			type: [String, Number],
			default: 160
		},
		// 图标高度，单位px
		height: {
			type: [String, Number],
			default: 160
		},
		// 是否显示组件
		show: {
			type: Boolean,
			default: true
		},
		// 组件距离上一个元素之间的距离，默认px单位
		marginTop: {
			type: [String, Number],
			default: 0
		},
		...uni.$uv?.props?.empty
	}
}exr<template>
	<view
	  class="uv-empty"
	  :style="[emptyStyle]"
	  v-if="show"
	>
		<uv-icon
		  v-if="!isImg"
		  :name="mode === 'message' ? 'chat' : `empty-${mode}`"
		  :size="iconSize"
		  :color="iconColor"
		  margin-top="14"
		></uv-icon>
		<image
		  v-else
		  :style="{
				width: $uv.addUnit(width),
				height: $uv.addUnit(height)
			}"
		  :src="icon"
		  mode="widthFix"
		></image>
		<text
		  class="uv-empty__text"
		  :style="[textStyle]"
		>{{text ? text : icons[mode]}}</text>
		<view class="uv-empty__wrap">
			<slot />
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * empty 内容为空
	 * @description 该组件用于需要加载内容，但是加载的第一页数据就为空，提示一个"没有内容"的场景， 我们精心挑选了十几个场景的图标，方便您使用。
	 * @tutorial https://www.uvui.cn/components/empty.html
	 * @property {String}			icon		内置图标名称，或图片路径，建议绝对路径
	 * @property {String}			text		提示文字
	 * @property {String}			textColor	文字颜色 (默认 '#c0c4cc' )
	 * @property {String | Number}	textSize	文字大小 （默认 14 ）
	 * @property {String}			iconColor	图标的颜色 （默认 '#c0c4cc' ）
	 * @property {String | Number}	iconSize	图标的大小 （默认 90 ）
	 * @property {String}			mode		选择预置的图标类型 （默认 'data' ）
	 * @property {String | Number}	width		图标宽度，单位px （默认 160 ）
	 * @property {String | Number}	height		图标高度，单位px （默认 160 ）
	 * @property {Boolean}			show		是否显示组件 （默认 true ）
	 * @property {String | Number}	marginTop	组件距离上一个元素之间的距离，默认px单位 （默认 0 ）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * 
	 * @event {Function} click 点击组件时触发
	 * @event {Function} close 点击关闭按钮时触发
	 * @example <uv-empty text="所谓伊人，在水一方" mode="list"></uv-empty>
	 */
	export default {
		name: "uv-empty",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				icons: {
					car: '购物车为空',
					page: '页面不存在',
					search: '没有搜索结果',
					address: '没有收货地址',
					'wifi-off': '没有WiFi',
					order: '订单为空',
					coupon: '没有优惠券',
					favor: '暂无收藏',
					permission: '无权限',
					history: '无历史记录',
					news: '无新闻列表',
					message: '消息列表为空',
					list: '列表为空',
					data: '数据为空',
					comment: '暂无评论',
				}
			}
		},
		computed: {
			// 组件样式
			emptyStyle() {
				const style = {}
				style.marginTop = this.$uv.addUnit(this.marginTop)
				// 合并customStyle样式，此参数通过mixin中的props传递
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			},
			// 文本样式
			textStyle() {
				const style = {}
				style.color = this.textColor
				style.fontSize = this.$uv.addUnit(this.textSize)
				return style
			},
			// 判断icon是否图片路径
			isImg() {
				const isBase64 = this.icon.indexOf('data:') > -1 && this.icon.indexOf('base64') > -1;
				return this.icon.indexOf('/') !== -1 || isBase64;
			}
		}
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	$uv-empty-text-margin-top: 20rpx !default;
	$uv-empty-slot-margin-top: 20rpx !default;
	.uv-empty {
		@include flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		&__text {
			@include flex;
			justify-content: center;
			align-items: center;
			margin-top: $uv-empty-text-margin-top;
		}
	}
	.uv-slot-wrap {
		@include flex;
		justify-content: center;
		align-items: center;
		margin-top: $uv-empty-slot-margin-top;
	}
</style>@X	x e100644 changelog.md )vw80n)40000 components ?˾Zco
mJ100644 package.json ^a,#< H$diEA100644 readme.md X\|$C1FMn?[);2x+## 1.0.9（2023-08-14）
1. 修复设置labelWidth属性时，节点渲染有闪动的BUG
## 1.0.8（2023-08-13）
1. 修复未设置rules的情况下报错的BUG
2. 优化错误提示
## 1.0.7（2023-08-10）
1. 修复在vue3+setup语法糖中错误文字动画错乱
## 1.0.6（2023-07-17）
1. 优化文档
2. 优化其他
## 1.0.5（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.4（2023-07-02）
uv-form  由于弹出层uv-transition的修改，组件内部做了相应的修改，参数不变。
## 1.0.3（2023-06-18）
1. 修改某些情况下的BUG
## 1.0.2（2023-06-15）
1.  修复支付宝报错的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-form 表单
q{ةxI 40000 uv-form-item Eq<1Rb! u40000 uv-form >&]P6ky!
_xP 100644 props.js  kzEekG100644 uv-form-item.vue %>VD2	\hcy%t :xSexport default {
	props: {
		// 当前form的需要验证字段的集合
		model: {
			type: Object,
			default: () => ({})
		},
		// 验证规则
		rules: {
			type: [Object, Function, Array],
			default: () => ({})
		},
		// 有错误时的提示方式，message-提示信息，toast-进行toast提示
		// border-bottom-下边框呈现红色，none-无提示
		errorType: {
			type: String,
			default: 'message'
		},
		// 是否显示表单域的下划线边框
		borderBottom: {
			type: Boolean,
			default: true
		},
		// label的位置，left-左边，top-上边
		labelPosition: {
			type: String,
			default: 'left'
		},
		// label的宽度，单位px
		labelWidth: {
			type: [String, Number],
			default: 45
		},
		// lable字体的对齐方式
		labelAlign: {
			type: String,
			default: 'left'
		},
		// lable的样式，对象形式
		labelStyle: {
			type: Object,
			default: () => ({})
		},
		...uni.$uv?.props?.form
	}
}!}X9xq input的label提示语
		label"'
		},
		// 绑定的值
		prop"O[Boolean],
			default: falseqSp]$''
		},
		// 右侧图标
		rightIco#"'
		},
		// 左侧图标
		leftIco#g左边的必填星号，只作显示用，具体校验必填的逻辑，请在rules中配置
		required"Gfalse
		},
		leftIconStyle: {
			type: [String, Object],
			default: ''	Item
	}
}xa<template>
	<view class="uv-form-item">
		<view
			class="uv-form-item__body"
			@tap="clickHandler"
			:style="[$uv.addStyle(customStyle), {
				flexDirection: (labelPosition || parentData.labelPosition) === 'left' ? 'row' : 'column'
			}]"
		>
			<!-- 微信小程序中，将一个参数设置空字符串，结果会变成字符串"true" -->
			<slot name="label">
				<view
					class="uv-form-item__body__left"
					v-if="required || leftIcon || label"
					:style="{
						width: $uv.addUnit(labelWidth || parentData.labelWidth),
						marginBottom: parentData.labelPosition === 'left' ? 0 : '5px',
					}"
				>
					<!-- 为了块对齐 -->
					<view class="uv-form-item__body__left__content">
						<!-- nvue不支持伪元素before -->
						<text
							v-if="required"
							class="uv-form-item__body__left__content__required"
						>*</text>
						<view
							class="uv-form-item__body__left__content__icon"
							v-if="leftIcon"
						>
							<uv-icon
								:name="leftIcon"
								:custom-style="leftIconStyle"
							></uv-icon>
						</view>
						<text
							class="uv-form-item__body__left__content__label"
							:style="[parentData.labelStyle, {
								justifyContent: parentData.labelAlign === 'left' ? 'flex-start' : parentData.labelAlign === 'center' ? 'center' : 'flex-end'
							}]"
						>{{ label }}</text>
					</view>
				</view>
			</slot>
			<view class="uv-form-item__body__right">
				<view class="uv-form-item__body__right__content">
					<view class="uv-form-item__body__right__content__slot">
						<slot />
					</view>
					<view class="item__body__right__content__icon">
						<slot name="right" />
					</view>
				</view>
			</view>
		</view>
		<slot name="error">
			<uv-transition 
			:show="true" 
			:duration="100" 
			mode="fade" 
			v-if="!!message && parentData.errorType === 'message'"
		>
				<text
					class="uv-form-item__body__right__message"
					:style="{
						marginLeft:  $uv.addUnit(parentData.labelPosition === 'top' ? 0 : (labelWidth || parentData.labelWidth))
					}"
				>{{ message }}</text>
			</uv-transition>
		</slot>
		<uv-line
			v-if="borderBottom"
			:color="message && parentData.errorType === 'border-bottom' ? '#f56c6c' : '#d6d7d9'"
		></uv-line>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Form 表单
	 * @description 此组件一般用于表单场景，可以配置Input输入框，Select弹出框，进行表单验证等。
	 * @tutorial https://www.uvui.cn/components/form.html
	 * @property {String}			label			input的label提示语
	 * @property {String}			prop			绑定的值
	 * @property {String | Boolean}	borderBottom	是否显示表单域的下划线边框
	 * @property {String | Number}	labelWidth		label的宽度，单位px
	 * @property {String}			rightIcon		右侧图标
	 * @property {String}			leftIcon		左侧图标
	 * @property {String | Object} leftIconStyle 左侧图标的样式
	 * @property {Boolean}			required		是否显示左边的必填星号，只作显示用，具体校验必填的逻辑，请在rules中配置 (默认 false )
	 *
	 * @example <uv-form-item label="姓名" prop="userInfo.name" borderBottom ref="item1"></uv-form-item>
	 */
	export default {
		name: 'uv-form-item',
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 错误提示语
				message: '',
				parentData: {
					// 提示文本的位置
					labelPosition: 'left',
					// 提示文本对齐方式
					labelAlign: 'left',
					// 提示文本的样式
					labelStyle: {},
					// 提示文本的宽度
					labelWidth: 45,
					// 错误提示方式
					errorType: 'message'
				}
			}
		},
		created() {
			this.init()
		},
		methods: {
			init() {
				// 父组件的实例
				this.updateParentData()
				if (!this.parent) {
					this.$uv.error('uv-form-item需要结合uv-form组件使用')
				}
			},
			// 获取父组件的参数
			updateParentData() {
				// 此方法写在mixin中
				this.getParentData('uv-form');
			},
			// 移除uv-form-item的校验结果
			clearValidate() {
				this.message = null
			},
			// 清空当前的组件的校验结果，并重置为初始值
			resetField() {
				// 找到原始值
				const value = this.$uv.getProperty(this.parent.originalModel, this.prop)
				// 将uv-form的model的prop属性链还原原始值
				this.$uv.setProperty(this.parent.model, this.prop, value)
				// 移除校验结果
				this.message = null
			},
			// 点击组件
			clickHandler() {
				this.$emit('click')
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-form-item {
		@include flex(column);
		font-size: 14px;
		color: $uv-main-color;
		&__body {
			@include flex;
			padding: 10px 0;
			&__left {
				@include flex;
				align-items: center;
				&__content {
					position: relative;
					@include flex;
					align-items: center;
					padding-right: 10rpx;
					flex: 1;
					&__icon {
						margin-right: 8rpx;
					}
					&__required {
						position: absolute;
						left: -9px;
						color: $uv-error;
						line-height: 20px;
						font-size: 20px;
						top: 3px;
					}
					&__label {
						@include flex;
						align-items: center;
						flex: 1;
						color: $uv-main-color;
						font-size: 15px;
					}
				}
			}
			&__right {
				flex: 1;
				&__content {
					@include flex;
					align-items: center;
					flex: 1;
					&__slot {
						flex: 1;
						/* #ifndef MP */
						@include flex;
						align-items: center;
						/* #endif */
					}
					&__icon {
						margin-left: 10rpx;
						color: $uv-light-color;
						font-size: 30rpx;
					}
				}
				&__message__box {
					height: 16px;
					line-height: 16px;
				}
				&__message {
					margin-top: -6px;
					line-height: 24px;
					font-size: 12px;
					color: $uv-error;
				}
			}
		}
	}
</style>,)ׯxo 100644 props.js l^B&gU[9100644 uv-form.vue v)kJQun100644 valid.js Mb~omt?ύɗ.x-<template>
	<view class="uv-form">
		<slot />
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from "./props.js";
	import Schema from "./valid.js";
	// 去除警告信息
	Schema.warning = function() {};
	/**
	 * Form 表单
	 * @description 此组件一般用于表单场景，可以配置Input输入框，Select弹出框，进行表单验证等。
	 * @tutorial https://www.uvui.cn/components/form.html
	 * @property {Object}						model			当前form的需要验证字段的集合
	 * @property {Object | Function | Array}	rules			验证规则
	 * @property {String}						errorType		错误的提示方式，见上方说明 ( 默认 message )
	 * @property {Boolean}						borderBottom	是否显示表单域的下划线边框   ( 默认 true ）
	 * @property {String}						labelPosition	表单域提示文字的位置，left-左侧，top-上方 ( 默认 'left' ）
	 * @property {String | Number}				labelWidth		提示文字的宽度，单位px  ( 默认 45 ）
	 * @property {String}						labelAlign		lable字体的对齐方式   ( 默认 ‘left' ）
	 * @property {Object}						labelStyle		lable的样式，对象形式
	 * @example <uv-form labelPosition="left" :model="model1" :rules="rules" ref="form1"></uv-form>
	 */
	export default {
		name: "uv-form",
		mixins: [mpMixin, mixin, props],
		provide() {
			return {
				uForm: this,
			};
		},
		data() {
			return {
				formRules: {},
				// 规则校验器
				validator: {},
				// 原始的model快照，用于resetFields方法重置表单时使用
				originalModel: null,
			};
		},
		watch: {
			// 监听规则的变化
			rules: {
				immediate: true,
				handler(n) {
					this.setRules(n);
				},
			},
			// 监听属性的变化，通知子组件uv-form-item重新获取信息
			propsChange(n) {
				if (this.children?.length) {
					this.children.map((child) => {
						// 判断子组件(uv-form-item)如果有updateParentData方法的话，就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
						typeof child.updateParentData == "function" &&
							child.updateParentData();
					});
				}
			},
			// 监听model的初始值作为重置表单的快照
			model: {
				immediate: true,
				handler(n) {
					if (!this.originalModel) {
						this.originalModel = this.$uv.deepClone(n);
					}
				},
			},
		},
		computed: {
			propsChange() {
				return [
					this.errorType,
					this.borderBottom,
					this.labelPosition,
					this.labelWidth,
					this.labelAlign,
					this.labelStyle,
				];
			},
		},
		created() {
			// 存储当前form下的所有uv-form-item的实例
			// 不能定义在data中，否则微信小程序会造成循环引用而报错
			this.children = [];
		},
		methods: {
			// 手动设置校验的规则，如果规则中有函数的话，微信小程序中会过滤掉，所以只能手动调用设置规则
			setRules(rules) {
				// 判断是否有规则
				if (Object.keys(rules).length === 0) return;
				if (process.env.NODE_ENV === 'development' && Object.keys(this.model).length === 0) {
					this.$uv.error('设置rules，model必须设置！如果已经设置，请刷新页面。');
					return;
				};
				this.formRules = rules;
				// 重新将规则赋予Validator
				this.validator = new Schema(rules);
			},
			// 清空所有uv-form-item组件的内容，本质上是调用了uv-form-item组件中的resetField()方法
			resetFields() {
				this.resetModel();
			},
			// 重置model为初始值的快照
			resetModel(obj) {
				// 历遍所有uv-form-item，根据其prop属性，还原model的原始快照
				this.children.map((child) => {
					const prop = child?.prop;
					const value = this.$uv.getProperty(this.originalModel, prop);
					this.$uv.setProperty(this.model, prop, value);
				});
			},
			// 清空校验结果
			clearValidate(props) {
				props = [].concat(props);
				this.children.map((child) => {
					// 如果uv-form-item的prop在props数组中，则清除对应的校验结果信息
					if (props[0] === undefined || props.includes(child.prop)) {
						child.message = null;
					}
				});
			},
			// 对部分表单字段进行校验
			async validateField(value, callback, event = null) {
				// $nextTick是必须的，否则model的变更，可能会延后于此方法的执行
				this.$nextTick(() => {
					// 校验错误信息，返回给回调方法，用于存放所有form-item的错误信息
					const errorsRes = [];
					// 如果为字符串，转为数组
					value = [].concat(value);
					// 历遍children所有子form-item
					this.children.map((child) => {
						// 用于存放form-item的错误信息
						const childErrors = [];
						if (value.includes(child.prop)) {
							// 获取对应的属性，通过类似'a.b.c'的形式
							const propertyVal = this.$uv.getProperty(
								this.model,
								child.prop
							);
							// 属性链数组
							const propertyChain = child.prop.split(".");
							const propertyName =
								propertyChain[propertyChain.length - 1];

							const rule = this.formRules[child.prop];
							// 如果不存在对应的规则，直接返回，否则校验器会报错
							if (!rule) return;
							// rule规则可为数组形式，也可为对象形式，此处拼接成为数组
							const rules = [].concat(rule);

							// 对rules数组进行校验
							for (let i = 0; i < rules.length; i++) {
								const ruleItem = rules[i];
								// 将uv-form-item的触发器转为数组形式
								const trigger = [].concat(ruleItem?.trigger);
								// 如果是有传入触发事件，但是此form-item却没有配置此触发器的话，不执行校验操作
								if (event && !trigger.includes(event)) continue;
								// 实例化校验对象，传入构造规则
								const validator = new Schema({
									[propertyName]: ruleItem,
								});
								validator.validate({
										[propertyName]: propertyVal,
									},
									(errors, fields) => {
										if (this.$uv.test.array(errors)) {
											errorsRes.push(...errors);
											childErrors.push(...errors);
										}
										this.$nextTick(() => {
											child.message = childErrors[0]?.message ? childErrors[0]?.message : null;
										})
									}
								);
							}
						}
					});
					// 执行回调函数
					typeof callback === "function" && callback(errorsRes);
				});
			},
			// 校验全部数据
			validate(callback) {
				return new Promise((resolve, reject) => {
					// $nextTick是必须的，否则model的变更，可能会延后于validate方法
					this.$nextTick(() => {
						// 获取所有form-item的prop，交给validateField方法进行校验
						const formItemProps = this.children.map(
							(item) => item.prop
						);
						this.validateField(formItemProps, (errors) => {
							if (errors.length) {
								// 如果错误提示方式为toast，则进行提示
								this.errorType === 'toast' && this.$uv.toast(errors[0].message)
								reject(errors)
							} else {
								resolve(true)
							}
						});
					});
				});
			},
		},
	};
</script>6Ȳx2gfunction _extends() {
    _extends = Object.assign || function (target) {
        for (let i = 1; i < arguments.length; i++) {
            const source = arguments[i]

            for (const key in source) {
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                    target[key] = source[key]
                }
            }
        }

        return target
    }

    return _extends.apply(this, arguments)
}

/* eslint no-console:0 */
const formatRegExp = /%[sdj%]/g
let warning = function warning() {} // don't print warning message when in production env or node runtime

if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production' && typeof window
	!== 'undefined' && typeof document !== 'undefined') {
    warning = function warning(type, errors) {
        if (typeof console !== 'undefined' && console.warn) {
            if (errors.every((e) => typeof e === 'string')) {
                console.warn(type, errors)
            }
        }
    }
}

function convertFieldsError(errors) {
    if (!errors || !errors.length) return null
    const fields = {}
    errors.forEach((error) => {
        const { field } = error
        fields[field] = fields[field] || []
        fields[field].push(error)
    })
    return fields
}

function format() {
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key]
    }

    let i = 1
    const f = args[0]
    const len = args.length

    if (typeof f === 'function') {
        return f.apply(null, args.slice(1))
    }

    if (typeof f === 'string') {
        let str = String(f).replace(formatRegExp, (x) => {
            if (x === '%%') {
                return '%'
            }

            if (i >= len) {
                return x
            }

            switch (x) {
            case '%s':
                return String(args[i++])

            case '%d':
                return Number(args[i++])

            case '%j':
                try {
                    return JSON.stringify(args[i++])
                } catch (_) {
                    return '[Circular]'
                }

                break

            default:
                return x
            }
        })

        for (let arg = args[i]; i < len; arg = args[++i]) {
            str += ` ${arg}`
        }

        return str
    }

    return f
}

function isNativeStringType(type) {
    return type === 'string' || type === 'url' || type === 'hex' || type === 'email' || type === 'pattern'
}

function isEmptyValue(value, type) {
    if (value === undefined || value === null) {
        return true
    }

    if (type === 'array' && Array.isArray(value) && !value.length) {
        return true
    }

    if (isNativeStringType(type) && typeof value === 'string' && !value) {
        return true
    }

    return false
}

function asyncParallelArray(arr, func, callback) {
    const results = []
    let total = 0
    const arrLength = arr.length

    function count(errors) {
        results.push.apply(results, errors)
        total++

        if (total === arrLength) {
            callback(results)
        }
    }

    arr.forEach((a) => {
        func(a, count)
    })
}

function asyncSerialArray(arr, func, callback) {
    let index = 0
    const arrLength = arr.length

    function next(errors) {
        if (errors && errors.length) {
            callback(errors)
            return
        }

        const original = index
        index += 1

        if (original < arrLength) {
            func(arr[original], next)
        } else {
            callback([])
        }
    }

    next([])
}

function flattenObjArr(objArr) {
    const ret = []
    Object.keys(objArr).forEach((k) => {
        ret.push.apply(ret, objArr[k])
    })
    return ret
}

function asyncMap(objArr, option, func, callback) {
    if (option.first) {
        const _pending = new Promise((resolve, reject) => {
            const next = function next(errors) {
                callback(errors)
                return errors.length ? reject({
                    errors,
                    fields: convertFieldsError(errors)
                }) : resolve()
            }

            const flattenArr = flattenObjArr(objArr)
            asyncSerialArray(flattenArr, func, next)
        })

        _pending.catch((e) => e)

        return _pending
    }

    let firstFields = option.firstFields || []

    if (firstFields === true) {
        firstFields = Object.keys(objArr)
    }

    const objArrKeys = Object.keys(objArr)
    const objArrLength = objArrKeys.length
    let total = 0
    const results = []
    const pending = new Promise((resolve, reject) => {
        const next = function next(errors) {
            results.push.apply(results, errors)
            total++

            if (total === objArrLength) {
                callback(results)
                return results.length ? reject({
                    errors: results,
                    fields: convertFieldsError(results)
                }) : resolve()
            }
        }

        if (!objArrKeys.length) {
            callback(results)
            resolve()
        }

        objArrKeys.forEach((key) => {
            const arr = objArr[key]

            if (firstFields.indexOf(key) !== -1) {
                asyncSerialArray(arr, func, next)
            } else {
                asyncParallelArray(arr, func, next)
            }
        })
    })
    pending.catch((e) => e)
    return pending
}

function complementError(rule) {
    return function (oe) {
        if (oe && oe.message) {
            oe.field = oe.field || rule.fullField
            return oe
        }

        return {
            message: typeof oe === 'function' ? oe() : oe,
            field: oe.field || rule.fullField
        }
    }
}

function deepMerge(target, source) {
    if (source) {
        for (const s in source) {
            if (source.hasOwnProperty(s)) {
                const value = source[s]

                if (typeof value === 'object' && typeof target[s] === 'object') {
                    target[s] = { ...target[s], ...value }
                } else {
                    target[s] = value
                }
            }
        }
    }

    return target
}

/**
 *  Rule for validating required fields.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function required(rule, value, source, errors, options, type) {
    if (rule.required && (!source.hasOwnProperty(rule.field) || isEmptyValue(value, type || rule.type))) {
        errors.push(format(options.messages.required, rule.fullField))
    }
}

/**
 *  Rule for validating whitespace.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function whitespace(rule, value, source, errors, options) {
    if (/^\s+$/.test(value) || value === '') {
        errors.push(format(options.messages.whitespace, rule.fullField))
    }
}

/* eslint max-len:0 */

const pattern = {
    // http://emailregex.com/
    email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
    url: new RegExp(
        '^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$',
        'i'
    ),
    hex: /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i
}
var types = {
    integer: function integer(value) {
        return /^(-)?\d+$/.test(value);
    },
    float: function float(value) {
        return /^(-)?\d+(\.\d+)?$/.test(value);
    },
    array: function array(value) {
        return Array.isArray(value)
    },
    regexp: function regexp(value) {
        if (value instanceof RegExp) {
            return true
        }

        try {
            return !!new RegExp(value)
        } catch (e) {
            return false
        }
    },
    date: function date(value) {
        return typeof value.getTime === 'function' && typeof value.getMonth === 'function' && typeof value.getYear
			=== 'function'
    },
    number: function number(value) {
        if (isNaN(value)) {
            return false
        }

        // 修改源码，将字符串数值先转为数值
        return typeof +value === 'number'
    },
    object: function object(value) {
        return typeof value === 'object' && !types.array(value)
    },
    method: function method(value) {
        return typeof value === 'function'
    },
    email: function email(value) {
        return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255
    },
    url: function url(value) {
        return typeof value === 'string' && !!value.match(pattern.url)
    },
    hex: function hex(value) {
        return typeof value === 'string' && !!value.match(pattern.hex)
    }
}
/**
 *  Rule for validating the type of a value.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function type(rule, value, source, errors, options) {
    if (rule.required && value === undefined) {
        required(rule, value, source, errors, options)
        return
    }

    const custom = ['integer', 'float', 'array', 'regexp', 'object', 'method', 'email', 'number', 'date', 'url', 'hex']
    const ruleType = rule.type

    if (custom.indexOf(ruleType) > -1) {
        if (!types[ruleType](value)) {
            errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type))
        } // straight typeof check
    } else if (ruleType && typeof value !== rule.type) {
        errors.push(format(options.messages.types[ruleType], rule.fullField, rule.type))
    }
}

/**
 *  Rule for validating minimum and maximum allowed values.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function range(rule, value, source, errors, options) {
    const len = typeof rule.len === 'number'
    const min = typeof rule.min === 'number'
    const max = typeof rule.max === 'number' // 正则匹配码点范围从U+010000一直到U+10FFFF的文字（补充平面Supplementary Plane）

    const spRegexp = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g
    let val = value
    let key = null
    const num = typeof value === 'number'
    const str = typeof value === 'string'
    const arr = Array.isArray(value)

    if (num) {
        key = 'number'
    } else if (str) {
        key = 'string'
    } else if (arr) {
        key = 'array'
    } // if the value is not of a supported type for range validation
    // the validation rule rule should use the
    // type property to also test for a particular type

    if (!key) {
        return false
    }

    if (arr) {
        val = value.length
    }

    if (str) {
        // 处理码点大于U+010000的文字length属性不准确的bug，如"𠮷𠮷𠮷".lenght !== 3
        val = value.replace(spRegexp, '_').length
    }

    if (len) {
        if (val !== rule.len) {
            errors.push(format(options.messages[key].len, rule.fullField, rule.len))
        }
    } else if (min && !max && val < rule.min) {
        errors.push(format(options.messages[key].min, rule.fullField, rule.min))
    } else if (max && !min && val > rule.max) {
        errors.push(format(options.messages[key].max, rule.fullField, rule.max))
    } else if (min && max && (val < rule.min || val > rule.max)) {
        errors.push(format(options.messages[key].range, rule.fullField, rule.min, rule.max))
    }
}

const ENUM = 'enum'
/**
 *  Rule for validating a value exists in an enumerable list.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function enumerable(rule, value, source, errors, options) {
    rule[ENUM] = Array.isArray(rule[ENUM]) ? rule[ENUM] : []

    if (rule[ENUM].indexOf(value) === -1) {
        errors.push(format(options.messages[ENUM], rule.fullField, rule[ENUM].join(', ')))
    }
}

/**
 *  Rule for validating a regular expression pattern.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param source The source object being validated.
 *  @param errors An array of errors that this rule may add
 *  validation errors to.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function pattern$1(rule, value, source, errors, options) {
    if (rule.pattern) {
        if (rule.pattern instanceof RegExp) {
            // if a RegExp instance is passed, reset `lastIndex` in case its `global`
            // flag is accidentally set to `true`, which in a validation scenario
            // is not necessary and the result might be misleading
            rule.pattern.lastIndex = 0

            if (!rule.pattern.test(value)) {
                errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern))
            }
        } else if (typeof rule.pattern === 'string') {
            const _pattern = new RegExp(rule.pattern)

            if (!_pattern.test(value)) {
                errors.push(format(options.messages.pattern.mismatch, rule.fullField, value, rule.pattern))
            }
        }
    }
}

const rules = {
    required,
    whitespace,
    type,
    range,
    enum: enumerable,
    pattern: pattern$1
}

/**
 *  Performs validation for string types.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function string(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value, 'string') && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options, 'string')

        if (!isEmptyValue(value, 'string')) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
            rules.pattern(rule, value, source, errors, options)

            if (rule.whitespace === true) {
                rules.whitespace(rule, value, source, errors, options)
            }
        }
    }

    callback(errors)
}

/**
 *  Validates a function.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function method(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates a number.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function number(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (value === '') {
            value = undefined
        }

        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates a boolean.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function _boolean(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates the regular expression type.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function regexp(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (!isEmptyValue(value)) {
            rules.type(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates a number is an integer.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function integer(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates a number is a floating point number.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function floatFn(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates an array.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function array(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value, 'array') && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options, 'array')

        if (!isEmptyValue(value, 'array')) {
            rules.type(rule, value, source, errors, options)
            rules.range(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates an object.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function object(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (value !== undefined) {
            rules.type(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

const ENUM$1 = 'enum'
/**
 *  Validates an enumerable list.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function enumerable$1(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (value !== undefined) {
            rules[ENUM$1](rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Validates a regular expression pattern.
 *
 *  Performs validation when a rule only contains
 *  a pattern property but is not declared as a string type.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function pattern$2(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value, 'string') && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (!isEmptyValue(value, 'string')) {
            rules.pattern(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

function date(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)

        if (!isEmptyValue(value)) {
            let dateObject

            if (typeof value === 'number') {
                dateObject = new Date(value)
            } else {
                dateObject = value
            }

            rules.type(rule, dateObject, source, errors, options)

            if (dateObject) {
                rules.range(rule, dateObject.getTime(), source, errors, options)
            }
        }
    }

    callback(errors)
}

function required$1(rule, value, callback, source, options) {
    const errors = []
    const type = Array.isArray(value) ? 'array' : typeof value
    rules.required(rule, value, source, errors, options, type)
    callback(errors)
}

function type$1(rule, value, callback, source, options) {
    const ruleType = rule.type
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value, ruleType) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options, ruleType)

        if (!isEmptyValue(value, ruleType)) {
            rules.type(rule, value, source, errors, options)
        }
    }

    callback(errors)
}

/**
 *  Performs validation for any type.
 *
 *  @param rule The validation rule.
 *  @param value The value of the field on the source object.
 *  @param callback The callback function.
 *  @param source The source object being validated.
 *  @param options The validation options.
 *  @param options.messages The validation messages.
 */

function any(rule, value, callback, source, options) {
    const errors = []
    const validate = rule.required || !rule.required && source.hasOwnProperty(rule.field)

    if (validate) {
        if (isEmptyValue(value) && !rule.required) {
            return callback()
        }

        rules.required(rule, value, source, errors, options)
    }

    callback(errors)
}

const validators = {
    string,
    method,
    number,
    boolean: _boolean,
    regexp,
    integer,
    float: floatFn,
    array,
    object,
    enum: enumerable$1,
    pattern: pattern$2,
    date,
    url: type$1,
    hex: type$1,
    email: type$1,
    required: required$1,
    any
}

function newMessages() {
    return {
        default: 'Validation error on field %s',
        required: '%s is required',
        enum: '%s must be one of %s',
        whitespace: '%s cannot be empty',
        date: {
            format: '%s date %s is invalid for format %s',
            parse: '%s date could not be parsed, %s is invalid ',
            invalid: '%s date %s is invalid'
        },
        types: {
            string: '%s is not a %s',
            method: '%s is not a %s (function)',
            array: '%s is not an %s',
            object: '%s is not an %s',
            number: '%s is not a %s',
            date: '%s is not a %s',
            boolean: '%s is not a %s',
            integer: '%s is not an %s',
            float: '%s is not a %s',
            regexp: '%s is not a valid %s',
            email: '%s is not a valid %s',
            url: '%s is not a valid %s',
            hex: '%s is not a valid %s'
        },
        string: {
            len: '%s must be exactly %s characters',
            min: '%s must be at least %s characters',
            max: '%s cannot be longer than %s characters',
            range: '%s must be between %s and %s characters'
        },
        number: {
            len: '%s must equal %s',
            min: '%s cannot be less than %s',
            max: '%s cannot be greater than %s',
            range: '%s must be between %s and %s'
        },
        array: {
            len: '%s must be exactly %s in length',
            min: '%s cannot be less than %s in length',
            max: '%s cannot be greater than %s in length',
            range: '%s must be between %s and %s in length'
        },
        pattern: {
            mismatch: '%s value %s does not match pattern %s'
        },
        clone: function clone() {
            const cloned = JSON.parse(JSON.stringify(this))
            cloned.clone = this.clone
            return cloned
        }
    }
}
const messages = newMessages()

/**
 *  Encapsulates a validation schema.
 *
 *  @param descriptor An object declaring validation rules
 *  for this schema.
 */

function Schema(descriptor) {
    this.rules = null
    this._messages = messages
    this.define(descriptor)
}

Schema.prototype = {
    messages: function messages(_messages) {
        if (_messages) {
            this._messages = deepMerge(newMessages(), _messages)
        }

        return this._messages
    },
    define: function define(rules) {
        if (!rules) {
            throw new Error('Cannot configure a schema with no rules')
        }

        if (typeof rules !== 'object' || Array.isArray(rules)) {
            throw new Error('Rules must be an object')
        }

        this.rules = {}
        let z
        let item

        for (z in rules) {
            if (rules.hasOwnProperty(z)) {
                item = rules[z]
                this.rules[z] = Array.isArray(item) ? item : [item]
            }
        }
    },
    validate: function validate(source_, o, oc) {
        const _this = this

        if (o === void 0) {
            o = {}
        }

        if (oc === void 0) {
            oc = function oc() {}
        }

        let source = source_
        let options = o
        let callback = oc

        if (typeof options === 'function') {
            callback = options
            options = {}
        }

        if (!this.rules || Object.keys(this.rules).length === 0) {
            if (callback) {
                callback()
            }

            return Promise.resolve()
        }

        function complete(results) {
            let i
            let errors = []
            let fields = {}

            function add(e) {
                if (Array.isArray(e)) {
                    let _errors

                    errors = (_errors = errors).concat.apply(_errors, e)
                } else {
                    errors.push(e)
                }
            }

            for (i = 0; i < results.length; i++) {
                add(results[i])
            }

            if (!errors.length) {
                errors = null
                fields = null
            } else {
                fields = convertFieldsError(errors)
            }

            callback(errors, fields)
        }

        if (options.messages) {
            let messages$1 = this.messages()

            if (messages$1 === messages) {
                messages$1 = newMessages()
            }

            deepMerge(messages$1, options.messages)
            options.messages = messages$1
        } else {
            options.messages = this.messages()
        }

        let arr
        let value
        const series = {}
        const keys = options.keys || Object.keys(this.rules)
        keys.forEach((z) => {
            arr = _this.rules[z]
            value = source[z]
            arr.forEach((r) => {
                let rule = r

                if (typeof rule.transform === 'function') {
                    if (source === source_) {
                        source = { ...source }
                    }

                    value = source[z] = rule.transform(value)
                }

                if (typeof rule === 'function') {
                    rule = {
                        validator: rule
                    }
                } else {
                    rule = { ...rule }
                }

                rule.validator = _this.getValidationMethod(rule)
                rule.field = z
                rule.fullField = rule.fullField || z
                rule.type = _this.getType(rule)

                if (!rule.validator) {
                    return
                }

                series[z] = series[z] || []
                series[z].push({
                    rule,
                    value,
                    source,
                    field: z
                })
            })
        })
        const errorFields = {}
        return asyncMap(series, options, (data, doIt) => {
            const { rule } = data
            let deep = (rule.type === 'object' || rule.type === 'array') && (typeof rule.fields === 'object' || typeof rule.defaultField
				=== 'object')
            deep = deep && (rule.required || !rule.required && data.value)
            rule.field = data.field

            function addFullfield(key, schema) {
                return { ...schema, fullField: `${rule.fullField}.${key}` }
            }

            function cb(e) {
                if (e === void 0) {
                    e = []
                }

                let errors = e

                if (!Array.isArray(errors)) {
                    errors = [errors]
                }

                if (!options.suppressWarning && errors.length) {
                    Schema.warning('async-validator:', errors)
                }

                if (errors.length && rule.message) {
                    errors = [].concat(rule.message)
                }

                errors = errors.map(complementError(rule))

                if (options.first && errors.length) {
                    errorFields[rule.field] = 1
                    return doIt(errors)
                }

                if (!deep) {
                    doIt(errors)
                } else {
                    // if rule is required but the target object
                    // does not exist fail at the rule level and don't
                    // go deeper
                    if (rule.required && !data.value) {
                        if (rule.message) {
                            errors = [].concat(rule.message).map(complementError(rule))
                        } else if (options.error) {
                            errors = [options.error(rule, format(options.messages.required, rule.field))]
                        } else {
                            errors = []
                        }

                        return doIt(errors)
                    }

                    let fieldsSchema = {}

                    if (rule.defaultField) {
                        for (const k in data.value) {
                            if (data.value.hasOwnProperty(k)) {
                                fieldsSchema[k] = rule.defaultField
                            }
                        }
                    }

                    fieldsSchema = { ...fieldsSchema, ...data.rule.fields }

                    for (const f in fieldsSchema) {
                        if (fieldsSchema.hasOwnProperty(f)) {
                            const fieldSchema = Array.isArray(fieldsSchema[f]) ? fieldsSchema[f] : [fieldsSchema[f]]
                            fieldsSchema[f] = fieldSchema.map(addFullfield.bind(null, f))
                        }
                    }

                    const schema = new Schema(fieldsSchema)
                    schema.messages(options.messages)

                    if (data.rule.options) {
                        data.rule.options.messages = options.messages
                        data.rule.options.error = options.error
                    }

                    schema.validate(data.value, data.rule.options || options, (errs) => {
                        const finalErrors = []

                        if (errors && errors.length) {
                            finalErrors.push.apply(finalErrors, errors)
                        }

                        if (errs && errs.length) {
                            finalErrors.push.apply(finalErrors, errs)
                        }

                        doIt(finalErrors.length ? finalErrors : null)
                    })
                }
            }

            let res

            if (rule.asyncValidator) {
                res = rule.asyncValidator(rule, data.value, cb, data.source, options)
            } else if (rule.validator) {
                res = rule.validator(rule, data.value, cb, data.source, options)

                if (res === true) {
                    cb()
                } else if (res === false) {
                    cb(rule.message || `${rule.field} fails`)
                } else if (res instanceof Array) {
                    cb(res)
                } else if (res instanceof Error) {
                    cb(res.message)
                }
            }

            if (res && res.then) {
                res.then(() => cb(), (e) => cb(e))
            }
        }, (results) => {
            complete(results)
        })
    },
    getType: function getType(rule) {
        if (rule.type === undefined && rule.pattern instanceof RegExp) {
            rule.type = 'pattern'
        }

        if (typeof rule.validator !== 'function' && rule.type && !validators.hasOwnProperty(rule.type)) {
            throw new Error(format('Unknown rule type %s', rule.type))
        }

        return rule.type || 'string'
    },
    getValidationMethod: function getValidationMethod(rule) {
        if (typeof rule.validator === 'function') {
            return rule.validator
        }

        const keys = Object.keys(rule)
        const messageIndex = keys.indexOf('message')

        if (messageIndex !== -1) {
            keys.splice(messageIndex, 1)
        }

        if (keys.length === 1 && keys[0] === 'required') {
            return validators.required
        }

        return validators[this.getType(rule)] || false
    }
}

Schema.register = function register(type, validator) {
    if (typeof validator !== 'function') {
        throw new Error('Cannot register a validator by type, validator is not a function')
    }

    validators[type] = validator
}

Schema.warning = warning
Schema.messages = messages

export default Schema
// # sourceMappingURL=index.js.map
zE *Wxa{
  "id": "uv-formform 表单TH9组件一般用于表单场景，可以配置Input输入框，Textarea文本域，Checkbox复选框，Radio单选框，开关$选择器等，进行表单验证等+formU!表单",
    "表单验证[icon",
			"uv-line",
			"uv-transition",
			"uv-action-sheet",
			"uv-input",
			"uv-button
=3x## Form 表单form**

此组件一般用于表单场景，可以配置`Input`输入框，`Textarea`文本域，`Checkbox`复选框，`Radio`5选框，开关选择器等，进行表单验证等/formz( style="font-size:14px;font-weight:700;";2	x e100644 changelog.md }`;G62<Aшu40000 components N4ʨDcp[Bl100644 package.json :8ZbSL.^v>"z100644 readme.md VUuߝe(J=bx ## 1.0.3（2023-08-14）
1. 新增参数textStyle，自定义文本样式
## 1.0.2（2023-06-27）
优化
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
1. 新增uv-loading-icon组件
9E)-x j间隔槽组件
x! 40000 uv-gap COnk=
QA*ǻ}xJ 100644 props.js 
ׇQ{\oy100644 uv-gap.vue Ur
l%詆Z20wA"# x9export default {
	props: {
		// 背景颜色（默认transparent）
		bgColor: {
			type: String,
			default: 'transparent'
		},
		// 分割槽高度，单位px（默认20）
		height: {
			type: [String, Number],
			default: 20
		},
		// 与上一个组件的距离
		marginTop: {
			type: [String, Number],
			default: 0
		},
		// 与下一个组件的距离
		marginBottom: {
			type: [String, Number],
			default: 0
		},
		...uni.$uv?.props?.gap
	}
}I"Ux_<template>
	<view class="uv-gap" :style="[gapStyle]"></view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * gap 间隔槽
	 * @description 该组件一般用于内容块之间的用一个灰色块隔开的场景，方便用户风格统一，减少工作量
	 * @tutorial https://www.uvui.cn/components/gap.html
	 * @property {String}			bgColor			背景颜色 （默认 'transparent' ）
	 * @property {String | Number}	height			分割槽高度，单位px （默认 20 ）
	 * @property {String | Number}	marginTop		与前一个组件的距离，单位px（ 默认 0 ）
	 * @property {String | Number}	marginBottom	与后一个组件的距离，单位px （默认 0 ）
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 * 
	 * @example <uv-gap height="80" bg-color="#bbb"></uv-gap>
	 */
	export default {
		name: "uv-gap",
		mixins: [mpMixin, mixin,props],
		computed: {
			gapStyle() {
				const style = {
					backgroundColor: this.bgColor,
					height: this.$uv.addUnit(this.height),
					marginTop: this.$uv.addUnit(this.marginTop),
					marginBottom: this.$uv.addUnit(this.marginBottom),
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		}
	};
</script>
9>'x s## Gap 间隔槽gap@_容块之间的用一个灰色块隔开的场景，方便用户风格统一，减少工作量1gapݥ
9U	x e100644 changelog.md a&K~40000 components 
܄ǭG$wcR 2100644 package.json 7|&>?$?ٹ100644 readme.md 2DKY@{?@xI 40000 uv-grid-item )AfoDeI'40000 uv-grid 7gۺNǠxP 100644 props.js k)ʝʈp{'100644 uv-grid-item.vue -uǤGHSO]5xTexport default {
	props: {
		// item标签的名称，作为与uv-tabbar的value参数匹配的标识符
		name: {
			type: [String, Number, null],
			default: null
		},
		// uv-ui内置图标或者绝对路径的图片
		icon: {
			icon: String,
			default: ''
		},
		// 图标大小，默认uv-tabbar的iconSize=20
		iconSize: {
			type: [String, Number],
			default: ''
		},
		// 右上角的角标提示信息
		badge: {
			type: [String, Number, null],
			default: null
		},
		// 是否显示圆点，将会覆盖badge参数
		dot: {
			type: Boolean,
			default: false
		},
		// 描述文本
		text: {
			type: String,
			default: ''
		},
		// 控制徽标的位置，对象或者字符串形式，可以设置top和right属性
		badgeStyle: {
			type: [Object, String],
			default: 'top: 6px;right:2px;'
		},
		...uni.$uv?.props?.tabbarItem
	}
}gOaxP  宫格的namehG背景颜色
		bgColor\"transparent)gridItem
	}
}"Lx(<template>
	<!-- #ifndef APP-NVUE -->
	<view
	    class="uv-grid-item"
	    hover-class="uv-grid-item--hover-class"
	    :hover-stay-time="200"
	    @tap="clickHandler"
	    :class="classes"
	    :style="[itemStyle]"
	>
		<slot />
	</view>
	<!-- #endif -->
	<!-- #ifdef APP-NVUE -->
	<view
	    class="uv-grid-item"
	    :hover-stay-time="200"
	    @tap="clickHandler"
	    :class="classes"
	    :style="[itemStyle]"
	>
		<slot />
	</view>
	<!-- #endif -->
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * gridItem 提示
	 * @description 宫格组件一般用于同时展示多个同类项目的场景，可以给宫格的项目设置徽标组件(badge)，或者图标等，也可以扩展为左右滑动的轮播形式。搭配uv-grid使用
	 * @tutorial https://www.uvui.cn/components/grid.html
	 * @property {String | Number}	name		宫格的name ( 默认 null )
	 * @property {String}			bgColor		宫格的背景颜色 （默认 'transparent' ）
	 * @property {Object}			customStyle	自定义样式，对象形式
	 * @event {Function} click 点击宫格触发
	 * @example <uv-grid-item></uv-grid-item>
	 */
	export default {
		name: "uv-grid-item",
		mixins: [mpMixin, mixin, props],
		emits: ['$uvGridItem','click'],
		data() {
			return {
				parentData: {
					col: 3, // 父组件划分的宫格数
					border: true, // 是否显示边框，根据父组件决定
				},
				// #ifdef APP-NVUE
				width: 0, // nvue下才这么计算，vue下放到computed中，否则会因为延时造成闪烁
				// #endif
				classes: [], // 类名集合，用于判断是否显示右边和下边框
			};
		},
		created() {
			// 父组件的实例
			this.updateParentData()
		},
		mounted() {
			this.init()
		},
		computed: {
			// #ifndef APP-NVUE
			// vue下放到computed中，否则会因为延时造成闪烁
			width() {
				return 100 / Number(this.parentData.col) + '%'
			},
			// #endif
			itemStyle() {
				const style = {
					background: this.bgColor,
					width: this.width
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		methods: {
			init() {
				// 用于在父组件uv-grid的children中被添加入子组件时，
				// 重新计算item的边框
				uni.$on('$uvGridItem', () => {
					this.gridItemClasses()
				})
				// #ifdef APP-NVUE
				// 获取元素该有的长度，nvue下要延时才准确
				this.$nextTick(function(){
					this.getItemWidth()
				})
				// #endif
				// 发出事件，通知所有的grid-item都重新计算自己的边框
				uni.$emit('$uvGridItem')
				this.gridItemClasses()
			},
			// 获取父组件的参数
			updateParentData() {
				// 此方法写在mixin中
				this.getParentData('uv-grid');
			},
			clickHandler() {
				let name = this.name
				// 如果没有设置name属性，历遍父组件的children数组，判断当前的元素是否和本实例this相等，找出当前组件的索引
				const children = this.parent?.children
				if(children && this.name === null) {
					name = children.findIndex(child => child === this)
				}
				// 调用父组件方法，发出事件
				this.parent && this.parent.childClick(name)
				this.$emit('click', name)
			},
			async getItemWidth() {
				// 如果是nvue，不能使用百分比，只能使用固定宽度
				let width = 0
				if(this.parent) {
					// 获取父组件宽度后，除以栅格数，得出每个item的宽度
					const parentWidth = await this.getParentWidth()
					width = parentWidth / Number(this.parentData.col) + 'px'
				}
				this.width = width
			},
			// 获取父元素的尺寸
			getParentWidth() {
				// #ifdef APP-NVUE
				// 返回一个promise，让调用者可以用await同步获取
				const dom = uni.requireNativePlugin('dom')
				return new Promise(resolve => {
					// 调用父组件的ref
					dom.getComponentRect(this.parent.$refs['uv-grid'], res => {
						resolve(res.size.width)
					})
				})
				// #endif
			},
			gridItemClasses() {
				if(this.parentData.border) {
					let classes = []
					this.parent.children.map((child, index) =>{
						if(this === child) {
							const len = this.parent.children.length
							// 贴近右边屏幕边沿的child，并且最后一个（比如只有横向2个的时候），无需右边框
							if((index + 1) % this.parentData.col !== 0 && index + 1 !== len) {
								classes.push('uv-border-right')
							}
							// 总的宫格数量对列数取余的值
							// 如果取余后，值为0，则意味着要将最后一排的宫格，都不需要下边框
							const lessNum = len % this.parentData.col === 0 ? this.parentData.col : len % this.parentData.col
							// 最下面的一排child，无需下边框
							if(index < len - lessNum) {
								classes.push('uv-border-bottom')
							}
						}
					})
					// 支付宝，头条小程序无法动态绑定一个数组类名，否则解析出来的结果会带有","，而导致失效
					// #ifdef MP-ALIPAY || MP-TOUTIAO
					classes = classes.join(' ')
					// #endif
					this.classes = classes
				}
			}
		},
		// #ifdef VUE2
		beforeDestroy() {
			// 移除事件监听，释放性能
			uni.$off('$uvGridItem')
		},
		// #endif
		// #ifdef VUE3
		unmounted() {
			// 移除事件监听，释放性能
			uni.$off('$uvGridItem')
		}
		// #endif
	};
</script>

<style lang="scss" scoped>
	$show-border: 1;
	$show-border-right: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-grid-item-hover-class-opcatiy:.5 !default;
	$uv-grid-item-margin-top:1rpx !default;
	$uv-grid-item-border-right-width:0.5px !default;
	$uv-grid-item-border-bottom-width:0.5px !default;
	$uv-grid-item-border-right-color:$uv-border-color !default;
	$uv-grid-item-border-bottom-color:$uv-border-color !default;
	.uv-grid-item {
		align-items: center;
		justify-content: center;
		position: relative;
		flex-direction: column;
		/* #ifndef APP-NVUE */
		box-sizing: border-box;
		display: flex;
		/* #endif */

		/* #ifdef MP */
		position: relative;
		float: left;
		/* #endif */

		/* #ifdef MP-WEIXIN */
		margin-top:$uv-grid-item-margin-top;
		/* #endif */

		&--hover-class {
			opacity:$uv-grid-item-hover-class-opcatiy;
		}
	}

	/* #ifdef APP-NVUE */
	// 由于nvue不支持组件内引入app.vue中再引入的样式，所以需要写在这里
	.uv-border-right {
		border-right-width:$uv-grid-item-border-right-width;
		border-color: $uv-grid-item-border-right-color;
	}

	.uv-border-bottom {
		border-bottom-width:$uv-grid-item-border-bottom-width;
		border-color:$uv-grid-item-border-bottom-color;
	}
	/* #endif */
</style>
.xK 100644 props.js GM^HFfc7z'`100644 uv-grid.vue ǉ)n̢`@afxZexport default {
	props: {
		// 分成几列
		col: {
			type: [String, Number],
			default: 3
		},
		// 是否显示边框
		border: {
			type: Boolean,
			default: false
		},
		// 宫格对齐方式，表现为数量少的时候，靠左，居中，还是靠右
		align: {
			type: String,
			default: 'left'
		},
		...uni.$uv?.props?.grid
	}
}3dxg<template>
	<view
	    class="uv-grid"
		ref='uv-grid'
	    :style="[gridStyle]"
	>
		<slot />
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * grid 宫格布局
	 * @description 宫格组件一般用于同时展示多个同类项目的场景，可以给宫格的项目设置徽标组件(badge)，或者图标等，也可以扩展为左右滑动的轮播形式。
	 * @tutorial https://www.uvui.cn/components/grid.html
	 * @property {String | Number}	col			宫格的列数（默认 3 ）
	 * @property {Boolean}			border		是否显示宫格的边框（默认 false ）
	 * @property {String}			align		宫格对齐方式，表现为数量少的时候，靠左，居中，还是靠右 （默认 'left' ）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * @event {Function} click 点击宫格触发
	 * @example <uv-grid :col="3" @click="click"></uv-grid>
	 */
	export default {
		name: 'uv-grid',
		mixins: [mpMixin, mixin, props],
		emits: ['click'],
		data() {
			return {
				index: 0,
				width: 0
			}
		},
		watch: {
			// 当父组件需要子组件需要共享的参数发生了变化，手动通知子组件
			parentData() {
				if (this.children.length) {
					this.children.map(child => {
						// 判断子组件(uv-radio)如果有updateParentData方法的话，就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
						typeof(child.updateParentData) == 'function' && child.updateParentData();
					})
				}
			},
		},
		created() {
			// 如果将children定义在data中，在微信小程序会造成循环引用而报错
			this.children = []
		},
		computed: {
			// 计算父组件的值是否发生变化
			parentData() {
				return [this.hoverClass, this.col, this.size, this.border];
			},
			// 宫格对齐方式
			gridStyle() {
				let style = {};
				switch (this.align) {
					case 'left':
						style.justifyContent = 'flex-start';
						break;
					case 'center':
						style.justifyContent = 'center';
						break;
					case 'right':
						style.justifyContent = 'flex-end';
						break;
					default:
						style.justifyContent = 'flex-start';
				};
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			}
		},
		methods: {
			// 此方法由uv-grid-item触发，用于在uv-grid发出事件
			childClick(name) {
				this.$emit('click', name)
			}
		}
	};
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
     $uv-grid-width:100% !default;
	.uv-grid {
		/* #ifdef MP */
		width: $uv-grid-width;
		position: relative;
		box-sizing: border-box;
		overflow: hidden;
		display: block;
		/* #endif */
		justify-content: center;
		@include flex;
		flex-wrap: wrap;
		align-items: center;
	}
</style>
EIlx,{
  "id": "uv-navbanavbar 自定义导航栏TH7",
  "description": "uv-navbar 此组件一般用于在特殊情况下，需要自定义导航栏的时候用到，一般建使用自带的原生导航栏+uv-navbaT" navbar",
    "自定义导航栏icon",
			"uv-status-ba+ڜ<x3;{
  "id": "uv-grid",
  "displayName": "uv-grid 宫格布局EH9grid 宫格组件一般用于同时展示多个同类项目的场景，可以给宫格的项目设置徽标组件(badge)，或:图标等，也可以扩展为左右滑动的轮播形弓*gridO!宫格布局",
    "grid	ʰ3x9## Switch 开关选择器

> **组件名：uv-switch**

选择开关用于在打开和关闭状态之间进行切换，支持异步操作。

# <a href="https://www.uvui.cn/components/switch.html" target="_blank">查看文档</a>

## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>（请不要 下载插件ZIP）</small>

### [更多插件，请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)

<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">

![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)

</a>

#### 如使用过程中有任何问题反馈，或者您对uv-ui有一些好的建议，欢迎加入uv-ui官方交流群：<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>uFx 3## Search 搜索 

> **组件名：uv-search**

搜索组件，集成了常见搜索框所需功能，支持前后插槽，用*可以一键引入，开箱即用。

# (searxpan8#pan_t[x ## Grid 宫格布局grid**

宫格组件一般用于同时展示多个同类项目的场景，可以给宫格的项目设置徽标组件(badge)，>者图标等，也可以扩展为左右滑动的轮播形式/grid+{	x e100644 changelog.md xR6j2q`R$Ff40000 components  Pq,J2zA100644 package.json 
[р籠W䘐H100644 readme.md &ᡭ}_
q`=DxM## 1.0.13（2023-12-06）
1. 优化
## 1.0.12（2023-12-06）
1. 阻止事件冒泡处理
## 1.0.11（2023-10-29）
1. imgMode默认值改成aspectFit
## 1.0.10（2023-08-13）
1. 优化nvue，方便自定义图标
## 1.0.9（2023-07-28）
1. 修改几个对应错误图标的BUG
## 1.0.8（2023-07-24）
1. 优化 支持base64图片
## 1.0.7（2023-07-17）
1. 修复  uv-icon 恢复uv-empty相关的图标
## 1.0.6（2023-07-13）
1. 修复icon设置name属性对应图标错误的BUG
## 1.0.5（2023-07-04）
1. 更新图标，删除一些不常用的图标
2. 删除base64，修改成ttf文件引入读取图标
3. 自定义图标文档说明：https://www.uvui.cn/guide/customIcon.html
## 1.0.4（2023-07-03）
1. 修复主题颜色在APP不生效的BUG
## 1.0.3（2023-05-24）
1. 将线上ttf字体包替换成base64，避免加载时或者网络差时候显示白色方块
## 1.0.2（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.1（2023-05-10）
1. 修复小程序中异常显示
## 1.0.0（2023-05-04）
新发版
jL4Hx" 40000 uv-icon v=C?D{&	x i100644 icons.js iڹc#Zelݼ100644 props.js vhϖ_pt<v+100644 uv-icon.vue [54
'Uշ+100644 uvicons.ttf O~h_~6Z|P<׾xqexport default {
	'uvicon-level': 'e68f',
	'uvicon-checkbox-mark': 'e659',
	'uvicon-folder': 'e694',
	'uvicon-movie': 'e67c',
	'uvicon-star-fill': 'e61e',
	'uvicon-star': 'e618',
	'uvicon-phone-fill': 'e6ac',
	'uvicon-phone': 'e6ba',
	'uvicon-apple-fill': 'e635',
	'uvicon-backspace': 'e64d',
	'uvicon-attach': 'e640',
	'uvicon-empty-data': 'e671',
	'uvicon-empty-address': 'e68a',
	'uvicon-empty-favor': 'e662',
	'uvicon-empty-car': 'e657',
	'uvicon-empty-order': 'e66b',
	'uvicon-empty-list': 'e672',
	'uvicon-empty-search': 'e677',
	'uvicon-empty-permission': 'e67d',
	'uvicon-empty-news': 'e67e',
	'uvicon-empty-history': 'e685',
	'uvicon-empty-coupon': 'e69b',
	'uvicon-empty-page': 'e60e',
	'uvicon-empty-wifi-off': 'e6cc',
	'uvicon-reload': 'e627',
	'uvicon-order': 'e695',
	'uvicon-server-man': 'e601',
	'uvicon-search': 'e632',
	'uvicon-more-dot-fill': 'e66f',
	'uvicon-scan': 'e631',
	'uvicon-map': 'e665',
	'uvicon-map-fill': 'e6a8',
	'uvicon-tags': 'e621',
	'uvicon-tags-fill': 'e613',
	'uvicon-eye': 'e664',
	'uvicon-eye-fill': 'e697',
	'uvicon-eye-off': 'e69c',
	'uvicon-eye-off-outline': 'e688',
	'uvicon-mic': 'e66d',
	'uvicon-mic-off': 'e691',
	'uvicon-calendar': 'e65c',
	'uvicon-trash': 'e623',
	'uvicon-trash-fill': 'e6ce',
	'uvicon-play-left': 'e6bf',
	'uvicon-play-right': 'e6b3',
	'uvicon-minus': 'e614',
	'uvicon-plus': 'e625',
	'uvicon-info-circle': 'e69f',
	'uvicon-info-circle-fill': 'e6a7',
	'uvicon-question-circle': 'e622',
	'uvicon-question-circle-fill': 'e6bc',
	'uvicon-close': 'e65a',
	'uvicon-checkmark': 'e64a',
	'uvicon-checkmark-circle': 'e643',
	'uvicon-checkmark-circle-fill': 'e668',
	'uvicon-setting': 'e602',
	'uvicon-setting-fill': 'e6d0',
	'uvicon-heart': 'e6a2',
	'uvicon-heart-fill': 'e68b',
	'uvicon-camera': 'e642',
	'uvicon-camera-fill': 'e650',
	'uvicon-more-circle': 'e69e',
	'uvicon-more-circle-fill': 'e684',
	'uvicon-chat': 'e656',
	'uvicon-chat-fill': 'e63f',
	'uvicon-bag': 'e647',
	'uvicon-error-circle': 'e66e',
	'uvicon-error-circle-fill': 'e655',
	'uvicon-close-circle': 'e64e',
	'uvicon-close-circle-fill': 'e666',
	'uvicon-share': 'e629',
	'uvicon-share-fill': 'e6bb',
	'uvicon-share-square': 'e6c4',
	'uvicon-shopping-cart': 'e6cb',
	'uvicon-shopping-cart-fill': 'e630',
	'uvicon-bell': 'e651',
	'uvicon-bell-fill': 'e604',
	'uvicon-list': 'e690',
	'uvicon-list-dot': 'e6a9',
	'uvicon-zhifubao-circle-fill': 'e617',
	'uvicon-weixin-circle-fill': 'e6cd',
	'uvicon-weixin-fill': 'e620',
	'uvicon-qq-fill': 'e608',
	'uvicon-qq-circle-fill': 'e6b9',
	'uvicon-moments-circel-fill': 'e6c2',
	'uvicon-moments': 'e6a0',
	'uvicon-car': 'e64f',
	'uvicon-car-fill': 'e648',
	'uvicon-warning-fill': 'e6c7',
	'uvicon-warning': 'e6c1',
	'uvicon-clock-fill': 'e64b',
	'uvicon-clock': 'e66c',
	'uvicon-edit-pen': 'e65d',
	'uvicon-edit-pen-fill': 'e679',
	'uvicon-email': 'e673',
	'uvicon-email-fill': 'e683',
	'uvicon-minus-circle': 'e6a5',
	'uvicon-plus-circle': 'e603',
	'uvicon-plus-circle-fill': 'e611',
	'uvicon-file-text': 'e687',
	'uvicon-file-text-fill': 'e67f',
	'uvicon-pushpin': 'e6d1',
	'uvicon-pushpin-fill': 'e6b6',
	'uvicon-grid': 'e68c',
	'uvicon-grid-fill': 'e698',
	'uvicon-play-circle': 'e6af',
	'uvicon-play-circle-fill': 'e62a',
	'uvicon-pause-circle-fill': 'e60c',
	'uvicon-pause': 'e61c',
	'uvicon-pause-circle': 'e696',
	'uvicon-gift-fill': 'e6b0',
	'uvicon-gift': 'e680',
	'uvicon-kefu-ermai': 'e660',
	'uvicon-server-fill': 'e610',
	'uvicon-coupon-fill': 'e64c',
	'uvicon-coupon': 'e65f',
	'uvicon-integral': 'e693',
	'uvicon-integral-fill': 'e6b1',
	'uvicon-home-fill': 'e68e',
	'uvicon-home': 'e67b',
	'uvicon-account': 'e63a',
	'uvicon-account-fill': 'e653',
	'uvicon-thumb-down-fill': 'e628',
	'uvicon-thumb-down': 'e60a',
	'uvicon-thumb-up': 'e612',
	'uvicon-thumb-up-fill': 'e62c',
	'uvicon-lock-fill': 'e6a6',
	'uvicon-lock-open': 'e68d',
	'uvicon-lock-opened-fill': 'e6a1',
	'uvicon-lock': 'e69d',
	'uvicon-red-packet': 'e6c3',
	'uvicon-photo-fill': 'e6b4',
	'uvicon-photo': 'e60d',
	'uvicon-volume-off-fill': 'e6c8',
	'uvicon-volume-off': 'e6bd',
	'uvicon-volume-fill': 'e624',
	'uvicon-volume': 'e605',
	'uvicon-download': 'e670',
	'uvicon-arrow-up-fill': 'e636',
	'uvicon-arrow-down-fill': 'e638',
	'uvicon-play-left-fill': 'e6ae',
	'uvicon-play-right-fill': 'e6ad',
	'uvicon-arrow-downward': 'e634',
	'uvicon-arrow-leftward': 'e63b',
	'uvicon-arrow-rightward': 'e644',
	'uvicon-arrow-upward': 'e641',
	'uvicon-arrow-down': 'e63e',
	'uvicon-arrow-right': 'e63c',
	'uvicon-arrow-left': 'e646',
	'uvicon-arrow-up': 'e633',
	'uvicon-skip-back-left': 'e6c5',
	'uvicon-skip-forward-right': 'e61f',
	'uvicon-arrow-left-double': 'e637',
	'uvicon-man': 'e675',
	'uvicon-woman': 'e626',
	'uvicon-en': 'e6b8',
	'uvicon-twitte': 'e607',
	'uvicon-twitter-circle-fill': 'e6cf'
}SƜٵjxZexport default {
	props: {
		// 图标类名
		name: {
			type: String,
			default: ''
		},
		// 图标颜色，可接受主题色
		color: {
			type: String,
			default: '#606266'
		},
		// 字体大小，单位px
		size: {
			type: [String, Number],
			default: '16px'
		},
		// 是否显示粗体
		bold: {
			type: Boolean,
			default: false
		},
		// 点击图标的时候传递事件出去的index（用于区分点击了哪一个）
		index: {
			type: [String, Number],
			default: null
		},
		// 触摸图标时的类名
		hoverClass: {
			type: String,
			default: ''
		},
		// 自定义扩展前缀，方便用户扩展自己的图标库
		customPrefix: {
			type: String,
			default: 'uvicon'
		},
		// 图标右边或者下面的文字
		label: {
			type: [String, Number],
			default: ''
		},
		// label的位置，只能右边或者下边
		labelPos: {
			type: String,
			default: 'right'
		},
		// label的大小
		labelSize: {
			type: [String, Number],
			default: '15px'
		},
		// label的颜色
		labelColor: {
			type: String,
			default: '#606266'
		},
		// label与图标的距离
		space: {
			type: [String, Number],
			default: '3px'
		},
		// 图片的mode
		imgMode: {
			type: String,
			default: 'aspectFit'
		},
		// 用于显示图片小图标时，图片的宽度
		width: {
			type: [String, Number],
			default: ''
		},
		// 用于显示图片小图标时，图片的高度
		height: {
			type: [String, Number],
			default: ''
		},
		// 用于解决某些情况下，让图标垂直居中的用途
		top: {
			type: [String, Number],
			default: 0
		},
		// 是否阻止事件传播
		stop: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.icon
	}
}ȶx<template>
	<view
	  class="uv-icon"
	  @tap="clickHandler"
	  :class="['uv-icon--' + labelPos]"
	>
		<image
		  class="uv-icon__img"
		  v-if="isImg"
		  :src="name"
		  :mode="imgMode"
		  :style="[imgStyle, $uv.addStyle(customStyle)]"
		></image>
		<text
		  v-else
		  class="uv-icon__icon"
		  :class="uClasses"
		  :style="[iconStyle, $uv.addStyle(customStyle)]"
		  :hover-class="hoverClass"
		>{{icon}}</text>
		<!-- 这里进行空字符串判断，如果仅仅是v-if="label"，可能会出现传递0的时候，结果也无法显示 -->
		<text
		  v-if="label !== ''" 
		  class="uv-icon__label"
		  :style="{
			color: labelColor,
			fontSize: $uv.addUnit(labelSize),
			marginLeft: labelPos == 'right' ? $uv.addUnit(space) : 0,
			marginTop: labelPos == 'bottom' ? $uv.addUnit(space) : 0,
			marginRight: labelPos == 'left' ? $uv.addUnit(space) : 0,
			marginBottom: labelPos == 'top' ? $uv.addUnit(space) : 0
		}"
		>{{ label }}</text>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	// nvue通过weex的dom模块引入字体，相关文档地址如下：
	// https://weex.apache.org/zh/docs/modules/dom.html#addrule
	import iconUrl from './uvicons.ttf';
	const domModule = weex.requireModule('dom')
	domModule.addRule('fontFace', {
		'fontFamily': "uvicon-iconfont",
		'src': "url('" + iconUrl + "')"
	})
	// #endif
	// 引入图标名称，已经对应的unicode
	import icons from './icons';
	import props from './props.js';
	/**
	 * icon 图标
	 * @description 基于字体的图标集，包含了大多数常见场景的图标。
	 * @tutorial https://www.uvui.cn/components/icon.html
	 * @property {String}			name			图标名称，见示例图标集
	 * @property {String}			color			图标颜色,可接受主题色 （默认 color['uv-content-color'] ）
	 * @property {String | Number}	size			图标字体大小，单位px （默认 '16px' ）
	 * @property {Boolean}			bold			是否显示粗体 （默认 false ）
	 * @property {String | Number}	index			点击图标的时候传递事件出去的index（用于区分点击了哪一个）
	 * @property {String}			hoverClass		图标按下去的样式类，用法同uni的view组件的hoverClass参数，详情见官网
	 * @property {String}			customPrefix	自定义扩展前缀，方便用户扩展自己的图标库 （默认 'uicon' ）
	 * @property {String | Number}	label			图标右侧的label文字
	 * @property {String}			labelPos		label相对于图标的位置，只能right或bottom （默认 'right' ）
	 * @property {String | Number}	labelSize		label字体大小，单位px （默认 '15px' ）
	 * @property {String}			labelColor		图标右侧的label文字颜色 （ 默认 color['uv-content-color'] ）
	 * @property {String | Number}	space			label与图标的距离，单位px （默认 '3px' ）
	 * @property {String}			imgMode			图片的mode
	 * @property {String | Number}	width			显示图片小图标时的宽度
	 * @property {String | Number}	height			显示图片小图标时的高度
	 * @property {String | Number}	top				图标在垂直方向上的定位 用于解决某些情况下，让图标垂直居中的用途  （默认 0 ）
	 * @property {Boolean}			stop			是否阻止事件传播 （默认 false ）
	 * @property {Object}			customStyle		icon的样式，对象形式
	 * @event {Function} click 点击图标时触发
	 * @event {Function} touchstart 事件触摸时触发
	 * @example <uv-icon name="photo" color="#2979ff" size="28"></uv-icon>
	 */
	export default {
		name: 'uv-icon',
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				colorType: [
					'primary',
					'success',
					'info',
					'error',
					'warning'
				]
			}
		},
		computed: {
			uClasses() {
				let classes = []
				classes.push(this.customPrefix)
				classes.push(this.customPrefix + '-' + this.name)
				// 主题色，通过类配置
				if (this.color && this.colorType.includes(this.color)) classes.push('uv-icon__icon--' + this.color)
				// 阿里，头条，百度小程序通过数组绑定类名时，无法直接使用[a, b, c]的形式，否则无法识别
				// 故需将其拆成一个字符串的形式，通过空格隔开各个类名
				//#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
				classes = classes.join(' ')
				//#endif
				return classes
			},
			iconStyle() {
				let style = {}
				style = {
					fontSize: this.$uv.addUnit(this.size),
					lineHeight: this.$uv.addUnit(this.size),
					fontWeight: this.bold ? 'bold' : 'normal',
					// 某些特殊情况需要设置一个到顶部的距离，才能更好的垂直居中
					top: this.$uv.addUnit(this.top)
				}
				// 非主题色值时，才当作颜色值
				if (this.color && !this.colorType.includes(this.color)) style.color = this.color
				return style
			},
			// 判断传入的name属性，是否图片路径，只要带有"/"均认为是图片形式
			isImg() {
				const isBase64 = this.name.indexOf('data:') > -1 && this.name.indexOf('base64') > -1;
				return this.name.indexOf('/') !== -1 || isBase64;
			},
			imgStyle() {
				let style = {}
				// 如果设置width和height属性，则优先使用，否则使用size属性
				style.width = this.width ? this.$uv.addUnit(this.width) : this.$uv.addUnit(this.size)
				style.height = this.height ? this.$uv.addUnit(this.height) : this.$uv.addUnit(this.size)
				return style
			},
			// 通过图标名，查找对应的图标
			icon() {
				// 如果内置的图标中找不到对应的图标，就直接返回name值，因为用户可能传入的是unicode代码
				const code = icons['uvicon-' + this.name];
				// #ifdef APP-NVUE
				if(!code) {
					return code ? unescape(`%u${code}`) : ['uvicon'].indexOf(this.customPrefix) > -1 ? unescape(`%u${this.name}`) : '';
				}
				// #endif
				return code ? unescape(`%u${code}`) : ['uvicon'].indexOf(this.customPrefix) > -1 ? this.name : '';
			}
		},
		methods: {
			clickHandler(e) {
				this.$emit('click', this.index)
				// 是否阻止事件冒泡
				this.stop && this.preventEvent(e)
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	// 变量定义
	$uv-icon-primary: $uv-primary !default;
	$uv-icon-success: $uv-success !default;
	$uv-icon-info: $uv-info !default;
	$uv-icon-warning: $uv-warning !default;
	$uv-icon-error: $uv-error !default;
	$uv-icon-label-line-height: 1 !default;
	/* #ifndef APP-NVUE */
	// 非nvue下加载字体
	@font-face {
		font-family: 'uvicon-iconfont';
		src: url('./uvicons.ttf') format('truetype');
	}
	/* #endif */
	.uv-icon {
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		align-items: center;
		&--left {
			flex-direction: row-reverse;
			align-items: center;
		}
		&--right {
			flex-direction: row;
			align-items: center;
		}
		&--top {
			flex-direction: column-reverse;
			justify-content: center;
		}
		&--bottom {
			flex-direction: column;
			justify-content: center;
		}
		&__icon {
			font-family: uvicon-iconfont;
			position: relative;
			@include flex;
			align-items: center;
			&--primary {
				color: $uv-icon-primary;
			}
			&--success {
				color: $uv-icon-success;
			}
			&--error {
				color: $uv-icon-error;
			}
			&--warning {
				color: $uv-icon-warning;
			}
			&--info {
				color: $uv-icon-info;
			}
		}
		&__img {
			/* #ifndef APP-NVUE */
			height: auto;
			will-change: transform;
			/* #endif */
		}
		&__label {
			/* #ifndef APP-NVUE */
			line-height: $uv-icon-label-line-height;
			/* #endif */
		}
	}
</style>)xК/e       0GSUB %z  8   TOS/2<I     `cmap  `  2glyf-    8head$      6hhea      $hmtxt       tlocar?(    <maxp      nameaj    post-M    
    \                            Z_<             D                       
 
             
 0 > DFLT latn                      liga                               2                         PfEd                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    ,               ,  
      V @  
*,68<DHQSWZ]`bfhsuwy  
,08:>FJSUY\_bdhkuwy{                                                                                      V ^ ` ` d l n n                         $$,.                            	 
       P Q R S T U V W X Y Z [ \ ] ^ _ ` 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 { | } ~                               ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O                                                                                                                                                                                                                                                                         `                                                          
  
                                                                                                         !  !     "  "     #  #     $  $   	  %  %   
  &  &     '  '     (  (     )  )     *  *     ,  ,     0  0   P  1  1   Q  2  2   R  3  3   S  4  4   T  5  5   U  6  6   V  8  8   W  :  :   X  ;  ;   Y  <  <   Z  >  >   [  ?  ?   \  @  @   ]  A  A   ^  B  B   _  C  C   `  D  D   a  F  F   b  G  G   c  H  H   d  J  J   e  K  K   f  L  L   g  M  M   h  N  N   i  O  O   j  P  P   k  Q  Q   l  S  S   m  U  U   n  V  V   o  W  W   p  Y  Y   q  Z  Z   r  \  \   s  ]  ]   t  _  _   u  `  `   v  b  b   w  d  d   x  e  e   y  f  f   z  h  h   {  k  k   |  l  l   }  m  m   ~  n  n     o  o     p  p     q  q     r  r     s  s     u  u     w  w     y  y     {  {     |  |     }  }     ~  ~                                                                                                                           !       "       #       $       %       &       '       (       )       *       +       ,       -       .       /       0       1       2       3       4       5       6       7       8       9       :       ;       <       =       >       ?       @       A       B       C       D       E       F       G       H       I       J       K       L       M       N       O       h  \*2$N8DH`	2	j	
$

>80HtB6fF.n`RF~l0$b.  l !2!V!!!""n"""#J##$Z$$$%&0&T&&'L'(F()0)X)**++D++-t-00d00142
2R23363r44`445|56
6F678889 9:@:;;=<==>2>t>?^?    + @  .'&/&'&32?6;676/76'&76/76?`&
a
&		%#$XZ	 
(^^ؚa		a         #";267.!#";267.Q **  **> **  **+s ++ ++s ++ +    "  #"/.?'.76?>&'%`
%	aff"ٙ( 		 !          " 7 ? O  %7%676&'%&>72&'&5"'&'&5>72%676&'#"&'>;2G




	(!	a	J3	
	B%C
]           ( 9 C M  2.'727&5>'"&>"&462.'267'>%"&4673"&467jv;5b/0! Iaff*L+6Vmf:^%T1^}N  E  VssVVr*F RR     I   ( 1  #776=./&73#264&"72"&46BA ++A++!
5AAQ+A++A+e   A   / H ] v    .'>7'>7.'"'.'&47>2"27>764'.'&".4>762"27>764'.'&"&=676?>765.""&'>7264&" ۥڥ[SQ|"##"|TP|"$$"|PT[[SP{"##"{PSSP|"##"|PS[Ok<<kFHHFllOOGFkkFGHEkkEH1GnGiPPi 	F""?8ڥۥA#"|QSTP|F##|PTSQ|"##"|PSSP{"##"{PSSP|"#<kllFHHFk<kEHGFkkFGHEk-'4DD5OeeN=#
	
t"       l   ' / < I  #5.'##";!>73264&%473#!&'!>=4&">75."N''1''1M
	;	O	zA''A''A		A		v    3   0 F J O  /#"&=467376#3>.67>54&'.7.6?>54'&462%!!pF!$$z"E=	-072
'+&#
7


?'%* $$+;	*m=Bs)	 Z30U 	e7$>	$$	    =    !"&463!2462"&46\4     * ) 5  %#5>'.#";326=36754&#>7.o	oo	_

tvZYvvYZvOpop_OVYwwYYww     | ;  #"/.>.'"3>7>"'&'.46767677>{*
f$[=mU.-Vm=a")uIDA246642ADId3c*P_.SkwkU,iY
	k2331aUB      Y 	 #  #32/.?#"&'54?>3!2:__		$$b
U?z)		$B	        E ? N _ n  %.'&"'6'&'727>&'."&'&"2767267>'6762"&'&"'.7>2"'.7>2=!!K!!K!!BK!!!LA"!K !!KB	,%,%%,%+	%,%,J.0

K,87!%(,,M&!77,M(),&!7 A
A
 

@A     , @  #"&4672>7#"&'5>735.'3#.=4675>7(my##	WO** xx **U*#Ĕ#})=b
#7#<&**
xx
***(Ĕ'   @   # ?  >7..'>7>7.#"&'5#"&46;5>232١٢갰@١٢鱰鰱F        i  ' <  &+54'#&##3!2676#"&=46;!76;M*M$mO'98("7-GGq / e:.	8&(7."%(C      I   $  #3276=4&"&462'>.B ++A**'4A+A++A+3
          !"&463!24\    @  U  67>7.67.'>7%.'&'&'54>7>>7!535#53546;3#3
/"C '_hw#q>O/77'!I"e2󊧧
A!PUH%!Q^cV!8	
8::H:`?      @ O     /76&/./.'#'&?3>?6?>/?>=.'.#'&/&'7>/&/576?6/7?6?3?%>4&.462V27%H'L(I&62WV47%H'L'G&62W'`
7*NJ:HO)7``
7)OJ:HN*7`2DD22DD2.'H%72VW47&H'L'J&62WW26&H'LtHO)6!__
6)NJ;HN)6``
6)NJ[DdDDdD//    @   3  >7..'>7#54&"#";26753264&١@١٢     d!     %26?&/5.'."!>7=N>IXI?Z?IXM& && ZdAU!-<<-!UEh      . D  /#.=467376#3>.67>4&'..6?>5&'&462iB y""r A9	
*.4/
	%($!	,

	("")	'h:>l'T^P	V4!;#"	     y 0  >7.'.'&'#"'#"'6756y*/#	-5:!BWa9%& D6M4(a74wB-g,WBVF"TC9R/: "!$	!   s :  67>73>74&'6776&'.'54'54'.'#2M:4J		J4:M3#)oo*D5R:*
(!!(
*:
R5)6
kk
6      d  0 :  &#!";26?326=4'.'5.'#"'&7>3!;2+G'(#6-+M!
nO'9q.U<GG."(& d;-
8&(&      @   # / ;  >7..'>7>7."&'5>2"&=462١ٞ⫪?١١⪫⫪       [   0 9 B  &#!"!>5&!43!#"&'>7!'&"264&"&462>&&76'&7]pb7r'44O33(7&&66&'rb3N43O3y         , 8 D `  %'!&546!626=.'!!>754&#";264&#";264&%764&"'&"2?264'#P"##"+@		@@		@@		@@		)g""##R@		@@	
?@		??		     t$ % N  56&'&'."3267327676&&'267676767#./7>7T//-@QwQ?.//ؔ	b#oH#.*;,[u1NJ9*UKRR1.-;;-.1R&exxe!(<9E-P\y*b#D"        $ 0  	.?>3!27'.#!"27>%#;264&=:
	:>;
**
:	B8A,2{2     g    5.'!5.'#!>75f/$0#$//$$$/.$/&$//$8$00$        T % 2 ? L Y  !.'>73#3!2654&'#532#!"&463!2+"&46;2#!"&463!25!.467!S<-7-==-]]XX(uf|uv|fff+99,+:==Yn    @   $ 1  >7..'>7%"&'5>23"&=462١?١١           $  >&'&"%&'676"&462&'<-OvOOvOD

''-<1;OOvOO      E   # ' 7 ; K O _ o                    #.=46;2'35##.'5>;2'35##"&'5>;2'35##"&=46;2'35##.'5>73";26=4&##.=4673";26=4&##5335##5335#%#"&'5>;23>=4&'#"&=46;23>=4&'#5335##5335#'3#%3#3#%3#Ӹ1ҸҸӸ1m¸¸,m¸¸g1122¸¸ùùͪ        X - 3 8 V   "&46;5.'#'&'#&#"#3+!>75>'67##!"&=>76&'5463!2'#"&=#.46;5#"&4673'&4627>3#32G+8'	 ** +}f|n")	&;;;;*

ED				+
C:+ * 	!* , ** ;$-
1b
 +PSS8F&,		FE		

+        . D  %&"327264%#.'6?27%#''.6763L		M/T 429?NTkeQ!,6I
3&,#		oK		N#b;S6:!)ERH7,!&3
N9%W      E  # 3 ?  #54."#!>7.%>2##!"&5467!"&=46233@G@3B&22&&22DaDw(g"?22>#g2&&33&&2h/BB/g%\\   ?     ) 2  >7..'>7264&"264&"264&" ١%%%%]%&>آآz&&&     @     -  >7..'>7264&""26=4&٢%%,@٢١?%     C  	     " '  	&67.'7&'7''6%>7!RW-_L6aL;C!RW_LG5aL/`LG5aL;!QX-_L6`M;C!RW       I % 1  !5>7>'.#"#!>5."&=462C0&<^;$B4@'44'(44e.A)#	6B3@#e4('44''4\

          0  ."'."67>&	&47>22?>2O!Q\R! R[S!BB9

9 ! K00;A<%
%;A;/ $$  $$ FG	?!S]S*44(		(0=E=    @   #  .'>7>7.!"&463!2٢_A<١٢e     D  ! 2 6 B  #5.'#!>7.#%>2#!.'>3!2!"&'5>25dJIdD%11%%11%CfD|(=iHaaHi1%%11%%1j1BB1i7m\      @      >7.5462"&"&462!%@l%%     p@    $   276 7..'>7#264&"+ 	,R>>RR>>RO,C,,C,?Ӝ#֜|>QQ>>RR>!,,C,,        h    ' 4 A  264&"264&"264&"!.463!2#!"&463!27#!"&467!//////333///       l )  %+.'.'.'&676737>jM@;e%*3	+^#2	9]3)*",^#	3*%e<?M$+",'3\:	3      >   &'&5>72)29*$M[*N     8   "'.76767) 2#: )M%      @   , /  >7..'>7'&#2?676'&5١(	?١١v     L   F T ` p  !"!>7.+"&546;2#767>.'&'&#"3!26=4&'?676'3&'.>+"&=46;2		22H65H12[$i$/V		j.				 G;tt:Hyy$''$g		[		         '  #"&46;27'&'5#.#!"#27>s:##;	C8BH	2z2     >  #  	&#7676&'".54>2*913
*$N?
[     S   (  !"!>54&>2"&!.76""'##':'':'
r6W#""'#'';''x      $  #"/'"&4?'.?>3?64
	3	U%U	3	'4&      @  F  >7.&'#"&'##"&'467&''&67>75475&7>7 .	!3&"01"&2!

THIT
@%%6!#
F\[F	#"6     l ) Y  &'&&'7>'&'.'#32>756&'.'.'.'&676;2?>*)3]9	2#^+	3*%e;@M,E:6\#&/^	)$e?)
0/U	:\3',"+$M?<e%*3	#^#3V^
/&#\6;E0	)?d%)       S @  %#"'.'&7'"'.67>27&7>762"'&'6762<"$&!"!K!"CK!	 "KB"!L!!L!"H"	
,-+X
-78"&
X/0)%"78,V40V-77      @   B  >7.>2"&7"&'5676?>765.""&'>7""EGmGiPPi 
	@h"-
(4DD5OeeO=#
      3 H V  ?#5377'.#'67&"#7>54&7&7>54&.7>'3<A r""<' Bk
	

K
	!$(%	
/4.\	


<۞FY("!
F.(		##	;!4w	P^T'l>:h	w	        7  "  .3>74'&5&676,:2# )=
2%M) [       o  ! * 7  %."!>4!&'&4762#%264&"726=4&"a+3,+#+^
#


$3..3?		fS  	  @     + 6 A L W b  >7.6/632&/6676?&#6&54?3&&'&/7&#"/57'377#6? R $ OY 	o~ 	NY^ #!OZ!	
nOX@q	PZ`	!$"P[!	q#	O[_	!EP\!%$      ;   N j  !%>=.'5463!232+"&=#"&46;5#"&46;'&46276232#7!.'4623!2674621"/#.		/////3		7:
	5.#1#.		/"N44N"/..4y//3		77		2#..#		        D   8  !.'>73#"3!275462"&="&4?#.4673C%%%		vL%%	%Pv
          ! 6 > N  .>5#"'%.767%6'2"'%.767%63+"&'>




	(!	
`k
J3
	BJ%
B
$         &  %."3!2>4462&'"&462y-4,,L+] 5./5            2 @ P  %/7&"#7>54&7&7>54&.7>'#.=467376pB 1
	

K
	!$(%	
/4.\	


%O""r A,(=:W		##	;!4w	P^T'l>:h	w	L,|!"(       P   I  %+.=462+.>#!"&'.+"&46;23!26?6&#!.463!2$()-,*11,*ZX!s)q		%%`	%	
      {   + F R b m  %.27#>'&'.7>&'#6'>4'32'7&#7376?>3&/#>47'27>?>&'&'  
,		,65<
	>:)IXqa\D
			>M)]2p.5(7/
u3 E3	'_5)7-		+500	



b!?
M2*'@				9!T*0*R;0.			#(0'	&      @    3 C M W  "264&264&">7."/7.'>7&#'.'>7'">4&#">4&[(O+/aUSl:>#"SllSOp,V				29G(EN/UmYGgMQ:#
_FG__G'C        l   + 7 ?  #5.'##";!>73264&5462"&75462"&473#N''1''19
	zA''A''U		A      @  A  >7.'7&676?73&'7>?.'.37.'.7.'&63 ;B[;AN(+-|UWe4@@A1&	-@.b%2	/GCN	%(!?# "0      @ Q ]  76/#"&/&/.?/.'546?'&6?>?>73>7.&'H%92WV29%H'Q'J%92WW08%H'S(2DD23CC>W49%H'Q'H%92WW09&H'Q'H%92WD23DD32D        $ 1  '."36?32?>?64?2?%U	3	
4'%S3'	4	T&R'%%˵        P   :  %+.=462+.>#!"&'.+"&46;2!2$()-,*11, s)q		%%`	%0        L  & 3 F Z  %#.'5>273%#.46;2=4627!.463!27"&=4+.4673%#""&'5>73$$[$M$P$$$$        H  (  %'>54."32672?6&%.'>7?!,Pis63P,,Pi91\)a`ai&]3:hP,PithP,  	eaaaa      \   %&"27	264



YY
p



Y
      276764&"4&"&h



hT
y 

      X  (  &7&'&.'>7>7.>'6]4h2[P'PmD">,*=%DfU d$"D/$@id7K$yzHM;	:/r5.H$5C&!      |   %!.'47>. )M%I*$29     x   !'&'&676[*
N%) 2#:
        `   # 1  .'>7267.'.!54&!546?6JcdJKccK1AAbAAYddY&ISRJ|cJKccKJc!BbAA11Ba-11-7~~4M"          >'!>4&#!6."zS
y!	
	
32

        	#&47	&462_p



Y



YY        ]   	"'&5&62	62



YY
#

mX          & / 8  .";6?7>74&2"&46.4627>2"&6m9!5
\CE:!!r!!-//[vCIB<*P

1Cv!!M!!&!       i ?  	".4676"'#&'467627>54&"276`!V^UC$$!843N"
	
7=V 659
!##BU_V!810=C<'$ 
	 ;&+=?F?228	      	   &"7267>'4'&
	
31


 z	

S        r  / ; E  #'&+"#!>7.#!"&'>;6?3;%>7..'>2v2	2v%32&3%33	22KddKKeeK-;;Z<<`KK2&%32&f&2BfIKdKKddKKd<--<<Z<      @   (  >7..'>7'&"2764.آ!


@١آ


         64/.!3!7276
!y	
Svi	

i      	364'	64&"

m
X


XY    	    )     9 Q U Y a g  !%>73!"&5>7;."!"&5>;>732"%265.+5."!!!!%#5>2'3."1P==PS  5P5_ HS>>SM!!  YMtM@k-9V90G1-1=RR=)66>RR>F:OO:0+;;+$//       | ) 6 < K Y  '&+5.'!37>73327>73>754&&'&5>232#&'&54637+&'.+"53ZT)!;,,::,$))	
 		+		&! $%!EV $I	
!P%,::,+;$&$(%)<C,
N       {   &"'&"2764m"g"!{c"!      @     .'>"6?6&/5.
@S
H     l ' 3 ?  "32!.'5467264&#.=>7#"3>4&'#"3>4&*9$$9*+8$$8+v9+$6%+88+$7$+9        m    =  !"3!>7.#!"/&?6!2&"'&"2?264/7>+[&&[	432232	622&%?i42333333   A   4  >7..'>7&"'&"2?264/764 ڢ
ij

jj
ii
ni
Aڢڢ		jj	ii	jj	
hi        | * 7 K Q a m  '&+5.'!327>73327>73>754&'&'&5>27#.#"&5463!22#5'&'&5>37+.+"53ZT)":,,;;,
6#
)	
7#		,	%1 $%ԝB)*L]EV I	5#P%,::,,:"'&"*(%)%'(&K`CO,!(
N     t  / 0 9 I U  #'&+"#!>7.#!"&546;6?332#264&"%'#/'!?.'>7v2	2v&32'3%33
	22j<Z<<Z<,uRGTC8BKddKKdd_KK2&%32&f&2BfJK-<<Z<<eY
B=ӘdKKddKKd     [  & - >  5.'.";267326562&>"&'3%676=>7
VG<X=FVPDZD* |	!	8uXXu8	R ,::, RBi,66,jNb@)	XuuX	)@       T    .'>!5>I``IH``HU`IHaaHI`W`IUUI`   @   !  >7.462"&2"&'> ""(@h"4i       7 @ I R  .";6?7>7.#'&76&'.'4>3'"&462"&462"&4626l9!5
[BD9`.uAB>G3:0ZvB0<  !!!!,//ZuBIA<*O

1Bu(*%?	#k>5_J'p7d!!!        t   G _ w   %"&4672"&4672#%.'&'..67>%>?>32#&'&?#"&46;%32+"&4?#"&46;2#3+&'54?#"&46;#3""	h"3##	M%4%k#1. !#~%a1&C2#?9I;

b
J6

\
1&C2#?O""4"		""4"		%.*""(jeCDe


d


oCC        a   >/.7> U)x#      W   	64&"	&"	27	264'.











		
       K  ' ? K W  #5."#54&"#!>54&!#!"5!54;26=326=32#";264&!#";264&ii$$$$""ijD

D



$##$S////        f     %77'#!5'	lI}SJ^&^ ] n}SĿ==^&^_       p   ? \        +"&4672+"&463'"&=>7!"3!.'5467264&3!26=.46754&'!!.'5>3>4&'"&'5>7!#23"!>75.#.4672675.'!"&=7>4&/5463!23%3!2675.4675.#!"%#"&46;2'";264&#5#"&46;2'";264&#m8+*9$$9*+8$$\3((22((3,:##:,+:##:)8&&8))7
&&
7)&33&'22''44''44z



m+88+$7$+88+$7$@*?
gg
?U?
gg
?:,"4#,::,"5",:}7*&8%*77*%9%*7i	?Q?	ii	?Q?
jee
AU@ee
AUA6\6      , @ L X  5.'3>75.'#5>7#;.#3267>7>754&+"=4;2+"=4;2[ē#*U** xx **OW	##ym(#
U

U
N
U

U
Ĕ(***
xx
**&<#7#
b=)'D






       $ < W d q     ,9FUbr  32'!.=74>?>3"&/3!2>57!"32265>;/.#"&=462"&4?6%2#"/&>#.=74>?>3!2'"7!>'5'./.#!'&/&/326?%!7>75#"&'5#%.5.+7'?>37!#%32265>;/&/!"7"&=462'2675.#"&4?6327"?6."/&67632'"32>/&R		D	#AVAe~[	E
(>)J	::H9	9C!
	DQ	 D	fQ
e
?S>
e	DZC9!,	C			O	+&:&E	[	:	:)	::n	9

9
D9
9!

w	)22)Cy''u

IH	H		H	
G	x

x				{	'00'
+44+]*!	
w}	!*i%%nf			G
H	xHG
xH
	H
z
G
H        $ -  %&'&767>7.'.462'264&Ğğc;OOvOO;++>++49776OvOOvO+>++>+   l@   & 0   276 7..'>7>7..462*!	,ќA@>RR>=RR=!--A--!@ӝ#՝*R>>RR>>R,B--B,    A  (  >7.&4?'&462762"/ 
jj

ji
in
iiAii	jj	ig	jj	   @    >7."/&46266

@


	   	      1 M Y e q }    .'#+"/#!3>74&"'.5>72%"&54673;2?3&#!264&#!"!264&#!"3264&+"#";264&>75."3264&"H2%T9

8U%11%|&-F]#;,1=(!!&?F]






+i~		~
	
BI%1111&%1]E%A+,:	3.##]E,&}mCz	B

B	%   @   )  >7..'>7'5."3276&١	@١آFG
S      %  7  .'>7".'5."#!>4&'#5>754&M;:MM:;Mp|]\zlqpk:MM::NNH\|}]HHmQQnH    D   , 8  %"&'>2264&".'&"27>764.'>7(#|QT}"$$"}QSTP}##=ܥ~oQ|##F|QTSQ}"$$"}QTܥۦ            264&"264&"26."A*?**?*t*@**@*t*?+*?*w**?** **?** **?**        S  $  %#!"&463!2"/&462462762Rg			vv	]"		vbv	        H   D J U b  #.46;27!.463!2'#&!3676.+.5467!3>='"&'5"&'>7.+";26/y($+88+	

9*Tn`WWWBBW8

S|
8**8 #T*8HnoBWWBAWW<        D    & . 6  #5!3#"&5>7!!3#%>7.&'7>7&>3DfM$䎎?MffMMff+D3, D3%C3I=Lg=?<fMMffMMf3D'3D     z   $  !"!>7.!%54!&'67%9%%v%%ov		65%C%%%71	e	     J ' 3  #/;.#>74&'6?26=/.'>7>q"W1mmnrVUsrVVr"nmm+N!qVrrVVrr       @  # Q Y  %'65.'"2727364'.'>7!"7!'&/#"'.56763!35'&'&'=5LiP&C6jO8/KmL:9LL9:L
	?G		
X#<oL.8Pi6D%PiK 9LL9:LL		 >R5     a    7!53?pp?<HߪVpp==7        ) M  &'&/&";3>=33>532674#54&'##4&'#?6?63#";R4R;''X&&uqu3<Q3
1FF14':'Cǲ;1Fx       q  "  !&7!67.&3765&aa====
n011S2%kj
~    T  ! 4 =  "&/+7>7'.'567&26=>76&462"&Pp88pPGGO>A:;@lk0O/-+/--8888V1}}1VFy(ff(yFPP7///P,0Ob-  	    K  ! + E a      #5.'!!>7.!"&'>3!2#32"/"&=6?254623"&'546;2+3#32#3#&/&6737627673#"/"&463!2#"&467!#"&463!2#1$$22$%11|j|Wb!	

!		2	
>				..				..		4666"g%11%%11%U%1:2*		]2)		]	]			]
"		"
]
33
aY    
    P       % 1 = C E  5557'&#!"!>7432+"&46!.463!2'!"&463!27"&'55*	x)

9..	mQ %Ym3       J    B N V ^ k  !"!>7.#532!#&'567#7>.'&'&#"!>754&%>'&'.#&=47;#?676&f4L -, L4fI&
&SKCS~$BL>``>Lutl
Q	;;
	        ~ 
   %7.'!/%'3!267 R+""(%w%})	w%%    ?    &  >7..4627"&462"&462 %&&%%>&&+&&     `   + 8 E R p  "3>7..4677+"&'475463%+"&467327+"&4673+"&4673%"&/5!32#"&'46?!VqqVUqqV<PP<=PP*bEbbbbW!rUUrrUUrQxPPxQt\EUoГ
!       P    ) 6 C P  '&#!"!>74"&'5!.5463!;#!"&463!27#!"&463!2'+"&46;2G	x	m	;		)y[//m Ym6		*y         " > G \  #'5.7>7.'&#&.6763&"6726447#."'.'>7327#		5(gs	=
	M/S!419?NTldQ	lW$=rh(5J8V"-/$QNb9%	)	H%` K		N#b;S6:!)ERV#_&H ])V"1,# Q5       Y' 0 C U d u  %"&'&'476732326?6?.'&546."2?>4&/&54>2'."2674&"'.547>3Xg.{z/g*%D
*/
,lqk,	)8H'-)kvkR.+(6+--UD#AU]TB$#[7<6+TU>L!%4z9  9"				2(-.Rkwi)+kykLX/SC#"BT_T*5@UU@5 &5$        0 @  ."'."67>&	&47>22?>2%'	7/O!Q\R! R[S!BB9

9 ! K00;A<%
%;A;/VK1E]5&W $$  $$ FG	?!S]S*44(		(0=E=XEPh]L&        I   # ' 7 ; K O _ o                #"&'5>73'35##"&=4673'35##"&=4673'35##"&'5>73'35##"&=46;2"3>75.##"&=46;2"3>=4&##5335##5335#%#"&=4673;2675.'#"&=4673;26=4&'#5335##5335#ж+жжж+j&j2222     K % 5 B  !5>32>'.#"#!>7.!!.546"26=4&C0';^;$A5@'44''44

$d/A)#
6B3@$e4''44''5A2]]         ,  '&/&"3;>75473;>53267&pi0#*8*$Y	s ?$        3  !227>54&'"'56;2#"'&'#&'743H'&EG7$2!-n9;6<[X)AW?o      d   '  %#!"&467!7!.467!5#!"&463!2dxxx}      2%  / ; D Q  .=."""'#3!264&'#5>754&'5&'>2"'73.7>O|]5,(2;qpk}MtNN:/	
		@#HH1W$H\|-QQnH,%!:NNM:M7	w     @    ( =  >7..'>76?'>7."&'.5>72ءZhAﴴ?آء4:v-ﴵﵴF      Y 	 $  3#.'>?63!.'47^^
	$#a
	;)		$C	
m	                                "        )        8        G        R      
 + a          	   &   	     	     	     	    	  -  	  C  	 
 Va  	  &Created by iconfontuvicon-iconfontRegularuvicon-iconfontuvicon-iconfontVersion 1.0uvicon-iconfontGenerated by svg2ttf from Fontello project.http://fontello.com C r e a t e d   b y   i c o n f o n t u v i c o n - i c o n f o n t R e g u l a r u v i c o n - i c o n f o n t u v i c o n - i c o n f o n t V e r s i o n   1 . 0 u v i c o n - i c o n f o n t G e n e r a t e d   b y   s v g 2 t t f   f r o m   F o n t e l l o   p r o j e c t . h t t p : / / f o n t e l l o . c o m         
                       	
 !"#$%&'()*+,-./0123456789:;<=>?@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[\]^_`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{|}~ starpause	star-fillskip-forward-rightweixin-filltagsquestion-circletrashvolume-fillpluswomanreloadthumb-down-fillshareserver-fillplus-circle-fillthumb-up	tags-fillminuszhifubao-circle-fillsettingplus-circle	bell-fill	volume-uptwitteqq-fill
thumb-downpause-circle-fillphoto
empty-page
server-manintegralfolderorderpause-circleeye-fill	grid-fillempty-couponeye-offlockmore-circleinfo-circlemomentslock-opened-fillheartminus-circle	lock-fillinfo-circle-fillmap-filllist-dot
phone-fillplay-right-fillplay-left-fillplay-circle	gift-fillintegral-fill
play-right
photo-fillpushpin-fillqq-circle-fillphone
share-fillquestion-circle-fill
volume-off	play-leftwarningmoments-circel-fill
red-packetshare-squareskip-back-leftwarning-fillvolume-off-fillshopping-cartwifi-offweixin-circle-fill
trash-filltwitter-circle-fillsetting-fillpushpinshopping-cart-fillscansearcharrow-uparrow-downward
apple-fillarrow-up-fillarrow-down-fillaccountarrow-leftwardarrow-right
arrow-down	chat-fillattacharrow-upwardcameracheckmark-circlearrow-rightward
arrow-leftbagcar-fill	checkmark
clock-fillcoupon-fill	backspaceclose-circlecarcamera-fillbellaccount-fillerror-circle-fillchat	empty-carcheckbox-markclosecalendaredit-pencoupon
kefu-ermaiempty-favoreyemapclose-circle-fillcheckmark-circle-fillempty-orderclockmicerror-circlemore-dot-filldownload
empty-data
empty-listemailmanempty-searchedit-pen-fillhomemovieempty-permission
empty-newsfile-text-fillgift
email-fillmore-circle-fillempty-history	file-texteye-off-outlineempty-address
heart-fillgrid	lock-open	home-filllevellistmic-offplay-circle-fillthumb-up-fill    Htqx{
  "id": "uv-icon",
  "displayName": "uv-icon 图标 全面兼容vue3+2、app、h5、小程序等多端",
  "version": "1.0.13",
  "description": "基于字体的图标集，包含了大多数常见场景的图标，支持自定义，支持自定义图片图标等。可自定义颜色、大小。",
  "keywords": [
    "uv-ui,uvui,uv-icon,icon,图标,字体图标"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.1.0"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "插件不采集任何数据",
      "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [
			"uv-ui-tools"
		],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "Vue": {
          "vue2": "y",
          "vue3": "y"
        },
        "App": {
          "app-vue": "y",
          "app-nvue": "y"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "y",
          "字节跳动": "y",
          "QQ": "y",
          "钉钉": "u",
          "快手": "u",
          "飞书": "u",
          "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        }
      }
    }
  }
}_97x K## uv-icon 图标库icon**

基于字体的图标集，包含了大多数常见场景的图标，支持自定义，支持自定义图片图标等】-icu][[
k	x e100644 changelog.md 3J6>BOB`40000 components F^SΆT
100644 package.json y`sȉMPFv:100644 readme.md I8\X%-H=TxE## 1.0.16（2023-12-21）
1. 修复设置show-menu-by-longpress不生效的BUG
## 1.0.15（2023-12-06）
1. 优化
## 1.0.14（2023-12-06）
1. 阻止事件冒泡问题
## 1.0.13（2023-11-15）
1. 修复webp之前未使用的BUG
## 1.0.12（2023-10-11）
1. 修复懒加载报错：https://gitee.com/climblee/uv-ui/issues/I869JS
## 1.0.11（2023-08-31）
1. 修复设置widthFix时出现显示不全的BUG
2. 修复抖音等平台在width和height属性改变时出现不显示的BUG
## 1.0.10（2023-08-29）
1. 修复异步修改宽高不生效的问题，问题来源：https://gitee.com/climblee/uv-ui/issues/I7WUQ3
## 1.0.9（2023-08-21）
1. 修复设置宽高为百分比不生效的BUG
## 1.0.8（2023-07-24）
1. 优化 nvue模式下增加cellChild参数，是否在list中cell节点下，nvue中cell下建议设置成true
## 1.0.7（2023-07-02）
修复VUE3模式下可能不显示的BUG
## 1.0.6（2023-07-02）
优化修改
## 1.0.5（2023-06-28）
修复duration属性不生效的BUG
## 1.0.4（2023-05-27）
1. 修复可能报错的问题
## 1.0.3（2023-05-24）
1. 去掉template中存在的this.导致头条小程序编译警告
## 1.0.2（2023-05-23）
1. 优化
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-image 图片
ޤx# 40000 uv-image 2BZ0TQLBxL 100644 props.js nJYov}bn100644 uv-image.vue *ܚEq@P*~ Lyxjexport default {
	props: {
		// 图片地址
		src: {
			type: String,
			default: ''
		},
		// 裁剪模式
		mode: {
			type: String,
			default: 'aspectFill'
		},
		// 宽度，单位任意
		width: {
			type: [String, Number],
			default: '300'
		},
		// 高度，单位任意
		height: {
			type: [String, Number],
			default: '225'
		},
		// 图片形状，circle-圆形，square-方形
		shape: {
			type: String,
			default: 'square'
		},
		// 圆角，单位任意
		radius: {
			type: [String, Number],
			default: 0
		},
		// 是否懒加载，微信小程序、App、百度小程序、字节跳动小程序
		lazyLoad: {
			type: Boolean,
			default: true
		},
		// 是否开启observer懒加载，nvue不生效
		observeLazyLoad: {
			type: Boolean,
			default: false
		},
		// 开启长按图片显示识别微信小程序码菜单
		showMenuByLongpress: {
			type: Boolean,
			default: true
		},
		// 加载中的图标，或者小图片
		loadingIcon: {
			type: String,
			default: 'photo'
		},
		// 加载失败的图标，或者小图片
		errorIcon: {
			type: String,
			default: 'error-circle'
		},
		// 是否显示加载中的图标或者自定义的slot
		showLoading: {
			type: Boolean,
			default: true
		},
		// 是否显示加载错误的图标或者自定义的slot
		showError: {
			type: Boolean,
			default: true
		},
		// 是否需要淡入效果
		fade: {
			type: Boolean,
			default: true
		},
		// 只支持网络资源，只对微信小程序有效
		webp: {
			type: Boolean,
			default: false
		},
		// 过渡时间，单位ms
		duration: {
			type: [String, Number],
			default: 500
		},
		// 背景颜色，用于深色页面加载图片时，为了和背景色融合
		bgColor: {
			type: String,
			default: '#f3f4f6'
		},
		// nvue模式下 是否直接显示，在uv-list等cell下面使用就需要设置
		cellChild: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.image
	}
}0Cx%,<template>
	<uv-transition
		v-if="show"
		:show="show"
		mode="fade"
		:duration="fade ? duration : 0"
		:cell-child="cellChild"
		:custom-style="wrapStyle"
	>
		<view
			class="uv-image"
			:class="[`uv-image--${elIndex}`]"
			@tap="onClick"
			:style="[wrapStyle, backgroundStyle]"
		>
			<image
				v-if="!isError && observeShow"
				:src="src"
				:mode="mode"
				@error="onErrorHandler"
				@load="onLoadHandler"
				:show-menu-by-longpress="showMenuByLongpress"
				:lazy-load="lazyLoad"
				class="uv-image__image"
				:style="[imageStyle]"
				:webp="webp"
			></image>
			<view
				v-if="showLoading && loading"
				class="uv-image__loading"
				:style="{
					borderRadius: shape == 'circle' ? '50%' : $uv.addUnit(radius),
					backgroundColor: bgColor,
					width: $uv.addUnit(width),
					height: $uv.addUnit(height)
				}"
			>
				<slot name="loading">
					<uv-icon
						:name="loadingIcon"
						:width="width"
						:height="height"
					></uv-icon>
				</slot>
			</view>
			<view
				v-if="showError && isError && !loading"
				class="uv-image__error"
				:style="{
					borderRadius: shape == 'circle' ? '50%' : $uv.addUnit(radius),
					width: $uv.addUnit(width),
					height: $uv.addUnit(height)
				}"
			>
				<slot name="error">
					<uv-icon
						:name="errorIcon"
						:width="width"
						:height="height"
					></uv-icon>
				</slot>
			</view>
		</view>
	</uv-transition>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Image 图片
	 * @description 此组件为uni-app的image组件的加强版，在继承了原有功能外，还支持淡入动画、加载中、加载失败提示、圆角值和形状等。
	 * @tutorial https://www.uvui.cn/components/image.html
	 * @property {String}			src 				图片地址
	 * @property {String}			mode 				裁剪模式，见官网说明 （默认 'aspectFill' ）
	 * @property {String | Number}	width 				宽度，单位任意，如果为数值，则为px单位 （默认 '300' ）
	 * @property {String | Number}	height 				高度，单位任意，如果为数值，则为px单位 （默认 '225' ）
	 * @property {String}			shape 				图片形状，circle-圆形，square-方形 （默认 'square' ）
	 * @property {String | Number}	radius		 		圆角值，单位任意，如果为数值，则为px单位 （默认 0 ）
	 * @property {Boolean}			lazyLoad			是否懒加载，仅微信小程序、App、百度小程序、字节跳动小程序有效 （默认 true ）
	 * @property {Boolean}			showMenuByLongpress	是否开启长按图片显示识别小程序码菜单，仅微信小程序有效 （默认 true ）
	 * @property {String}			loadingIcon 		加载中的图标，或者小图片 （默认 'photo' ）
	 * @property {String}			errorIcon 			加载失败的图标，或者小图片 （默认 'error-circle' ）
	 * @property {Boolean}			showLoading 		是否显示加载中的图标或者自定义的slot （默认 true ）
	 * @property {Boolean}			showError 			是否显示加载错误的图标或者自定义的slot （默认 true ）
	 * @property {Boolean}			fade 				是否需要淡入效果 （默认 true ）
	 * @property {Boolean}			webp 				只支持网络资源，只对微信小程序有效 （默认 false ）
	 * @property {String | Number}	duration 			搭配fade参数的过渡时间，单位ms （默认 500 ）
	 * @property {String}			bgColor 			背景颜色，用于深色页面加载图片时，为了和背景色融合  (默认 '#f3f4f6' )
	 * @property {Object}			customStyle  		定义需要用到的外部样式
	 * @event {Function}	click	点击图片时触发
	 * @event {Function}	error	图片加载失败时触发
	 * @event {Function} load 图片加载成功时触发
	 * @example <uv-image width="100%" height="300px" :src="src"></uv-image>
	 */
	export default {
		name: 'uv-image',
		emits: ['click','load','error'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 图片是否加载错误，如果是，则显示错误占位图
				isError: false,
				// 初始化组件时，默认为加载中状态
				loading: true,
				// 图片加载完成时，去掉背景颜色，因为如果是png图片，就会显示灰色的背景
				backgroundStyle: {},
				// 用于fade模式的控制组件显示与否
				show: false,
				// 是否开启图片出现在可视范围进行加载（另一种懒加载）
				observeShow: !this.observeLazyLoad,
				elIndex: '',
				// 因为props的值无法修改，故需要一个中间值
				imgWidth: this.width,
				// 因为props的值无法修改，故需要一个中间值
				imgHeight: this.height,
				thresholdValue: 50
			};
		},
		watch: {
			src: {
				immediate: true,
				handler(n) {
					if (!n) {
						// 如果传入null或者''，或者false，或者undefined，标记为错误状态
						this.isError = true
					} else {
						this.isError = false;
						this.loading = true;
					}
				}
			},
			width(newVal){
				// 这样做的目的是避免在更新时候，某些平台动画会恢复关闭状态
				this.show = false;
				this.$uv.sleep(2).then(res=>{
					this.show = true;
				});
				this.imgWidth = newVal;
			},
			height(newVal){
				// 这样做的目的是避免在更新时候，某些平台动画会恢复关闭状态
				this.show = false;
				this.$uv.sleep(2).then(res=>{
					this.show = true;
				});
				this.imgHeight = newVal;
			}
		},
		computed: {
			wrapStyle() {
				let style = {};
				// 通过调用addUnit()方法，如果有单位，如百分比，px单位等，直接返回，如果是纯粹的数值，则加上rpx单位
				if(this.mode !== 'heightFix') {
					style.width = this.$uv.addUnit(this.imgWidth);
				}
				if(this.mode !== 'widthFix') {
					style.height = this.$uv.addUnit(this.imgHeight);
				}
				// 如果是显示圆形，设置一个很多的半径值即可
				style.borderRadius = this.shape == 'circle' ? '10000px' : this.$uv.addUnit(this.radius)
				// 如果设置圆角，必须要有hidden，否则可能圆角无效
				style.overflow = this.radius > 0 ? 'hidden' : 'visible'
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			},
			imageStyle() {
				let style = {};
				style.borderRadius = this.shape == 'circle' ? '10000px' : this.$uv.addUnit(this.radius);
				// #ifdef APP-NVUE
				style.width = this.$uv.addUnit(this.imgWidth);
				style.height = this.$uv.addUnit(this.imgHeight);
				// #endif
				return style;
			}
		},
		created() {
			this.elIndex = this.$uv.guid();
			this.observer = {}
			this.observerName = 'lazyLoadContentObserver'
		},
		mounted() {
			this.show = true;
			this.$nextTick(()=>{
				if(this.observeLazyLoad) this.observerFn();
			})
		},
		methods: {
			// 点击图片
			onClick() {
				this.$emit('click')
			},
			// 图片加载失败
			onErrorHandler(err) {
				this.loading = false
				this.isError = true
				this.$emit('error', err)
			},
			// 图片加载完成，标记loading结束
			onLoadHandler(event) {
				if(this.mode == 'widthFix') this.imgHeight = 'auto'
				if(this.mode == 'heightFix') this.imgWidth = 'auto'
				this.loading = false
				this.isError = false
				this.$emit('load', event)
				this.removeBgColor()
			},
			// 移除图片的背景色
			removeBgColor() {
				// 淡入动画过渡完成后，将背景设置为透明色，否则png图片会看到灰色的背景
				this.backgroundStyle = {
					backgroundColor: 'transparent'
				};
			},
			// 观察图片是否在可见视口
			observerFn(){
				// 在需要用到懒加载的页面，在触发底部的时候触发tOnLazyLoadReachBottom事件，保证所有图片进行加载
				this.$nextTick(() => {
					uni.$once('onLazyLoadReachBottom', () => {
						if (!this.observeShow) this.observeShow = true
					})
				})
				setTimeout(() => {
					// #ifndef APP-NVUE
					this.disconnectObserver(this.observerName)
					const contentObserver = uni.createIntersectionObserver(this)
					contentObserver.relativeToViewport({
						bottom: this.thresholdValue
					}).observe(`.uv-image--${this.elIndex}`, (res) => {
						if (res.intersectionRatio > 0) {
							// 懒加载状态改变
							this.observeShow = true
							// 如果图片已经加载，去掉监听，减少性能消耗
							this.disconnectObserver(this.observerName)
						}
					})
					this[this.observerName] = contentObserver
					// #endif
					// #ifdef APP-NVUE
					this.observeShow = true;
					// #endif
				}, 50)
			},
			disconnectObserver(observerName) {
				const observer = this[observerName]
				observer && observer.disconnect()
			}
		}
	};
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-image-error-top:0px !default;
	$uv-image-error-left:0px !default;
	$uv-image-error-width:100% !default;
	$uv-image-error-hight:100% !default;
	$uv-image-error-background-color:$uv-bg-color !default;
	$uv-image-error-color:$uv-tips-color !default;
	$uv-image-error-font-size: 46rpx !default;

	.uv-image {
		position: relative;
		transition: opacity 0.5s ease-in-out;

		&__image {
			width: 100%;
			height: 100%;
		}

		&__loading,
		&__error {
			position: absolute;
			top: $uv-image-error-top;
			left: $uv-image-error-left;
			width: $uv-image-error-width;
			height: $uv-image-error-hight;
			@include flex;
			align-items: center;
			justify-content: center;
			background-color: $uv-image-error-background-color;
			color: $uv-image-error-color;
			font-size: $uv-image-error-font-size;
		}
	}
</style>
yI)xN7{
  "id": "uv-image",
  "displayName": "uv-image 图片EH16image 此组件为uni-app的image组件的加强版，在继承了原有功能外，增加observer懒加载功能，还支持C入动画、加载中、加载失败提示、圆角值和形状等+imageO!image",
    "图片transition",
			"uv-icon
Cx ## Image 图片image**

此组件为`uni-app`的`image`组件的加强版，在继承了原有功能外，增加`observer`懒加载功能，L支持淡入动画、加载中、加载失败提示、圆角值和形状等/imagesw][}
0	x e100644 changelog.md qW Gl +dI40000 components "	#ÓhzL100644 package.json 76.n_dd;100644 readme.md `WAɿV͇ɸX*ZAxz 40000 uv-index-anchor ŠipŠ40000 uv-index-item 	];O(ro!P40000 uv-index-list 5d,B$~(|1xS 100644 props.js IױS<(100644 uv-index-anchor.vue fvAȘ@g8hp" xexport default {
	props: {
		// 列表锚点文本内容
		text: {
			type: [String, Number],
			default: ''
		},
		// 列表锚点文字颜色
		color: {
			type: String,
			default: '#606266'
		},
		// 列表锚点文字大小，单位默认px
		size: {
			type: [String, Number],
			default: 14
		},
		// 列表锚点背景颜色
		bgColor: {
			type: String,
			default: '#dedede'
		},
		// 列表锚点高度，单位默认px
		height: {
			type: [String, Number],
			default: 32
		},
		...uni.$uv?.props?.indexAnchor
	}
}YEѰx
O<template>
	<!-- #ifdef APP-NVUE -->
	<header>
	<!-- #endif -->
	<view
	  :class="['uv-index-anchor',{'uv-index-anchor-sticky': parentData.sticky}]"
		:ref="`uv-index-anchor-${text}`"
	  :style="{
			height: $uv.addUnit(height),
			backgroundColor: bgColor
		}"
	>
		<text
		  class="uv-index-anchor__text"
		  :style="{
				fontSize: $uv.addUnit(size),
				color: color
			}"
		>{{ text }}</text>
	</view>
	<!-- #ifdef APP-NVUE -->
	</header>
	<!-- #endif -->
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * IndexAnchor 列表锚点
	 * @description 
	 * @tutorial https://www.uvui.cn/components/indexList.html
	 * @property {String | Number}	text	列表锚点文本内容
	 * @property {String}			color	列表锚点文字颜色 ( 默认 '#606266' )
	 * @property {String | Number}	size	列表锚点文字大小，单位默认px ( 默认 14 )
	 * @property {String}			bgColor	列表锚点背景颜色 ( 默认 '#dedede' )
	 * @property {String | Number}	height	列表锚点高度，单位默认px ( 默认 32 )
	 * @example <uv-index-anchor :text="indexList[index]"></uv-index-anchor>
	 */
	export default {
		name: 'uv-index-anchor',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				parentData: {
					sticky: true
				}
			}
		},
		created() {
			this.init()
		},
		methods: {
			init() {
				// 此处会活动父组件实例，并赋值给实例的parent属性
				const indexList = this.$uv.$parent.call(this, 'uv-index-list')
				if (!indexList) { 
					return this.$uv.error('uv-index-anchor必须要搭配uv-index-list组件使用')
				}
				this.parentData.sticky = indexList.sticky;
				// 将当前实例放入到uv-index-list中
				indexList.anchors.push(this)
				const indexListItem = this.$uv.$parent.call(this, 'uv-index-item')
				// #ifndef APP-NVUE
				// 只有在非nvue下，uv-index-anchor才是嵌套在uv-index-item中的
				if (!indexListItem) {
					return this.$uv.error('uv-index-anchor必须要搭配uv-index-item组件使用')
				}
				// 设置uv-index-item的id为anchor的text标识符，因为非nvue下滚动列表需要依赖scroll-view滚动到元素的特性
				indexListItem.id = this.text.charCodeAt(0)
				// #endif
			}
		},
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-index-anchor {
		@include flex;
		align-items: center;
		padding-left: 15px;
		z-index: 1;
		&-sticky {
			position: sticky;
			top: 0;
		}
		&__text {
			@include flex;
			align-items: center;
		}
	}
</style>
oݭx- 100644 uv-index-item.vue g?ZN6غ7lxS<template>
	<!-- #ifdef APP-NVUE -->
	<cell ref="uv-index-item">
		<!-- #endif -->
		<view
			class="uv-index-item"
			:id="`uv-index-item-${id}`"
			:class="[`uv-index-item-${id}`]"
		>
			<slot />
		</view>
		<!-- #ifdef APP-NVUE -->
	</cell>
	<!-- #endif -->
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	// 由于weex为阿里的KPI业绩考核的产物，所以不支持百分比单位，这里需要通过dom查询组件的宽度
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * IndexItem 
	 * @description 
	 * @tutorial https://www.uvui.cn/components/indexList.html
	 * @property {String}
	 * @event {Function}
	 * @example
	 */
	export default {
		name: 'uv-index-item',
		mixins: [mpMixin, mixin],
		data() {
			return {
				// 本组件到滚动条顶部的距离
				top: 0,
				height: 0,
				id: ''
			}
		},
		created() {
			// 子组件uv-index-anchor的实例
			this.anchor = {}
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				// 此处会活动父组件实例，并赋值给实例的parent属性
				this.getParentData('uv-index-list')
				if (!this.parent) {
					return this.$uv.error('uv-index-item必须要搭配uv-index-list组件使用')
				}
				this.$uv.sleep().then(() =>{
					this.getIndexItemRect().then(size => {
						// 由于对象的引用特性，此处会同时生效到父组件的children数组的本实例的top属性中，供父组件判断读取
						this.top = Math.ceil(size.top)
						this.height = Math.ceil(size.height)
					})
				})
			},
			getIndexItemRect() {
				return new Promise(resolve => {
					// #ifndef APP-NVUE
					this.$uvGetRect('.uv-index-item').then(size => {
						resolve(size)
					})
					// #endif

					// #ifdef APP-NVUE
					const ref = this.$refs['uv-index-item']
					dom.getComponentRect(ref, res => {
						resolve(res.size)
					})
					// #endif
				}) 
			}
		},
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
</style>
,ExQ 100644 props.js 5naSIvH0FF?K100644 uv-index-list.vue 29GE3K*J!8!xexport default {
	props: {
		// 右边锚点非激活的颜色
		inactiveColor: {
			type: String,
			default: '#606266'
		},
		// 右边锚点激活的颜色
		activeColor: {
			type: String,
			default: '#5677fc'
		},
		// 索引字符列表，数组形式
		indexList: {
			type: Array,
			default: () => []
		},
		// 是否开启锚点自动吸顶
		sticky: {
			type: Boolean,
			default: true
		},
		// 自定义导航栏的高度
		customNavHeight: {
			type: [String, Number],
			default: 0
		},
		...uni.$uv?.props?.indexList
	}
}>x6v<template>
	<view class="uv-index-list">
		<!-- #ifdef APP-NVUE -->
		<list
			:scrollTop="scrollTop"
			enable-back-to-top
			:offset-accuracy="1"
			:style="{
				maxHeight: $uv.addUnit(scrollViewHeight,'px')
			}"
			@scroll="scrollHandler"
			ref="uvList"
		>
			<cell ref="header">
				<slot name="header" />
			</cell>
			<slot />
			<cell>
				<slot name="footer" />
			</cell>
		</list>
		<!-- #endif -->
		<!-- #ifndef APP-NVUE -->
		<scroll-view
			:scrollTop="scrollTop"
			:scrollIntoView="scrollIntoView"
			:offset-accuracy="1"
			:style="{
				maxHeight: $uv.addUnit(scrollViewHeight,'px')
			}"
			scroll-y
			@scroll="scrollHandler"
			ref="uvList"
		>
			<view>
				<slot name="header" />
			</view>
			<slot />
			<view>
				<slot name="footer" />
			</view>
		</scroll-view>
		<!-- #endif -->
		<view
			class="uv-index-list__letter"
			ref="uv-index-list__letter"
			:style="{ top: $uv.addUnit(letterInfo.top || 100 ,'px') }"
			@touchstart="touchStart"
			@touchmove.stop.prevent="touchMove"
			@touchend.stop.prevent="touchEnd"
			@touchcancel.stop.prevent="touchEnd"
		>
			<view
				class="uv-index-list__letter__item"
				v-for="(item, index) in uIndexList"
				:key="index"
				:style="{
					backgroundColor: activeIndex === index ? activeColor : 'transparent'
				}"
			>
				<text
					class="uv-index-list__letter__item__index"
					:style="{color: activeIndex === index ? '#fff' : inactiveColor}"
				>{{ item }}</text>
			</view>
		</view>
		<uv-transition
			mode="fade"
			:show="touching"
			:customStyle="{
				position: 'fixed',
				right: '40px',
				top: $uv.addUnit(indicatorTop,'px'),
				zIndex: 2
			}"
		>
			<view class="uv-index-list__indicator__box">
				<view
					class="uv-index-list__indicator"
					:class="['uv-index-list__indicator--show']"
					:style="{
						height: $uv.addUnit(indicatorHeight,'px'),
						width: $uv.addUnit(indicatorHeight,'px')
					}"
				>
					<text class="uv-index-list__indicator__text">{{ uIndexList[activeIndex] }}</text>
				</view>
			</view>
		</uv-transition>
	</view>
</template>

<script>
	const indexList = () => {
		const indexList = [];
		const charCodeOfA = 'A'.charCodeAt(0);
		for (let i = 0; i < 26; i++) {
			indexList.push(String.fromCharCode(charCodeOfA + i));
		}
		return indexList;
	}
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	// 由于weex为阿里的KPI业绩考核的产物，所以不支持百分比单位，这里需要通过dom查询组件的宽度
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * IndexList 索引列表
	 * @description  通过折叠面板收纳内容区域
	 * @tutorial https://www.uvui.cn/components/indexList.html
	 * @property {String}			inactiveColor	右边锚点非激活的颜色 ( 默认 '#606266' )
	 * @property {String}			activeColor		右边锚点激活的颜色 ( 默认 '#5677fc' )
	 * @property {Array}			indexList		索引字符列表，数组形式
	 * @property {Boolean}			sticky			是否开启锚点自动吸顶 ( 默认 true )
	 * @property {String | Number}	customNavHeight	自定义导航栏的高度 ( 默认 0 )
	 * */ 
	export default {
		name: 'uv-index-list',
		mixins: [mpMixin, mixin, props],
		// #ifdef MP-WEIXIN
		// 将自定义节点设置成虚拟的，更加接近Vue组件的表现，能更好的使用flex属性
		options: {
			virtualHost: true
		},
		// #endif
		data() {
			return {
				// 当前正在被选中的字母索引
				activeIndex: -1,
				touchmoveIndex: 1,
				// 索引字母的信息
				letterInfo: {
					height: 0,
					itemHeight: 0,
					top: 0
				},
				// 设置字母指示器的高度，后面为了让指示器跟随字母，并将尖角部分指向字母的中部，需要依赖此值
				indicatorHeight: 50,
				// 字母放大指示器的top值，为了让其指向当前激活的字母
				// indicatorTop: 0
				// 当前是否正在被触摸状态
				touching: false,
				// 滚动条顶部top值
				scrollTop: 0,
				// scroll-view的高度
				scrollViewHeight: 0,
				// 系统信息
				sys: '',
				scrolling: false,
				scrollIntoView: '',
				hasHeight: 0,
				timer: 0,
				disTap: false
			}
		},
		computed: {
			// 如果有传入外部的indexList锚点数组则使用，否则使用内部生成A-Z字母
			uIndexList() {
				return this.indexList.length ? this.indexList : indexList()
			},
			// 字母放大指示器的top值，为了让其指向当前激活的字母
			indicatorTop() {
				const {
					top,
					itemHeight
				} = this.letterInfo
				return Math.floor(top + itemHeight * this.activeIndex + itemHeight / 2 - this.indicatorHeight / 2) - 8
			}
		},
		watch: {
			// 监听字母索引的变化，重新设置尺寸
			uIndexList: {
				immediate: true,
				handler() {
					this.$uv.sleep().then(() => {
						this.setIndexListLetterInfo()
					})
				}
			}
		},
		created() {
			this.sys = this.$uv.sys()
			this.children = []
			this.anchors = []
			this.init()
		},
		mounted() {
			this.setIndexListLetterInfo()
		},
		methods: {
			init() {
				// 设置列表的高度为整个屏幕的高度
				//减去this.customNavHeight，并将this.scrollViewHeight设置为maxHeight
				//解决当uv-index-list组件放在tabbar页面时,scroll-view内容较少时，还能滚动
				this.scrollViewHeight = this.sys.windowHeight - this.$uv.getPx(this.customNavHeight)
			},
			// 索引列表被触摸
			touchStart(e) {
				// 获取触摸点信息
				const touchStart = e.changedTouches[0]
				if (!touchStart || this.disTap) return
				this.touching = true
				const {
					pageY
				} = touchStart
				// 根据当前触摸点的坐标，获取当前触摸的为第几个字母
				const currentIndex = this.getIndexListLetter(pageY)
				this.setValueForTouch(currentIndex)
			},
			// 索引字母列表被触摸滑动中
			touchMove(e) {
				// 获取触摸点信息
				let touchMove = e.changedTouches[0]
				if (!touchMove || this.disTap) return;

				// 滑动结束后迅速开始第二次滑动时候 touching 为 false 造成不显示 indicator 问题
				if (!this.touching) {
					this.touching = true
				}
				const {
					pageY
				} = touchMove
				const currentIndex = this.getIndexListLetter(pageY)
				this.setValueForTouch(currentIndex)
			},
			// 触摸结束
			touchEnd(e) {
				// 延时一定时间后再隐藏指示器，为了让用户看的更直观，同时也是为了消除快速切换uv-transition的show带来的影响
				this.$uv.sleep(300).then(() => {
					this.touching = false
				})
				this.$emit('select',this.activeIndex);
			},
			// 获取索引列表的尺寸以及单个字符的尺寸信息
			getIndexListLetterRect() {
				return new Promise(resolve => {
					// 延时一定时间，以获取dom尺寸
					// #ifndef APP-NVUE
					this.$uvGetRect('.uv-index-list__letter').then(size => {
						resolve(size)
					})
					// #endif

					// #ifdef APP-NVUE
					const ref = this.$refs['uv-index-list__letter']
					dom.getComponentRect(ref, res => {
						resolve(res.size)
					})
					// #endif
				})
			},
			// 设置indexList索引的尺寸信息
			setIndexListLetterInfo() {
				this.getIndexListLetterRect().then(size => {
					const {
						top,
						height
					} = size
					const windowHeight = this.$uv.sys().windowHeight;
					let customNavHeight = 0
					// 消除各端导航栏非原生和原生导致的差异，让索引列表字母对屏幕垂直居中
					if (this.customNavHeight == 0) {
						// #ifdef H5
						customNavHeight = this.$uv.sys().windowTop
						// #endif
						// #ifndef H5
						// 在非H5中，为原生导航栏，其高度不算在windowHeight内，这里设置为负值，后面相加时变成减去其高度的一半
						customNavHeight = 0
						// #endif
					} else {
						customNavHeight = this.$uv.getPx(this.customNavHeight)
					}
					this.letterInfo = {
						height,
						// 为了让字母列表对屏幕绝对居中，让其对导航栏进行修正，也即往上偏移导航栏的一半高度
						top: (windowHeight - height) / 2 + customNavHeight / 2,
						itemHeight: Math.floor(height / this.uIndexList.length)
					}
				})
			},
			// 获取当前被触摸的索引字母
			getIndexListLetter(pageY) {
				const {
					top,
					height,
					itemHeight
				} = this.letterInfo
				// 对H5的pageY进行修正，这是由于uni-app自作多情在H5中将触摸点的坐标跟H5的导航栏结合导致的问题
				// #ifdef H5
				pageY += this.$uv.sys().windowTop
				// #endif
				// #ifdef APP-NVUE
				pageY += top
				// #endif
				// 对第一和最后一个字母做边界处理，因为用户可能在字母列表上触摸到两端的尽头后依然继续滑动
				if (pageY < top) {
					return 0
				} else if (pageY >= top + height) {
					// 如果超出了，取最后一个字母
					return this.uIndexList.length - 1
				} else {
					// 将触摸点的Y轴偏移值，减去索引字母的top值，除以每个字母的高度，即可得到当前触摸点落在哪个字母上
					return Math.floor((pageY - top) / itemHeight);
				}
			},
			// 设置各项由触摸而导致变化的值
			setValueForTouch(currentIndex) {
				// 如果偏移量太小，前后得出的会是同一个索引字母，为了防抖，进行返回
				if (currentIndex === this.activeIndex) return
				this.activeIndex = currentIndex
				// #ifndef APP-NVUE || MP-WEIXIN
				// 在非nvue中，由于anchor和item都在uv-index-item中，所以需要对index-item进行偏移
				this.scrollIntoView = `uv-index-item-${this.uIndexList[currentIndex].charCodeAt(0)}`
				// #endif
				// #ifdef MP-WEIXIN
				// 微信小程序下，scroll-view的scroll-into-view属性无法对slot中的内容的id生效，只能通过设置scrollTop的形式去移动滚动条
				this.scrollTop = this.children[currentIndex].top
				// #endif
				// #ifdef APP-NVUE
				// 在nvue中，由于cell和header为同级元素，所以实际是需要对header(anchor)进行偏移
				const anchor = `uv-index-anchor-${this.uIndexList[currentIndex]}`
				dom.scrollToElement(this.anchors[currentIndex].$refs[anchor], {
					offset: 0,
					animated: false
				})
				// #endif
			},
			getHeaderRect() {
				// 获取header slot的高度，因为list组件中获取元素的尺寸是没有top值的
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs.header, res => {
						resolve(res.size)
					})
				})
			},
			// scroll-view的滚动事件
			async scrollHandler(e) {
				if (this.touching || this.scrolling) return
				// 每过一定时间取样一次，减少资源损耗以及可能带来的卡顿
				this.scrolling = true
				this.disTap = true;
				clearTimeout(this.timer);
				this.timer = setTimeout(()=>{
					this.disTap = false;
				},200)
				this.$uv.sleep(30).then(() => {
					this.scrolling = false
				})
				let scrollTop = 0
				const len = this.children.length
				let children = this.children
				const anchors = this.anchors
				const customNavHeight = this.$uv.getPx(this.customNavHeight);
				// #ifdef APP-NVUE
				// nvue下获取的滚动条偏移为负数，需要转为正数
				scrollTop = Math.abs(e.contentOffset.y)
				// 获取header slot的尺寸信息
				const header = await this.getHeaderRect()
				// item的top值，在nvue下，模拟出的anchor的top，类似非nvue下的index-item的top
				let top = header.height
				// 由于list组件无法获取cell的top值，这里通过header slot和各个item之间的height，模拟出类似非nvue下的位置信息
				children = this.children.map((item, index) => {
					if(item.height>0) this.hasHeight = item.height;
					item.height = item.height>0?item.height:this.hasHeight;
					const child = {
						height: item.height,
						top
					}
					// 进行累加，给下一个item提供计算依据
					top += item.height + anchors[index].height
					return child
				})
				// #endif
				// #ifndef APP-NVUE
				// 非nvue通过detail获取滚动条位移
				scrollTop = e.detail.scrollTop
				// #endif
				for (let i = 0; i < len; i++) {
					const item = children[i],
						nextItem = children[i + 1]
					// 如果滚动条高度小于第一个item的top值，此时无需设置任意字母为高亮
					if (scrollTop + customNavHeight <= children[0].top || scrollTop >= children[len - 1].top + children[len -
							1].height) {
						this.activeIndex = -1
						break
					} else if (!nextItem) { 
						// 当不存在下一个item时，意味着历遍到了最后一个
						this.activeIndex = len - 1
						break
					} else if (scrollTop + customNavHeight > item.top && scrollTop + customNavHeight < nextItem.top) {
						this.activeIndex = i
						break
					}
				}
			},
		},
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-index-list {

		&__letter {
			position: fixed;
			right: 0;
			text-align: center;
			z-index: 3;
			padding: 0 6px;

			&__item {
				width: 16px;
				height: 16px;
				border-radius: 100px;
				margin: 1px 0;
				@include flex;
				align-items: center;
				justify-content: center;

				&--active {
					background-color: $uv-primary;
				}

				&__index {
					font-size: 12px;
					text-align: center;
					line-height: 12px;
				}
			}
		}
		&__indicator__box {
			width: 65px;
			height: 65px;
			padding: 6px;
			transform: rotate(-45deg);
		}
		&__indicator {
			width: 50px;
			height: 50px;
			border-radius: 100px 100px 0 100px;
			text-align: center;
			color: #ffffff;
			background-color: #c9c9c9;
			@include flex;
			justify-content: center;
			align-items: center;

			&__text {
				font-size: 28px;
				line-height: 28px;
				font-weight: bold;
				color: #fff;
				transform: rotate(45deg);
				text-align: center;
			}
		}
	}
</style>
KxIxNG{
  "id": "uv-index-list",
  "displayName": "uv-index-list 索引列表=H7$展示索引列表，右侧带索引的列表，方便快速定位到具体内容，通常用于城市/机场选择等场景。C类似于微信通讯录页面",
  "keywords": [
    "uv-index-listo!index-list",
    "索引列表transitiϲIMx ## IndexList 索引列表index-list**

用于展示索引列表，右侧带索引的列表，方便快速定位到具体内容，通常用于城市/机9选择等场景，类似于微信通讯录页面。

# (	indexList/d?-̪	x e100644 changelog.md +5M3ɍW(kD40000 components Zv'PL[y100644 package.json i*N`ŮYl\hA100644 readme.md  ~FqY"P Z<}x# 40000 uv-input TÆFT[Kɺ;&2ܶըجxL 100644 props.js iI9ՠ,FH6100644 uv-input.vue  =y)j>\>;ap^xG3<template>
    <view class="uv-input" :class="inputClass" :style="[wrapperStyle]">
      <view class="uv-input__content">
        <view class="uv-input__content__prefix-icon">
          <slot name="prefix">
            <uv-icon
							v-if="prefixIcon"
              :name="prefixIcon"
              size="18"
              :customStyle="prefixIconStyle"
            ></uv-icon>
          </slot>
        </view>
        <view class="uv-input__content__field-wrapper" @click="clickHandler">
				<!-- 根据uni-app的input组件文档，H5和APP中只要声明了password参数(无论true还是false)，type均失效，此时
				为了防止type=number时，又存在password属性，type无效，此时需要设置password为undefined
			 -->
        	<input
        	  class="uv-input__content__field-wrapper__field"
        	  :style="[inputStyle]"
        	  :type="type"
        	  :focus="focus"
        	  :cursor="cursor"
        	  :value="innerValue"
        	  :auto-blur="autoBlur"
        	  :disabled="disabled || readonly"
        	  :maxlength="maxlength"
        	  :placeholder="placeholder"
        	  :placeholder-style="placeholderStyle"
        	  :placeholder-class="placeholderClass"
        	  :confirm-type="confirmType"
        	  :confirm-hold="confirmHold"
        	  :hold-keyboard="holdKeyboard"
        	  :cursor-spacing="cursorSpacing"
        	  :adjust-position="adjustPosition"
        	  :selection-end="selectionEnd"
        	  :selection-start="selectionStart"
        	  :password="password || type === 'password' || undefined"
            :ignoreCompositionEvent="ignoreCompositionEvent"
        	  @input="onInput"
        	  @blur="onBlur"
        	  @focus="onFocus"
        	  @confirm="onConfirm"
        	  @keyboardheightchange="onkeyboardheightchange"
        	/>
        </view>
        <view
          class="uv-input__content__clear"
          v-if="isShowClear"
          @tap="onClear"
        >
          <uv-icon
            name="close"
            size="11"
            color="#ffffff"
            customStyle="line-height: 12px"
          ></uv-icon>
        </view>
        <view class="uv-input__content__subfix-icon">
          <slot name="suffix">
            <uv-icon
							v-if="suffixIcon"
              :name="suffixIcon"
              size="18"
              :customStyle="suffixIconStyle"
            ></uv-icon>
          </slot>
        </view>
      </view>
    </view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from "./props.js";
	/**
	 * Input 输入框
	 * @description  此组件为一个输入框，默认没有边框和样式，是专门为配合表单组件uv-form而设计的，利用它可以快速实现表单验证，输入内容，下拉选择等功能。
	 * @tutorial https://www.uvui.cn/components/input.html
	 * @property {String | Number}	value					输入的值
	 * @property {String}			type					输入框类型，见上方说明 （ 默认 'text' ）
	 * @property {Boolean}			fixed					如果 textarea 是在一个 position:fixed 的区域，需要显示指定属性 fixed 为 true，兼容性：微信小程序、百度小程序、字节跳动小程序、QQ小程序 （ 默认 false ）
	 * @property {Boolean}			disabled				是否禁用输入框 （ 默认 false ）
	 * @property {String}			disabledColor			禁用状态时的背景色（ 默认 '#f5f7fa' ）
	 * @property {Boolean}			clearable				是否显示清除控件 （ 默认 false ）
	 * @property {Boolean}			password				是否密码类型 （ 默认 false ）
	 * @property {String | Number}	maxlength				最大输入长度，设置为 -1 的时候不限制最大长度 （ 默认 -1 ）
	 * @property {String}			placeholder				输入框为空时的占位符
	 * @property {String}			placeholderClass		指定placeholder的样式类，注意页面或组件的style中写了scoped时，需要在类名前写/deep/ （ 默认 'input-placeholder' ）
	 * @property {String | Object}	placeholderStyle		指定placeholder的样式，字符串/对象形式，如"color: red;"
	 * @property {Boolean}			showWordLimit			是否显示输入字数统计，只在 type ="text"或type ="textarea"时有效 （ 默认 false ）
	 * @property {String}			confirmType				设置右下角按钮的文字，兼容性详见uni-app文档 （ 默认 'done' ）
	 * @property {Boolean}			confirmHold				点击键盘右下角按钮时是否保持键盘不收起，H5无效 （ 默认 false ）
	 * @property {Boolean}			holdKeyboard			focus时，点击页面的时候不收起键盘，微信小程序有效 （ 默认 false ）
	 * @property {Boolean}			focus					自动获取焦点，在 H5 平台能否聚焦以及软键盘是否跟随弹出，取决于当前浏览器本身的实现。nvue 页面不支持，需使用组件的 focus()、blur() 方法控制焦点 （ 默认 false ）
	 * @property {Boolean}			autoBlur				键盘收起时，是否自动失去焦点，目前仅App3.0.0+有效 （ 默认 false ）
	 * @property {Boolean}			disableDefaultPadding	是否去掉 iOS 下的默认内边距，仅微信小程序，且type=textarea时有效 （ 默认 false ）
	 * @property {String ｜ Number}	cursor					指定focus时光标的位置（ 默认 -1 ）
	 * @property {String ｜ Number}	cursorSpacing			输入框聚焦时底部与键盘的距离 （ 默认 30 ）
	 * @property {String ｜ Number}	selectionStart			光标起始位置，自动聚集时有效，需与selection-end搭配使用 （ 默认 -1 ）
	 * @property {String ｜ Number}	selectionEnd			光标结束位置，自动聚集时有效，需与selection-start搭配使用 （ 默认 -1 ）
	 * @property {Boolean}			adjustPosition			键盘弹起时，是否自动上推页面 （ 默认 true ）
	 * @property {String}			inputAlign				输入框内容对齐方式（ 默认 'left' ）
	 * @property {String | Number}	fontSize				输入框字体的大小 （ 默认 '15px' ）
	 * @property {String}			color					输入框字体颜色	（ 默认 '#303133' ）
	 * @property {Function}			formatter			    内容式化函数
	 * @property {String}			prefixIcon				输入框前置图标
	 * @property {String | Object}	prefixIconStyle			前置图标样式，对象或字符串
	 * @property {String}			suffixIcon				输入框后置图标
	 * @property {String | Object}	suffixIconStyle			后置图标样式，对象或字符串
	 * @property {String}			border					边框类型，surround-四周边框，bottom-底部边框，none-无边框 （ 默认 'surround' ）
	 * @property {Boolean}			readonly				是否只读，与disabled不同之处在于disabled会置灰组件，而readonly则不会 （ 默认 false ）
	 * @property {String}			shape					输入框形状，circle-圆形，square-方形 （ 默认 'square' ）
	 * @property {Object}			customStyle				定义需要用到的外部样式
	 * @property {Boolean}			ignoreCompositionEvent	是否忽略组件内对文本合成系统事件的处理。
	 * @example <uv-input v-model="value" :password="true" suffix-icon="lock-fill" />
	 */
	export default {
		name: "uv-input",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 输入框的值
				innerValue: "",
				// 是否处于获得焦点状态
				focused: false,
				// 过滤处理方法
				innerFormatter: value => value
			}
		},
		created() {
			// #ifdef VUE2
			this.innerValue = this.value;
			// #endif
			// #ifdef VUE3
			this.innerValue = this.modelValue;
			// #endif
		},
		watch: {
			value(newVal){
				this.innerValue = newVal;
			},
			modelValue(newVal){
				this.innerValue = newVal;
			}
		},
		computed: {
			// 是否显示清除控件
			isShowClear() {
				const { clearable, readonly, focused, innerValue } = this;
				return !!clearable && !readonly && !!focused && innerValue !== "";
			},
			// 组件的类名
			inputClass() {
				let classes = [],
					{ border, disabled, shape } = this;
				border === "surround" &&
					(classes = classes.concat(["uv-border", "uv-input--radius"]));
				classes.push(`uv-input--${shape}`);
				border === "bottom" &&
					(classes = classes.concat([
						"uv-border-bottom",
						"uv-input--no-radius",
					]));
				return classes.join(" ");
			},
			// 组件的样式
			wrapperStyle() {
				const style = {};
				// 禁用状态下，被背景色加上对应的样式
				if (this.disabled) {
					style.backgroundColor = this.disabledColor;
				}
				// 无边框时，去除内边距
				if (this.border === "none") {
					style.padding = "0";
				} else {
					// 由于uni-app的iOS开发者能力有限，导致需要分开写才有效
					style.paddingTop = "6px";
					style.paddingBottom = "6px";
					style.paddingLeft = "9px";
					style.paddingRight = "9px";
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			},
			// 输入框的样式
			inputStyle() {
				const style = {
					color: this.color,
					fontSize: this.$uv.addUnit(this.fontSize),
					textAlign: this.inputAlign
				};
				// #ifndef APP-NVUE
				if(this.disabled || this.readonly) {
					style['pointer-events'] = 'none';
				}
				// #endif
				return style;
			}
		},
		methods: {
			// 在微信小程序中，不支持将函数当做props参数，故只能通过ref形式调用
			setFormatter(e) {
				this.innerFormatter = e
			},
			// 当键盘输入时，触发input事件
			onInput(e) {
				let { value = "" } = e.detail || {};
				// 格式化过滤方法
				const formatter = this.formatter || this.innerFormatter
				const formatValue = formatter(value)
				// 为了避免props的单向数据流特性，需要先将innerValue值设置为当前值，再在$nextTick中重新赋予设置后的值才有效
				this.innerValue = value
				this.$nextTick(() => {
					this.innerValue = formatValue;
					this.valueChange();
				})
			},
			// 输入框失去焦点时触发
			onBlur(event) {
				this.$emit("blur", event.detail.value);
				// H5端的blur会先于点击清除控件的点击click事件触发，导致focused
				// 瞬间为false，从而隐藏了清除控件而无法被点击到
				this.$uv.sleep(100).then(() => {
					this.focused = false;
				});
				// 尝试调用uv-form的验证方法
				this.$uv.formValidate(this, "blur");
			},
			// 输入框聚焦时触发
			onFocus(event) {
				this.focused = true;
				this.$emit("focus");
			},
			// 点击完成按钮时触发
			onConfirm(event) {
				this.$emit("confirm", this.innerValue);
			},
			// 键盘高度发生变化的时候触发此事件
			// 兼容性：微信小程序2.7.0+、App 3.1.0+
			onkeyboardheightchange(e) {
				this.$emit("keyboardheightchange",e);
			},
			// 内容发生变化，进行处理
			valueChange() {
				if(this.isClear) this.innerValue = '';
				const value = this.innerValue;
				this.$nextTick(() => {
					this.$emit("input", value);
					this.$emit("update:modelValue", value);
					this.$emit("change", value);
					// 尝试调用uv-form的验证方法
					this.$uv.formValidate(this, "change");
				});
			},
			// 点击清除控件
			onClear() {
				this.innerValue = "";
				this.isClear = true;
				this.$uv.sleep(200).then(res=>{
					this.isClear = false;
				})
				this.$nextTick(() => {
					this.$emit("clear");
					this.valueChange();
				});
			},
			/**
			 * 在安卓nvue上，事件无法冒泡
			 * 在某些时间，我们希望监听uv-from-item的点击事件，此时会导致点击uv-form-item内的uv-input后
			 * 无法触发uv-form-item的点击事件，这里通过手动调用uv-form-item的方法进行触发
			 */
			clickHandler() {
				// #ifdef APP-NVUE
				if (this.$uv.os() === "android") {
					const formItem = this.$uv.$parent.call(this, "uv-form-item");
					if (formItem) {
						formItem.clickHandler();
					}
				}
				// #endif
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-border: 1;
	$show-border-surround: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-input {
		@include flex(row);
		align-items: center;
		justify-content: space-between;
		flex: 1;
		&--radius,
		&--square {
			border-radius: 4px;
		}
		&--no-radius {
			border-radius: 0;
		}
		&--circle {
			border-radius: 100px;
		}
		&__content {
			flex: 1;
			@include flex(row);
			align-items: center;
			justify-content: space-between;
			&__field-wrapper {
				position: relative;
				@include flex(row);
				margin: 0;
				flex: 1;
				&__field {
					line-height: 26px;
					text-align: left;
					color: $uv-main-color;
					height: 24px;
					font-size: 15px;
					flex: 1;
				}
			}
			&__clear {
				width: 20px;
				height: 20px;
				border-radius: 100px;
				background-color: #c6c7cb;
				@include flex(row);
				align-items: center;
				justify-content: center;
				transform: scale(0.82);
				margin-left: 15px;
			}
			&__subfix-icon {
				margin-left: 4px;
			}
			&__prefix-icon {
				margin-right: 4px;
			}
		}
	}
</style>-xO:{
  "id": "uv-input",
  "displayName": "uv-input 输入框=H13",
  "description": "uv-input 该组件为一个输入框，默认没有边框和样式，是专门为配合表单组件uv-fo_rm而设计的，利用它可以快速实现表单验证，输入内容，下拉选择等功能Ouv-inputo!input",
    "输入框V	x e100644 changelog.md |V!y40000 components #(9Z-ZJ*100644 package.json iLakR]Hl%u]To100644 readme.md A	!_9R`8ٿx_m## 1.1.20（2024-01-20）
1. 优化 uv-loading-page重构，避免初始加载的时候先显示页面的问题，小程序平台由于性能问题，可能还是会短暂出现，请注意优化处理
2. 优化 uv-textarea confirmType默认值改成return，支持换行
3. 优化 uv-ui-tools luch-request更新
4. 修复 uv-drop-down parentData不变的BUG
5. 修复 uv-picker 上个版本引出的BUG
6. 修复 uv-image 设置show-menu-by-longpress不生效的BUG
7. 修复 uv-upload 动态设置deletable为false不生效的BUG
## 1.1.19（2023-12-12）
1. 优化 uv-toast部分重构，支持取消遮罩不影响点击其他元素 a. 增加z-index参数；b. 增加overlay参数
2. 优化 关于组件如何阻止事件冒泡，增加相关说明：[组件怎么阻止事件冒泡](https://www.uvui.cn/components/feature.html#组件怎么阻止事件冒泡)
3. 优化 持续优化文档
4. 修复 uv-tabs current为字符串activeStyle不生效的BUG
5. 修复 uv-vtabs 在change回调中设置current，快速点击菜单，导致死循环的BUG
6. 修复 uv-cell right-icon插槽编译到APP端不显示的BUG，问题来源：[https://gitee.com/climblee/uv-ui/issues/I8LXZI](https://gitee.com/climblee/uv-ui/issues/I8LXZI)
## 1.1.18（2023-11-28）
0. 优化 uv-datetime-picker 增加round属性，设置弹窗圆角
1. 优化 uv-subsection 增加customItemStyle属性，方便修改bar样式，比如设置圆角
2. 修复 uv-picker issues反馈的问题uv-picker在组合式API的自定义组件中，columns动态赋值无法显示选项：[https://gitee.com/climblee/uv-ui/issues/I8H0GQ](https://gitee.com/climblee/uv-ui/issues/I8H0GQ)
3. 修复 uv-popup issues问题：[https://gitee.com/climblee/uv-ui/issues/I8HDLO](https://gitee.com/climblee/uv-ui/issues/I8HDLO)
4. 修复 uv-skeletons 支付宝小程序报错的BUG
5. 修复 uv-image webp之前未使用的BUG & 微信报错的BUG
6. 修复 uv-modal 上版本引出的确认和取消按钮均不显示，还有高度的BUG
## 1.1.17（2023-11-10）
0. 交流反馈 欢迎加入uv-ui官方群1交流反馈： 549833913（1000+）
1. 交流反馈 欢迎加入uv-ui官方群2交流反馈： 206060892
2. 新增 新增其他小组件下载入口：其他小组件
3. 优化 uv-calendars 增加readonly属性，是否为只读状态，只读状态下禁止选择日期
4. 修复 uv-search 禁用时，不能触发click的BUG
5. 修复 uv-checkbox and uv-radio label文字过长，不换行的相关说明及处理
6. 修复 uv-input and uv-search 点击clear按钮在微信小程序不好触发的BUG
7. 修复 uv-list 修复设置ellipsis不生效的BUG
8. 修复 uv-index-list 修复sticky属性不生效的BUG
## 1.1.16（2023-10-30）
1. 交流反馈 欢迎加入uv-ui官方群1交流反馈： 549833913（940+/1000）
2. 交流反馈 欢迎加入uv-ui官方群2交流反馈： 206060892
3. 新增 uv-skeletons 骨架屏，全新升级骨架屏，更加灵活，体验更加，强烈推荐使用新版骨架屏。一般用于页面在请求远程数据尚未完成时，在内容加载出来前展示与内容布局结构一致的灰白块，提升用户视觉体验。
4. 优化 uv-button 增加后置插槽suffix，方便在按钮文字后面增加图标等
5. 优化 uv-popup vue模式内容有背景色，设置圆角被遮挡的情况
6. 优化 uv-tabs 点击一个选项，change事件重复派发的问题
7. 优化 持续优化文档及其他
8. 修复 uv-album 设置singleSize、multipleSize、space等值带单位，存在不显示的BUG
9. 修复 uv-picker 省市级示例设置defaultValue，再次选择第二列错乱的BUG
10. 修复 uv-icon imgMode默认值改成aspectFit，否则会导致支付宝平台name设置为本地图片显示不全的BUG
11. 修复 uv-transition 在APP-IOS上不能正常显示的BUG
12. 修复 uv-toast、uv-swipe-action、uv-sticky、uv-notify、uv-notice-bar、uv-grid、uv-count-down、uv-code等组件，unmounted兼容vue3
## 1.1.15（2023-10-12）
1. 优化 uv-keyboard a. 增加disKeys参数，mode = "car"下，被禁用的键，如：['I','O']； b. 增加customabc参数，mode = "car"下，是否启用自定义中英文切换内容模式，为了兼容支付宝等小程序不兼容嵌套插槽，导致同时显示自定义内容和原始内容； c. 增加ref方法changeCarMode，mode = "car"下， 调用此方法可以切换中英文模式； d. 增加@changeCarInputMode，mode = "car"下，调用此方法可以进行切换中英文； e. 增加插槽abc，mode = "car"下，自定义中英文切换内容
2. 优化 uv-checkbox uv-radio 优化：https://gitee.com/climblee/uv-ui/issues/I872VD
3. 优化 uv-picker 将immediate-change默认值改为true，该值在于change回调的及时性，微信小程序生效
4. 优化 uv-tags 兼容customStyle参数等优化
5. 修复 uv-transition 部分情况，修改某属性自动关闭的BUG
6. 修复 uv-calendars 懒加载报错：https://gitee.com/climblee/uv-ui/issues/I869JS
7. 修复 uv-datetime-picker 设置minDate出现选择错乱的BUG
8. 修复 uv-input 搜狗输入法下存在不可清空的情况
9. 修复 uv-calendars selected没有设置了info或者info设置为空字符串后，文本则无法恢复BUG
## 1.1.14（2023-09-27）
1. 优化 uv-list-item 可使用customStyle变量进行样式控制
2. 优化 uv-cell 增加cellStyle参数，方便自定义单元格的样式
3. 优化 uv-switch 优化细节
4. 优化 不断优化[文档](https://www.uvui.cn/)
5. 修复 uv-button 通过customStyle修改按钮宽度，组件中最外层节点不改变的问题
6. 修复 uv-calendars a. 修复range模式下，selected设置了info后选中后，导致文本不恢复的问题；b. 修复multiple模式下，selected自定义信息的颜色没变，依然是白色
7. 修复 uv-checkbox uv-checkbox-group之change回调中v-model值不更新的BUG
## 1.1.13（2023-09-15）
1. 优化 uv-button a. 增加参数iconSize，用于控制图标的大小；b. 增加open-type="agreePrivacyAuthorization"类型，用户同意隐私协议事件回调
2. 优化 uv-picker 三级联动的案例：[https://www.uvui.cn/components/picker.html#省市区三级联动](https://www.uvui.cn/components/picker.html#省市区三级联动)
3. 修复 uv-read-more 全局设置rpx时，导致展开高度不对的BUG
4. 修复 uv-tabs a. 设置lineWidth未带单位产生的误差BUG；b. 首次加载时，处理下划线会有左到右的过渡效果
5. 修复 uv-textaera 设置autoHeight后出现高度异常的BUG
6. 修复 uv-input H5等情况设置禁用或可读情况下，点击事件无效的问题，nvue需要特殊处理
7. 修复 uv-calendars a. 在vue2+小程序渲染时闪烁的问题；b. 增加allowSameDay参数，是否允许日期范围的起止时间为同一天，mode=range时有效
8. 修复 uv-safe-bottom 兼容飞书小程序
9. 修复 uv-album 添加依赖，避免导入运行有误
10. 修复 uv-ui-tools 优化组件用到的相关
## 1.1.12（2023-09-10）
1. 修复 uv-popup a. h5初始zIndex错误的问题；b. 修复全局设置prop无效的问题
2. 修复 uv-button 修复多个按钮由view包裹，显示在一行宽度不正常的BUG
3. 修复 uv-modal a. 修复两个按钮之间竖线不显示的问题；b. uv-ui项目自定义按钮示例修复
4. 修复 uv-calendars 修复国际化失效的BUG
5. 修复 uv-keyboard 修复键盘change回调事件产生冲突的BUG
## 1.1.11（2023-09-02）
1. 优化 uv-calendars a. 去除range参数，由mode="range"替换；b. 新增mode参数，不传 / multiple / range，分别为单日期， 多个日期，选择日期范围；c. 与uv-calendar选择日期的功能保持一致
2. 优化 uv-modal a. 增加align参数，设置文本对齐方式；b. 增加textStyle参数，扩展文本样式
3. 优化 uv-datetime-picker a. 增加mode="year"模式，方便只选择年；b. 增加clearDate参数，是否清除上次选择
4. 修复 uv-ui-tools 设置customstyle同名计算属性报错：The computed property "customStyle" is already defined as a prop
5. 修复 uv-image a. 设置widthFix时出现显示不全的BUG；b. 修复抖音等平台在width和height属性改变时出现不显示的BUG
6. 修复 uv-checkbox 点击空隙处或label插槽内容不会选中的问题
7. 修复 uv-radio 点击空隙处或label插槽内容不会选中的问题
8. 修复 uv-calendars 在pages.json中设置easycom会报错的BUG
9. 修复 uv-index-list 设置customNavHeight导致定位不准确的BUG
## 1.1.10（2023-08-30）
1. 交流反馈 欢迎加入uv-ui官方群1交流反馈： 549833913
2. 交流反馈 欢迎加入uv-ui官方群2交流反馈： 206060892
3. 优化 uv-calendars 1. 去除range参数，由mode="range"替换；2. 新增mode参数，不传 / multiple / range，分别为单日期， 多个日期，选择日期范围；3. 与uv-calendar选择日期的功能保持一致
4. 新增 uv-album 新增相册组件及相关文档
5. 优化 其他优化
6. 修复 uv-text app-nvue设置align不生效的BUG
7. 修复 uv-drop-down 自定义内容，点击自定义内容时会自动关闭弹窗的问题
8. 修复 uv-image 异步修改宽高不生效的问题，问题来源：https://gitee.com/climblee/uv-ui/issues/I7WUQ3
9. 修复 uv-calendars 通过setConfig修改属性不生效的问题，出自评论区：https://ext.dcloud.net.cn/plugin?id=12287
10. 修复 uv-list 设置边框不生效的BUG
## 1.1.9（2023-08-27）
1. 优化 uv-calendars 1. 去除range参数，由mode="range"替换；2. 新增mode参数，不传 / multiple / range，分别为单日期， 多个日期，选择日期范围；3. 与uv-calendar选择日期的功能保持一致
2. 优化 uv-picker 增加round属性，设置圆角
3. 修复 uv-calendars 点击返回今天按钮时，monthSwitch方法回调参数返回月份不是当天对应月份
4. 修复 uv-radio 1. 设置 labelSize 属性设置无效的问题：https://gitee.com/climblee/uv-ui/issues/I7W6UN；2. v-model 绑定布尔值控制台报警：https://gitee.com/climblee/uv-ui/issues/I7W714
5. 修复 uv-checkbox 1. 设置 label 属性为布尔值不生效的BUG
## 1.1.8（2023-08-24）
1. 优化 uv-popup 弹出不丝滑优化思路：https://www.uvui.cn/components/popup.html#yh
2. 修复 uv-switch 取消value传值，只能使用v-model传值，避免异步操作不生效的BUG
3. 修复 uv-index-list ios端滚动过程中+快速点击右侧导航页面出现空白的BUG
4. 修复 uv-rate 1. 支付宝报错的BUG; 2. 不能选半星的BUG
5. 修复 uv-model 异步loading时，确认回调还会一直触发的BUG
6. 修复 uv-swiper 标题文字过多未隐藏掉的BUG
7. 修复 uv-text app-nvue编译不能自动换行的BUG
## 1.1.7（2023-08-22）
1. 优化 uv-drop-down a. 增加@change回调，返回弹窗关闭状态； b. 增加init方法，方便位置改变进行调整
2. 优化 部分文档优化
3. 修复 uv-input a. app-nvue-ios端不能输入的BUG；b. 键盘高度等值不返回BUG
4. 修复 uv-scroll-list 报错导致不能移动指示器的BUG
5. 修复 uv-search 边距值在上次更新中误改导致不对的BUG
6. 修复 uv-image 设置width和height为100%不生效的BUG
## 1.1.6（2023-08-18）
1. 优化 优化文档
2. 修复 uv-list 使用列表右侧显示 switch，switchChange回调中返回数据为undefined的BUG
3. 修复 uv-checkbox 数据多不换行的BUG
4. 修复 uv-upload 1. 图片预览位置错误的BUG；2. 视频预览不生效的BUG；3. 改变上传视频宽高不生效的BUG
5. 修复 uv-navbar 在部分ios高版本机型，返回按钮不好操作的问题
6. 修复 uv-waterfall 只有一条数据的时候，切换的时候数据会左右显示错误的BUG
## 1.1.5（2023-08-14）
1. 优化 uv-pick-color 删除scrollTop参数，内部修改后就不需要了
2. 优化 uv-loading-icon 增加textStyle参数，可自定义文本样式，比如给上边距
3. 修复 uv-safe-bottom 百度小程序报错的BUG
4. 修复 uv-form 设置labelWidth属性时，节点渲染有闪动的BUG
5. 修复 uv-grid 设置col属性时，节点渲染有闪动的BUG
6. 修复 uv-parse 阻止a标签跳转文档说明
## 1.1.4（2023-08-13）
1. 优化 nvue自定义图标 [详细文档-nvue中自定义图标库](https://www.uvui.cn/guide/customIcon.html#nvue%E4%B8%AD%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9B%BE%E6%A0%87%E5%BA%93)
2. 优化 uv.$uv.http 在APP.vue页面使用报错的BUG： [Api集中管理](https://www.uvui.cn/js/http.html#_3-api%E9%9B%86%E4%B8%AD%E7%AE%A1%E7%90%86)
3. 修复 uv-navbar app-nvue运行ios存在背景图片错乱的问题
4. 修复 uv-list app-nvue运行ios存在，分包页面不滚动
5. 修复 uv-textarea 值为null或undefined时显示错误的bug
6. 修复 uv-search 值为null或undefined时显示错误的bug
7. 修复 uv-scroll-list vue2编译报错的BUG
8. 修复 uv-calendars 选择月份弹窗层级的问题
9. 修复 uv-form 动画在vue3 setup语法糖中错乱，以及表单其他相关问题解决： [Issues](https://gitee.com/my_dear_li_pan/uv-ui/issues/I7SNTT)
10. 修复 uv-picker-color 滚动页面无法点击的BUG：增加scrollTop参数，设置滚动条的位置。不设置如果页面出现滚动就需要传该值，会出现颜色面板无法进行选颜色的情况。
11. 交流反馈 欢迎加入uv-ui官方群1交流反馈： [549833913](https://www.uvui.cn/components/addQQGroup.html)
12. 交流反馈 欢迎加入uv-ui官方群2交流反馈： [206060892](https://www.uvui.cn/components/addQQGroup.html)
## 1.1.3（2023-08-06）
1. 优化 uv-calendars 1. 增加startText参数; 2. 增加endText参数; 3. 增加selected中的参数; 4. 优化日历范围选择
2. 优化 uv-empty icon属性支持base64图片
3. 优化 uv-navbar 增加背景图片的裁剪模式参数imgMode
4. 优化 uv-picker-color 颜色值不对的BUG
5. 优化 [API文档优化](https://www.uvui.cn/components/changelog.html)
6. 优化 常见问题增加：[怎么隐藏uv-tabs等组件的滚动条](https://www.uvui.cn/components/problem.html#%E4%B9%9D%E3%80%81%E6%80%8E%E4%B9%88%E9%9A%90%E8%97%8Fuv-tabs%E7%AD%89%E7%BB%84%E4%BB%B6%E7%9A%84%E6%BB%9A%E5%8A%A8%E6%9D%A1)
7. 修复 uv-radio name为数字0时不能选中的BUG
8. 修复 uv-textarea 1. v-model设置为数据时的BUG；2. 复制过多内容，计数显示错误的BUG；3. maxlength为-1改成不显示计数
9. 修复 uv-code-input 在vue2模式下，v-model设置为0时不生效的BUG
10. 修复 uv-input 在vue2模式下，v-model设置为0时不生效的BUG
11. 修复 uv-search 在vue2模式下，v-model设置为0时不生效的BUG
12. 修复 uv-ui-tools 1. 路由拦截修复；2. 增加events参数
## 1.1.2（2023-08-03）
1. 新增 uv-calendars 新版日历发布
2. 新增 uv-toolbar 组件独立发布，老用户更新uv-picker，需要手动删除uv-picker目录下的uv-toolbar目录，否则会有冲突提示
3. 优化 uv-tags 增加cellChild参数
4. 优化 uv-navbar 兼容背景图片
5. 优化 uv-notice-bar 竖向滚动时候增加change回调
## 1.1.1（2023-07-30）
1. 新增 uv-drop-down 下拉筛选组件，兼容app-nvue及多端
2. 优化 uv-textarea 增加confirm-hold参数，方便设置进行换行处理
3. 优化 其他关于文档的优化等
## 1.1.0（2023-07-26）
1. 重构 uv-list  全面重构，提高性能，放弃使用scroll-view，具体文档参考：uv-list列表
2. 优化 uv-search 1. 增加prefix和suffix 前置和后置插槽；2. 增加boxStyle参数，方便控制输入框部分的样式
3. 优化 文档优化：获取节点布局信息，文档新增nvue获取方式的说明
## 1.0.22（2023-07-26）
1. 优化 uv-textarea 组件 增加textStyle和countStyle属性，方便控制文本样式
2. 优化 uv-swiper 增加竖向播放属性：vertical
3. 优化 uv-icon 支持base64图片格式
4. 优化 uv-transition 和 uv-image 增加参数cellChild属性，避免nvue中出现回收后不显示的BUG
5. 优化 uv-button 增加customTextStyle属性，方便自定义按钮文字样式
6. 优化 优化部分文档说明
7. 修复 uv-slider 修改背景颜色属性为backgroundColor，避免设置不生效
8. 修复 uv-index-list 1. 修复全局设置成rpx存在的高度BUG；2. 修复其他BUG
## 1.0.21（2023-07-22）
1. 新增 uv-scroll-list 横向滚动列表组件
2. 优化 增加测试占位图，方便开发者使用线上图片进行测试：[https://www.uvui.cn/components/testPic.html](https://www.uvui.cn/components/testPic.html)
3. 优化 uv-calendar 组件文档示例等优化，增加setFormatter说明
4. 优化 uv-notice-bar 优化文档，说明不显示左边图标的使用方法
5. 修复 uv-input 在微信小程序端清除内容存在不能清除的BUG
6. 修复 uv-button 1. 解决微信小程序动态设置hover-class点击态不消失的BUG; 2. 文档优化
7. 修复 uv-waterfall 在tab切换等场景快速切换时，会出现报错的BUG
8. 优化 优化其他
## 1.0.20（2023-07-18）
1. 修复 uv-textarea 设置-1不生效
2. 修复 uv-icon 恢复uv-empty相关的图标
3. 修复 uv-empty 恢复设置mode属性的内置图标
4. 优化 [优化文档](https://www.uvui.cn)
## 1.0.19（2023-07-14）
1. 优化 uv-waterfall 当changeList未处理数据时，正确返回对应列的数据，避免误导
2. 修复 uv-rate VUE3模式下设置value属性不生效的BUG
3. 修复 uv-input VUE3模式下设置value属性不生效的BUG
4. 修复 uv-search VUE3模式下设置value属性不生效的BUG
5. 修复 uv-code-input VUE3模式下设置value属性不生效的BUG
6. 修复 uv-number-box VUE3模式下设置value属性不生效的BUG
7. 修复 uv-radio VUE3模式下设置value属性不生效的BUG
8. 修复 uv-checkbox VUE3模式下设置value属性不生效的BUG
9. 修复 uv-textarea VUE3模式下设置value属性不生效的BUG
10. 修复 uv-switch VUE3模式下设置value属性不生效的BUG
11. 修复 uv-slider VUE3模式下设置value属性不生效的BUG
12. 修复 uv-datetime-picker VUE3模式下设置value属性不生效的BUG
13. 修复 uv-icon 部分图标错误的BUG
## 1.0.18（2023-07-06）
1. 优化 uv-icon 1. 更新图标，删除一些不常用的图标；2. 删除base64，修改成ttf文件引入读取图标。uv-icon 图标
2. 优化 uv-icon nvue自定义图标用法，文档说明：[点击跳转](https://www.uvui.cn/guide/customIcon.html)
3. 优化 uv-upload 文档示例代码，增加fileList参数说明：[点击跳转](https://www.uvui.cn/components/upload.html#filelist-options)
4. 修复 uv-checkbox vue3模式下，动态修改v-model绑定的值无效的BUG
5. 修复 uv-radio vue3模式下，动态修改v-model绑定的值无效的BUG
6. 修复 uv-datetime-picker vue3模式下，动态修改v-model绑定的值无效的BUG
## 1.0.17（2023-07-04）
1. 优化 uv-icon 修复，NVUE平台主题颜色在APP不生效的BUG
2. 优化 uv-notice-bar 优化，增加disableScroll属性
3. 优化 uv-input uv-back-top uv-cell uv-form uv-search uv-modal uv-navbar uv-index-list uv-empty uv-upload 去除插槽判断，避免某些平台不显示的BUG
4. 优化 uv-form 优化文档
5. 优化 优化其他相关文档
## 1.0.16（2023-07-03）
1. 优化 uv-transition 动画组件，代码重构优化，性能更加友好，增加自定义动画功能。详情[参考文档](https://www.uvui.cn/components/transition.html)
2. 优化 uv-popup 弹出层，代码重构优化，性能翻倍，小程序体验性能更加，避免卡顿。打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/popup.html)
3. 优化 uv-calendar 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/actionSheet.html)
4. 优化 uv-action-sheet 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/calendar.html)
5. 优化 uv-datetime-picker 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/datetimePicker.html)
6. 优化 uv-form 由于弹出层uv-transition的修改，组件内部做了相应的修改，参数不变。
7. 优化 uv-keyboard 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/keyboard.html)
8. 优化 uv-modal 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/modal.html)
9. 优化 uv-notify 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/notify.html)
10. 优化 uv-overlay 由于弹出层uv-transition的修改，组件内部做了相应的修改，参数不变。
11. 优化 uv-pick-color 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/pickColor.html)
12. 优化 uv-picker 由于弹出层uv-popup的修改，打开和关闭方法更改，详情[参考文档](https://www.uvui.cn/components/picker.html)
13. 优化 uv-tooltip 由于弹出层uv-transition的修改，组件内部做了相应的修改，参数不变。
14. 优化 uv-loading-page 由于弹出层uv-transition的修改，组件内部做了相应的修改，参数不变。
15. 优化 相关文档的优化更改。
16. 修复 uv-safe-bottom 修复，在百度程序，抖音小程序不生效的BUG
## 1.0.15（2023-06-29）
1. 欢迎加QQ群交流：[549833913](https://www.uvui.cn/components/addQQGroup.html)
2. 优化 uv-swiper 优化：1. 增加titleStyle属性，方便修改标题样式；2. 标题上去掉是否是图片的判断，避免无后缀的图片不显示
3. 优化 uv-steps 优化：1. 增加插槽title; 3. 文档关于插槽相关的参数说明完善；增加customStyle属性
4. 优化 uv-checkbox 优化：增加label文字插槽，与radio保持一致，优化文档相关说明
5. 优化 uv-modal 优化：增加closeLoading方法，方便异步加载手动取消加载状态，更新文档
6. 优化 uv-image 增加文档说明：uv-list、 uv-waterfall等组件在 Android平台使用了list封装，所以在该组件中仍然不能使用uv-image等组件
7. 优化 优化更多文档
8. 修复 uv-vtabs 修复非联动情况下，内容过多的情况，滚动一段距离，再切换未滚动到顶部的BUG
9. 修复 uv-image 修复：duration属性不生效的BUG
10. 修复 uv-code-input 修复：使用:disabledKeyboard="true"属性，事件全部失效的BUG
11. 修复 uv-button 修复：设置open-type="chooseAvatar"等值不生效的BUG
## 1.0.14（2023-06-25）
1. 欢迎加QQ群交流：[549833913](https://www.uvui.cn/components/addQQGroup.html)
2. 优化 uv-count-down 增加外部样式customStyle参数
3. 优化 文档的全面优化
4. 修复 uv-count-to 1. 修复继续滚动的函数 2. 修改文档错误 4. 适配px和rpx的单位 4. 适配customStyle参数
5. 修复 uv-load-more 修复customStyle参数设置背景等不生效的BUG
6. 修复 uv-code-input 优化下边框
7. 修复 uv-tabs 添加uv-icon依赖
8. 修复 uv-grid 优化修改
9. 修复 uv-cell 优化修改
## 1.0.13（2023-06-20）
1. 优化 uv-calendar formatter格式化中增加topInfo参数
2. 优化 uv-tabs 增加customStyle参数
3. 优化 文档优化，便于开发者直接开干
4. 优化 uv-switch 优化size属性，适配单位传递
5. 修复 uv-ui-tools、uv-form、uv-picker 修复vue3编译支付宝异常
6. 修复 uv-ui-tools、uv-form、uv-picker 修复vue3编译支付宝异常
7. 修复 uv-parse 修复在nvue不显示的BUG
8. 修复 uv-form 修复某些条件下报错的BUG
## 1.0.12（2023-06-14）
1. 优化部分组件，优化文档部分细节
2. uv-popup、uv-modal 修复遮罩层zIndex问题
3. uv-form 在vue3的setup语法中ref使用uvForm会导致报错
4. uv-tabs activeStyle设置字体大小，可能会导致下划线位置不对BUG
5. uv-pick-color 百度小程序点击报错
6. uv-transition 恢复this.$nextTick
7. uv-picker 抖音小程序选择的时候报错，导致不能关闭的BUG
8. uv-checkbox 多余的属性labelDisabled，导致APP中报错提示
9. uv-tabbar 底部安全距离组件无效的BUG
10. uv-vtabs 头部存在的时候，联动不准确的BUG
## 1.0.11（2023-06-12）
1. uv-radio-group、uv-checkbox-group 兼容自定义样式customStyle，方便通过样式调整整体位置等，数据较多时允许换行
2. uv-ui-tools 优化内置样式等，解决微信小程序使用uvui提示 Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors，[详情](https://www.uvui.cn/components/problem.html)
3. uv-datetime-picker 取消defaultIndex参数，目前传该值也没实际意义
4. uv-tabbar 增加iconSize参数
5. uv-calendar 增加change回调
6. uv-calendar 修复BUG
7. uv-rate 修复只读或禁止状态下设置value无效的问题
8. uv-popup 修复zIndex问题
9. uv-modal 修复zIndex问题
10. 文档-扩展配置更新：[扩展配置](https://www.uvui.cn/components/setting.html)
11. 文档-优化更新：[uv-ui文档](https://www.uvui.cn/components/changelog.html)
12. 文档-新增常见问题：[常见问题](https://www.uvui.cn/components/problem.html)
13. 优化其他
## 1.0.10（2023-06-05）
1. uv-navbar 渐变背景色兼容
2. uv-calendar 日历选择BUG修复
## 1.0.9（2023-06-05）
1. 新增uv-vtabs垂直选项卡组件，主要用于分类展示，分类切换功能，支持联动和不联动两种模式
2. uv-qrcode，uv-datetime-picker，uv-subsection等文档说明优化，避免开发困难；优化API相关说明
3. uv-notice-bar 1. 修复在触发error函数报错的BUG；2. 修复在text值为undefined的时候，解决报错BUG
4. uv-button 等组件修复触发两次事件的BUG
5. uv-datetime-picker 1. 修复重置值存在不更新的BUG；2. 优化文档，增加filter使用方法说明
6. uv-badge 修复type等属性为null或undefined的时候不显示徽标的BUG
7. uv-ui-tools 优化工具组件，兼容更多功能，小程序分享功能优化等
...
## 1.0.8（2023-05-27）
1. uv-waterfall修复在百度小程序中可能存在的BUG；去掉原有的slot方式
2. uv-image修复可能报错的问题
3. uv-pick-color 在文档预览模式中无法点击的问题
4. uv-index-list 修复select事件不触发的问题
5. 优化其他组件及示例项目等
## 1.0.7（2023-05-25）
1. uv-icon 将线上ttf字体包替换成base64，避免加载时或者网络差时候显示白色方块
2. uv-text 去掉多余的data-index属性，避免警告
3. uv-upload 在fileList的watch中增加deep属性
4. uv-pick-color 去掉template中存在的this.导致头条小程序编译警告
5. uv-image 去掉template中存在的this.导致头条小程序编译警告
## 1.0.6（2023-05-23）
1. 新增uv-pick-color颜色选择器组件
2. uv-toolbar组件增加showBorder属性，是否显示下边框
3. uv-transition组件在百度小程序等平台不支持this.$nextick导致下面的逻辑不执行，使用延时替换方案
4. uv-ui-tools组件中bem()函数兼容百度/头条小程序等
5. uv-waterfall组件修复在百度/头条小程序显示异常等BUG，增加changeList回调函数处理数据，同步更新示例等
6. uv-image组件修复在百度/头条小程序等开启observeLazyLoad后显示异常BUG
7. uv-tabs组件修复上次更新导致的在nvue中不滚动的BUG
8. uv-qrcode组件修复在部分平台不显示加载的BUG
9. 修复其他已知问题等
## 1.0.5（2023-05-17）
1. 新增uv-qrcode二维码组件
2. 修复uv-tooltip在vue2模式下的BUG
3. 优化部分问题
## 1.0.4（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.3（2023-05-12）
1. 修复uv-input在vue3模式下双向绑定问题
2. 修复uv-textarea在vue3模式下双向绑定问题
3. 修复uv-rate在vue3模式下双向绑定问题
## 1.0.2（2023-05-11）
1. 更新文档
2. 增加插件下载入口
## 1.0.1（2023-05-10）
1. 所有组件依赖
2. 上传示例项目
## 1.0.0（2023-05-10）
1. uv-ui
mxm	## 1.0.5（2023-10-12）
1K
2
3^
4Z
5vD，具体参考[车牌键盘禁用键等设@a$keyboard.html#车牌键盘i禁用键等设置)
## 1.0.4（2023-09-04）
1. 优化，修改文件名称
## 1.0.3（2023-09-04）
1.7 0.2（2023-07-02）
uv-keyboard AQH参考文档'"keyboard.html
## 1.0.1k}Dmuv-keyboard 键盘
­x} 40000 uv-keyboard-car 80Ӑӂ"P¬40000 uv-keyboard-number (_lv'Raj40000 uv-keyboard |TEZxfa5/xS 100644 props.js =<g*f#*x];ɗ100644 uv-keyboard-car.vue 鞑G)$D8N2*u xyexport default {
	props: {
		// 是否打乱键盘按键的顺序
		random: {
			type: Boolean,
			default: false
		},
		// 输入一个中文后，是否自动切换到英文
		autoChange: {
			type: Boolean,
			default: false
		},
		// 被禁用的键
		disKeys: {
			type: Array,
			default: ()=>[]
		},
		// 是否自定义abc
		customabc: {
			type: Boolean,
			default: false
		}
	}
}5x	#<template>
	<view
		class="uv-keyboard"
		@touchmove.stop.prevent="noop"
	>
		<view
			v-for="(group, i) in abc ? engKeyBoardList : areaList"
			:key="i"
			class="uv-keyboard__button"
			:index="i"
			:class="[i + 1 === 4 && 'uv-keyboard__button--center']"
		>
			<view
				v-if="i === 3"
				class="uv-keyboard__button__inner-wrapper"
			>
				<view
					class="uv-keyboard__button__inner-wrapper__left"
					hover-class="uv-hover-class"
					:hover-stay-time="200"
					@tap="changeCarInputMode"
				>
					<slot>
						<template v-if="!customabc">
							<text
								class="uv-keyboard__button__inner-wrapper__left__lang"
								:class="[!abc && 'uv-keyboard__button__inner-wrapper__left__lang--active']"
							>中</text>
							<text class="uv-keyboard__button__inner-wrapper__left__line">/</text>
							<text
								class="uv-keyboard__button__inner-wrapper__left__lang"
								:class="[abc && 'uv-keyboard__button__inner-wrapper__left__lang--active']"
							>英</text>
						</template>
					</slot>
				</view>
			</view>
			<view
				class="uv-keyboard__button__inner-wrapper"
				v-for="(item, j) in group"
				:key="j"
			>
				<view
					:class="['uv-keyboard__button__inner-wrapper__inner',{'uv-keyboard__button__inner-wrapper__inner--disabled': isDisabled(i,j)}]"
					:hover-stay-time="200"
					@tap="carInputClick(i, j)"
					:hover-class="isDisabled(i,j)?'none':'uv-hover-class'"
				>
					<text class="uv-keyboard__button__inner-wrapper__inner__text">{{ item }}</text>
				</view>
				<view class="uv-keyboard__button__inner-wrapper__disabled--mask" v-if="isDisabled(i,j)"></view>
			</view>
			<view
				v-if="i === 3"
				@touchstart="backspaceClick"
				@touchend="clearTimer"
				class="uv-keyboard__button__inner-wrapper"
			>
				<view
					class="uv-keyboard__button__inner-wrapper__right"
					hover-class="uv-hover-class"
					:hover-stay-time="200"
				>
					<uv-icon
						size="28"
						name="backspace"
						color="#303133"
					></uv-icon>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * keyboard 键盘组件
	 * @description 此为uvui自定义的键盘面板，内含了数字键盘，车牌号键，身份证号键盘3种模式，都有可以打乱按键顺序的选项。
	 * @tutorial https://www.uvui.cn/components/keyboard.html
	 * @property {Boolean} random 是否打乱键盘的顺序
	 * @event {Function} change 点击键盘触发
	 * @event {Function} backspace 点击退格键触发
	 * @example <uv-keyboard ref="uKeyboard" mode="car" v-model="show"></uv-keyboard>
	 */
	export default {
		name: "uv-keyboard",
		mixins: [mpMixin, mixin, props],
		emits: ['backspace','change','changeCarInputMode'],
		data() {
			return {
				// 车牌输入时，abc=true为输入车牌号码，bac=false为输入省份中文简称
				abc: false
			};
		},
		computed: {
			areaList() {
				let data = [
					'京',
					'沪',
					'粤',
					'津',
					'冀',
					'豫',
					'云',
					'辽',
					'黑',
					'湘',
					'皖',
					'鲁',
					'苏',
					'浙',
					'赣',
					'鄂',
					'桂',
					'甘',
					'晋',
					'陕',
					'蒙',
					'吉',
					'闽',
					'贵',
					'渝',
					'川',
					'青',
					'琼',
					'宁',
					'挂',
					'藏',
					'港',
					'澳',
					'新',
					'使',
					'学'
				];
				let tmp = [];
				// 打乱顺序
				if (this.random) data = this.$uv.randomArray(data);
				// 切割成二维数组
				tmp[0] = data.slice(0, 10);
				tmp[1] = data.slice(10, 20);
				tmp[2] = data.slice(20, 30);
				tmp[3] = data.slice(30, 36);
				return tmp;
			},
			engKeyBoardList() {
				let data = [
					1,
					2,
					3,
					4,
					5,
					6,
					7,
					8,
					9,
					0,
					'Q',
					'W',
					'E',
					'R',
					'T',
					'Y',
					'U',
					'I',
					'O',
					'P',
					'A',
					'S',
					'D',
					'F',
					'G',
					'H',
					'J',
					'K',
					'L',
					'Z',
					'X',
					'C',
					'V',
					'B',
					'N',
					'M'
				];
				let tmp = [];
				if (this.random) data = this.$uv.randomArray(data);
				tmp[0] = data.slice(0, 10);
				tmp[1] = data.slice(10, 20);
				tmp[2] = data.slice(20, 30);
				tmp[3] = data.slice(30, 36);
				return tmp;
			},
			isDisabled(i,j) {
				return (i,j)=>{
					let value = '';
					if (this.abc) value = this.engKeyBoardList[i][j];
					else value = this.areaList[i][j];
					return this.disKeys.indexOf(value) > -1;
				}
			}
		},
		methods: {
			// 点击键盘按钮
			carInputClick(i, j) {
				if(this.isDisabled(i,j)) return;
				let value = '';
				// 不同模式，获取不同数组的值
				if (this.abc) value = this.engKeyBoardList[i][j];
				else value = this.areaList[i][j];
				// 如果允许自动切换，则将中文状态切换为英文
				if (!this.abc && this.autoChange) this.$uv.sleep(200).then(() => this.abc = true)
				this.$emit('change', value);
			},
			// 修改汽车牌键盘的输入模式，中文|英文
			changeCarInputMode() {
				this.abc = !this.abc;
				this.$emit('changeCarInputMode',this.abc);
			},
			// 点击退格键
			backspaceClick() {
				this.$emit('backspace');
				clearInterval(this.timer); //再次清空定时器，防止重复注册定时器
				this.timer = null;
				this.timer = setInterval(() => {
					this.$emit('backspace');
				}, 250);
			},
			clearTimer() {
				clearInterval(this.timer);
				this.timer = null;
			},
		}
	};
</script>

<style lang="scss" scoped>
	$show-hover: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-car-keyboard-background-color: rgb(224, 228, 230) !default;
	$uv-car-keyboard-padding:6px 0 6px !default;
	$uv-car-keyboard-button-inner-width:64rpx !default;
	$uv-car-keyboard-button-inner-background-color:#FFFFFF !default;
	$uv-car-keyboard-button-height:80rpx !default;
	$uv-car-keyboard-button-inner-box-shadow:0 1px 0px #999992 !default;
	$uv-car-keyboard-button-border-radius:4px !default;
	$uv-car-keyboard-button-inner-margin:8rpx 5rpx !default;
	$uv-car-keyboard-button-text-font-size:16px !default;
	$uv-car-keyboard-button-text-color:$uv-main-color !default;
	$uv-car-keyboard-center-inner-margin: 0 4rpx !default;
	$uv-car-keyboard-special-button-width:134rpx !default;
	$uv-car-keyboard-lang-font-size:16px !default;
	$uv-car-keyboard-lang-color:$uv-main-color !default;
	$uv-car-keyboard-active-color:$uv-primary !default;
	$uv-car-keyboard-line-font-size:15px !default;
	$uv-car-keyboard-line-color:$uv-main-color !default;
	$uv-car-keyboard-line-margin:0 1px !default;
	$uv-car-keyboard-uv-hover-class-background-color:#BBBCC6 !default;

	.uv-keyboard {
		@include flex(column);
		justify-content: space-around;
		background-color: $uv-car-keyboard-background-color;
		align-items: stretch;
		padding: $uv-car-keyboard-padding;

		&__button {
			@include flex;
			justify-content: center;
			flex: 1;
			/* #ifndef APP-NVUE */
			/* #endif */

			&__inner-wrapper {
				position: relative;
				box-shadow: $uv-car-keyboard-button-inner-box-shadow;
				margin: $uv-car-keyboard-button-inner-margin;
				border-radius: $uv-car-keyboard-button-border-radius;
				
				&__disabled--mask {
					position: absolute;
					left: 0;
					top: 0;
					bottom: 0;
					right: 0;
					width: $uv-car-keyboard-button-inner-width;
					height: $uv-car-keyboard-button-height;
				}

				&__inner {
					@include flex;
					justify-content: center;
					align-items: center;
					width: $uv-car-keyboard-button-inner-width;
					background-color: $uv-car-keyboard-button-inner-background-color;
					height: $uv-car-keyboard-button-height;
					border-radius: $uv-car-keyboard-button-border-radius;
					
					&--disabled {
						opacity: 0.5;
					}

					&__text {
						font-size: $uv-car-keyboard-button-text-font-size;
						color: $uv-car-keyboard-button-text-color;
					}
				}

				&__left,
				&__right {
					border-radius: $uv-car-keyboard-button-border-radius;
					width: $uv-car-keyboard-special-button-width;
					height: $uv-car-keyboard-button-height;
					background-color: $uv-car-keyboard-uv-hover-class-background-color;
					@include flex;
					justify-content: center;
					align-items: center;
					box-shadow: $uv-car-keyboard-button-inner-box-shadow;
				}

				&__left {
					&__line {
						font-size: $uv-car-keyboard-line-font-size;
						color: $uv-car-keyboard-line-color;
						margin: $uv-car-keyboard-line-margin;
					}

					&__lang {
						font-size: $uv-car-keyboard-lang-font-size;
						color: $uv-car-keyboard-lang-color;

						&--active {
							color: $uv-car-keyboard-active-color;
						}
					}
				}
			}
		}
	}

	.uv-hover-class {
		background-color: $uv-car-keyboard-uv-hover-class-background-color;
	}
</style>
~>xV 100644 props.js `=@Z0NY:o<100644 uv-keyboard-number.vue ݑ>{hkR)5"ȿxOexport default {
	props: {
		// 键盘的类型，number-数字键盘，card-身份证键盘
		mode: {
			type: String,
			default: 'number'
		},
		// 是否显示键盘的"."符号
		dotDisabled: {
			type: Boolean,
			default: false
		},
		// 是否打乱键盘按键的顺序
		random: {
			type: Boolean,
			default: false
		}
	}
}Vx7<template>
	<view
		class="uv-keyboard"
		@touchmove.stop.prevent="noop"
	>
		<view
			class="uv-keyboard__button-wrapper"
			v-for="(item, index) in numList"
			:key="index"
		>
			<view
				class="uv-keyboard__button-wrapper__button"
				:style="[itemStyle(index)]"
				@tap="keyboardClick(item)"
				hover-class="uv-hover-class"
				:hover-stay-time="200"
			>
				<text class="uv-keyboard__button-wrapper__button__text">{{ item }}</text>
			</view>
		</view>
		<view
			class="uv-keyboard__button-wrapper"
		>
			<view
				class="uv-keyboard__button-wrapper__button uv-keyboard__button-wrapper__button--gray"
				hover-class="uv-hover-class"
				:hover-stay-time="200"
				@touchstart.stop="backspaceClick"
				@touchend="clearTimer"
			>
				<uv-icon
					name="backspace"
					color="#303133"
					size="28"
				></uv-icon>
			</view>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * keyboard 键盘组件
	 * @description
	 * @tutorial
	 * @property {String}	mode		键盘的类型，number-数字键盘，card-身份证键盘
	 * @property {Boolean}	dotDisabled	是否显示键盘的"."符号
	 * @property {Boolean}	random		是否打乱键盘按键的顺序
	 * @event {Function} change		点击键盘触发
	 * @event {Function} backspace	点击退格键触发
	 * @example
	 */
	export default {
		mixins: [mpMixin, mixin, props],
		emits: ['backspace','change'],
		data() {
			return {
				backspace: 'backspace', // 退格键内容
				dot: '.', // 点
				timer: null, // 长按多次删除的事件监听
				cardX: 'X' // 身份证的X符号
			};
		},
		computed: {
			// 键盘需要显示的内容
			numList() {
				let tmp = [];
				if (this.dotDisabled && this.mode == 'number') {
					if (!this.random) {
						return [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
					} else {
						return this.$uv.randomArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
					}
				} else if (!this.dotDisabled && this.mode == 'number') {
					if (!this.random) {
						return [1, 2, 3, 4, 5, 6, 7, 8, 9, this.dot, 0];
					} else {
						return this.$uv.randomArray([1, 2, 3, 4, 5, 6, 7, 8, 9, this.dot, 0]);
					}
				} else if (this.mode == 'card') {
					if (!this.random) {
						return [1, 2, 3, 4, 5, 6, 7, 8, 9, this.cardX, 0];
					} else {
						return this.$uv.randomArray([1, 2, 3, 4, 5, 6, 7, 8, 9, this.cardX, 0]);
					}
				}
			},
			// 按键的样式，在非乱序&&数字键盘&&不显示点按钮时，index为9时，按键占位两个空间
			itemStyle() {
				return index => {
					let style = {};
					if (this.mode == 'number' && this.dotDisabled && index == 9) style.width = '464rpx';
					return style;
				};
			},
			// 是否让按键显示灰色，只在非乱序&&数字键盘&&且允许点按键的时候
			btnBgGray() {
				return index => {
					if (!this.random && index == 9 && (this.mode != 'number' || (this.mode == 'number' && !this
							.dotDisabled))) return true;
					else return false;
				};
			},
		},
		created() {

		},
		methods: {
			// 点击退格键
			backspaceClick() {
				this.$emit('backspace');
				clearInterval(this.timer); //再次清空定时器，防止重复注册定时器
				this.timer = null;
				this.timer = setInterval(() => {
					this.$emit('backspace');
				}, 250);
			},
			clearTimer() {
				clearInterval(this.timer);
				this.timer = null;
			},
			// 获取键盘显示的内容
			keyboardClick(val) {
				// 允许键盘显示点模式和触发非点按键时，将内容转为数字类型
				if (!this.dotDisabled && val != this.dot && val != this.cardX) val = Number(val);
				this.$emit('change', val);
			}
		}
	};
</script>

<style lang="scss" scoped>
	$show-hover: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-number-keyboard-background-color:rgb(224, 228, 230) !default;
	$uv-number-keyboard-padding:8px 10rpx 8px 10rpx !default;
	$uv-number-keyboard-button-width:222rpx !default;
	$uv-number-keyboard-button-margin:4px 6rpx !default;
	$uv-number-keyboard-button-border-top-left-radius:4px !default;
	$uv-number-keyboard-button-border-top-right-radius:4px !default;
	$uv-number-keyboard-button-border-bottom-left-radius:4px !default;
	$uv-number-keyboard-button-border-bottom-right-radius:4px !default;
	$uv-number-keyboard-button-height: 90rpx!default;
	$uv-number-keyboard-button-background-color:#FFFFFF !default;
	$uv-number-keyboard-button-box-shadow:0 2px 0px #BBBCBE !default;
	$uv-number-keyboard-text-font-size:20px !default;
	$uv-number-keyboard-text-font-weight:500 !default;
	$uv-number-keyboard-text-color:$uv-main-color !default;
	$uv-number-keyboard-gray-background-color:rgb(200, 202, 210) !default;
	$uv-number-keyboard-uv-hover-class-background-color: #BBBCC6 !default;

	.uv-keyboard {
		@include flex;
		flex-direction: row;
		justify-content: space-around;
		background-color: $uv-number-keyboard-background-color;
		flex-wrap: wrap;
		padding: $uv-number-keyboard-padding;

		&__button-wrapper {
			box-shadow: $uv-number-keyboard-button-box-shadow;
			margin: $uv-number-keyboard-button-margin;
			border-top-left-radius: $uv-number-keyboard-button-border-top-left-radius;
			border-top-right-radius: $uv-number-keyboard-button-border-top-right-radius;
			border-bottom-left-radius: $uv-number-keyboard-button-border-bottom-left-radius;
			border-bottom-right-radius: $uv-number-keyboard-button-border-bottom-right-radius;

			&__button {
				width: $uv-number-keyboard-button-width;
				height: $uv-number-keyboard-button-height;
				background-color: $uv-number-keyboard-button-background-color;
				@include flex;
				justify-content: center;
				align-items: center;
				border-top-left-radius: $uv-number-keyboard-button-border-top-left-radius;
				border-top-right-radius: $uv-number-keyboard-button-border-top-right-radius;
				border-bottom-left-radius: $uv-number-keyboard-button-border-bottom-left-radius;
				border-bottom-right-radius: $uv-number-keyboard-button-border-bottom-right-radius;

				&__text {
					font-size: $uv-number-keyboard-text-font-size;
					font-weight: $uv-number-keyboard-text-font-weight;
					color: $uv-number-keyboard-text-color;
				}

				&--gray {
					background-color: $uv-number-keyboard-gray-background-color;
				}
			}
		}
	}

	.uv-hover-class {
		background-color: $uv-number-keyboard-uv-hover-class-background-color;
	}
</style>
	xO 100644 props.js v!.`R#].yo100644 uv-keyboard.vue `[6o	ׂ{jڳzx\export default {
	props: {
		// 键盘的类型，number-数字键盘，card-身份证键盘，car-车牌号键盘
		mode: {
			type: String,
			default: 'number'
		},
		// 是否显示键盘的"."符号
		dotDisabled: {
			type: Boolean,
			default: false
		},
		// 是否显示顶部工具条
		tooltip: {
			type: Boolean,
			default: true
		},
		// 是否显示工具条中间的提示
		showTips: {
			type: Boolean,
			default: true
		},
		// 工具条中间的提示文字
		tips: {
			type: String,
			default: ''
		},
		// 是否显示工具条左边的"取消"按钮
		showCancel: {
			type: Boolean,
			default: true
		},
		// 是否显示工具条右边的"完成"按钮
		showConfirm: {
			type: Boolean,
			default: true
		},
		// 是否打乱键盘按键的顺序
		random: {
			type: Boolean,
			default: false
		},
		// 是否开启底部安全区适配，开启的话，会在iPhoneX机型底部添加一定的内边距
		safeAreaInsetBottom: {
			type: Boolean,
			default: true
		},
		// 是否允许通过点击遮罩关闭键盘
		closeOnClickOverlay: {
			type: Boolean,
			default: true
		},
		// 是否允许点击确认按钮关闭组件
		closeOnClickConfirm: {
			type: Boolean,
			default: true
		},
		// 是否显示遮罩，某些时候数字键盘时，用户希望看到自己的数值，所以可能不想要遮罩
		overlay: {
			type: Boolean,
			default: true
		},
		// z-index值
		zIndex: {
			type: [String, Number],
			default: 10075
		},
		// 取消按钮的文字
		cancelText: {
			type: String,
			default: '取消'
		},
		// 确认按钮的文字
		confirmText: {
			type: String,
			default: '确定'
		},
		// 输入一个中文后，是否自动切换到英文
		autoChange: {
			type: Boolean,
			default: false
		},
		// 被禁用的键
		disKeys: {
			type: Array,
			default: ()=>[]
		},
		// 是否自定义abc
		customabc: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.keyboard
	}
}WKx[<template>
	<uv-popup
		ref="keyboardPopup"
		mode="bottom"
	  :overlay="overlay"
	  :closeOnClickOverlay="closeOnClickOverlay"
	  :safeAreaInsetBottom="safeAreaInsetBottom"
	  :zIndex="zIndex"
	  :customStyle="{ backgroundColor: 'rgb(214, 218, 220)' }"
		@change="popupChange"
	>
		<view class="uv-keyboard">
			<slot />
			<view
			  class="uv-keyboard__tooltip"
			  v-if="tooltip"
			>
				<view
				  hover-class="uv-hover-class"
				  :hover-stay-time="100"
				>
					<text
					  class="uv-keyboard__tooltip__item uv-keyboard__tooltip__cancel"
					  v-if="showCancel"
					  @tap="onCancel"
					>{{showCancel && cancelText}}</text>
				</view>
				<view>
					<text
					  v-if="showTips"
					  class="uv-keyboard__tooltip__item uv-keyboard__tooltip__tips"
					>{{tips ? tips : mode == 'number' ? '数字键盘' : mode == 'card' ? '身份证键盘' : '车牌号键盘'}}</text>
				</view>
				<view
				  hover-class="uv-hover-class"
				  :hover-stay-time="100"
				>
					<text
					  v-if="showConfirm"
					  @tap="onConfirm"
					  class="uv-keyboard__tooltip__item uv-keyboard__tooltip__submit"
					  hover-class="uv-hover-class"
					>{{showConfirm && confirmText}}</text>
				</view>
			</view>
			<template v-if="mode == 'number' || mode == 'card'">
				<uv-keyboard-number
				  :random="random"
				  @backspace="backspace"
				  @change="change"
				  :mode="mode"
				  :dotDisabled="dotDisabled"
				></uv-keyboard-number>
			</template>
			<template v-else>
				<uv-keyboard-car
					ref="uvKeyboardCarRef"
				  :random="random"
					:autoChange="autoChange"
					:disKeys="disKeys"
					:customabc="customabc"
				  @backspace="backspace"
				  @change="change"
					@changeCarInputMode="changeCarInputMode"
				>
					<slot name="abc"></slot>
				</uv-keyboard-car>
			</template>
		</view>
	</uv-popup>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * keyboard 键盘
	 * @description 此为uViw自定义的键盘面板，内含了数字键盘，车牌号键，身份证号键盘3中模式，都有可以打乱按键顺序的选项。
	 * @tutorial https://www.uvui.cn/components/keyboard.html
	 * @property {String}			mode				键盘类型，见官网基本使用的说明 （默认 'number' ）
	 * @property {Boolean}			dotDisabled			是否显示"."按键，只在mode=number时有效 （默认 false ）
	 * @property {Boolean}			tooltip				是否显示键盘顶部工具条 （默认 true ）
	 * @property {Boolean}			showTips			是否显示工具条中间的提示 （默认 true ）
	 * @property {String}			tips				工具条中间的提示文字，见上方基本使用的说明，如不需要，请传""空字符
	 * @property {Boolean}			showCancel			是否显示工具条左边的"取消"按钮 （默认 true ）
	 * @property {Boolean}			showConfirm			是否显示工具条右边的"完成"按钮（ 默认 true ）
	 * @property {Boolean}			random				是否打乱键盘按键的顺序 （默认 false ）
	 * @property {Boolean}			safeAreaInsetBottom	是否开启底部安全区适配 （默认 true ）
	 * @property {Boolean}			closeOnClickOverlay	是否允许点击遮罩收起键盘 （默认 true ）
	 * @property {Boolean}			show				控制键盘的弹出与收起（默认 false ）
	 * @property {Boolean}			overlay				是否显示遮罩 （默认 true ）
	 * @property {String | Number}	zIndex				弹出键盘的z-index值 （默认 1075 ）
	 * @property {String}			cancelText			取消按钮的文字 （默认 '取消' ）
	 * @property {String}			confirmText			确认按钮的文字 （默认 '确认' ）
	 * @property {Object}			customStyle			自定义样式，对象形式
	 * @event {Function} change 按键被点击(不包含退格键被点击)
	 * @event {Function} cancel 键盘顶部工具条左边的"取消"按钮被点击
	 * @event {Function} confirm 键盘顶部工具条右边的"完成"按钮被点击
	 * @event {Function} backspace 键盘退格键被点击
	 * @example <uv-keyboard mode="number" v-model="show"></uv-keyboard>
	 */
	export default {
		name: "uv-keyboard",
		mixins: [mpMixin, mixin, props],
		emits: ['close','change','confirm','cancel','backspace','changeCarInputMode'],
		methods: {
			open() {
				this.$refs.keyboardPopup.open();
			},
			close() {
				this.$refs.keyboardPopup.close();
			},
			popupChange(e) {
				if(!e.show) this.$emit('close');
			},
			change(e) {
				this.$emit('change', e);
			},
			// 输入完成
			onConfirm() {
				this.$emit('confirm');
				if(this.closeOnClickConfirm) this.close();
			},
			// 取消输入
			onCancel() {
				this.$emit('cancel');
				this.close();
			},
			// 退格键
			backspace() {
				this.$emit('backspace');
			},
			// car模式切换中文|英文方法
			changeCarInputMode(e) {
				this.$emit('changeCarInputMode',e);
			},
			changeCarMode() {
				this.$refs.uvKeyboardCarRef && this.$refs.uvKeyboardCarRef.changeCarInputMode();
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-hover: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-keyboard {

		&__tooltip {
			@include flex;
			justify-content: space-between;
			background-color: #FFFFFF;
			padding: 14px 12px;

			&__item {
				color: #333333;
				flex: 1;
				text-align: center;
				font-size: 15px;
			}

			&__submit {
				text-align: right;
				color: $uv-primary;
			}

			&__cancel {
				text-align: left;
				color: #888888;
			}

			&__tips {
				color: $uv-tips-color;
			}
		}
	}
</style>
_'x/={
  "id": "uv-keyboard",
  "displayName": "uv-keyboard 键盘EH5keyboard 该组件为自定义的键盘面板，内含了数字键盘，车牌号键，身份证号键盘3种模式，都有可以打乱按键顺序的选项+keyboardO!keyboard",
    "键盘popup",
			"uv-icon
Ghx ## Keyboard 键盘

> **组件名：uv-keyboard**

该组件为自定义的键盘面板，内含了数字键盘，车牌号键O身份证号键盘3种模式，都有可以打乱按键顺序的选项。

# (keyboard{$ߌ	x e100644 changelog.md ZKQnu.40000 components {=-r?c%XK100644 package.json PoU*Bܺ)r/;100644 readme.md ԕrMKډ>(^ϚB?xa 9## 1.0.2（2023-06-20）
1. 适配height参数携带单体line-progress 线形进度条
/ʫx+ 40000 uv-line-progress k;dO_`e{P=GxT 100644 props.js #}
 0bv100644 uv-line-progress.vue "*zsS2%{
kOJxexport default {
	props: {
		// 激活部分的颜色
		activeColor: {
			type: String,
			default: '#19be6b'
		},
		inactiveColor: {
			type: String,
			default: '#ececec'
		},
		// 进度百分比，数值
		percentage: {
			type: [String, Number],
			default: 0
		},
		// 是否在进度条内部显示百分比的值
		showText: {
			type: Boolean,
			default: true
		},
		// 进度条的高度，单位px
		height: {
			type: [String, Number],
			default: 12
		},
		...uni.$uv?.props?.lineProgress
	}
}x<template>
	<view
	    class="uv-line-progress"
	    :style="[$uv.addStyle(customStyle)]"
	>
		<view
		    class="uv-line-progress__background"
		    ref="uv-line-progress__background"
		    :style="[{
				backgroundColor: inactiveColor,
				height: $uv.addUnit($uv.getPx(height))
			}]"
		>
		</view>
		<view
		    class="uv-line-progress__line"
		    :style="[progressStyle]"
		> 
			<slot>
				<text v-if="showText && percentage >= 10" class="uv-line-progress__text">{{innserPercentage + '%'}}</text>
			</slot> 
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * lineProgress 线型进度条
	 * @description 展示操作或任务的当前进度，比如上传文件，是一个线形的进度条。
	 * @tutorial https://www.uvui.cn/components/lineProgress.html
	 * @property {String}			activeColor		激活部分的颜色 ( 默认 '#19be6b' )
	 * @property {String}			inactiveColor	背景色 ( 默认 '#ececec' )
	 * @property {String | Number}	percentage		进度百分比，数值 ( 默认 0 )
	 * @property {Boolean}			showText		是否在进度条内部显示百分比的值 ( 默认 true )
	 * @property {String | Number}	height			进度条的高度，单位px ( 默认 12 )
	 * 
	 * @example <uv-line-progress :percent="70" :show-percent="true"></uv-line-progress>
	 */
	export default {
		name: "uv-line-progress",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				lineWidth: 0,
			}
		},
		watch: {
			percentage(n) {
				this.resizeProgressWidth()
			}
		},
		computed: {
			progressStyle() { 
				let style = {}
				style.width = this.lineWidth
				style.backgroundColor = this.activeColor
				style.height = this.$uv.addUnit(this.$uv.getPx(this.height))
				return style
			},
			innserPercentage() {
				// 控制范围在0-100之间
				return this.$uv.range(0, 100, this.percentage)
			}
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				this.$uv.sleep(20).then(() => {
					this.resizeProgressWidth()
				})
			},
			getProgressWidth() {
				// #ifndef APP-NVUE
				return this.$uvGetRect('.uv-line-progress__background')
				// #endif

				// #ifdef APP-NVUE
				// 返回一个promise
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs['uv-line-progress__background'], (res) => {
						resolve(res.size)
					})
				})
				// #endif
			},
			resizeProgressWidth() {
				this.getProgressWidth().then(size => {
					const {
						width
					} = size
					// 通过设置的percentage值，计算其所占总长度的百分比
					this.lineWidth = width * this.innserPercentage / 100 + 'px'
				})
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-line-progress {
		align-items: stretch;
		position: relative;
		@include flex(row);
		flex: 1;
		overflow: hidden;
		border-radius: 100px;

		&__background {
			background-color: #ececec;
			border-radius: 100px;
			flex: 1;
		}

		&__line {
			position: absolute;
			top: 0;
			left: 0;
			bottom: 0;
			align-items: center;
			@include flex(row);
			color: #ffffff;
			border-radius: 100px;
			transition: width 0.5s ease;
			justify-content: flex-end;
		}

		&__text {
			font-size: 10px;
			align-items: center;
			text-align: right;
			color: #FFFFFF;
			margin-right: 5px;
			transform: scale(0.9);
		}
	}
</style>
|^xP{
  "id": "uv-line-progress",
  "displayName": "uv-line-progress 线形进度条9J2",
  "description": "uv-line-progress 该组件展示操作或任务的当前进度，比如上传文件，是一个线形的度条yline-progress!progress",
    "进度条CH
nx U## LineProgress 线形进度条hline-progress**

展示操作或任务的当前进度，比如上传文件，是一个线形的进度条1lineProgressZa	x e100644 changelog.md ^ z-}| *40000 components GE/zf@DPz100644 package.json dF7Z`A:v100644 readme.md u3[sܗy6@qx j线条组件
yLx" 40000 uv-line  _=@9pDU⑯#WëxK 100644 props.js u v;@SZn>d100644 uv-line.vue lPy$Û{j%jS,x:export default {
	props: {
		color: {
			type: String,
			default: '#d6d7d9'
		},
		// 长度，竖向时表现为高度，横向时表现为长度，可以为百分比，带px单位的值等
		length: {
			type: [String, Number],
			default: '100%'
		},
		// 线条方向，col-竖向，row-横向
		direction: {
			type: String,
			default: 'row'
		},
		// 是否显示细边框
		hairline: {
			type: Boolean,
			default: true
		},
		// 线条与上下左右元素的间距，字符串形式，如"30px"、"20px 30px"
		margin: {
			type: [String, Number],
			default: 0
		},
		// 是否虚线，true-虚线，false-实线
		dashed: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.line
	}
}1Ҽx<	<template>
	<view
	    class="uv-line"
	    :style="[lineStyle]"
	>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * line 线条
	 * @description 此组件一般用于显示一根线条，用于分隔内容块，有横向和竖向两种模式，且能设置0.5px线条，使用也很简单
	 * @tutorial https://www.uvui.cn/components/line.html
	 * @property {String}			color		线条的颜色 ( 默认 '#d6d7d9' )
	 * @property {String | Number}	length		长度，竖向时表现为高度，横向时表现为长度，可以为百分比，带px单位的值等 ( 默认 '100%' )
	 * @property {String}			direction	线条的方向，row-横向，col-竖向 (默认 'row' )
	 * @property {Boolean}			hairline	是否显示细线条 (默认 true )
	 * @property {String | Number}	margin		线条与上下左右元素的间距，字符串形式，如"30px"  (默认 0 )
	 * @property {Boolean}			dashed		是否虚线，true-虚线，false-实线 (默认 false )
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * @example <uv-line color="red"></uv-line>
	 */
	export default {
		name: 'uv-line',
		mixins: [mpMixin, mixin, props],
		computed: {
			lineStyle() {
				const style = {}
				style.margin = this.margin
				// 如果是水平线条，边框高度为1px，再通过transform缩小一半，就是0.5px了
				if (this.direction === 'row') {
					// 此处采用兼容分开写，兼容nvue的写法
					style.borderBottomWidth = '1px'
					style.borderBottomStyle = this.dashed ? 'dashed' : 'solid'
					style.width = this.$uv.addUnit(this.length)
					if (this.hairline) style.transform = 'scaleY(0.5)'
				} else {
					// 如果是竖向线条，边框宽度为1px，再通过transform缩小一半，就是0.5px了
					style.borderLeftWidth = '1px'
					style.borderLeftStyle = this.dashed ? 'dashed' : 'solid'
					style.height = this.$uv.addUnit(this.length)
					if (this.hairline) style.transform = 'scaleX(0.5)'
				}
				style.borderColor = this.color
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		}
	}
</script>

<style lang="scss" scoped>
	.uv-line {
		/* #ifndef APP-NVUE */
		vertical-align: middle;
		/* #endif */
	}
</style>
=
ex 5## Line 线条

> **组件名：uv-line**

此组件一般用于显示一根线条，用于分隔内容块，有横向和竖向;两种模式，且能设置0.5px线条，使用也很简单2in2	x e100644 changelog.md RL	Jl?DʀS40000 components ~	!-+0ϫb!100644 package.json _G0<4fݙ[100644 readme.md n(wP7ٙQ<"%xW## 1.0.7（2023-10-13）
1. unmounted兼容vue3
## 1.0.6（2023-08-03）
1. 竖向滚动时候增加change回调
## 1.0.5（2023-07-21）
1. 增加icon类型，支持设置false不显示图标
2. 优化文档
## 1.0.4（2023-07-03）
1. 增加disableScroll 属性，禁止自动滚动
2. 优化文档
## 1.0.3（2023-06-04）
1.  修复text传值为null报错的问题
## 1.0.2（2023-05-30）
1. 修复error报错的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-notice-bar 滚动通知
9+dxA "## 1.0.2（2023-08-13）
1. 修复link 超链接组件
%'x" 40000 uv-link e`,gݦWhwUxK 100644 props.js j(Y}NEv8Q100644 uv-link.vue LXS{IkQp@,x7export default {
	props: {
		// 文字颜色
		color: {
			type: String,
			default: ''
		},
		// 字体大小，单位px
		fontSize: {
			type: [String, Number],
			default: 14
		},
		// 是否显示下划线
		underLine: {
			type: Boolean,
			default: false
		},
		// 要跳转的链接
		href: {
			type: String,
			default: ''
		},
		// 小程序中复制到粘贴板的提示语
		mpTips: {
			type: String,
			default: '链接已复制，请在浏览器打开'
		},
		// 下划线颜色
		lineColor: {
			type: String,
			default: ''
		},
		// 超链接的问题，不使用slot形式传入，是因为nvue下无法修改颜色
		text: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.link
	}
}8f+xy
<template>
	<text
	    class="uv-link"
	    @tap.stop="openLink"
	    :style="[linkStyle, $uv.addStyle(customStyle)]"
	>{{text}}</text>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * link 超链接
	 * @description 该组件为超链接组件，在不同平台有不同表现形式：在APP平台会通过plus环境打开内置浏览器，在小程序中把链接复制到粘贴板，同时提示信息，在H5中通过window.open打开链接。
	 * @tutorial https://www.uvui.cn/components/link.html
	 * @property {String}			color		文字颜色 （默认 color['uv-primary'] ）
	 * @property {String ｜ Number}	fontSize	字体大小，单位px （默认 15 ）
	 * @property {Boolean}			underLine	是否显示下划线 （默认 false ）
	 * @property {String}			href		跳转的链接，要带上http(s)
	 * @property {String}			mpTips		各个小程序平台把链接复制到粘贴板后的提示语（默认“链接已复制，请在浏览器打开”）
	 * @property {String}			lineColor	下划线颜色，默认同color参数颜色 
	 * @property {String}			text		超链接的问题，不使用slot形式传入，是因为nvue下无法修改颜色 
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * 
	 * @example <uv-link href="http://www.uvui.cn">蜀道难，难于上青天</uv-link>
	 */
	export default {
		name: "uv-link",
		emits:['click'],
		mixins: [mpMixin, mixin, props],
		computed: {
			linkStyle() {
				const style = {
					color: this.color,
					fontSize: this.$uv.addUnit(this.fontSize),
					// line-height设置为比字体大小多2px
					lineHeight: this.$uv.addUnit(this.$uv.getPx(this.fontSize) + 2),
					textDecoration: this.underLine ? 'underline' : 'none'
				}
				return style
			}
		},
		methods: {
			openLink() {
				// #ifdef APP-PLUS
				plus.runtime.openURL(this.href)
				// #endif
				// #ifdef H5
				window.open(this.href)
				// #endif
				// #ifdef MP
				uni.setClipboardData({
					data: this.href,
					success: () => {
						uni.hideToast();
						this.$nextTick(() => {
							this.$uv.toast(this.mpTips);
						})
					}
				});
				// #endif
				this.$emit('click')
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-link-line-height:1 !default;

	.uv-link {
		/* #ifndef APP-NVUE */
		line-height: $uv-link-line-height;
		/* #endif */
		@include flex;
		flex-wrap: wrap;
		flex: 1;
		color: $uv-primary;
	}
</style>
sH [x ~{
  "id": "uv-linklink 超链接 6I2#uv-link 该组件为超链接组件uv-link(!link",
    "超链接c9;qxp ## Link 超链接Jlink**

该组件为超链接组件，在不同平台有不同表现形式1linkݥB[	x e100644 changelog.md l-xAĜMN	2Z40000 components -R 楁?JTGAa100644 package.json VGvI](WY100644 readme.md FD`92;<U]6ڲ?x## 1.0.9（2023-11-10）
1. 修复设置ellipsis不生效的BUG
## 1.0.8（2023-09-20）
1. listItem优化可使用customStyle变量进行样式控制
## 1.0.7（2023-08-29）
1. 修复边框的BUG
## 1.0.6（2023-08-16）
1. 修复switch开关返回undefined的问题
2. 优化初始化可能导致的闪动
## 1.0.5（2023-08-07）
1. 修复分包页面在ios端，nvue编译不能滚动的BUG
## 1.0.4（2023-08-04）
1. nvue修复  触底不触发事件的BUG
2. 更新文档说明事件触发
## 1.0.3（2023-07-28）
1. 修改可能造成样式污染的BUG
## 1.0.2（2023-07-26）
1. 全面重构，用法与之前保持一致，参数全部变化
2. 新增多个功能参数，方便一键构建列表
3. List列表组件，包含基本列表样式、默认插槽机制、可扩展插槽机制、长列表性能优化、多端兼容。
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-list 列表
	/ԩxI 40000 uv-list-item 3)$"^i׾RD~40000 uv-list ˝*[^4r:/ޘf1Mx, 100644 uv-list-item.vue ;HY(toO1x2$<template>
	<!-- #ifdef APP-NVUE -->
	<cell :keep-scroll-position="keepScrollPosition">
		<!-- #endif -->
		<view 
			:class="{ 'uv-list-item--disabled': disabled }" 
			:style="[$uv.addStyle(customStyle),{'background-color':customStyle.backgroundColor?customStyle.backgroundColor:'#fff'}]"
			:hover-class="(!clickable && !link) || disabled || showSwitch ? '' : 'uv-list-item--hover'"
			class="uv-list-item" @click="onClick">
			<view v-if="!isFirstChild" class="border--left" :class="{ 'uv-list--border': border }"></view>
			<view class="uv-list-item__wrapper">
				<slot>
					<view class="uv-list-item__container"
						:class="{ 'container--right': showArrow || link, 'flex--direction': directionData === 'column'}"
						:style="{paddingTop:padding.top,paddingLeft:padding.left,paddingRight:padding.right,paddingBottom:padding.bottom}">
						<slot name="header">
							<view class="uv-list-item__header">
								<view v-if="thumb" class="uv-list-item__icon">
									<image :src="thumb" class="uv-list-item__icon-img" :class="['uv-list--' + thumbSize]" />
								</view>
								<view v-else-if="showExtraIcon" class="uv-list-item__icon">
									<uv-icon :name="extraIcon.icon" :customPrefix="extraIcon.customPrefix" :color="extraIcon.color" :size="extraIcon.size" />
								</view>
							</view>
						</slot>
						<slot name="body">
							<view class="uv-list-item__content"
								:class="{ 'uv-list-item__content--center': thumb || showExtraIcon || showBadge || showSwitch }">
								<text v-if="title" class="uv-list-item__content-title"
									:class="[ellipsis && `uv-line-${ellipsis}`]">{{ title }}</text>
								<text v-if="note" class="uv-list-item__content-note">{{ note }}</text>
							</view>
						</slot>
						<slot name="footer">
							<view v-if="rightText || showBadge || showSwitch" class="uv-list-item__extra"
								:class="{ 'flex--justify': directionData === 'column' }">
								<text v-if="rightText" class="uv-list-item__extra-text">{{ rightText }}</text>
								<uv-badge
									v-if="showBadge"
									:show="!!(badge.show || badge.isDot || badge.value)"
									:isDot="badge.isDot"
									:value="badge.value"
									:max="badge.max"
									:type="badge.type"
									:showZero="badge.showZero"
									:bgColor="badge.bgColor"
									:color="badge.color"
									:shape="badge.shape"
									:numberType="badge.numberType"
									:inverted="badge.inverted"
									customStyle="margin-left: 4px;"
								></uv-badge>
								<uv-switch v-if="showSwitch" :value="switchChecked" :disabled="disabled" @change="onSwitchChange"></uv-switch>
							</view>
						</slot>
					</view>
				</slot>
			</view>
			<uv-icon v-if="showArrow || link" size="34rpx" class="uv-icon-wrapper" color="#bbb" name="arrow-right" />
		</view>
		<!-- #ifdef APP-NVUE -->
	</cell>
	<!-- #endif -->
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	/**
	 * ListItem 列表子组件
	 * @description 列表子组件
	 * @tutorial https://ext.dcloud.net.cn/plugin?id=24
	 * @property {String} 	title 							标题
	 * @property {String} 	note 							描述
	 * @property {String} 	thumb 							左侧缩略图，若thumb有值，则不会显示扩展图标
	 * @property {String}  	thumbSize = [lg|base|sm]		略缩图大小
	 * 	@value 	 lg			大图
	 * 	@value 	 base		一般
	 * 	@value 	 sm			小图
	 * @property {String} 	rightText 						右侧文字内容
	 * @property {Boolean} 	disabled = [true|false]			是否禁用
	 * @property {Boolean} 	clickable = [true|false] 		是否开启点击反馈
	 * @property {String} 	link = [navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈
	 *  @value 	navigateTo 	同 uni.navigateTo()
	 * 	@value redirectTo 	同 uni.redirectTo()
	 * 	@value reLaunch   	同 uni.reLaunch()
	 * 	@value switchTab  	同 uni.switchTab()
	 * @property {String | PageURIString} 	to  			跳转目标页面
	 * @property {Boolean} 	showBadge = [true|false] 		是否显示数字角标
	 * @property {Object} 	badge  扩展数字角标的参数，格式为 :badge="{value: 122}"
	 * @property {Boolean} 	showSwitch = [true|false] 		是否显示Switch
	 * @property {Boolean} 	switchChecked = [true|false] 	Switch是否被选中
	 * @property {Boolean} 	showExtraIcon = [true|false] 	左侧是否显示扩展图标
	 * @property {Object} 	extraIcon 						扩展图标参数，格式为 :extraIcon="{icon: 'photo',size: '30px'}"
	 * @property {String} 	direction = [row|column]		排版方向
	 * @value row 			水平排列
	 * @value column 		垂直排列
	 * @event {Function} 	click 							点击 uniListItem 触发事件
	 * @event {Function} 	switchChange 					点击切换 Switch 时触发
	 */
	export default {
		name: 'uv-list-item',
		mixins: [mpMixin, mixin],
		emits: ['click', 'switchChange'],
		props: {
			direction: {
				type: String,
				default: 'row'
			},
			title: {
				type: String,
				default: ''
			},
			note: {
				type: String,
				default: ''
			},
			ellipsis: {
				type: [Number, String],
				default: 0
			},
			disabled: {
				type: [Boolean, String],
				default: false
			},
			clickable: {
				type: Boolean,
				default: false
			},
			showArrow: {
				type: [Boolean, String],
				default: false
			},
			link: {
				type: [Boolean, String],
				default: false
			},
			to: {
				type: String,
				default: ''
			},
			showSwitch: {
				type: [Boolean, String],
				default: false
			},
			switchChecked: {
				type: [Boolean, String],
				default: false
			},
			showBadge: {
				type: [Boolean, String],
				default: false
			},
			badge: {
				type: Object,
				default () {
					return {}
				}
			},
			rightText: {
				type: String,
				default: ''
			},
			thumb: {
				type: String,
				default: ''
			},
			thumbSize: {
				type: String,
				default: 'base'
			},
			showExtraIcon: {
				type: [Boolean, String],
				default: false
			},
			extraIcon: {
				type: Object,
				default () {
					return {
						name: '',
						color: '#000000',
						size: 20,
						customPrefix: ''
					};
				}
			},
			border: {
				type: Boolean,
				default: false
			},
			customStyle: {
				type: Object,
				default () {
					return {
						padding: '',
						backgroundColor: '#FFFFFF'
					}
				}
			},
			keepScrollPosition: {
				type: Boolean,
				default: false
			}
		},
		computed: {
			directionData(){
				return this.direction ? this.direction : (this.parentData.direction ? this.parentData.direction : 'row');
			}
		},
		watch: {
			'customStyle.padding': {
				handler(padding) {
					if(padding) this.setPadding(padding);
				},
				immediate: true
			}
		},
		data() {
			return {
				isFirstChild: false,
				padding: {
					top: "",
					right: "",
					bottom: "",
					left: ""
				},
				parentData: {
					direction: 'row',
					padding: 0
				}
			};
		},
		created() {
			this.updateParentData();
		},
		mounted() {
			this.init();
			this.list = this.getForm()
			// 判断是否存在 uv-list 组件
			if (this.list) {
				if (!this.list.firstChildAppend) {
					this.list.firstChildAppend = true;
					this.isFirstChild = true;
				}
			}
		},
		methods: {
			init(){
				if (!this.parent) {
					this.$uv.error('uv-list-item必须搭配uv-list组件使用');
				}
				this.$nextTick(()=>{
					if(!(this.padding.top || this.padding.right|| this.padding.bottom|| this.padding.left)){
						this.setPadding(this.parentData.padding);
					}
				})
			},
			updateParentData() {
				this.getParentData('uv-list');
			},
			setPadding(padding){
				if(typeof padding == 'number'){
					padding += ''
				}
				let paddingArr = padding.split(' ')
				if (paddingArr.length === 1) {
					const allPadding = paddingArr[0]
					this.padding = {
						"top": allPadding,
						"right": allPadding,
						"bottom": allPadding,
						"left": allPadding
					}
				} else if (paddingArr.length === 2) {
					const [verticalPadding, horizontalPadding] = paddingArr;
					this.padding = {
						"top": verticalPadding,
						"right": horizontalPadding,
						"bottom": verticalPadding,
						"left": horizontalPadding
					}
				} else if (paddingArr.length === 4) {
						const [topPadding, rightPadding, bottomPadding, leftPadding] = paddingArr;
						this.padding = {
							"top": topPadding,
							"right": rightPadding,
							"bottom": bottomPadding,
							"left": leftPadding
						}
				}
			},
			/**
			 * 获取父元素实例
			 */
			getForm(name = 'uniList') {
				let parent = this.$parent;
				let parentName = parent.$options.name;
				while (parentName !== name) {
					parent = parent.$parent;
					if (!parent) return false
					parentName = parent.$options.name;
				}
				return parent;
			},
			onClick() {
				if (this.to !== '') {
					this.openPage();
					return;
				}
				if (this.clickable || this.link) {
					this.$emit('click', {
						data: {}
					});
				}
			},
			onSwitchChange(e) {
				this.$emit('switchChange', e);
			},
			openPage() {
				if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
					this.pageApi(this.link);
				} else {
					this.pageApi('navigateTo');
				}
			},
			pageApi(api) {
				let callback = {
					url: this.to,
					success: res => {
						this.$emit('click', {
							data: res
						});
					},
					fail: err => {
						this.$emit('click', {
							data: err
						});
					}
				}
				switch (api) {
					case 'navigateTo':
						uni.navigateTo(callback)
						break
					case 'redirectTo':
						uni.redirectTo(callback)
						break
					case 'reLaunch':
						uni.reLaunch(callback)
						break
					case 'switchTab':
						uni.switchTab(callback)
						break
					default:
						uni.navigateTo(callback)
				}
			}
		}
	};
</script>

<style lang="scss" scoped>
	$show-lines: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	$uv-font-size-sm:12px;
	$uv-font-size-base:14px;
	$uv-font-size-lg:16px;
	$uv-spacing-col-lg: 12px;
	$uv-spacing-row-lg: 15px;
	$uv-img-size-sm:20px;
	$uv-img-size-base:26px;
	$uv-img-size-lg:40px;
	$uv-border-color:#e5e5e5;
	$uv-bg-color-hover:#f1f1f1;
	$uv-text-color-grey:#999;
	$list-item-pd: $uv-spacing-col-lg $uv-spacing-row-lg;

	.uv-list-item {
		@include flex(row);
		font-size: $uv-font-size-lg;
		position: relative;
		justify-content: space-between;
		align-items: center;
		background-color: #fff;
		/* #ifdef H5 */
		cursor: pointer;
		/* #endif */
	}

	.uv-list-item--disabled {
		opacity: 0.3;
	}

	.uv-list-item--hover {
		background-color: $uv-bg-color-hover !important;
	}
	
	.uv-list-item__wrapper {
		@include flex(column);
		flex: 1;
	}

	.uv-list-item__container {
		position: relative;
		@include flex(row);
		padding: $list-item-pd;
		padding-left: $uv-spacing-row-lg;
		flex: 1;
		overflow: hidden;
	}

	.container--right {
		padding-right: 0;
	}

	.uv-list--border {
		position: absolute;
		top: 0;
		right: 0;
		left: 0;
		/* #ifdef APP-NVUE */
		border-top-color: $uv-border-color;
		border-top-style: solid;
		border-top-width: 0.5px;
		/* #endif */
	}

	/* #ifndef APP-NVUE */
	.uv-list--border:after {
		position: absolute;
		top: 0;
		right: 0;
		left: 0;
		height: 1px;
		content: '';
		-webkit-transform: scaleY(0.5);
		transform: scaleY(0.5);
		background-color: $uv-border-color;
	}

	/* #endif */
	.uv-list-item__content {
		@include flex(column);
		padding-right: 8px;
		flex: 1;
		color: #3b4144;
		justify-content: space-between;
		overflow: hidden;
	}

	.uv-list-item__content--center {
		justify-content: center;
	}

	.uv-list-item__content-title {
		font-size: $uv-font-size-base;
		color: #3b4144;
		overflow: hidden;
	}

	.uv-list-item__content-note {
		margin-top: 6rpx;
		color: $uv-text-color-grey;
		font-size: $uv-font-size-sm;
		overflow: hidden;
	}

	.uv-list-item__extra {
		@include flex(row);
		justify-content: flex-end;
		align-items: center;
	}

	.uv-list-item__header {
		@include flex(row);
		align-items: center;
	}

	.uv-list-item__icon {
		margin-right: 18rpx;
		flex-direction: row;
		justify-content: center;
		align-items: center;
	}

	.uv-list-item__icon-img {
		/* #ifndef APP-NVUE */
		display: block;
		/* #endif */
		height: $uv-img-size-base;
		width: $uv-img-size-base;
		margin-right: 10px;
	}

	.uv-icon-wrapper {
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		align-items: center;
		padding: 0 10px;
	}

	.flex--direction {
		flex-direction: column;
		/* #ifndef APP-NVUE */
		align-items: initial;
		/* #endif */
	}

	.flex--justify {
		/* #ifndef APP-NVUE */
		justify-content: initial;
		/* #endif */
	}

	.uv-list--lg {
		height: $uv-img-size-lg;
		width: $uv-img-size-lg;
	}

	.uv-list--base {
		height: $uv-img-size-base;
		width: $uv-img-size-base;
	}

	.uv-list--sm {
		height: $uv-img-size-sm;
		width: $uv-img-size-sm;
	}

	.uv-list-item__extra-text {
		color: $uv-text-color-grey;
		font-size: $uv-font-size-sm;
	}
</style>i:x' 100644 uv-list.vue ?>\)]qխݿ%x
<template>
	<!-- #ifndef APP-NVUE -->
	<view 
		class="uv-list"
		:style="[$uv.addStyle(customStyle)]"
	>
		<view 
			v-if="border" 
			class="uv-list--border-top"
			:style="[{ 'background-color': borderColor }]"
		></view>
		<slot />
		<view 
			v-if="border" 
			class="uv-list--border-bottom"
			:style="[{ 'background-color': borderColor }]"
		></view>
	</view>
	<!-- #endif -->
	<!-- #ifdef APP-NVUE -->
	<list 
		:bounce="true" 
		:scrollable="true" 
		show-scrollbar 
		:render-reverse="false" 
		class="uv-list" 
		:class="{ 'uv-list--border': border }"
		:style="[
			{ 'border-top-color': borderColor, 'border-bottom-color':borderColor  },
			$uv.addStyle(customStyle)
		]"
		:enableBackToTop="false"
		:loadmoreoffset="15"
		@scroll="scroll"
		@loadmore="loadMore">
		<slot />
	</list>
	<!-- #endif -->
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	/**
	 * List 列表
	 * @description 列表组件
	 * @tutorial https://www.uvui.cn/components/list.html
	 * @property {Boolean} border = [true|false] 是否显示边框
	 * @property {String} borderColor 边框颜色
	 * @property {String} direction 排版方向，默认row，列表里面使用其他组件  最好设置成column
	 */
	export default {
		name: 'uv-list',
		mixins: [mpMixin, mixin],
		'mp-weixin': {
			options: {
				multipleSlots: false
			}
		},
		props: {
			border: {
				type: Boolean,
				default: false
			},
			borderColor: {
				type: String,
				default: '#dadbde'
			},
			// 排版方向，默认row，列表里面使用其他组件  最好设置成column
			direction: {
				type: String,
				default: 'row'
			},
			// 内边距
			padding: {
				type: [String,Number],
				default: '20rpx 30rpx'
			}
		},
		created() {
			this.firstChildAppend = false;
		},
		computed: {
			parentData() {
				return [this.direction,this.padding];
			}
		},
		methods: {
			loadMore(e) {
				this.$emit('scrolltolower');
			},
			scroll(e) {
				this.$emit('scroll', e);
			}
		}
	};
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	
	.uv-list {
		position: relative;
		@include flex(column);
		background-color: #fff;
	}

	.uv-list--border {
		position: relative;
		/* #ifdef APP-NVUE */
		border-top-color: $uv-border-color;
		border-top-style: solid;
		border-top-width: 0.5px;
		border-bottom-color: $uv-border-color;
		border-bottom-style: solid;
		border-bottom-width: 0.5px;
		/* #endif */
		z-index: -1;
	}

	/* #ifndef APP-NVUE */

	.uv-list--border-top {
		position: absolute;
		top: 0;
		right: 0;
		left: 0;
		height: 1px;
		-webkit-transform: scaleY(0.5);
		transform: scaleY(0.5);
		background-color: $uv-border-color;
		z-index: 1;
	}

	.uv-list--border-bottom {
		position: absolute;
		bottom: 0;
		right: 0;
		left: 0;
		height: 1px;
		-webkit-transform: scaleY(0.5);
		transform: scaleY(0.5);
		background-color: $uv-border-color;
	}

	/* #endif */
</style>
uyx E5{
  "id": "uv-list",
  "displayName": "uv-list 列表=H[9",
  "description": "uv-list 多功能高性能列表组件",
  "keywords": [
    "uv-listo!list",
    "列表	rHMnx## List 列表

> **组件名：uv-list**

List列表组件，包含基本列表样式、默认插槽机制、可扩展插槽机制、长列表性能优化、多端兼容。

在vue页面里，它默认使用页面级滚动，这样做的目的是性能更加友好。在app-nvue页面里，它默认使用原生list组件滚动，这样的长列表，在滚动出屏幕外后，系统会回收不可见区域的渲染内存资源，不会造成滚动越长手机越卡的问题。

uv-list组件是父容器，里面的核心是uv-list-item子组件，它代表列表中的一个可重复行，子组件可以无限循环。

uv-list-item有很多风格，uv-list-item组件通过内置的属性，满足一些常用的场景。当内置属性不满足需求时，可以通过扩展插槽来自定义列表内容，插槽包括：默认插槽（完全自定义内容）、具名插槽（header | body | footer），根据需求进行扩展。

内置属性可以覆盖的场景包括：导航列表、设置列表、小图标列表等，其他不能满足的场景使用插槽进行扩展。

# <a href="https://www.uvui.cn/components/list.html" target="_blank">查看文档</a>

## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>（请不要 下载插件ZIP）</small>

### [更多插件，请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)

<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">

![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)

</a>

#### 如使用过程中有任何问题反馈，或者您对uv-ui有一些好的建议，欢迎加入uv-ui官方交流群：<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>p	x e100644 changelog.md 84s_n iB40000 components <o~GH8100644 package.json P.6AMFѦ $~G7100644 readme.md .4G,LVG"}::CxS 3## 1.0.2（2023-06-21）
1. 优化customStyle属性Rload-more 加载更多
D*%	x' 40000 uv-load-more vInV6([_xP 100644 props.js Ƽ(pޡWƌ!́%Q100644 uv-load-more.vue +PW0|36vdN5o!nxexport default {
	props: {
		// 组件状态，loadmore-加载前的状态，loading-加载中的状态，nomore-没有更多的状态
		status: {
			type: String,
			default: 'loadmore'
		},
		// 组件背景色
		bgColor: {
			type: String,
			default: 'transparent'
		},
		// 是否显示加载中的图标
		icon: {
			type: Boolean,
			default: true
		},
		// 字体大小
		fontSize: {
			type: [String, Number],
			default: 14
		},
		// 图标大小
		iconSize: {
			type: [String, Number],
			default: 16
		},
		// 字体颜色
		color: {
			type: String,
			default: '#606266'
		},
		// 加载中状态的图标，spinner-花朵状图标，circle-圆圈状，semicircle-半圆
		loadingIcon: {
			type: String,
			default: 'spinner'
		},
		// 加载前的提示语
		loadmoreText: {
			type: String,
			default: '加载更多'
		},
		// 加载中提示语
		loadingText: {
			type: String,
			default: '正在加载...'
		},
		// 没有更多的提示语
		nomoreText: {
			type: String,
			default: '没有更多了'
		},
		// 在“没有更多”状态下，是否显示粗点
		isDot: {
			type: Boolean,
			default: false
		},
		// 加载中图标的颜色
		iconColor: {
			type: String,
			default: '#b7b7b7'
		},
		// 上边距
		marginTop: {
			type: [String, Number],
			default: 10
		},
		// 下边距
		marginBottom: {
			type: [String, Number],
			default: 10
		},
		// 高度，单位px
		height: {
			type: [String, Number],
			default: 'auto'
		},
		// 是否显示左边分割线
		line: {
			type: Boolean,
			default: false
		},
		// 线条颜色
		lineColor: {
			type: String,
			default: '#E6E8EB'
		},
		// 是否虚线，true-虚线，false-实线
		dashed: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.loadmore
	}
}lúx:<template>
	<view
	    class="uv-loadmore"
	    :style="[{
				backgroundColor: bgColor,
				marginBottom: $uv.addUnit(marginBottom),
				marginTop: $uv.addUnit(marginTop),
				height: $uv.addUnit(height),
			},
			$uv.addStyle(customStyle)]"
	>
		<uv-line
		    length="140rpx"
		    :color="lineColor"
		    :hairline="false"
			:dashed="dashed"
			v-if="line"
		></uv-line>
		<!-- 加载中和没有更多的状态才显示两边的横线 -->
		<view
		    :class="status == 'loadmore' || status == 'nomore' ? 'uv-more' : ''"
		    class="uv-loadmore__content"
		>
			<view
			    class="uv-loadmore__content__icon-wrap"
			    v-if="status === 'loading' && icon"
			>
				<uv-loading-icon
				    :color="iconColor"
				    :size="iconSize"
				    :mode="loadingIcon"
				></uv-loading-icon>
			</view>
			<!-- 如果没有更多的状态下，显示内容为dot（粗点），加载特定样式 -->
			<text
			    class="uv-line-1"
			    :style="[loadTextStyle]"
			    :class="[(status == 'nomore' && isDot == true) ? 'uv-loadmore__content__dot-text' : 'uv-loadmore__content__text']"
			    @tap="loadMore"
			>{{ showText }}</text>
		</view>
		<uv-line
		    length="140rpx"
		    :color="lineColor"
			:hairline="false"
			:dashed="dashed"
			v-if="line"
		></uv-line>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';

	/**
	 * loadmore 加载更多
	 * @description 此组件一般用于标识页面底部加载数据时的状态。
	 * @tutorial https://www.uvui.cn/components/loadMore.html
	 * @property {String}			status			组件状态（默认 'loadmore' ）
	 * @property {String}			bgColor			组件背景颜色，在页面是非白色时会用到（默认 'transparent' ）
	 * @property {Boolean}			icon			加载中时是否显示图标（默认 true ）
	 * @property {String | Number}	fontSize		字体大小（默认 14 ）
	 * @property {String | Number}	iconSize		图标大小（默认 17 ）
	 * @property {String}			color			字体颜色（默认 '#606266' ）
	 * @property {String}			loadingIcon		加载图标（默认 'circle' ）
	 * @property {String}			loadmoreText	加载前的提示语（默认 '加载更多' ）
	 * @property {String}			loadingText		加载中提示语（默认 '正在加载...' ）
	 * @property {String}			nomoreText		没有更多的提示语（默认 '没有更多了' ）
	 * @property {Boolean}			isDot			到上一个相邻元素的距离 （默认 false ）
	 * @property {String}			iconColor		加载中图标的颜色 （默认 '#b7b7b7' ）
	 * @property {String}			lineColor		线条颜色（默认 #E6E8EB ）
	 * @property {String | Number}	marginTop		上边距 （默认 10 ）
	 * @property {String | Number}	marginBottom	下边距 （默认 10 ）
	 * @property {String | Number}	height			高度，单位px （默认 'auto' ）
	 * @property {Boolean}			line			是否显示左边分割线  （默认 false ）
	 * @property {Boolean}			dashed		// 是否虚线，true-虚线，false-实线  （默认 false ）
	 * @event {Function} loadmore status为loadmore时，点击组件会发出此事件
	 * @example <uv-loadmore :status="status" icon-type="iconType" load-text="loadText" />
	 */
	export default {
		name: "uv-loadmore",
		mixins: [mpMixin, mixin,props],
		data() {
			return {
				// 粗点
				dotText: "●"
			}
		},
		computed: {
			// 加载的文字显示的样式
			loadTextStyle() {
				return {
					color: this.color,
					fontSize: this.$uv.addUnit(this.fontSize),
					lineHeight: this.$uv.addUnit(this.fontSize),
					backgroundColor: this.bgColor,
				}
			},
			// 显示的提示文字
			showText() {
				let text = '';
				if (this.status == 'loadmore') text = this.loadmoreText
				else if (this.status == 'loading') text = this.loadingText
				else if (this.status == 'nomore' && this.isDot) text = this.dotText;
				else text = this.nomoreText;
				return text;
			}
		},
		methods: {
			loadMore() {
				// 只有在“加载更多”的状态下才发送点击事件，内容不满一屏时无法触发底部上拉事件，所以需要点击来触发
				if (this.status == 'loadmore') this.$emit('loadmore');
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-lines: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-loadmore {
		@include flex(row);
		align-items: center;
		justify-content: center;
		flex: 1;

		&__content {
			margin: 0 15px;
			@include flex(row);
			align-items: center;
			justify-content: center;

			&__icon-wrap {
				margin-right: 8px;
			}

			&__text {
				font-size: 14px;
				color: $uv-content-color;
			}

			&__dot-text {
				font-size: 15px;
				color: $uv-tips-color;
			}
		}
	}
</style>
4	x e100644 changelog.md ~D66AeӐ 40000 components |}rIc8 pg?Hzá100644 package.json zz-R!Ik~6100644 readme.md {_bx.G2i{n?x* 40000 uv-loading-icon &;8QɥΨԳZJ>-xS 100644 props.js NDacW c9100644 uv-loading-icon.vue VPG QmX9j7dh	ϿIx`export default {
	props: {
		// 是否显示组件
		show: {
			type: Boolean,
			default: true
		},
		// 颜色
		color: {
			type: String,
			default: '#909193'
		},
		// 提示文字颜色
		textColor: {
			type: String,
			default: '#909193'
		},
		// 文字和图标是否垂直排列
		vertical: {
			type: Boolean,
			default: false
		},
		// 模式选择，circle-圆形，spinner-花朵形，semicircle-半圆形
		mode: {
			type: String,
			default: 'spinner'
		},
		// 图标大小，单位默认px
		size: {
			type: [String, Number],
			default: 24
		},
		// 文字大小
		textSize: {
			type: [String, Number],
			default: 15
		},
		// 文字样式
		textStyle: {
			type: Object,
			default () {
				return {}
			}
		},
		// 文字内容
		text: {
			type: [String, Number],
			default: ''
		},
		// 动画模式 https://www.runoob.com/cssref/css3-pr-animation-timing-function.html
		timingFunction: {
			type: String,
			default: 'linear'
		},
		// 动画执行周期时间
		duration: {
			type: [String, Number],
			default: 1200
		},
		// mode=circle时的暗边颜色
		inactiveColor: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.loadingIcon
	}
}"x;.<template>
	<view
		class="uv-loading-icon"
		:style="[$uv.addStyle(customStyle)]"
		:class="[vertical && 'uv-loading-icon--vertical']"
		v-if="show"
	>
		<view
			v-if="!webviewHide"
			class="uv-loading-icon__spinner"
			:class="[`uv-loading-icon__spinner--${mode}`]"
			ref="ani"
			:style="{
				color: color,
				width: $uv.addUnit(size),
				height: $uv.addUnit(size),
				borderTopColor: color,
				borderBottomColor: otherBorderColor,
				borderLeftColor: otherBorderColor,
				borderRightColor: otherBorderColor,
				'animation-duration': `${duration}ms`,
				'animation-timing-function': mode === 'semicircle' || mode === 'circle' ? timingFunction : ''
			}"
		>
			<block v-if="mode === 'spinner'">
				<!-- #ifndef APP-NVUE -->
				<view
					v-for="(item, index) in array12"
					:key="index"
					class="uv-loading-icon__dot"
				>
				</view>
				<!-- #endif -->
				<!-- #ifdef APP-NVUE -->
				<!-- 此组件内部图标部分无法设置宽高，即使通过width和height配置了也无效 -->
				<loading-indicator
					v-if="!webviewHide"
					class="uv-loading-indicator"
					:animating="true"
					:style="{
						color: color,
						width: $uv.addUnit(size),
						height: $uv.addUnit(size)
					}"
				/>
				<!-- #endif -->
			</block>
		</view>
		<text
			v-if="text"
			class="uv-loading-icon__text"
			:style="[{
				fontSize: $uv.addUnit(textSize),
				color: textColor,
			},$uv.addStyle(textStyle)]"
		>{{text}}</text>
	</view>
</template>

<script>
	import { colorGradient } from '@/uni_modules/uv-ui-tools/libs/function/colorGradient.js'
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const animation = weex.requireModule('animation');
	// #endif
	/**
	 * loading 加载动画
	 * @description 警此组件为一个小动画，目前用在uvui的loadmore加载更多和switch开关等组件的正在加载状态场景。
	 * @tutorial https://www.uvui.cn/components/loading.html
	 * @property {Boolean}			show			是否显示组件  (默认 true)
	 * @property {String}			color			动画活动区域的颜色，只对 mode = flower 模式有效（默认#909193）
	 * @property {String}			textColor		提示文本的颜色（默认#909193）
	 * @property {Boolean}			vertical		文字和图标是否垂直排列 (默认 false )
	 * @property {String}			mode			模式选择，见官网说明（默认 'circle' ）
	 * @property {String | Number}	size			加载图标的大小，单位px （默认 24 ）
	 * @property {String | Number}	textSize		文字大小（默认 15 ）
	 * @property {String | Number}	text			文字内容 
	 * @property {Object}	textStyle 文字样式
	 * @property {String}			timingFunction	动画模式 （默认 'ease-in-out' ）
	 * @property {String | Number}	duration		动画执行周期时间（默认 1200）
	 * @property {String}			inactiveColor	mode=circle时的暗边颜色 
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 * @example <uv-loading mode="circle"></uv-loading>
	 */
	export default {
		name: 'uv-loading-icon',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// Array.form可以通过一个伪数组对象创建指定长度的数组
				// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from
				array12: Array.from({
					length: 12
				}),
				// 这里需要设置默认值为360，否则在安卓nvue上，会延迟一个duration周期后才执行
				// 在iOS nvue上，则会一开始默认执行两个周期的动画
				aniAngel: 360, // 动画旋转角度
				webviewHide: false, // 监听webview的状态，如果隐藏了页面，则停止动画，以免性能消耗
				loading: false, // 是否运行中，针对nvue使用
			}
		},
		computed: {
			// 当为circle类型时，给其另外三边设置一个更轻一些的颜色
			// 之所以需要这么做的原因是，比如父组件传了color为红色，那么需要另外的三个边为浅红色
			// 而不能是固定的某一个其他颜色(因为这个固定的颜色可能浅蓝，导致效果没有那么细腻良好)
			otherBorderColor() {
				const lightColor = colorGradient(this.color, '#ffffff', 100)[80]
				if (this.mode === 'circle') {
					return this.inactiveColor ? this.inactiveColor : lightColor
				} else {
					return 'transparent'
				}
			}
		},
		watch: {
			show(n) {
				// nvue中，show为true，且为非loading状态，就重新执行动画模块
				// #ifdef APP-NVUE
				if (n && !this.loading) {
					setTimeout(() => {
						this.startAnimate()
					}, 30)
				}
				// #endif
			}
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				setTimeout(() => {
					// #ifdef APP-NVUE
					this.show && this.nvueAnimate()
					// #endif
					// #ifdef APP-PLUS 
					this.show && this.addEventListenerToWebview()
					// #endif
				}, 20)
			},
			// 监听webview的显示与隐藏
			addEventListenerToWebview() {
				// webview的堆栈
				const pages = getCurrentPages()
				// 当前页面
				const page = pages[pages.length - 1]
				// 当前页面的webview实例
				const currentWebview = page.$getAppWebview()
				// 监听webview的显示与隐藏，从而停止或者开始动画(为了性能)
				currentWebview.addEventListener('hide', () => {
					this.webviewHide = true
				})
				currentWebview.addEventListener('show', () => {
					this.webviewHide = false
				})
			},
			// #ifdef APP-NVUE
			nvueAnimate() {
				// nvue下，非spinner类型时才需要旋转，因为nvue的spinner类型，使用了weex的
				// loading-indicator组件，自带旋转功能
				this.mode !== 'spinner' && this.startAnimate()
			},
			// 执行nvue的animate模块动画
			startAnimate() {
				this.loading = true
				const ani = this.$refs.ani
				if (!ani) return
				animation.transition(ani, {
					// 进行角度旋转
					styles: {
						transform: `rotate(${this.aniAngel}deg)`,
						transformOrigin: 'center center'
					},
					duration: this.duration,
					timingFunction: this.timingFunction,
					// delay: 10
				}, () => {
					// 每次增加360deg，为了让其重新旋转一周
					this.aniAngel += 360
					// 动画结束后，继续循环执行动画，需要同时判断webviewHide变量
					// nvue安卓，页面隐藏后依然会继续执行startAnimate方法
					this.show && !this.webviewHide ? this.startAnimate() : this.loading = false
				})
			}
			// #endif
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-loading-icon-color: #c8c9cc !default;
	$uv-loading-icon-text-margin-left:4px !default;
	$uv-loading-icon-text-color:$uv-content-color !default;
	$uv-loading-icon-text-font-size:14px !default;
	$uv-loading-icon-text-line-height:20px !default;
	$uv-loading-width:30px !default;
	$uv-loading-height:30px !default;
	$uv-loading-max-width:100% !default;
	$uv-loading-max-height:100% !default;
	$uv-loading-semicircle-border-width: 2px !default;
	$uv-loading-semicircle-border-color:transparent !default;
	$uv-loading-semicircle-border-top-right-radius: 100px !default;
	$uv-loading-semicircle-border-top-left-radius: 100px !default;
	$uv-loading-semicircle-border-bottom-left-radius: 100px !default;
	$uv-loading-semicircle-border-bottom-right-radiu: 100px !default;
	$uv-loading-semicircle-border-style: solid !default;
	$uv-loading-circle-border-top-right-radius: 100px !default;
	$uv-loading-circle-border-top-left-radius: 100px !default;
	$uv-loading-circle-border-bottom-left-radius: 100px !default;
	$uv-loading-circle-border-bottom-right-radiu: 100px !default;
	$uv-loading-circle-border-width:2px !default;
	$uv-loading-circle-border-top-color:#e5e5e5 !default;
	$uv-loading-circle-border-right-color:$uv-loading-circle-border-top-color !default;
	$uv-loading-circle-border-bottom-color:$uv-loading-circle-border-top-color !default;
	$uv-loading-circle-border-left-color:$uv-loading-circle-border-top-color !default;
	$uv-loading-circle-border-style:solid !default;
	$uv-loading-icon-host-font-size:0px !default;
	$uv-loading-icon-host-line-height:1 !default;
	$uv-loading-icon-vertical-margin:6px 0 0 !default;
	$uv-loading-icon-dot-top:0 !default;
	$uv-loading-icon-dot-left:0 !default;
	$uv-loading-icon-dot-width:100% !default;
	$uv-loading-icon-dot-height:100% !default;
	$uv-loading-icon-dot-before-width:2px !default;
	$uv-loading-icon-dot-before-height:25% !default;
	$uv-loading-icon-dot-before-margin:0 auto !default;
	$uv-loading-icon-dot-before-background-color:currentColor !default;
	$uv-loading-icon-dot-before-border-radius:40% !default;

	.uv-loading-icon {
		/* #ifndef APP-NVUE */
		// display: inline-flex;
		/* #endif */
		flex-direction: row;
		align-items: center;
		justify-content: center;
		color: $uv-loading-icon-color;

		&__text {
			margin-left: $uv-loading-icon-text-margin-left;
			color: $uv-loading-icon-text-color;
			font-size: $uv-loading-icon-text-font-size;
			line-height: $uv-loading-icon-text-line-height;
		}

		&__spinner {
			width: $uv-loading-width;
			height: $uv-loading-height;
			position: relative;
			/* #ifndef APP-NVUE */
			box-sizing: border-box;
			max-width: $uv-loading-max-width;
			max-height: $uv-loading-max-height;
			animation: uv-rotate 1s linear infinite;
			/* #endif */
		}

		&__spinner--semicircle {
			border-width: $uv-loading-semicircle-border-width;
			border-color: $uv-loading-semicircle-border-color;
			border-top-right-radius: $uv-loading-semicircle-border-top-right-radius;
			border-top-left-radius: $uv-loading-semicircle-border-top-left-radius;
			border-bottom-left-radius: $uv-loading-semicircle-border-bottom-left-radius;
			border-bottom-right-radius: $uv-loading-semicircle-border-bottom-right-radiu;
			border-style: $uv-loading-semicircle-border-style;
		}

		&__spinner--circle {
			border-top-right-radius: $uv-loading-circle-border-top-right-radius;
			border-top-left-radius: $uv-loading-circle-border-top-left-radius;
			border-bottom-left-radius: $uv-loading-circle-border-bottom-left-radius;
			border-bottom-right-radius: $uv-loading-circle-border-bottom-right-radiu;
			border-width: $uv-loading-circle-border-width;
			border-top-color: $uv-loading-circle-border-top-color;
			border-right-color: $uv-loading-circle-border-right-color;
			border-bottom-color: $uv-loading-circle-border-bottom-color;
			border-left-color: $uv-loading-circle-border-left-color;
			border-style: $uv-loading-circle-border-style;
		}

		&--vertical {
			flex-direction: column
		}
	}

	/* #ifndef APP-NVUE */
	:host {
		font-size: $uv-loading-icon-host-font-size;
		line-height: $uv-loading-icon-host-line-height;
	}

	.uv-loading-icon {
		&__spinner--spinner {
			animation-timing-function: steps(12)
		}

		&__text:empty {
			display: none
		}

		&--vertical &__text {
			margin: $uv-loading-icon-vertical-margin;
			color: $uv-content-color;
		}

		&__dot {
			position: absolute;
			top: $uv-loading-icon-dot-top;
			left: $uv-loading-icon-dot-left;
			width: $uv-loading-icon-dot-width;
			height: $uv-loading-icon-dot-height;

			&:before {
				display: block;
				width: $uv-loading-icon-dot-before-width;
				height: $uv-loading-icon-dot-before-height;
				margin: $uv-loading-icon-dot-before-margin;
				background-color: $uv-loading-icon-dot-before-background-color;
				border-radius: $uv-loading-icon-dot-before-border-radius;
				content: " "
			}
		}
	}

	@for $i from 1 through 12 {
		.uv-loading-icon__dot:nth-of-type(#{$i}) {
			transform: rotate($i * 30deg);
			opacity: 1 - 0.0625 * ($i - 1);
		}
	}

	@keyframes uv-rotate {
		0% {
			transform: rotate(0deg)
		}

		to {
			transform: rotate(1turn)
		}
	}

	/* #endif */
</style>
X"x{
  "id": "uv-loading-iconloading-icon 加载动画TH3组件为一个小动画，目前用在uv-ui的uv-load-more加载更多等组件，还可以运用在项目中正在加载状	态场景+uv-loading-iconU!loading",
    "加载动画	0E)x '## LoadingIcon 加载动画loading-icon**

此组件为一个小动画，目前用在 `uv-ui` 的 `uv-load-more` 加载更多等组件，还可以运用"项目中正在加载状态场景/	loadingIc}Ό{	x e100644 changelog.md K~d	赹(
040000 components oj"NC!㥎٫100644 package.json ̛Zs7e7`%	U100644 readme.md :]jvEgkjMdow?Jx4## 1.0.4（2024-01-20）
1. 修改上版本带出的问题
## 1.0.3（2024-01-15）
1. 重构，避免初始加载的时候先显示页面的问题
## 1.0.2（2023-07-02）
uv-loading-page  由于弹出层uv-transition的修改，组件内部做了相应的修改，参数不变。
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-loading-page 加载页
x* 40000 uv-loading-page p	Ǟ6)!Vʣᘝ8hxS 100644 props.js lmh@`100644 uv-loading-page.vue m_پwUAvO"^=x-export default {
	props: {
		// 提示内容
		loadingText: {
			type: [String, Number],
			default: ''
		},
		// 文字上方用于替换loading动画的图片
		image: {
			type: String,
			default: ''
		},
		// 加载动画的模式，circle-圆形，spinner-花朵形，semicircle-半圆形
		loadingMode: {
			type: String,
			default: 'circle'
		},
		// 是否加载中
		loading: {
			type: Boolean,
			default: false
		},
		// 背景色
		bgColor: {
			type: String,
			default: '#fff'
		},
		// 文字颜色
		color: {
			type: String,
			default: '#C8C8C8'
		},
		// 文字大小
		fontSize: {
			type: [String, Number],
			default: 16
		},
		// 图标大小
		iconSize: {
			type: [String, Number],
			default: 26
		},
		// 加载中图标的颜色，只能rgb或者十六进制颜色值
		loadingColor: {
			type: String,
			default: '#C8C8C8'
		},
		// 过渡时间
		duration: {
			type: [String, Number],
			default: 300
		},
		...uni.$uv?.props?.loadingPage
	}
}8rpxY<template>
	<view class="uv-loading-page uv-flex-column" v-if="showLoading" :style="[loadingPageStyle]">
		<image v-if="image!=''" :src="image" class="uv-loading-page__img" mode="widthFit" :style="[{
			width: $uv.addUnit(iconSize),
			height: $uv.addUnit(iconSize)
		}]"></image>
		<uv-loading-icon v-else :mode="loadingMode" :size="iconSize" :color="loadingColor"></uv-loading-icon>
		<slot>
			<text class="uv-loading-page__text" :style="[{
				fontSize: $uv.addUnit(fontSize),
				color: color
			}]">{{ loadingText }}</text>
		</slot>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from "./props.js";
	/**
	 * loadingPage 加载动画
	 * @description 警此组件为一个小动画，目前用在uvui的loadmore加载更多和switch开关等组件的正在加载状态场景。
	 * @tutorial https://www.uvui.cn/components/loading.html
	 * 
	 * @property {Boolean}	loading  是否加载中 （默认 false ）
	 * @property {String | Number}	loadingText		提示内容  (默认 '正在加载' )
	 * @property {String}  image  文字上方用于替换loading动画的图片
	 * @property {String}  loadingMode  加载动画的模式，circle-圆形，spinner-花朵形，semicircle-半圆形 （默认 'circle' ）
	 * @property {String}  bgColor  背景色 （默认 '#ffffff' ）
	 * @property {String}  color  文字颜色 （默认 '#C8C8C8' ）
	 * @property {String | Number}	fontSize  文字大小 （默认 19 ）
	 * @property {String | Number}	iconSize  图标大小 （默认 28 ）
	 * @property {String}  loadingColor	加载中图标的颜色，只能rgb或者十六进制颜色值 （默认 '#C8C8C8' ）
	 * @property {String | Number}	duration  关闭加载时的过渡时间，单位ms （默认 300 ）
	 * 
	 * @example <uv-loading mode="circle"></uv-loading>
	 */
	export default {
		name: "uv-loading-page",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				showLoading: false,
				opacity: 1
			}
		},
		watch: {
			loading: {
				immediate: true,
				handler(newVal) {
					if (newVal) {
						this.showLoading = true;
						this.opacity = 1;
					} else {
						this.opacity = 0;
						this.$nextTick(() => {
							this.$uv.sleep(this.duration).then(res => {
								this.showLoading = false;
							})
						})
					}
				}
			}
		},
		computed: {
			loadingPageStyle() {
				const style = {
					'position': 'fixed',
					'top': '0',
					'left': '0',
					'right': '0',
					'bottom': '0',
					'zIndex': '999',
					'background-color': this.bgColor,
					'transition-duration': `${this.duration}ms`,
					'opacity': this.opacity
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		}
	}
</script>
<style scoped lang="scss">
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	$uv-loading-icon-margin-bottom: 10px !default;
	.uv-loading-page {
		flex: 1;
		justify-content: center;
		align-items: center;
		padding-bottom: 150px;
		transition-property: opacity;
		&__text {
			margin-top: $uv-loading-icon-margin-bottom;
		}
	}
</style>=|xH{
  "id": "uv-loading-page",
  "displayName": "uv-loading-page 加载页EJ4ing-page 该组件是一个页面级的加载效果，可以在页面初始化数据等场景使用，与骨架屏有相似之*"ing-pagP"page",
    "loading
transitionv ԋ2-x C## LoadingPage 加载页loading-page**

该组件是一个页面级的加载效果，可以在页面初始化数据等场景使用，与骨架屏有相	似之处1
loadingPag֦r	x e100644 changelog.md 2(nl܁0b@40000 components |*Ƽ.-V!t2100644 package.json *\:?/aRݻW100644 readme.md #tvE(Fﾋƛ<߼Gx|## 1.0.11（2023-12-20）
1. 优化
## 1.0.10（2023-12-19）
1. 修复confirm中快速使用closeLoading关闭加载状态失效的BUG
## 1.0.9（2023-11-28）
1. 修复上版本引出的确认和取消按钮均不显示，还有高度的BUG
## 1.0.8（2023-09-08）
1. 修复两个按钮之间竖线不显示的问题
2. uv-ui项目自定义按钮示例修改
## 1.0.7（2023-08-30）
1. 增加align参数，设置文本对齐方式，left  center right
2. 增加textStyle参数，设置文本样式
## 1.0.6（2023-08-23）
1. 修复异步loading时，确认回调还会一直触发
## 1.0.5（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.4（2023-07-02）
uv-modal  由于弹出层uv-popup的修改，打开和关闭方法更改，详情参考文档：https://www.uvui.cn/components/modal.html
## 1.0.3（2023-06-29）
1. 增加closeLoading方法，方便异步加载手动取消
2. 更新文档
## 1.0.2（2023-06-11）
1. 新增zIndex参数
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-modal 模态框
r`gԣx# 40000 uv-modal 
=@Z8,<xL 100644 props.js lf5K
fB	{w100644 uv-modal.vue Ew3LhD3.*:;I/1exRexport default {
	props: {
		// 标题
		title: {
			type: [String],
			default: ''
		},
		// 弹窗内容
		content: {
			type: String,
			default: ''
		},
		// 确认文案
		confirmText: {
			type: String,
			default: '确认'
		},
		// 取消文案
		cancelText: {
			type: String,
			default: '取消'
		},
		// 是否显示确认按钮
		showConfirmButton: {
			type: Boolean,
			default: true
		},
		// 是否显示取消按钮
		showCancelButton: {
			type: Boolean,
			default: false
		},
		// 确认按钮颜色
		confirmColor: {
			type: String,
			default: '#2979ff'
		},
		// 取消文字颜色
		cancelColor: {
			type: String,
			default: '#606266'
		},
		// 对调确认和取消的位置
		buttonReverse: {
			type: Boolean,
			default: false
		},
		// 是否开启缩放效果
		zoom: {
			type: Boolean,
			default: true
		},
		// 层级
		zIndex: {
			type: [String, Number],
			default: 10075
		},
		// 是否异步关闭，只对确定按钮有效
		asyncClose: {
			type: Boolean,
			default: false
		},
		// 是否允许点击遮罩关闭modal
		closeOnClickOverlay: {
			type: Boolean,
			default: true
		},
		// 给一个负的margin-top，往上偏移，避免和键盘重合的情况
		negativeTop: {
			type: [String, Number],
			default: 0
		},
		// modal宽度，不支持百分比，可以数值，px，rpx单位
		width: {
			type: [String, Number],
			default: '650rpx'
		},
		// 文本对齐方式，默认left
		align: {
			type: String,
			default: 'left'
		},
		// 文本自定义样式
		textStyle: {
			type: [Object, String],
			default: ''
		},
		...uni.$uv?.props?.modal
	}
}&hxxi<template>
	<uv-popup
		ref="modalPopup"
		mode="center"
		:zoom="zoom"
    :zIndex="zIndex"
		:customStyle="{
			borderRadius: '6px', 
			overflow: 'hidden',
			marginTop: `-${$uv.addUnit(negativeTop)}`
		}"
		:closeOnClickOverlay="closeOnClickOverlay"
		:safeAreaInsetBottom="false"
		:duration="400"
		@change="popupChange"
	>
		<view
			class="uv-modal"
			:style="{
				width: $uv.addUnit(width),
			}"
		>
			<text
				class="uv-modal__title"
				v-if="title"
			>{{ title }}</text>
			<view
				class="uv-modal__content"
				:style="{
					paddingTop: `${title ? 12 : 25}px`
				}"
			>
				<slot>
					<text 
						class="uv-modal__content__text"
						:style="[
							{
								textAlign: align
							},
							nvueStyle,
							$uv.addStyle(textStyle)
						]"
					>{{ content }}</text>
				</slot>
			</view>
			<slot name="confirmButton">
				<uv-line></uv-line>
				<view
					v-if="showConfirmButton || showCancelButton"
					class="uv-modal__button-group"
					:style="{
						flexDirection: buttonReverse ? 'row-reverse' : 'row'
					}"
				>
					<view
						class="uv-modal__button-group__wrapper uv-modal__button-group__wrapper--cancel"
						:hover-stay-time="150"
						hover-class="uv-modal__button-group__wrapper--hover"
						:class="[showCancelButton && !showConfirmButton && 'uv-modal__button-group__wrapper--only-cancel']"
						v-if="showCancelButton"
						@tap="cancelHandler"
					>
						<text
							class="uv-modal__button-group__wrapper__text"
							:style="{
								color: cancelColor
							}"
						>{{ cancelText }}</text>
					</view>
					<uv-line
						direction="column"
						v-if="showConfirmButton && showCancelButton"
					></uv-line>
					<view
						class="uv-modal__button-group__wrapper uv-modal__button-group__wrapper--confirm"
						:hover-stay-time="150"
						hover-class="uv-modal__button-group__wrapper--hover"
						:class="[!showCancelButton && showConfirmButton && 'uv-modal__button-group__wrapper--only-confirm']"
						v-if="showConfirmButton"
						@tap="confirmHandler"
					>
						<uv-loading-icon v-if="loading"></uv-loading-icon>
						<text
							v-else
							class="uv-modal__button-group__wrapper__text"
							:style="{
								color: confirmColor
							}"
						>{{ confirmText }}</text>
					</view>
				</view>
			</slot>
		</view>
	</uv-popup>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Modal 模态框
	 * @description 弹出模态框，常用于消息提示、消息确认、在当前页面内完成特定的交互操作。
	 * @tutorial https://www.uvui.cn/components/modul.html
	 * @property {String}			title				标题内容
	 * @property {String}			content				模态框内容，如传入slot内容，则此参数无效
	 * @property {String}			confirmText			确认按钮的文字 （默认 '确认' ）
	 * @property {String}			cancelText			取消按钮的文字 （默认 '取消' ）
	 * @property {Boolean}			showConfirmButton	是否显示确认按钮 （默认 true ）
	 * @property {Boolean}			showCancelButton	是否显示取消按钮 （默认 false ）
	 * @property {String}			confirmColor		确认按钮的颜色 （默认 '#2979ff' ）
	 * @property {String}			cancelColor			取消按钮的颜色 （默认 '#606266' ）
	 * @property {Boolean}			buttonReverse		对调确认和取消的位置 （默认 false ）
	 * @property {Boolean}			zoom				是否开启缩放模式 （默认 true ）
	 * @property {Boolean}			asyncClose			是否异步关闭，只对确定按钮有效，见上方说明 （默认 false ）
	 * @property {Boolean}			closeOnClickOverlay	是否允许点击遮罩关闭该组件 （默认 true ）
	 * @property {String | Number}	negativeTop			往上偏移的值，给一个负的margin-top，往上偏移，避免和键盘重合的情况，单位任意，数值则默认为px单位 （默认 0 ）
	 * @property {String | Number}	width				modal宽度，不支持百分比，可以数值，px，rpx单位 （默认 '650rpx' ）
	 * @property {String} align 文本对齐方式 （默认'left'） 
	 * @property {String | Object} textStyle 文本扩展样式
	 * @event {Function} confirm	点击确认按钮时触发
	 * @event {Function} cancel		点击取消按钮时触发
	 * @event {Function} close		点击遮罩关闭出发，closeOnClickOverlay为true有效
	 * @example <uv-modal ref="modalPopup" title="title" content="content"></uv-modal>
	 */
	export default {
		name: 'uv-modal',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				loading: false
			}
		},
		computed: {
			nvueStyle() {
				const style = {};
				// 避免nvue中不能换行的问题
				// #ifdef APP-NVUE
				style.width = this.$uv.addUnit(this.$uv.getPx(this.width) - 50,'px');
				// #endif
				return style;
			}
		},
		methods: {
			open() {
				this.$refs.modalPopup.open();
				if (this.loading) this.loading = false;
			},
			close() {
				this.$refs.modalPopup.close();
			},
			popupChange(e) {
				if(!e.show) this.$emit('close');
			},
			// 点击确定按钮
			confirmHandler() {
				if(!this.loading) {
					this.$emit('confirm');
				}
				// 如果配置了异步关闭，将按钮值为loading状态
				if (this.asyncClose) {
					this.loading = true;
				} else {
					this.close();
				}
			},
			// 点击取消按钮
			cancelHandler() {
				this.$emit('cancel');
				this.close();
			},
			closeLoading() {
				this.$nextTick(()=>{
					this.loading = false;
				})
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-modal-border-radius: 6px;

	.uv-modal {
		width: 650rpx;
		border-radius: $uv-modal-border-radius;
		overflow: hidden;

		&__title {
			font-size: 16px;
			font-weight: bold;
			color: $uv-content-color;
			text-align: center;
			padding-top: 25px;
		}

		&__content {
			padding: 12px 25px 25px 25px;
			@include flex;
			justify-content: center;

			&__text {
				line-height: 48rpx;
				font-size: 15px;
				color: $uv-content-color;
				flex: 1;
			}
		}

		&__button-group {
			@include flex;
			height: 48px;

			&__wrapper {
				flex: 1;
				@include flex;
				justify-content: center;
				align-items: center;
				height: 48px;
				
				&--confirm,
				&--only-cancel {
					border-bottom-right-radius: $uv-modal-border-radius;
				}
				
				&--cancel,
				&--only-confirm {
					border-bottom-left-radius: $uv-modal-border-radius;
				}

				&--hover {
					background-color: $uv-bg-color;
				}

				&__text {
					color: $uv-content-color;
					font-size: 16px;
					text-align: center;
				}
			}
		}
	}
</style>
px:{
  "id": "uv-modal",
  "displayName": "uv-modal 模态框EH11",
  "description": "支持自定义内容，与uniapp提供的API uni.showModal类似，但是功能更强大，更加灵活.modalO!modal",
    "模态框)popup",
			"uv-line",
			"uv-loading-icon
?7~xJ## Modal 模态框modal**

弹出模态框，常用于消息提示、消息确认、在当前页面内完成特定的交互操作。

特性：持自定义内容，与uniapp提供的API `uni.showModal` 类似，但是功能更强大，更加灵活。

运用场景： 窗验证码输入等场景

# 7(modal{ʌ	x e100644 changelog.md OصaEV
9%v40000 components ݍW+yR:[ 100644 package.json B |LF~)XVz8100644 readme.md A.~Ed)^>)xk## 1.0.7（2023-08-16）
1. 修复ios可能存在点击返回按钮点不到的情况
## 1.0.6（2023-08-07）
1. 修复nvue在ios端可能存在背景图样式错乱的BUG
## 1.0.5（2023-08-04）
1.  bgColor设置背景图片，增加imgMode属性
## 1.0.4（2023-08-01）
1.  bgColor属性支持背景图片，在线图片或base64图片都可以
## 1.0.3（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.2（2023-06-05）
1. 兼容渐变背景色
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-navbar 自定义导航栏
=bBx$ 40000 uv-navbar ;?o:ދIdNxM 100644 props.js GΒ_@C100644 uv-navbar.vue j׭_o4L;,'TO| axexport default {
	props: {
		// 是否开启顶部安全区适配
		safeAreaInsetTop: {
			type: Boolean,
			default: true
		},
		// 固定在顶部时，是否生成一个等高元素，以防止塌陷
		placeholder: {
			type: Boolean,
			default: false
		},
		// 是否固定在顶部
		fixed: {
			type: Boolean,
			default: true
		},
		// 是否显示下边框
		border: {
			type: Boolean,
			default: false
		},
		// 左边的图标
		leftIcon: {
			type: String,
			default: 'arrow-left'
		},
		// 左边的提示文字
		leftText: {
			type: String,
			default: ''
		},
		// 左右的提示文字
		rightText: {
			type: String,
			default: ''
		},
		// 右边的图标
		rightIcon: {
			type: String,
			default: ''
		},
		// 标题
		title: {
			type: [String, Number],
			default: ''
		},
		// 背景颜色
		bgColor: {
			type: String,
			default: '#ffffff'
		},
		imgMode: {
			type: String,
			default: 'aspectFill'
		},
		// 标题的宽度
		titleWidth: {
			type: [String, Number],
			default: '400rpx'
		},
		// 导航栏高度
		height: {
			type: [String, Number],
			default: '44px'
		},
		// 左侧返回图标的大小
		leftIconSize: {
			type: [String, Number],
			default: 20
		},
		// 左侧返回图标的颜色
		leftIconColor: {
			type: String,
			default: '#303133'
		},
		// 点击左侧区域(返回图标)，是否自动返回上一页
		autoBack: {
			type: Boolean,
			default: false
		},
		// 标题的样式，对象或字符串
		titleStyle: {
			type: [String, Object],
			default: ''
		},
		...uni.$uv?.props?.navbar
	}
},\巤xG<template>
	<view class="uv-navbar">
		<view
			class="uv-navbar__placeholder"
			v-if="fixed && placeholder"
			:style="{
				height: $uv.addUnit($uv.getPx(height) + $uv.sys().statusBarHeight,'px'),
			}"
		></view>
		<view :class="[fixed && 'uv-navbar--fixed']">
			<image class="uv-navbar--bgimg" :src="bgColor" :mode="imgMode" v-if="isImg" :style="[bgImgStyle]"></image>
			<uv-status-bar
				v-if="safeAreaInsetTop"
				:bgColor="getStatusbgColor"
			></uv-status-bar>
			<view
				class="uv-navbar__content"
				:class="[border && 'uv-border-bottom']"
				:style="[{
					height: $uv.addUnit(height)
				},getBgColor]"
			>
				<view
					class="uv-navbar__content__left"
					hover-class="uv-navbar__content__left--hover"
					hover-start-time="150"
					@tap="leftClick"
				>
					<slot name="left">
						<uv-icon
							v-if="leftIcon"
							:name="leftIcon"
							:size="leftIconSize"
							:color="leftIconColor"
						></uv-icon>
						<text
							v-if="leftText"
							:style="{
								color: leftIconColor
							}"
							class="uv-navbar__content__left__text"
						>{{ leftText }}</text>
					</slot>
				</view>
				<slot name="center">
					<text
						class="uv-line-1 uv-navbar__content__title"
						:style="[{
							width: $uv.addUnit(titleWidth),
							flex: '0 1 auto'
						}, $uv.addStyle(titleStyle)]"
					>{{ title }}</text>
				</slot>
				<view
					class="uv-navbar__content__right"
					@tap="rightClick"
				>
					<slot name="right">
						<uv-icon
							v-if="rightIcon"
							:name="rightIcon"
							size="20"
						></uv-icon>
						<text
							v-if="rightText"
							class="uv-navbar__content__right__text"
						>{{ rightText }}</text>
					</slot>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Navbar 自定义导航栏
	 * @description 此组件一般用于在特殊情况下，需要自定义导航栏的时候用到，一般建议使用uni-app带的导航栏。
	 * @tutorial https://www.uvui.cn/components/navbar.html
	 * @property {Boolean}			safeAreaInsetTop	是否开启顶部安全区适配  （默认 true ）
	 * @property {Boolean}			placeholder			固定在顶部时，是否生成一个等高元素，以防止塌陷 （默认 false ）
	 * @property {Boolean}			fixed				导航栏是否固定在顶部 （默认 false ）
	 * @property {Boolean}			border				导航栏底部是否显示下边框 （默认 false ）
	 * @property {String}			leftIcon			左边返回图标的名称，只能为uvui自带的图标 （默认 'arrow-left' ）
	 * @property {String}			leftText			左边的提示文字
	 * @property {String}			rightText			右边的提示文字
	 * @property {String}			rightIcon			右边返回图标的名称，只能为uvui自带的图标
	 * @property {String}			title				导航栏标题，如设置为空字符，将会隐藏标题占位区域
	 * @property {String}			bgColor				导航栏背景设置 （默认 '#ffffff' ）
	 * @property {String | Number}	titleWidth			导航栏标题的最大宽度，内容超出会以省略号隐藏 （默认 '400rpx' ）
	 * @property {String | Number}	height				导航栏高度(不包括状态栏高度在内，内部自动加上)（默认 '44px' ）
	 * @property {String | Number}	leftIconSize		左侧返回图标的大小（默认 20px ）
	 * @property {String | Number}	leftIconColor		左侧返回图标的颜色（默认 #303133 ）
	 * @property {Boolean}	        autoBack			点击左侧区域(返回图标)，是否自动返回上一页（默认 false ）
	 * @property {Object | String}	titleStyle			标题的样式，对象或字符串
	 * @event {Function} leftClick		点击左侧区域
	 * @event {Function} rightClick		点击右侧区域
	 * @example <uv-navbar title="剑未配妥，出门已是江湖" left-text="返回" right-text="帮助" @click-left="onClickBack" @click-right="onClickRight"></uv-navbar>
	 */
	export default {
		name: 'uv-navbar',
		mixins: [mpMixin, mixin, props],
		data() {
			return {

			}
		},
		computed: {
			getBgColor(){
				const style = {};
				if(this.bgColor){
					if (this.bgColor.indexOf("gradient") > -1) {// 渐变色
						style.backgroundImage = this.bgColor;
					}else if(this.isImg){
						style.background = 'transparent';
					}else {
						style.background = this.bgColor;
					}
				}
				return style;
			},
			getStatusbgColor() {
				if(this.bgColor){
					if(this.isImg){
						return 'transparent';
					}else {
						return this.bgColor;
					}
				}
			},
			// 判断传入的bgColor属性，是否图片路径，只要带有"/"均认为是图片形式
			isImg() {
				const isBase64 = this.bgColor.indexOf('data:') > -1 && this.bgColor.indexOf('base64') > -1;
				return this.bgColor.indexOf('/') !== -1 || isBase64;
			},
			bgImgStyle() {
				const style = {};
				if(this.safeAreaInsetTop) {
					style.height = this.$uv.addUnit(this.$uv.sys().statusBarHeight + 44, 'px');
				} else {
					style.height = '44px';
				}
				return style;
			}
		},
		methods: {
			// 点击左侧区域
			leftClick() {
				// 如果配置了autoBack，自动返回上一页
				this.$emit('leftClick')
				if(this.autoBack) {
					uni.navigateBack()
				}
			},
			// 点击右侧区域
			rightClick() {
				this.$emit('rightClick')
			}
		}
	}
</script>

<style lang="scss" scoped>
 	$show-border: 1;
	$show-border-bottom: 1;
	$show-lines: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-navbar {
		position: relative;
		&--fixed {
			position: fixed;
			left: 0;
			right: 0;
			top: 0;
			z-index: 11;
		}
		
		&--bgimg {
			position: absolute;
			left: 0;
			right: 0;
			bottom: 0;
			top: 0;
			/* #ifndef APP-NVUE */
			width: 100%;
			height: 100%;
			/* #endif */
			/* #ifdef APP-NVUE */
			width: 750rpx;
			/* #endif */
		}

		&__content {
			@include flex(row);
			align-items: center;
			height: 44px;
			background-color: #9acafc;
			position: relative;
			justify-content: center;

			&__left,
			&__right {
				padding: 0 13px;
				position: absolute;
				top: 0;
				bottom: 0;
				@include flex(row);
				align-items: center;
			}

			&__left {
				left: 0;
				
				&--hover {
					opacity: 0.7;
				}

				&__text {
					font-size: 15px;
					margin-left: 3px;
				}
			}

			&__title {
				text-align: center;
				font-size: 16px;
				color: $uv-main-color;
			}

			&__right {
				right: 0;

				&__text {
					font-size: 15px;
					margin-left: 3px;
				}
			}
		}
	}
</style>
0?x ## Navbar 自定义导航栏navbar**

此组件一般用于在特殊情况下，需要自定义导航栏的时候用到，一般建议使用自带的原生6导航栏，支持渐变色、透明色、图片背景/navbar{2ٓ	x e100644 changelog.md Զ&QZc8:R40000 components WOH- ֵX100644 package.json H!?l\LukT100644 readme.md J%!Q%CK|Ǒ<u6x" -network 无网络提示
x( 40000 uv-no-network #L$k57¡xQ 100644 props.js Y[˛ ڕk{Hc100644 uv-no-network.vue _ORqOKoH|p \xAqexport default {
	props: {
		// 页面文字提示
		tips: {
			type: String,
			default: '哎呀，网络信号丢失'
		},
		// 一个z-index值，用于设置没有网络这个组件的层次，因为页面可能会有其他定位的元素层级过高，导致此组件被覆盖
		zIndex: {
			type: [String, Number],
			default: ''
		},
		// image 没有网络的图片提示
		image: {
			type: String,
			default: 'data:image/png;base64,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'
		},
		...uni.$uv?.props?.noNetwork
	}
}h4x"<template>
	<uv-overlay
	    :show="!isConnected"
		:zIndex="zIndex"
	    @touchmove.stop.prevent="noop"
		:customStyle="{
			backgroundColor: '#fff',
			display: 'flex',
			justifyContent: 'center',
		}"
	>
		<view
		    class="uv-no-network"
		>
			<uv-icon
			    :name="image"
			    size="150"
			    imgMode="widthFit"
			    class="uv-no-network__error-icon"
			></uv-icon>
			<text class="uv-no-network__tips">{{tips}}</text>
			<!-- 只有APP平台，才能跳转设置页，因为需要调用plus环境 -->
			<!-- #ifdef APP-PLUS -->
			<view class="uv-no-network__app">
				<text class="uv-no-network__app__setting">请检查网络，或前往</text>
				<text
				    class="uv-no-network__app__to-setting"
				    @tap="openSettings"
				>设置</text>
			</view>
			<!-- #endif -->
			<view class="uv-no-network__retry">
				<uv-button
				    size="mini"
				    text="重试"
				    type="primary"
					plain
				    @click="retry"
				></uv-button>
			</view>
		</view>
	</uv-overlay>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';

	/**
	 * noNetwork 无网络提示
	 * @description 该组件无需任何配置，引入即可，内部自动处理所有功能和事件。
	 * @tutorial https://www.uvui.cn/components/noNetwork.html
	 * @property {String}			tips 	没有网络时的提示语 （默认：'哎呀，网络信号丢失' ）
	 * @property {String | Number}	zIndex	组件的z-index值 
	 * @property {String}			image	无网络的图片提示，可用的src地址或base64图片 
	 * @event {Function}			retry	用户点击页面的"重试"按钮时触发
	 * @example <uv-no-network></uv-no-network>
	 */
	export default {
		name: "uv-no-network",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				isConnected: true, // 是否有网络连接
				networkType: "none", // 网络类型
			}
		},
		mounted() {
			this.isIOS = (uni.getSystemInfoSync().platform === 'ios')
			uni.onNetworkStatusChange((res) => {
				this.isConnected = res.isConnected
				this.networkType = res.networkType
				this.emitEvent(this.networkType)
			})
			uni.getNetworkType({
				success: (res) => {
					this.networkType = res.networkType
					this.emitEvent(this.networkType)
					if (res.networkType == 'none') {
						this.isConnected = false
					} else {
						this.isConnected = true
					}
				}
			})
		},
		methods: {
			retry() {
				// 重新检查网络
				uni.getNetworkType({
					success: (res) => {
						this.networkType = res.networkType
						this.emitEvent(this.networkType)
						if (res.networkType == 'none') {
							this.$uv.toast('无网络连接')
							this.isConnected = false
						} else {
							this.$uv.toast('网络已连接')
							this.isConnected = true
						}
					}
				})
				this.$emit('retry')
			},
			// 发出事件给父组件
			emitEvent(networkType) {
				this.$emit(networkType === 'none' ? 'disconnected' : 'connected')
			},
			async openSettings() {
				if (this.networkType == "none") {
					this.openSystemSettings()
					return
				}
			},
			openAppSettings() {
				this.gotoAppSetting()
			},
			openSystemSettings() {
				// 以下方法来自5+范畴，如需深究，请自行查阅相关文档
				// https://ask.dcloud.net.cn/docs/
				if (this.isIOS) {
					this.gotoiOSSetting()
				} else {
					this.gotoAndroidSetting()
				}
			},
			network() {
				var result = null
				var cellularData = plus.ios.newObject("CTCellularData")
				var state = cellularData.plusGetAttribute("restrictedState")
				if (state == 0) {
					result = null
				} else if (state == 2) {
					result = 1
				} else if (state == 1) {
					result = 2
				}
				plus.ios.deleteObject(cellularData)
				return result
			},
			gotoAppSetting() {
				if (this.isIOS) {
					var UIApplication = plus.ios.import("UIApplication")
					var application2 = UIApplication.sharedApplication()
					var NSURL2 = plus.ios.import("NSURL")
					var setting2 = NSURL2.URLWithString("app-settings:")
					application2.openURL(setting2)
					plus.ios.deleteObject(setting2)
					plus.ios.deleteObject(NSURL2)
					plus.ios.deleteObject(application2)
				} else {
					var Intent = plus.android.importClass("android.content.Intent")
					var Settings = plus.android.importClass("android.provider.Settings")
					var Uri = plus.android.importClass("android.net.Uri")
					var mainActivity = plus.android.runtimeMainActivity()
					var intent = new Intent()
					intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
					var uri = Uri.fromParts("package", mainActivity.getPackageName(), null)
					intent.setData(uri)
					mainActivity.startActivity(intent)
				}
			},
			gotoiOSSetting() {
				var UIApplication = plus.ios.import("UIApplication")
				var application2 = UIApplication.sharedApplication()
				var NSURL2 = plus.ios.import("NSURL")
				var setting2 = NSURL2.URLWithString("App-prefs:root=General")
				application2.openURL(setting2)
				plus.ios.deleteObject(setting2)
				plus.ios.deleteObject(NSURL2)
				plus.ios.deleteObject(application2)
			},
			gotoAndroidSetting() {
				var Intent = plus.android.importClass("android.content.Intent")
				var Settings = plus.android.importClass("android.provider.Settings")
				var mainActivity = plus.android.runtimeMainActivity()
				var intent = new Intent(Settings.ACTION_SETTINGS)
				mainActivity.startActivity(intent)
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-no-network {
		@include flex(column);
		justify-content: center;
		align-items: center;
		margin-top: -100px;

		&__tips {
			color: $uv-tips-color;
			font-size: 14px;
			margin-top: 15px;
		}

		&__app {
			@include flex(row);
			margin-top: 6px;

			&__setting {
				color: $uv-light-color;
				font-size: 13px;
			}

			&__to-setting {
				font-size: 13px;
				color: $uv-primary;
				margin-left: 3px;
			}
		}

		&__retry {
			@include flex(row);
			justify-content: center;
			margin-top: 15px;
		}
	}
</style>
<9'>x5D{
  "id": "uv-no-network",
  "displayName": "uv-no-network 无网络9P1-network 该组件在没有任何网络的情况下，显示在内容上方，无需任何配置，引入即可，内部自动理所有功能和事件 -network!"etwork",
    "无网络\Xicon",
			"uv-buttqMx *## NoNetwork 无网络提示no-network**

该组件在没有任何网络的情况下，显示在内容上方，无需任何配置，引入即可，内部动处理所有功能和事件1	noNetworkݥ*	x e100644 changelog.md <Y}5ps;k1+40000 components Ve%ȜbaL'100644 package.json 񼢖Nc[`Gل100644 readme.md asnɯ%ܞ_jBx{ 40000 uv-column-notice 1^\;0.M	~|40000 uv-notice-bar \<<Y{o"40000 uv-row-notice uN	9fpvP~<]1xT 100644 props.js 9T	0܂f՗P͑100644 uv-column-notice.vue sƿtQHDɾs$#Xx|export default {
	props: {
		// 显示的内容，字符串
		text: {
			type: [Array],
			default: ''
		},
		// 是否显示左侧的音量图标
		icon: {
			type: [String, Boolean, null],
			default: 'volume'
		},
		// 通告模式，link-显示右箭头，closable-显示右侧关闭图标
		mode: {
			type: String,
			default: ''
		},
		// 文字颜色，各图标也会使用文字颜色
		color: {
			type: String,
			default: '#f9ae3d'
		},
		// 背景颜色
		bgColor: {
			type: String,
			default: '#fdf6ec'
		},
		// 字体大小，单位px
		fontSize: {
			type: [String, Number],
			default: 14
		},
		// 水平滚动时的滚动速度，即每秒滚动多少px(px)，这有利于控制文字无论多少时，都能有一个恒定的速度
		speed: {
			type: [String, Number],
			default: 80
		},
		// direction = row时，是否使用步进形式滚动
		step: {
			type: Boolean,
			default: false
		},
		// 滚动一个周期的时间长，单位ms
		duration: {
			type: [String, Number],
			default: 1500
		},
		// 是否禁止用手滑动切换，仅`direction="column"生效`
		// 目前HX2.6.11，只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序
		disableTouch: {
			type: Boolean,
			default: true
		},
		// 是否禁止滚动，仅`direction="column"生效`
		disableScroll: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.columnNotice
	}
}7qcx%<template>
	<view
		class="uv-notice"
		@tap="clickHandler"
	>
		<slot name="icon">
			<view
				class="uv-notice__left-icon"
				v-if="icon"
			>
				<uv-icon
					:name="icon"
					:color="color"
					size="19"
				></uv-icon>
			</view>
		</slot>
		<view
			class="uv-notice__content"
			ref="uv-notice__content"
		>
			<view
				ref="uv-notice__content__text"
				class="uv-notice__content__text"
				:style="[animationStyle]"
			>
				<text
					v-for="(item, index) in innerText"
					:key="index"
					:style="[textStyle]"
				>{{item}}</text>
			</view>
		</view>
		<view
			class="uv-notice__right-icon"
			v-if="['link', 'closable'].includes(mode)"
		>
			<uv-icon
				v-if="mode === 'link'"
				name="arrow-right"
				:size="17"
				:color="color"
			></uv-icon>
			<uv-icon
				v-if="mode === 'closable'"
				@click="close"
				name="close"
				:size="16"
				:color="color"
			></uv-icon>
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const animation = uni.requireNativePlugin('animation')
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * RowNotice 滚动通知中的水平滚动模式
	 * @description 水平滚动
	 * @tutorial https://www.uvui.cn/components/noticeBar.html
	 * @property {String | Number}	text			显示的内容，字符串
	 * @property {String}			icon			是否显示左侧的音量图标 (默认 'volume' )
	 * @property {String}			mode			通告模式，link-显示右箭头，closable-显示右侧关闭图标
	 * @property {String}			color			文字颜色，各图标也会使用文字颜色 (默认 '#f9ae3d' )
	 * @property {String}			bgColor			背景颜色 (默认 ''#fdf6ec' )
	 * @property {String | Number}	fontSize		字体大小，单位px (默认 14 )
	 * @property {String | Number}	speed			水平滚动时的滚动速度，即每秒滚动多少px(rpx)，这有利于控制文字无论多少时，都能有一个恒定的速度  (默认 80 )
	 * 
	 * @event {Function} click 点击通告文字触发
	 * @event {Function} close 点击右侧关闭图标触发
	 * @example 
	 */
	export default {
		name: 'uv-row-notice',
		emits: ['click','close'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				animationDuration: '0', // 动画执行时间
				animationPlayState: 'paused', // 动画的开始和结束执行
				// nvue下，内容发生变化，导致滚动宽度也变化，需要标志为是否需要重新计算宽度
				// 不能在内容变化时直接重新计算，因为nvue的animation模块上一次的滚动不是刚好结束，会有影响
				nvueInit: true,
				show: true
			};
		},
		watch: {
			text: {
				immediate: true,
				handler(newValue, oldValue) {
					// #ifdef APP-NVUE
					this.nvueInit = true
					// #endif
					// #ifndef APP-NVUE
					this.vue()
					// #endif
					
					if(!this.$uv.test.string(newValue)) {
						this.$uv.error('noticebar组件direction为row时，要求text参数为字符串形式')
					}
				}
			},
			fontSize() {
				// #ifdef APP-NVUE
				this.nvueInit = true
				// #endif
				// #ifndef APP-NVUE
				this.vue()
				// #endif
			},
			speed() {
				// #ifdef APP-NVUE
				this.nvueInit = true
				// #endif
				// #ifndef APP-NVUE
				this.vue()
				// #endif
			}
		},
		computed: {
			// 文字内容的样式
			textStyle() {
				let style = {}
				style.color = this.color
				style.fontSize = this.$uv.addUnit(this.fontSize)
				return style
			},
			animationStyle() {
				let style = {}
				style.animationDuration = this.animationDuration
				style.animationPlayState = this.animationPlayState
				return style
			},
			// 内部对用户传入的数据进一步分割，放到多个text标签循环，否则如果用户传入的字符串很长（100个字符以上）
			// 放在一个text标签中进行滚动，在低端安卓机上，动画可能会出现抖动现象，需要分割到多个text中可解决此问题
			innerText() {
				let result = [],
					// 每组text标签的字符长度
					len = 20
				const textArr = this.text? this.text.split(''):[]
				for (let i = 0; i < textArr.length; i += len) {
					// 对拆分的后的text进行slice分割，得到的为数组再进行join拼接为字符串
					result.push(textArr.slice(i, i + len).join(''))
				}
				return result
			}
		},
		mounted() {
			// #ifdef APP-PLUS
			// 在APP上(含nvue)，监听当前webview是否处于隐藏状态(进入下一页时即为hide状态)
			// 如果webivew隐藏了，为了节省性能的损耗，应停止动画的执行，同时也是为了保持进入下一页返回后，滚动位置保持不变
			var pages = getCurrentPages()
			var page = pages[pages.length - 1]
			var currentWebview = page.$getAppWebview()
			currentWebview.addEventListener('hide', () => {
				this.webviewHide = true
			})
			currentWebview.addEventListener('show', () => {
				this.webviewHide = false
			})
			// #endif

			this.init()
		},
		methods: {
			init() {
				// #ifdef APP-NVUE
				this.nvue()
				// #endif

				// #ifndef APP-NVUE
				this.vue()
				// #endif
				
				if(!this.$uv.test.string(this.text)) {
					this.$uv.error('noticebar组件direction为row时，要求text参数为字符串形式')
				}
			},
			// vue版处理
			async vue() {
				// #ifndef APP-NVUE
				let boxWidth = 0,
					textWidth = 0
				// 进行一定的延时
				await this.$uv.sleep()
				// 查询盒子和文字的宽度
				textWidth = (await this.$uvGetRect('.uv-notice__content__text')).width
				boxWidth = (await this.$uvGetRect('.uv-notice__content')).width
				// 根据t=s/v(时间=路程/速度)，这里为何不需要加上#uv-notice-box的宽度，因为中设置了.uv-notice-content样式中设置了padding-left: 100%
				// 恰巧计算出来的结果中已经包含了#uv-notice-box的宽度
				this.animationDuration = `${textWidth / this.$uv.getPx(this.speed)}s`
				// 这里必须这样开始动画，否则在APP上动画速度不会改变
				this.animationPlayState = 'paused'
				setTimeout(() => {
					this.animationPlayState = 'running'
				}, 10)
				// #endif
			},
			// nvue版处理
			async nvue() {
				// #ifdef APP-NVUE
				this.nvueInit = false
				let boxWidth = 0,
					textWidth = 0
				// 进行一定的延时
				await this.$uv.sleep()
				// 查询盒子和文字的宽度
				textWidth = (await this.getNvueRect('uv-notice__content__text')).width
				boxWidth = (await this.getNvueRect('uv-notice__content')).width
				// 将文字移动到盒子的右边沿，之所以需要这么做，是因为nvue不支持100%单位，否则可以通过css设置
				animation.transition(this.$refs['uv-notice__content__text'], {
					styles: {
						transform: `translateX(${boxWidth}px)`
					},
				}, () => {
					// 如果非禁止动画，则开始滚动
					!this.stopAnimation && this.loopAnimation(textWidth, boxWidth)
				});
				// #endif
			},
			loopAnimation(textWidth, boxWidth) {
				// #ifdef APP-NVUE
				animation.transition(this.$refs['uv-notice__content__text'], {
					styles: {
						// 目标移动终点为-textWidth，也即当文字的最右边贴到盒子的左边框的位置
						transform: `translateX(-${textWidth}px)`
					},
					// 滚动时间的计算为，时间 = 路程(boxWidth + textWidth) / 速度，最后转为毫秒
					duration: (boxWidth + textWidth) / this.$uv.getPx(this.speed) * 1000,
					delay: 10
				}, () => {
					animation.transition(this.$refs['uv-notice__content__text'], {
						styles: {
							// 重新将文字移动到盒子的右边沿
							transform: `translateX(${this.stopAnimation ? 0 : boxWidth}px)`
						},
					}, () => {
						// 如果非禁止动画，则继续下一轮滚动
						if (!this.stopAnimation) {
							// 判断是否需要初始化计算尺寸
							if (this.nvueInit) {
								this.nvue()
							} else {
								this.loopAnimation(textWidth, boxWidth)
							}
						}
					});
				})
				// #endif
			},
			getNvueRect(el) {
				// #ifdef APP-NVUE
				// 返回一个promise
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs[el], (res) => {
						resolve(res.size)
					})
				})
				// #endif
			},
			// 点击通告栏
			clickHandler(index) {
				this.$emit('click')
			},
			// 点击右侧按钮，需要判断点击的是关闭图标还是箭头图标
			close() {
				this.$emit('close')
			}
		},
		// #ifdef APP-NVUE
		// #ifdef VUE2
		beforeDestroy() {
			this.stopAnimation = true
		},
		// #endif
		// #ifdef VUE3
		unmounted() {
			this.stopAnimation = true
		}
		// #endif
		// #endif
	};
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-notice {
		@include flex;
		align-items: center;
		justify-content: space-between;

		&__left-icon {
			align-items: center;
			margin-right: 5px;
		}

		&__right-icon {
			margin-left: 5px;
			align-items: center;
		}

		&__content {
			text-align: right;
			flex: 1;
			@include flex;
			flex-wrap: nowrap;
			overflow: hidden;

			&__text {
				font-size: 14px;
				color: $uv-warning;
				/* #ifndef APP-NVUE */
				// 这一句很重要，为了能让滚动左右连接起来
				padding-left: 100%;
				word-break: keep-all;
				white-space: nowrap;
				animation: uv-loop-animation 10s linear infinite both;
				/* #endif */
				@include flex(row);
			}
		}

	}
	/* #ifndef APP-NVUE */
	@keyframes uv-loop-animation {
		0% {
			transform: translate3d(0, 0, 0);
		}

		100% {
			transform: translate3d(-100%, 0, 0);
		}
	}
	/* #endif */
</style>
(X xK"swiper
			:disable-touch="disableTouch"
			:vertical="step ? false : true"
			circular
			:interval="duration"
			:autoplay="!disableScroll"Pswiper"
			:style="[swiperStyle]"
			@change="noticeChange"
		>
			<swiper-item
text"
				:key="index"
				class="uv-notice__swiper__item"
			>
				<text
					class="uv-notice__swiper__item__text uv-line-1"
!, item }}</text>
			</swiper-item>
		</swiper:H24z+**
	 * ColumnNotice 滚动通知中的垂直滚动 内部组件
	 * @description 该组件用于滚动通告场景，是其中垂直滚动方式1LArray}			text < %（ 默认 'volume' ）mode #i 4（ 默认 '#f9ae3d' ）( 		背景颜色 （ 默认 '#fdf6ec' ）.- （ 默认 14 ）.（ 默认 80 ）
	 * @property {Boolean}			step			direction = row时，是否使用步进形式滚动 （ 默认 false ）
	 *.duration		滚动一个周期的时间长，单位ms （ 默认 1500 ）
	 * @property {Boolean}			disableTouch	是否禁止用滑动切换   目前HX2.6.11，只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序 （ 默认 true ）(emits: ['click','close','chang*
Pif(!this.$uv.test.array?:column时，要求text参数为数组形式')
					}
				};// 垂直或者水平滚动
			vertical() {
				if (this.mode == 'horizontal') return false
				else return true
			},
			// NVNUE中的swiper在css中样式不生效
			swiperStyle(){
				const style = {};Sstyle.flex = 1;
				style.height = '16px';
				// #endif
				return style;
			}
		}	index:0
			}
		},
		methods: {
			noticeChange(e){
				this.index = e.detail.current
				this.$emit('change', this.index);
			}d ( 6, this.index)
			},
			// 点击关闭按钮
			close( ose')
			}
		}!,$show-lines: 1;".variable.scss';"`)swiper {
			height: 16px;
			@include fleZ#,	flex: 1;

			&__item {
				@include flex;
	]#:		overflow: hidden;

				&__text {
					font-size: 14px;
	$}
			}
		}
	}
</style>
1%cxQ 100644 props.js ?C,	I8-"#_T100644 uv-notice-bar.vue |V|\sԙ	ֵ:\gxyexport default {
	props: {
		// 显示的内容，数组
		text: {
			type: [Array, String],
			default: () => []
		},
		// 通告滚动模式，row-横向滚动，column-竖向滚动
		direction: {
			type: String,
			default: 'row'
		},
		// direction = row时，是否使用步进形式滚动
		step: {
			type: Boolean,
			default: false
		},
		// 是否显示左侧的音量图标
		icon: {
			type: [String, Boolean, null],
			default: 'volume'
		},
		// 通告模式，link-显示右箭头，closable-显示右侧关闭图标
		mode: {
			type: String,
			default: ''
		},
		// 文字颜色，各图标也会使用文字颜色
		color: {
			type: String,
			default: '#f9ae3d'
		},
		// 背景颜色
		bgColor: {
			type: String,
			default: '#fdf6ec'
		},
		// 水平滚动时的滚动速度，即每秒滚动多少px(px)，这有利于控制文字无论多少时，都能有一个恒定的速度
		speed: {
			type: [String, Number],
			default: 80
		},
		// 字体大小
		fontSize: {
			type: [String, Number],
			default: 14
		},
		// 滚动一个周期的时间长，单位ms
		duration: {
			type: [String, Number],
			default: 2000
		},
		// 跳转的页面路径
		url: {
			type: String,
			default: ''
		},
		// 页面跳转的类型
		linkType: {
			type: String,
			default: 'navigateTo'
		},
		// 是否禁止用手滑动切换
		// 目前HX2.6.11，只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序
		disableTouch: {
			type: Boolean,
			default: true
		},
		// 是否禁止滚动，仅`direction="column"生效`
		disableScroll: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.noticeBar
	}
}hjx<template>
	<view
		class="uv-notice-bar"
		v-if="show"
		:style="[{
			backgroundColor: bgColor
		}, $uv.addStyle(customStyle)]"
	>
		<template v-if="direction === 'column' || (direction === 'row' && step)">
			<uv-column-notice
				:color="color"
				:bgColor="bgColor"
				:text="text"
				:mode="mode"
				:step="step"
				:icon="icon"
				:disable-touch="disableTouch"
				:disable-scroll="disableScroll"
				:fontSize="fontSize"
				:duration="duration"
				@close="close"
				@click="click"
				@change="change"
			></uv-column-notice>
		</template>
		<template v-else>
			<uv-row-notice
				:color="color"
				:bgColor="bgColor"
				:text="text"
				:mode="mode"
				:fontSize="fontSize"
				:speed="speed"
				:url="url"
				:linkType="linkType"
				:icon="icon"
				@close="close"
				@click="click"
			></uv-row-notice>
		</template>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';

	/**
	 * noticeBar 滚动通知
	 * @description 该组件用于滚动通告场景，有多种模式可供选择
	 * @tutorial https://www.uvui.cn/components/noticeBar.html
	 * @property {Array | String}	text			显示的内容，数组
	 * @property {String}			direction		通告滚动模式，row-横向滚动，column-竖向滚动 ( 默认 'row' )
	 * @property {Boolean}			step			direction = row时，是否使用步进形式滚动  ( 默认 false )
	 * @property {String}			icon			是否显示左侧的音量图标 ( 默认 'volume' )
	 * @property {String}			mode			通告模式，link-显示右箭头，closable-显示右侧关闭图标
	 * @property {String}			color			文字颜色，各图标也会使用文字颜色 ( 默认 '#f9ae3d' )
	 * @property {String}			bgColor			背景颜色 ( 默认 '#fdf6ec' )
	 * @property {String | Number}	speed			水平滚动时的滚动速度，即每秒滚动多少px(px)，这有利于控制文字无论多少时，都能有一个恒定的速度 ( 默认 80 )
	 * @property {String | Number}	fontSize		字体大小 ( 默认 14 )
	 * @property {String | Number}	duration		滚动一个周期的时间长，单位ms ( 默认 2000 )
	 * @property {Boolean}			disableTouch	是否禁止用手滑动切换 目前HX2.6.11，只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序（默认34） ( 默认 true )
	 * @property {String}			url				跳转的页面路径
	 * @property {String}			linkType		页面跳转的类型 ( 默认 navigateTo )
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 * 
	 * @event {Function}			click			点击通告文字触发
	 * @event {Function}			close			点击右侧关闭图标触发
	 * @example <uv-notice-bar :more-icon="true" :list="list"></uv-notice-bar>
	 */
	export default {
		name: "uv-notice-bar",
		emits: ['click','close','change'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				show: true
			}
		},
		methods: {
			// 点击通告栏
			click(index) {
				this.$emit('click', index)
				if (this.url && this.linkType) {
					// 此方法写在mixin中，另外跳转的url和linkType参数也在mixin的props中
					this.openPage()
				}
			},
			// 点击关闭按钮
			close() {
				this.show = false
				this.$emit('close')
			},
			// 竖向滚动时触发
			change(index){
				this.$emit('change',index)
			}
		}
	};
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-notice-bar {
		overflow: hidden;
		padding: 9px 12px;
		flex: 1;
	}
</style>
0aڡxQ 100644 props.js ˡ5zPوRUB100644 uv-row-notice.vue }ޟ?TY/M6 hpx: ONr3r!...uni.$uv?.props?.rowNotice
	}
}DLjAx K{
  "id": "uv-notice-otice-bar 滚动通知EbIotice-bar 该组件用于滚动通告场景，有多种模式可供选择+otice-L%otice",
    "滚动公告	Y\x E## NoticeBar 滚动通知Ynotice-bar**

该组件用于滚动通告场景，有多种模式可供选择。灵活配A	noticeBarz( style="font-size:14px;font-weight:700;"r^\	x e100644 changelog.md ]STf|hӹ<40000 components i$ #.+	100644 package.json I[T2\˪f>100644 readme.md H#DO-IPJi"(Pt=x|## 1.0.3（2023-10-13）
1. unmounted兼容vue3
## 1.0.2（2023-07-02）
uv-notify  由于弹出层uv-popup的修改，打开和关闭方法更改，详情参考文档：https://www.uvui.cn/components/notify.html
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-notify 消息提示
%>Ȉx$ 40000 uv-notify &J
*`o8yPY*xM 100644 props.js W('is%JLcRQ_L100644 uv-notify.vue Vd{vc 4$sxM<template>
	<uv-transition
		mode="slide-top"
		:customStyle="containerStyle"
		:show="open"
	>
		<view
			class="uv-notify"
			:class="[`uv-notify--${tmpConfig.type}`]"
			:style="[backgroundColor, $uv.addStyle(customStyle)]"
		>
			<uv-status-bar v-if="tmpConfig.safeAreaInsetTop"></uv-status-bar>
			<view class="uv-notify__warpper">
				<slot name="icon">
					<uv-icon
						v-if="['success', 'warning', 'error'].includes(tmpConfig.type)"
						:name="tmpConfig.icon"
						:color="tmpConfig.color"
						:size="1.3 * tmpConfig.fontSize"
						:customStyle="{marginRight: '4px'}"
					></uv-icon>
				</slot>
				<text
					class="uv-notify__warpper__text"
					:style="{
						fontSize: $uv.addUnit(tmpConfig.fontSize),
						color: tmpConfig.color
					}"
				>{{ tmpConfig.message }}</text>
			</view>
		</view>
	</uv-transition>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * notify 顶部提示
	 * @description 该组件一般用于页面顶部向下滑出一个提示，尔后自动收起的场景
	 * @tutorial
	 * @property {String | Number}	top					到顶部的距离 ( 默认 0 )
	 * @property {String}			type				主题，primary，success，warning，error ( 默认 'primary' )
	 * @property {String}			color				字体颜色 ( 默认 '#ffffff' )
	 * @property {String}			bgColor				背景颜色
	 * @property {String}			message				展示的文字内容
	 * @property {String | Number}	duration			展示时长，为0时不消失，单位ms ( 默认 3000 )
	 * @property {String | Number}	fontSize			字体大小 ( 默认 15 )
	 * @property {Boolean}			safeAreaInsetTop	是否留出顶部安全距离（状态栏高度） ( 默认 false )
	 * @property {Object}			customStyle			组件的样式，对象形式
	 * @event {Function}	open	开启组件时调用的函数
	 * @event {Function}	close	关闭组件式调用的函数
	 * @example <uv-notify message="Hi uvui"></uv-notify>
	 */
	export default {
		name: 'uv-notify',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 是否展示组件
				open: false,
				timer: null,
				config: {
					// 到顶部的距离
					top: this.top,
					// type主题，primary，success，warning，error
					type: this.type,
					// 字体颜色
					color: this.color,
					// 背景颜色
					bgColor: this.bgColor,
					// 展示的文字内容
					message: this.message,
					// 展示时长，为0时不消失，单位ms
					duration: this.duration,
					// 字体大小
					fontSize: this.fontSize,
					// 是否留出顶部安全距离（状态栏高度）
					safeAreaInsetTop: this.safeAreaInsetTop
				},
				// 合并后的配置，避免多次调用组件后，可能会复用之前使用的配置参数
				tmpConfig: {}
			}
		},
		computed: {
			containerStyle() {
				let top = 0
				if (this.tmpConfig.top === 0) {
					// #ifdef H5
					// H5端，导航栏为普通元素，需要将组件移动到导航栏的下边沿
					// H5的导航栏高度为44px
					top = 44
					// #endif
				}
				const style = {
					top: this.$uv.addUnit(this.tmpConfig.top === 0 ? top : this.tmpConfig.top),
					// 因为组件底层为uv-transition组件，必须将其设置为fixed定位
					// 让其出现在导航栏底部
					position: 'fixed',
					left: 0,
					right: 0,
					zIndex: 10076
				}
				return style
			},
			// 组件背景颜色
			backgroundColor() {
				const style = {}
				if (this.tmpConfig.bgColor) {
					style.backgroundColor = this.tmpConfig.bgColor
				}
				return style
			},
			// 默认主题下的图标
			icon() {
				let icon
				if (this.tmpConfig.type === 'success') {
					icon = 'checkmark-circle'
				} else if (this.tmpConfig.type === 'error') {
					icon = 'close-circle'
				} else if (this.tmpConfig.type === 'warning') {
					icon = 'error-circle'
				}
				return icon
			}
		},
		created() {
			// 通过主题的形式调用toast，批量生成方法函数
			['primary', 'success', 'error', 'warning'].map(item => {
				this[item] = message => this.show({
					type: item,
					message
				})
			})
		},
		methods: {
			show(options) {
				// 不将结果合并到this.config变量，避免多次调用uv-toast，前后的配置造成混乱
				this.tmpConfig = this.$uv.deepMerge(this.config, options)
				// 任何定时器初始化之前，都要执行清除操作，否则可能会造成混乱
				this.clearTimer()
				this.open = true
				if (this.tmpConfig.duration > 0) {
					this.timer = setTimeout(() => {
						this.open = false
						// 倒计时结束，清除定时器，隐藏toast组件
						this.clearTimer()
						// 判断是否存在callback方法，如果存在就执行
						typeof(this.tmpConfig.complete) === 'function' && this.tmpConfig.complete()
					}, this.tmpConfig.duration)
				}
			},
			// 关闭notify
			close() {
				this.clearTimer()
			},
			clearTimer() {
				this.open = false
				// 清除定时器
				clearTimeout(this.timer)
				this.timer = null
			}
		},
		// #ifdef VUE2
		beforeDestroy() {
			this.clearTimer()
		},
		// #endif
		// #ifdef VUE3
		unmounted() {
			this.clearTimer()
		}
		// #endif
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-notify-padding: 8px 10px !default;
	$uv-notify-text-font-size: 15px !default;
	$uv-notify-primary-bgColor: $uv-primary !default;
	$uv-notify-success-bgColor: $uv-success !default;
	$uv-notify-error-bgColor: $uv-error !default;
	$uv-notify-warning-bgColor: $uv-warning !default;


	.uv-notify {
		padding: $uv-notify-padding;

		&__warpper {
			@include flex;
			align-items: center;
			text-align: center;
			justify-content: center;

			&__text {
				font-size: $uv-notify-text-font-size;
				text-align: center;
			}
		}

		&--primary {
			background-color: $uv-notify-primary-bgColor;
		}

		&--success {
			background-color: $uv-notify-success-bgColor;
		}

		&--error {
			background-color: $uv-notify-error-bgColor;
		}

		&--warning {
			background-color: $uv-notify-warning-bgColor;
		}
	}
</style>
|K	1x n## Notify 消息提示^notify**

该组件一般用于页面顶部向下滑出一个提示，后自动收起的场景1notifyZT	x e100644 changelog.md ?W|6u2(U|Q40000 components !Z?[Mr}\TU%100644 package.json wnvRp(100644 readme.md kڕpնƨ:7?x( 40000 uv-number-box AWHY}|ڠgij#8xQ 100644 props.js d3E<0Lajv100644 uv-number-box.vue i7r+GB,qhSJMuxexport default {
	props: {
		value: {
			type: [String, Number],
			default: 0
		},
		modelValue: {
			type: [String, Number],
			default: 0
		},
		// 步进器标识符，在change回调返回
		name: {
			type: [String, Number],
			default: ''
		},
		// 最小值
		min: {
			type: [String, Number],
			default: 1
		},
		// 最大值
		max: {
			type: [String, Number],
			default: Number.MAX_SAFE_INTEGER
		},
		// 加减的步长，可为小数
		step: {
			type: [String, Number],
			default: 1
		},
		// 是否只允许输入整数
		integer: {
			type: Boolean,
			default: false
		},
		// 是否禁用，包括输入框，加减按钮
		disabled: {
			type: Boolean,
			default: false
		},
		// 是否禁用输入框
		disabledInput: {
			type: Boolean,
			default: false
		},
		// 是否开启异步变更，开启后需要手动控制输入值
		asyncChange: {
			type: Boolean,
			default: false
		},
		// 输入框宽度，单位为px
		inputWidth: {
			type: [String, Number],
			default: 35
		},
		// 是否显示减少按钮
		showMinus: {
			type: Boolean,
			default: true
		},
		// 是否显示增加按钮
		showPlus: {
			type: Boolean,
			default: true
		},
		// 显示的小数位数
		decimalLength: {
			type: [String, Number, null],
			default: null
		},
		// 是否开启长按加减手势
		longPress: {
			type: Boolean,
			default: true
		},
		// 输入框文字和加减按钮图标的颜色
		color: {
			type: String,
			default: '#323233'
		},
		// 按钮大小，宽高等于此值，单位px，输入框高度和此值保持一致
		buttonSize: {
			type: [String, Number],
			default: 30
		},
		// 输入框和按钮的背景颜色
		bgColor: {
			type: String,
			default: '#EBECEE'
		},
		// 指定光标于键盘的距离，避免键盘遮挡输入框，单位px
		cursorSpacing: {
			type: [String, Number],
			default: 100
		},
		// 是否禁用增加按钮
		disablePlus: {
			type: Boolean,
			default: false
		},
		// 是否禁用减少按钮
		disableMinus: {
			type: Boolean,
			default: false
		},
		// 加减按钮图标的样式
		iconStyle: {
			type: [Object, String],
			default: ''
		},
		...uni.$uv?.props?.numberBox
	}
};rx0x<template>
	<view class="uv-number-box">
		<view
		  class="uv-number-box__slot"
		  @tap.stop="clickHandler('minus')"
		  @touchstart="onTouchStart('minus')"
		  @touchend.stop="clearTimeout"
		  v-if="showMinus && $slots.minus"
		>
			<slot name="minus" />
		</view>
		<view
		  v-else-if="showMinus"
		  class="uv-number-box__minus"
		  @tap.stop="clickHandler('minus')"
		  @touchstart="onTouchStart('minus')"
		  @touchend.stop="clearTimeout"
		  hover-class="uv-number-box__minus--hover"
		  hover-stay-time="150"
		  :class="{ 'uv-number-box__minus--disabled': isDisabled('minus') }"
		  :style="[buttonStyle('minus')]"
		>
			<uv-icon
			  name="minus"
			  :color="isDisabled('minus') ? '#c8c9cc' : '#323233'"
			  size="15"
			  bold
				:customStyle="iconStyle"
			></uv-icon>
		</view>
		<slot name="input">
			<input
			  :disabled="disabledInput || disabled"
			  :cursor-spacing="getCursorSpacing"
			  :class="{ 'uv-number-box__input--disabled': disabled || disabledInput }"
			  v-model="currentValue"
			  class="uv-number-box__input"
			  @blur="onBlur"
			  @focus="onFocus"
			  @input="onInput"
			  type="number"
			  :style="[inputStyle]"
			/>
		</slot>
		<view
		  class="uv-number-box__slot"
		  @tap.stop="clickHandler('plus')"
		  @touchstart="onTouchStart('plus')"
		  @touchend.stop="clearTimeout"
		  v-if="showPlus && $slots.plus"
		>
			<slot name="plus" />
		</view>
		<view
		  v-else-if="showPlus"
		  class="uv-number-box__plus"
		  @tap.stop="clickHandler('plus')"
		  @touchstart="onTouchStart('plus')"
		  @touchend.stop="clearTimeout"
		  hover-class="uv-number-box__plus--hover"
		  hover-stay-time="150"
		  :class="{ 'uv-number-box__minus--disabled': isDisabled('plus') }"
		  :style="[buttonStyle('plus')]"
		>
			<uv-icon
			  name="plus"
			  :color="isDisabled('plus') ? '#c8c9cc' : '#323233'"
			  size="15"
			  bold
				:customStyle="iconStyle"
			></uv-icon>
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * numberBox 步进器
	 * @description 该组件一般用于商城购物选择物品数量的场景。
	 * @tutorial https://www.uvui.cn/components/numberBox.html
	 * @property {String | Number}	value / v-model			用于双向绑定的值，初始化时设置设为默认min值(最小值)  （默认 0 ）
	 * @property {String | Number}	name			步进器标识符，在change回调返回
	 * @property {String | Number}	min				最小值 （默认 1 ）
	 * @property {String | Number}	max				最大值 （默认 Number.MAX_SAFE_INTEGER ）
	 * @property {String | Number}	step			加减的步长，可为小数 （默认 1 ）
	 * @property {Boolean}			integer			是否只允许输入整数 （默认 false ）
	 * @property {Boolean}			disabled		是否禁用，包括输入框，加减按钮 （默认 false ）
	 * @property {Boolean}			disabledInput	是否禁用输入框 （默认 false ）
	 * @property {Boolean}			asyncChange		是否开启异步变更，开启后需要手动控制输入值 （默认 false ）
	 * @property {String | Number}	inputWidth		输入框宽度，单位为px （默认 35 ）
	 * @property {Boolean}			showMinus		是否显示减少按钮 （默认 true ）
	 * @property {Boolean}			showPlus		是否显示增加按钮 （默认 true ）
	 * @property {String | Number}	decimalLength	显示的小数位数
	 * @property {Boolean}			longPress		是否开启长按加减手势 （默认 true ）
	 * @property {String}			color			输入框文字和加减按钮图标的颜色 （默认 '#323233' ）
	 * @property {String | Number}	buttonSize		按钮大小，宽高等于此值，单位px，输入框高度和此值保持一致 （默认 30 ）
	 * @property {String}			bgColor			输入框和按钮的背景颜色 （默认 '#EBECEE' ）
	 * @property {String | Number}	cursorSpacing	指定光标于键盘的距离，避免键盘遮挡输入框，单位px （默认 100 ）
	 * @property {Boolean}			disablePlus		是否禁用增加按钮 （默认 false ）
	 * @property {Boolean}			disableMinus	是否禁用减少按钮 （默认 false ）
	 * @property {Object ｜ String}	iconStyle		加减按钮图标的样式
	 * @event {Function}	onFocus	输入框活动焦点
	 * @event {Function}	onBlur	输入框失去焦点
	 * @event {Function}	onInput	输入框值发生变化
	 * @event {Function}	onChange
	 * @example <uv-number-box v-model="value" @change="valChange"></uv-number-box>
	 */
	export default {
		name: 'uv-number-box',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 输入框实际操作的值
				currentValue: '',
				// 定时器
				longPressTimer: null
			}
		},
		watch: {
			// 多个值之间，只要一个值发生变化，都要重新检查check()函数
			watchChange(n) {
				this.check()
			},
			value(newVal) {
				if (newVal !== this.currentValue) {
					this.currentValue = this.format(this.value)
				}
			},
			modelValue(newVal) {
				if (newVal !== this.currentValue) {
					this.currentValue = this.format(this.modelValue)
				}
			}
		},
		computed: {
			getCursorSpacing() {
				// 判断传入的单位，如果为px单位，需要转成px
				return this.$uv.getPx(this.cursorSpacing)
			},
			// 按钮的样式
			buttonStyle() {
				return (type) => {
					const style = {
						backgroundColor: this.bgColor,
						height: this.$uv.addUnit(this.buttonSize),
						color: this.color
					}
					if (this.isDisabled(type)) {
						style.backgroundColor = '#f7f8fa'
					}
					return style
				}
			},
			// 输入框的样式
			inputStyle() {
				const disabled = this.disabled || this.disabledInput
				const style = {
					color: this.color,
					backgroundColor: this.bgColor,
					height: this.$uv.addUnit(this.buttonSize),
					width: this.$uv.addUnit(this.inputWidth)
				}
				return style
			},
			// 用于监听多个值发生变化
			watchChange() {
				return [this.integer, this.decimalLength, this.min, this.max]
			},
			isDisabled() {
				return (type) => {
					if (type === 'plus') {
						// 在点击增加按钮情况下，判断整体的disabled，是否单独禁用增加按钮，以及当前值是否大于最大的允许值
						return (
							this.disabled ||
							this.disablePlus ||
							this.currentValue >= this.max
						)
					}
					// 点击减少按钮同理
					return (
						this.disabled ||
						this.disableMinus ||
						this.currentValue <= this.min
					)
				}
			},
		},
		created() {
			this.init()
		},
		methods: {
			init() {
				const value = this.value || this.modelValue;
				this.currentValue = this.format(value)
			},
			// 格式化整理数据，限制范围
			format(value) {
				value = this.filter(value)
				// 如果为空字符串，那么设置为0，同时将值转为Number类型
				value = value === '' ? 0 : +value
				// 对比最大最小值，取在min和max之间的值
				value = Math.max(Math.min(this.max, value), this.min)
				// 如果设定了最大的小数位数，使用toFixed去进行格式化
				if (this.decimalLength !== null) {
					value = value.toFixed(this.decimalLength)
				}
				return value
			},
			// 过滤非法的字符
			filter(value) {
				// 只允许0-9之间的数字，"."为小数点，"-"为负数时候使用
				value = String(value).replace(/[^0-9.-]/g, '')
				// 如果只允许输入整数，则过滤掉小数点后的部分
				if (this.integer && value.indexOf('.') !== -1) {
					value = value.split('.')[0]
				}
				return value;
			},
			check() {
				// 格式化了之后，如果前后的值不相等，那么设置为格式化后的值
				const val = this.format(this.currentValue);
				if (val !== this.currentValue) {
					this.currentValue = val
				}
			},
			// 输入框活动焦点
			onFocus(event) {
				this.$emit('focus', {
					...event.detail,
					name: this.name,
				})
			},
			// 输入框失去焦点
			onBlur(event) {
				// 对输入值进行格式化
				const value = this.format(event.detail.value)
				// 发出blur事件
				this.$emit(
					'blur', {
						...event.detail,
						name: this.name,
					}
				)
			},
			// 输入框值发生变化
			onInput(e) {
				const {
					value = ''
				} = e.detail || {}
				// 为空返回
				if (value === '') return
				let formatted = this.filter(value)
				// 最大允许的小数长度
				if (this.decimalLength !== null && formatted.indexOf('.') !== -1) {
					const pair = formatted.split('.');
					formatted = `${pair[0]}.${pair[1].slice(0, this.decimalLength)}`
				}
				formatted = this.format(formatted)
				this.emitChange(formatted);
			},
			// 发出change事件
			emitChange(value) {
				// 如果开启了异步变更值，则不修改内部的值，需要用户手动在外部通过v-model变更
				if (!this.asyncChange) {
					this.$nextTick(() => {
						this.$emit('input', value)
						this.$emit('update:modelValue', value)
						this.currentValue = value
						this.$forceUpdate()
					})
				}
				this.$emit('change', {
					value,
					name: this.name,
				});
			},
			onChange() {
				const {
					type
				} = this
				if (this.isDisabled(type)) {
					return this.$emit('overlimit', type)
				}
				const diff = type === 'minus' ? -this.step : +this.step
				const value = this.format(this.add(+this.currentValue, diff))
				this.emitChange(value)
				this.$emit(type)
			},
			// 对值扩大后进行四舍五入，再除以扩大因子，避免出现浮点数操作的精度问题
			add(num1, num2) {
				const cardinal = Math.pow(10, 10);
				return Math.round((num1 + num2) * cardinal) / cardinal
			},
			// 点击加减按钮
			clickHandler(type) {
				this.type = type
				this.onChange()
			},
			longPressStep() {
				// 每隔一段时间，重新调用longPressStep方法，实现长按加减
				this.clearTimeout()
				this.longPressTimer = setTimeout(() => {
					this.onChange()
					this.longPressStep()
				}, 250);
			},
			onTouchStart(type) {
				if (!this.longPress) return
				this.clearTimeout()
				this.type = type
				// 一定时间后，默认达到长按状态
				this.longPressTimer = setTimeout(() => {
					this.onChange()
					this.longPressStep()
				}, 600)
			},
			// 触摸结束，清除定时器，停止长按加减
			onTouchEnd() {
				if (!this.longPress) return
				this.clearTimeout()
			},
			// 清除定时器
			clearTimeout() {
				clearTimeout(this.longPressTimer)
				this.longPressTimer = null
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-numberBox-hover-bgColor: #E6E6E6 !default;
	$uv-numberBox-disabled-color: #c8c9cc !default;
	$uv-numberBox-disabled-bgColor: #f7f8fa !default;
	$uv-numberBox-plus-radius: 4px !default;
	$uv-numberBox-minus-radius: 4px !default;
	$uv-numberBox-input-text-align: center !default;
	$uv-numberBox-input-font-size: 15px !default;
	$uv-numberBox-input-padding: 0 !default;
	$uv-numberBox-input-margin: 0 2px !default;
	$uv-numberBox-input-disabled-color: #c8c9cc !default;
	$uv-numberBox-input-disabled-bgColor: #f2f3f5 !default;
	.uv-number-box {
		@include flex(row);
		align-items: center;
		&__slot {
			/* #ifndef APP-NVUE */
			touch-action: none;
			/* #endif */
		}
		&__plus,
		&__minus {
			width: 35px;
			@include flex;
			justify-content: center;
			align-items: center;
			/* #ifndef APP-NVUE */
			touch-action: none;
			/* #endif */
			&--hover {
				background-color: $uv-numberBox-hover-bgColor !important;
			}
			&--disabled {
				color: $uv-numberBox-disabled-color;
				background-color: $uv-numberBox-disabled-bgColor;
			}
		}
		&__plus {
			border-top-right-radius: $uv-numberBox-plus-radius;
			border-bottom-right-radius: $uv-numberBox-plus-radius;
		}
		&__minus {
			border-top-left-radius: $uv-numberBox-minus-radius;
			border-bottom-left-radius: $uv-numberBox-minus-radius;
		}
		&__input {
			position: relative;
			text-align: $uv-numberBox-input-text-align;
			font-size: $uv-numberBox-input-font-size;
			padding: $uv-numberBox-input-padding;
			margin: $uv-numberBox-input-margin;
			@include flex;
			align-items: center;
			justify-content: center;
			&--disabled {
				color: $uv-numberBox-input-disabled-color;
				background-color: $uv-numberBox-input-disabled-bgColor;
			}
		}
	}
</style>.y[x &D{
  "id": "uv-number-box",
  "displayName": "uv-number-box 步进器?JW2",
  "description": "uv-number-box 该组件一般用于商城购物选择物品数量(	umber-box!"umber",
    "步进器\icq(_gxl 5## NumberBox 步进器

> **组件名：uv-number-box1商城购物选择物品数量;umberBoxOW7	x e100644 changelog.md q8t5{&_n^-40000 components ٩NZƧ=100644 package.json dqW z^100644 readme.md NWFՎr.ց֮I@.xo## 1.0.3（2023-07-02）
uv-overlay  由于弹出层uv-transition的修改，组件内部做了相应的修改，参数不变。
## 1.0.2（2023-06-29）
1. 优化，H5端禁止穿透滚动
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
1. 新增uv-overlay组件
(v5x% 40000 uv-overlay kH")kg(p:5xN 100644 props.js &|a?qzJU-oHA100644 uv-overlay.vue SVcE*uSHgxOexport default {
	props: {
		// 是否显示遮罩
		show: {
			type: Boolean,
			default: false
		},
		// 层级z-index
		zIndex: {
			type: [String, Number],
			default: 10070
		},
		// 遮罩的过渡时间，单位为ms
		duration: {
			type: [String, Number],
			default: 300
		},
		// 不透明度值，当做rgba的第四个参数
		opacity: {
			type: [String, Number],
			default: 0.5
		},
		...uni.$uv?.props?.overlay
	}
}x8	<template>
	<uv-transition
	  :show="show"
		mode="fade"
	  custom-class="uv-overlay"
	  :duration="duration"
	  :custom-style="overlayStyle"
	  @click="clickHandler"
		@touchmove.stop.prevent="clear"
	>
		<slot />
	</uv-transition>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';

	/**
	 * overlay 遮罩
	 * @description 创建一个遮罩层，用于强调特定的页面元素，并阻止用户对遮罩下层的内容进行操作，一般用于弹窗场景
	 * @tutorial https://www.uvui.cn/components/overlay.html
	 * @property {Boolean}			show		是否显示遮罩（默认 false ）
	 * @property {String | Number}	zIndex		zIndex 层级（默认 10070 ）
	 * @property {String | Number}	duration	动画时长，单位毫秒（默认 300 ）
	 * @property {String | Number}	opacity		不透明度值，当做rgba的第四个参数 （默认 0.5 ）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * @event {Function} click 点击遮罩发送事件
	 * @example <uv-overlay :show="show" @click="show = false"></uv-overlay>
	 */
	export default {
		name: "uv-overlay",
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		watch: {
			show(newVal){
				// #ifdef H5
				if(newVal){
					document.querySelector('body').style.overflow = 'hidden';
				}else{
					document.querySelector('body').style.overflow = '';
				}
				// #endif
			}
		},
		computed: {
			overlayStyle() {
				const style = {
					position: 'fixed',
					top: 0,
					left: 0,
					right: 0,
					zIndex: this.zIndex,
					bottom: 0,
					'background-color': `rgba(0, 0, 0, ${this.opacity})`
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		methods: {
			clickHandler() {
				this.$emit('click')
			},
			clear() {}
		}
	}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
$uv-overlay-top:0 !default;
$uv-overlay-left:0 !default;
$uv-overlay-width:100% !default;
$uv-overlay-height:100% !default;
$uv-overlay-background-color:rgba(0, 0, 0, .7) !default;
.uv-overlay {
	position: fixed;
	top:$uv-overlay-top;
	left:$uv-overlay-left;
	width: $uv-overlay-width;
	height:$uv-overlay-height;
	background-color:$uv-overlay-background-color;
}
/* #endif */
</style>
g+q\xs>{
  "id": "uv-overlay",
  "displayName": "uv-overlay 遮罩层9J3",
  "description": "uv-overlay 创建一个遮罩层，用于强调特定的页面元素，并阻止用户对遮罩下层的容进行操作，一般用于弹窗场景，uv-popup、uv-toast、uv-tooltip等组件就是用了该组件。",
  "keywords"overla"overlay",
    "遮罩层,
			"uv-transition
πbx	## Overlay 遮罩层overlay**

创建一个遮罩层，用于强调特定的页面元素，并阻止用户对遮罩下层的内容进行操作，W般用于弹窗场景，uv-popup、uv-toast、uv-tooltip等组件就是用了该组件1overlayZ<x D100644 changelog.md EuxcƢ3.ѩX40000 components 5ݞ8h<s6@xw-voi100644 package.json D:؍}Q=U100644 readme.md xs{{4_iL40000 static QaMSF1<If4ߐMxj## 1.0.4（2023-07-17）
1. 优化文档
2. 优化其他
## 1.0.3（2023-06-19）
1. 修复nvue模式下不显示的BUG
## 1.0.2（2023-06-02）
1. 修复可能存在的BUG
2. 优化
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-parse 富文本解析器
m(x# 40000 uv-parse Tuap&=ʒ;xl 40000 node 1}[3@Hߦ &SW100644 parser.js }#OnGCU100644 uv-parse.vue *l? )m;26z.(Qx$ 100644 node.vue XWq7ʍ2Ѡě#x=-<template>
  <view :id="attrs.id" :class="'_block _'+name+' '+attrs.class" :style="attrs.style">
    <block v-for="(n, i) in childs" v-bind:key="i">
      <!-- 图片 -->
      <!-- 占位图 -->
      <image v-if="n.name==='img'&&!n.t&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
      <!-- 显示图片 -->
      <!-- #ifdef H5 || (APP-PLUS && VUE2) -->
      <img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
      <!-- #endif -->
      <!-- #ifndef H5 || (APP-PLUS && VUE2) -->
      <!-- 表格中的图片，使用 rich-text 防止大小不正确 -->
      <rich-text v-if="n.name==='img'&&n.t" :style="'display:'+n.t" :nodes="[{attrs:{style:n.attrs.style,src:n.attrs.src},name:'img'}]" :data-i="i" @tap.stop="imgTap" />
      <!-- #endif -->
      <!-- #ifndef H5 || APP-PLUS -->
      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
      <!-- #endif -->
      <!-- #ifdef APP-PLUS && VUE3 -->
      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
      <!-- #endif -->
      <!-- 文本 -->
      <!-- #ifdef MP-WEIXIN -->
      <text v-else-if="n.text" :user-select="opts[4]=='force'&&isiOS" decode>{{n.text}}</text>
      <!-- #endif -->
      <!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
      <text v-else-if="n.text" decode>{{n.text}}</text>
      <!-- #endif -->
      <text v-else-if="n.name==='br'">\n</text>
      <!-- 链接 -->
      <view v-else-if="n.name==='a'" :id="n.attrs.id" :class="(n.attrs.href?'_a ':'')+n.attrs.class" hover-class="_hover" :style="'display:inline;'+n.attrs.style" :data-i="i" @tap.stop="linkTap">
        <node name="span" :childs="n.children" :opts="opts" style="display:inherit" />
      </view>
      <!-- 视频 -->
      <!-- #ifdef APP-PLUS -->
      <view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
      <!-- #endif -->
      <!-- #ifndef APP-PLUS -->
      <video v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
      <!-- #endif -->
      <!-- #ifdef H5 || APP-PLUS -->
      <iframe v-else-if="n.name==='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
      <embed v-else-if="n.name==='embed'" :style="n.attrs.style" :src="n.attrs.src" />
      <!-- #endif -->
      <!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
      <!-- 音频 -->
      <audio v-else-if="n.name==='audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
      <!-- #endif -->
      <view v-else-if="(n.name==='table'&&n.c)||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
        <node v-if="n.name==='li'" :childs="n.children" :opts="opts" />
        <view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
          <node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="opts" />
          <block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
            <view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
              <node :childs="tr.children" :opts="opts" />
            </view>
            <view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
              <view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
                <node :childs="td.children" :opts="opts" />
              </view>
            </view>
          </block>
        </view>
      </view>
      
      <!-- 富文本 -->
      <!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
      <rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
      <!-- #endif -->
      <!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
      <rich-text v-else-if="!n.c" :id="n.attrs.id" :style="'display:inline;'+n.f" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
      <!-- #endif -->
      <!-- 继续递归 -->
      <view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
        <node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs" :childs="n2.children" :opts="opts" />
      </view>
      <node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="opts" />
    </block>
  </view>
</template>
<script module="handler" lang="wxs">
// 行内标签列表
var inlineTags = {
  abbr: true,
  b: true,
  big: true,
  code: true,
  del: true,
  em: true,
  i: true,
  ins: true,
  label: true,
  q: true,
  small: true,
  span: true,
  strong: true,
  sub: true,
  sup: true
}
/**
 * @description 判断是否为行内标签
 */
module.exports = {
  isInline: function (tagName, style) {
    return inlineTags[tagName] || (style || '').indexOf('display:inline') !== -1
  }
}
</script>
<script>

import node from './node'
export default {
  name: 'node',
  options: {
    // #ifdef MP-WEIXIN
    virtualHost: true,
    // #endif
    // #ifdef MP-TOUTIAO
    addGlobalClass: false
    // #endif
  },
  data () {
    return {
      ctrl: {},
      // #ifdef MP-WEIXIN
      isiOS: uni.getSystemInfoSync().system.includes('iOS')
      // #endif
    }
  },
  props: {
    name: String,
    attrs: {
      type: Object,
      default () {
        return {}
      }
    },
    childs: Array,
    opts: Array
  },
  components: {

    // #ifndef (H5 || APP-PLUS) && VUE3
    node
    // #endif
  },
  mounted () {
    this.$nextTick(() => {
      for (this.root = this.$parent; this.root.$options.name !== 'uv-parse'; this.root = this.root.$parent);
    })
    // #ifdef H5 || APP-PLUS
    if (this.opts[0]) {
      let i
      for (i = this.childs.length; i--;) {
        if (this.childs[i].name === 'img') break
      }
      if (i !== -1) {
        this.observer = uni.createIntersectionObserver(this).relativeToViewport({
          top: 500,
          bottom: 500
        })
        this.observer.observe('._img', res => {
          if (res.intersectionRatio) {
            this.$set(this.ctrl, 'load', 1)
            this.observer.disconnect()
          }
        })
      }
    }
    // #endif
  },
  beforeDestroy () {
    // #ifdef H5 || APP-PLUS
    if (this.observer) {
      this.observer.disconnect()
    }
    // #endif
  },
  methods:{
    // #ifdef MP-WEIXIN
    toJSON () { return this },
    // #endif
    /**
     * @description 播放视频事件
     * @param {Event} e
     */
    play (e) {
      this.root.$emit('play')
      // #ifndef APP-PLUS
      if (this.root.pauseVideo) {
        let flag = false
        const id = e.target.id
        for (let i = this.root._videos.length; i--;) {
          if (this.root._videos[i].id === id) {
            flag = true
          } else {
            this.root._videos[i].pause() // 自动暂停其他视频
          }
        }
        // 将自己加入列表
        if (!flag) {
          const ctx = uni.createVideoContext(id
            // #ifndef MP-BAIDU
            , this
            // #endif
          )
          ctx.id = id
          if (this.root.playbackRate) {
            ctx.playbackRate(this.root.playbackRate)
          }
          this.root._videos.push(ctx)
        }
      }
      // #endif
    },

    /**
     * @description 图片点击事件
     * @param {Event} e
     */
    imgTap (e) {
      const node = this.childs[e.currentTarget.dataset.i]
      if (node.a) {
        this.linkTap(node.a)
        return
      }
      if (node.attrs.ignore) return
      // #ifdef H5 || APP-PLUS
      node.attrs.src = node.attrs.src || node.attrs['data-src']
      // #endif
      this.root.$emit('imgtap', node.attrs)
      // 自动预览图片
      if (this.root.previewImg) {
        uni.previewImage({
          // #ifdef MP-WEIXIN
          showmenu: this.root.showImgMenu,
          // #endif
          // #ifdef MP-ALIPAY
          enablesavephoto: this.root.showImgMenu,
          enableShowPhotoDownload: this.root.showImgMenu,
          // #endif
          current: parseInt(node.attrs.i),
          urls: this.root.imgList
        })
      }
    },

    /**
     * @description 图片长按
     */
    imgLongTap (e) {
      // #ifdef APP-PLUS
      const attrs = this.childs[e.currentTarget.dataset.i].attrs
      if (this.opts[3] && !attrs.ignore) {
        uni.showActionSheet({
          itemList: ['保存图片'],
          success: () => {
            const save = path => {
              uni.saveImageToPhotosAlbum({
                filePath: path,
                success () {
                  uni.showToast({
                    title: '保存成功'
                  })
                }
              })
            }
            if (this.root.imgList[attrs.i].startsWith('http')) {
              uni.downloadFile({
                url: this.root.imgList[attrs.i],
                success: res => save(res.tempFilePath)
              })
            } else {
              save(this.root.imgList[attrs.i])
            }
          }
        })
      }
      // #endif
    },

    /**
     * @description 图片加载完成事件
     * @param {Event} e
     */
    imgLoad (e) {
      const i = e.currentTarget.dataset.i
      /* #ifndef H5 || (APP-PLUS && VUE2) */
      if (!this.childs[i].w) {
        // 设置原宽度
        this.$set(this.ctrl, i, e.detail.width)
      } else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
        // 加载完毕，取消加载中占位图
        this.$set(this.ctrl, i, 1)
      }
      this.checkReady()
    },

    /**
     * @description 检查是否所有图片加载完毕
     */
    checkReady () {
      if (this.root && !this.root.lazyLoad) {
        this.root._unloadimgs -= 1
        if (!this.root._unloadimgs) {
          setTimeout(() => {
            this.root.getRect().then(rect => {
              this.root.$emit('ready', rect)
            }).catch(() => {
              this.root.$emit('ready', {})
            })
          }, 350)
        }
      }
    },

    /**
     * @description 链接点击事件
     * @param {Event} e
     */
    linkTap (e) {
      const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
      const attrs = node.attrs || e
      const href = attrs.href
      this.root.$emit('linktap', Object.assign({
        innerText: this.root.getText(node.children || []) // 链接内的文本内容
      }, attrs))
      if (href) {
        if (href[0] === '#') {
          // 跳转锚点
          this.root.navigateTo(href.substring(1)).catch(() => { })
        } else if (href.split('?')[0].includes('://')) {
          // 复制外部链接
          if (this.root.copyLink) {
            // #ifdef H5
            window.open(href)
            // #endif
            // #ifdef MP
            uni.setClipboardData({
              data: href,
              success: () =>
                uni.showToast({
                  title: '链接已复制'
                })
            })
            // #endif
            // #ifdef APP-PLUS
            plus.runtime.openWeb(href)
            // #endif
          }
        } else {
          // 跳转页面
          uni.navigateTo({
            url: href,
            fail () {
              uni.switchTab({
                url: href,
                fail () { }
              })
            }
          })
        }
      }
    },

    /**
     * @description 错误事件
     * @param {Event} e
     */
    mediaError (e) {
      const i = e.currentTarget.dataset.i
      const node = this.childs[i]
      // 加载其他源
      if (node.name === 'video' || node.name === 'audio') {
        let index = (this.ctrl[i] || 0) + 1
        if (index > node.src.length) {
          index = 0
        }
        if (index < node.src.length) {
          this.$set(this.ctrl, i, index)
          return
        }
      } else if (node.name === 'img') {
        // #ifdef H5 && VUE3
        if (this.opts[0] && !this.ctrl.load) return
        // #endif
        // 显示错误占位图
        if (this.opts[2]) {
          this.$set(this.ctrl, i, -1)
        }
        this.checkReady()
      }
      if (this.root) {
        this.root.$emit('error', {
          source: node.name,
          attrs: node.attrs,
          // #ifndef H5 && VUE3
          errMsg: e.detail.errMsg
          // #endif
        })
      }
    }
  }
}
</script>
<style>
/* a 标签默认效果 */
._a {
  padding: 1.5px 0 1.5px 0;
  color: #366092;
  word-break: break-all;
}

/* a 标签点击态效果 */
._hover {
  text-decoration: underline;
  opacity: 0.7;
}

/* 图片默认效果 */
._img {
  max-width: 100%;
  -webkit-touch-callout: none;
}

/* 内部样式 */

._block {
  display: block;
}

._b,
._strong {
  font-weight: bold;
}

._code {
  font-family: monospace;
}

._del {
  text-decoration: line-through;
}

._em,
._i {
  font-style: italic;
}

._h1 {
  font-size: 2em;
}

._h2 {
  font-size: 1.5em;
}

._h3 {
  font-size: 1.17em;
}

._h5 {
  font-size: 0.83em;
}

._h6 {
  font-size: 0.67em;
}

._h1,
._h2,
._h3,
._h4,
._h5,
._h6 {
  display: block;
  font-weight: bold;
}

._image {
  height: 1px;
}

._ins {
  text-decoration: underline;
}

._li {
  display: list-item;
}

._ol {
  list-style-type: decimal;
}

._ol,
._ul {
  display: block;
  padding-left: 40px;
  margin: 1em 0;
}

._q::before {
  content: '"';
}

._q::after {
  content: '"';
}

._sub {
  font-size: smaller;
  vertical-align: sub;
}

._sup {
  font-size: smaller;
  vertical-align: super;
}

._thead,
._tbody,
._tfoot {
  display: table-row-group;
}

._tr {
  display: table-row;
}

._td,
._th {
  display: table-cell;
  vertical-align: middle;
}

._th {
  font-weight: bold;
  text-align: center;
}

._ul {
  list-style-type: disc;
}

._ul ._ul {
  margin: 0;
  list-style-type: circle;
}

._ul ._ul ._ul {
  list-style-type: square;
}

._abbr,
._b,
._code,
._del,
._em,
._i,
._ins,
._label,
._q,
._span,
._strong,
._sub,
._sup {
  display: inline;
}

/* #ifdef APP-PLUS */
._video {
  width: 300px;
  height: 225px;
}
/* #endif */
</style>x`c/**
 * @fileoverview html 解析器
 */

// 配置
const config = {
  // 信任的标签（保持标签名不变）
  trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),

  // 块级标签（转为 div，其他的非信任标签转为 span）
  blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),

  // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
  // 行内标签
  inlineTags: makeMap('abbr,b,big,code,del,em,i,ins,label,q,small,span,strong,sub,sup'),
  // #endif

  // 要移除的标签
  ignoreTags: makeMap('area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr'),

  // 自闭合的标签
  voidTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),

  // html 实体
  entities: {
    lt: '<',
    gt: '>',
    quot: '"',
    apos: "'",
    ensp: '\u2002',
    emsp: '\u2003',
    nbsp: '\xA0',
    semi: ';',
    ndash: '–',
    mdash: '—',
    middot: '·',
    lsquo: '‘',
    rsquo: '’',
    ldquo: '“',
    rdquo: '”',
    bull: '•',
    hellip: '…',
    larr: '←',
    uarr: '↑',
    rarr: '→',
    darr: '↓'
  },

  // 默认的标签样式
  tagStyle: {
    // #ifndef APP-PLUS-NVUE
    address: 'font-style:italic',
    big: 'display:inline;font-size:1.2em',
    caption: 'display:table-caption;text-align:center',
    center: 'text-align:center',
    cite: 'font-style:italic',
    dd: 'margin-left:40px',
    mark: 'background-color:yellow',
    pre: 'font-family:monospace;white-space:pre',
    s: 'text-decoration:line-through',
    small: 'display:inline;font-size:0.8em',
    strike: 'text-decoration:line-through',
    u: 'text-decoration:underline'
    // #endif
  },

  // svg 大小写对照表
  svgDict: {
    animatetransform: 'animateTransform',
    lineargradient: 'linearGradient',
    viewbox: 'viewBox',
    attributename: 'attributeName',
    repeatcount: 'repeatCount',
    repeatdur: 'repeatDur'
  }
}
const tagSelector={}
const {
  windowWidth,
  // #ifdef MP-WEIXIN
  system
  // #endif
} = uni.getSystemInfoSync()
const blankChar = makeMap(' ,\r,\n,\t,\f')
let idIndex = 0

// #ifdef H5 || APP-PLUS
config.ignoreTags.iframe = undefined
config.trustTags.iframe = true
config.ignoreTags.embed = undefined
config.trustTags.embed = true
// #endif
// #ifdef APP-PLUS-NVUE
config.ignoreTags.source = undefined
config.ignoreTags.style = undefined
// #endif

/**
 * @description 创建 map
 * @param {String} str 逗号分隔
 */
function makeMap (str) {
  const map = Object.create(null)
  const list = str.split(',')
  for (let i = list.length; i--;) {
    map[list[i]] = true
  }
  return map
}

/**
 * @description 解码 html 实体
 * @param {String} str 要解码的字符串
 * @param {Boolean} amp 要不要解码 &amp;
 * @returns {String} 解码后的字符串
 */
function decodeEntity (str, amp) {
  let i = str.indexOf('&')
  while (i !== -1) {
    const j = str.indexOf(';', i + 3)
    let code
    if (j === -1) break
    if (str[i + 1] === '#') {
      // &#123; 形式的实体
      code = parseInt((str[i + 2] === 'x' ? '0' : '') + str.substring(i + 2, j))
      if (!isNaN(code)) {
        str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1)
      }
    } else {
      // &nbsp; 形式的实体
      code = str.substring(i + 1, j)
      if (config.entities[code] || (code === 'amp' && amp)) {
        str = str.substr(0, i) + (config.entities[code] || '&') + str.substr(j + 1)
      }
    }
    i = str.indexOf('&', i + 1)
  }
  return str
}

/**
 * @description 合并多个块级标签，加快长内容渲染
 * @param {Array} nodes 要合并的标签数组
 */
function mergeNodes (nodes) {
  let i = nodes.length - 1
  for (let j = i; j >= -1; j--) {
    if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
      if (i - j >= 5) {
        nodes.splice(j + 1, i - j, {
          name: 'div',
          attrs: {},
          children: nodes.slice(j + 1, i + 1)
        })
      }
      i = j - 1
    }
  }
}

/**
 * @description html 解析器
 * @param {Object} vm 组件实例
 */
function Parser (vm) {
  this.options = vm || {}
  this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
  this.imgList = vm.imgList || []
  this.imgList._unloadimgs = 0
  this.plugins = vm.plugins || []
  this.attrs = Object.create(null)
  this.stack = []
  this.nodes = []
  this.pre = (this.options.containerStyle || '').includes('white-space') && this.options.containerStyle.includes('pre') ? 2 : 0
}

/**
 * @description 执行解析
 * @param {String} content 要解析的文本
 */
Parser.prototype.parse = function (content) {
  // 插件处理
  for (let i = this.plugins.length; i--;) {
    if (this.plugins[i].onUpdate) {
      content = this.plugins[i].onUpdate(content, config) || content
    }
  }

  new Lexer(this).parse(content)
  // 出栈未闭合的标签
  while (this.stack.length) {
    this.popNode()
  }
  if (this.nodes.length > 50) {
    mergeNodes(this.nodes)
  }
  return this.nodes
}

/**
 * @description 将标签暴露出来（不被 rich-text 包含）
 */
Parser.prototype.expose = function () {
  // #ifndef APP-PLUS-NVUE
  for (let i = this.stack.length; i--;) {
    const item = this.stack[i]
    if (item.c || item.name === 'a' || item.name === 'video' || item.name === 'audio') return
    item.c = 1
  }
  // #endif
}

/**
 * @description 处理插件
 * @param {Object} node 要处理的标签
 * @returns {Boolean} 是否要移除此标签
 */
Parser.prototype.hook = function (node) {
  for (let i = this.plugins.length; i--;) {
    if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) === false) {
      return false
    }
  }
  return true
}

/**
 * @description 将链接拼接上主域名
 * @param {String} url 需要拼接的链接
 * @returns {String} 拼接后的链接
 */
Parser.prototype.getUrl = function (url) {
  const domain = this.options.domain
  if (url[0] === '/') {
    if (url[1] === '/') {
      // // 开头的补充协议名
      url = (domain ? domain.split('://')[0] : 'http') + ':' + url
    } else if (domain) {
      // 否则补充整个域名
      url = domain + url
    } /* #ifdef APP-PLUS */ else {
      url = plus.io.convertLocalFileSystemURL(url)
    } /* #endif */
  } else if (!url.includes('data:') && !url.includes('://')) {
    if (domain) {
      url = domain + '/' + url
    } /* #ifdef APP-PLUS */ else {
      url = plus.io.convertLocalFileSystemURL(url)
    } /* #endif */
  }
  return url
}

/**
 * @description 解析样式表
 * @param {Object} node 标签
 * @returns {Object}
 */
Parser.prototype.parseStyle = function (node) {
  const attrs = node.attrs
  const list = (this.tagStyle[node.name] || '').split(';').concat((attrs.style || '').split(';'))
  const styleObj = {}
  let tmp = ''

  if (attrs.id && !this.xml) {
    // 暴露锚点
    if (this.options.useAnchor) {
      this.expose()
    } else if (node.name !== 'img' && node.name !== 'a' && node.name !== 'video' && node.name !== 'audio') {
      attrs.id = undefined
    }
  }

  // 转换 width 和 height 属性
  if (attrs.width) {
    styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')
    attrs.width = undefined
  }
  if (attrs.height) {
    styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')
    attrs.height = undefined
  }

  for (let i = 0, len = list.length; i < len; i++) {
    const info = list[i].split(':')
    if (info.length < 2) continue
    const key = info.shift().trim().toLowerCase()
    let value = info.join(':').trim()
    if ((value[0] === '-' && value.lastIndexOf('-') > 0) || value.includes('safe')) {
      // 兼容性的 css 不压缩
      tmp += `;${key}:${value}`
    } else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) {
      // 重复的样式进行覆盖
      if (value.includes('url')) {
        // 填充链接
        let j = value.indexOf('(') + 1
        if (j) {
          while (value[j] === '"' || value[j] === "'" || blankChar[value[j]]) {
            j++
          }
          value = value.substr(0, j) + this.getUrl(value.substr(j))
        }
      } else if (value.includes('rpx')) {
        // 转换 rpx（rich-text 内部不支持 rpx）
        value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px')
      }
      styleObj[key] = value
    }
  }

  node.attrs.style = tmp
  return styleObj
}

/**
 * @description 解析到标签名
 * @param {String} name 标签名
 * @private
 */
Parser.prototype.onTagName = function (name) {
  this.tagName = this.xml ? name : name.toLowerCase()
  if (this.tagName === 'svg') {
    this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
    config.ignoreTags.style = undefined // svg 标签内 style 可用
  }
}

/**
 * @description 解析到属性名
 * @param {String} name 属性名
 * @private
 */
Parser.prototype.onAttrName = function (name) {
  name = this.xml ? name : name.toLowerCase()
  if (name.substr(0, 5) === 'data-') {
    if (name === 'data-src' && !this.attrs.src) {
      // data-src 自动转为 src
      this.attrName = 'src'
    } else if (this.tagName === 'img' || this.tagName === 'a') {
      // a 和 img 标签保留 data- 的属性，可以在 imgtap 和 linktap 事件中使用
      this.attrName = name
    } else {
      // 剩余的移除以减小大小
      this.attrName = undefined
    }
  } else {
    this.attrName = name
    this.attrs[name] = 'T' // boolean 型属性缺省设置
  }
}

/**
 * @description 解析到属性值
 * @param {String} val 属性值
 * @private
 */
Parser.prototype.onAttrVal = function (val) {
  const name = this.attrName || ''
  if (name === 'style' || name === 'href') {
    // 部分属性进行实体解码
    this.attrs[name] = decodeEntity(val, true)
  } else if (name.includes('src')) {
    // 拼接主域名
    this.attrs[name] = this.getUrl(decodeEntity(val, true))
  } else if (name) {
    this.attrs[name] = val
  }
}

/**
 * @description 解析到标签开始
 * @param {Boolean} selfClose 是否有自闭合标识 />
 * @private
 */
Parser.prototype.onOpenTag = function (selfClose) {
  // 拼装 node
  const node = Object.create(null)
  node.name = this.tagName
  node.attrs = this.attrs
  // 避免因为自动 diff 使得 type 被设置为 null 导致部分内容不显示
  if (this.options.nodes.length) {
    node.type = 'node'
  }
  this.attrs = Object.create(null)

  const attrs = node.attrs
  const parent = this.stack[this.stack.length - 1]
  const siblings = parent ? parent.children : this.nodes
  const close = this.xml ? selfClose : config.voidTags[node.name]

  // 替换标签名选择器
  if (tagSelector[node.name]) {
    attrs.class = tagSelector[node.name] + (attrs.class ? ' ' + attrs.class : '')
  }

  // 转换 embed 标签
  if (node.name === 'embed') {
    // #ifndef H5 || APP-PLUS
    const src = attrs.src || ''
    // 按照后缀名和 type 将 embed 转为 video 或 audio
    if (src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8') || (attrs.type || '').includes('video')) {
      node.name = 'video'
    } else if (src.includes('.mp3') || src.includes('.wav') || src.includes('.aac') || src.includes('.m4a') || (attrs.type || '').includes('audio')) {
      node.name = 'audio'
    }
    if (attrs.autostart) {
      attrs.autoplay = 'T'
    }
    attrs.controls = 'T'
    // #endif
    // #ifdef H5 || APP-PLUS
    this.expose()
    // #endif
  }

  // #ifndef APP-PLUS-NVUE
  // 处理音视频
  if (node.name === 'video' || node.name === 'audio') {
    // 设置 id 以便获取 context
    if (node.name === 'video' && !attrs.id) {
      attrs.id = 'v' + idIndex++
    }
    // 没有设置 controls 也没有设置 autoplay 的自动设置 controls
    if (!attrs.controls && !attrs.autoplay) {
      attrs.controls = 'T'
    }
    // 用数组存储所有可用的 source
    node.src = []
    if (attrs.src) {
      node.src.push(attrs.src)
      attrs.src = undefined
    }
    this.expose()
  }
  // #endif

  // 处理自闭合标签
  if (close) {
    if (!this.hook(node) || config.ignoreTags[node.name]) {
      // 通过 base 标签设置主域名
      if (node.name === 'base' && !this.options.domain) {
        this.options.domain = attrs.href
      } /* #ifndef APP-PLUS-NVUE */ else if (node.name === 'source' && parent && (parent.name === 'video' || parent.name === 'audio') && attrs.src) {
        // 设置 source 标签（仅父节点为 video 或 audio 时有效）
        parent.src.push(attrs.src)
      } /* #endif */
      return
    }

    // 解析 style
    const styleObj = this.parseStyle(node)

    // 处理图片
    if (node.name === 'img') {
      if (attrs.src) {
        // 标记 webp
        if (attrs.src.includes('webp')) {
          node.webp = 'T'
        }
        // data url 图片如果没有设置 original-src 默认为不可预览的小图片
        if (attrs.src.includes('data:') && !attrs['original-src']) {
          attrs.ignore = 'T'
        }
        if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
          for (let i = this.stack.length; i--;) {
            const item = this.stack[i]
            if (item.name === 'a') {
              node.a = item.attrs
            }
            if (item.name === 'table' && !node.webp && !attrs.src.includes('cloud://')) {
              if (!styleObj.display || styleObj.display.includes('inline')) {
                node.t = 'inline-block'
              } else {
                node.t = styleObj.display
              }
              styleObj.display = undefined
            }
            // #ifndef H5 || APP-PLUS
            const style = item.attrs.style || ''
            if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || parseInt(styleObj.width) > 100)) {
              styleObj.width = '100% !important'
              styleObj.height = ''
              for (let j = i + 1; j < this.stack.length; j++) {
                this.stack[j].attrs.style = (this.stack[j].attrs.style || '').replace('inline-', '')
              }
            } else if (style.includes('flex') && styleObj.width === '100%') {
              for (let j = i + 1; j < this.stack.length; j++) {
                const style = this.stack[j].attrs.style || ''
                if (!style.includes(';width') && !style.includes(' width') && style.indexOf('width') !== 0) {
                  styleObj.width = ''
                  break
                }
              }
            } else if (style.includes('inline-block')) {
              if (styleObj.width && styleObj.width[styleObj.width.length - 1] === '%') {
                item.attrs.style += ';max-width:' + styleObj.width
                styleObj.width = ''
              } else {
                item.attrs.style += ';max-width:100%'
              }
            }
            // #endif
            item.c = 1
          }
          attrs.i = this.imgList.length.toString()
          let src = attrs['original-src'] || attrs.src
          // #ifndef H5 || MP-ALIPAY || APP-PLUS || MP-360
          if (this.imgList.includes(src)) {
            // 如果有重复的链接则对域名进行随机大小写变换避免预览时错位
            let i = src.indexOf('://')
            if (i !== -1) {
              i += 3
              let newSrc = src.substr(0, i)
              for (; i < src.length; i++) {
                if (src[i] === '/') break
                newSrc += Math.random() > 0.5 ? src[i].toUpperCase() : src[i]
              }
              newSrc += src.substr(i)
              src = newSrc
            }
          }
          // #endif
          this.imgList.push(src)
          if (!node.t) {
            this.imgList._unloadimgs += 1
          }
          // #ifdef H5 || APP-PLUS
          if (this.options.lazyLoad) {
            attrs['data-src'] = attrs.src
            attrs.src = undefined
          }
          // #endif
        }
      }
      if (styleObj.display === 'inline') {
        styleObj.display = ''
      }
      // #ifndef APP-PLUS-NVUE
      if (attrs.ignore) {
        styleObj['max-width'] = styleObj['max-width'] || '100%'
        attrs.style += ';-webkit-touch-callout:none'
      }
      // #endif
      // 设置的宽度超出屏幕，为避免变形，高度转为自动
      if (parseInt(styleObj.width) > windowWidth) {
        styleObj.height = undefined
      }
      // 记录是否设置了宽高
      if (!isNaN(parseInt(styleObj.width))) {
        node.w = 'T'
      }
      if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
        node.h = 'T'
      }
    } else if (node.name === 'svg') {
      siblings.push(node)
      this.stack.push(node)
      this.popNode()
      return
    }
    for (const key in styleObj) {
      if (styleObj[key]) {
        attrs.style += `;${key}:${styleObj[key].replace(' !important', '')}`
      }
    }
    attrs.style = attrs.style.substr(1) || undefined
    // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
    if (!attrs.style) {
      delete attrs.style
    }
    // #endif
  } else {
    if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
      this.pre = node.pre = 1
    }
    node.children = []
    this.stack.push(node)
  }

  // 加入节点树
  siblings.push(node)
}

/**
 * @description 解析到标签结束
 * @param {String} name 标签名
 * @private
 */
Parser.prototype.onCloseTag = function (name) {
  // 依次出栈到匹配为止
  name = this.xml ? name : name.toLowerCase()
  let i
  for (i = this.stack.length; i--;) {
    if (this.stack[i].name === name) break
  }
  if (i !== -1) {
    while (this.stack.length > i) {
      this.popNode()
    }
  } else if (name === 'p' || name === 'br') {
    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
    siblings.push({
      name,
      attrs: {
        class: tagSelector[name] || '',
        style: this.tagStyle[name] || ''
      }
    })
  }
}

/**
 * @description 处理标签出栈
 * @private
 */
Parser.prototype.popNode = function () {
  const node = this.stack.pop()
  let attrs = node.attrs
  const children = node.children
  const parent = this.stack[this.stack.length - 1]
  const siblings = parent ? parent.children : this.nodes

  if (!this.hook(node) || config.ignoreTags[node.name]) {
    // 获取标题
    if (node.name === 'title' && children.length && children[0].type === 'text' && this.options.setTitle) {
      uni.setNavigationBarTitle({
        title: children[0].text
      })
    }
    siblings.pop()
    return
  }

  if (node.pre && this.pre !== 2) {
    // 是否合并空白符标识
    this.pre = node.pre = undefined
    for (let i = this.stack.length; i--;) {
      if (this.stack[i].pre) {
        this.pre = 1
      }
    }
  }

  const styleObj = {}

  // 转换 svg
  if (node.name === 'svg') {
    if (this.xml > 1) {
      // 多层 svg 嵌套
      this.xml--
      return
    }
    // #ifdef APP-PLUS-NVUE
    (function traversal (node) {
      if (node.name) {
        // 调整 svg 的大小写
        node.name = config.svgDict[node.name] || node.name
        for (const item in node.attrs) {
          if (config.svgDict[item]) {
            node.attrs[config.svgDict[item]] = node.attrs[item]
            node.attrs[item] = undefined
          }
        }
        for (let i = 0; i < (node.children || []).length; i++) {
          traversal(node.children[i])
        }
      }
    })(node)
    // #endif
    // #ifndef APP-PLUS-NVUE
    let src = ''
    const style = attrs.style
    attrs.style = ''
    attrs.xmlns = 'http://www.w3.org/2000/svg';
    (function traversal (node) {
      if (node.type === 'text') {
        src += node.text
        return
      }
      const name = config.svgDict[node.name] || node.name
      src += '<' + name
      for (const item in node.attrs) {
        const val = node.attrs[item]
        if (val) {
          src += ` ${config.svgDict[item] || item}="${val}"`
        }
      }
      if (!node.children) {
        src += '/>'
      } else {
        src += '>'
        for (let i = 0; i < node.children.length; i++) {
          traversal(node.children[i])
        }
        src += '</' + name + '>'
      }
    })(node)
    node.name = 'img'
    node.attrs = {
      src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
      style,
      ignore: 'T'
    }
    node.children = undefined
    // #endif
    this.xml = false
    config.ignoreTags.style = true
    return
  }

  // #ifndef APP-PLUS-NVUE
  // 转换 align 属性
  if (attrs.align) {
    if (node.name === 'table') {
      if (attrs.align === 'center') {
        styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto'
      } else {
        styleObj.float = attrs.align
      }
    } else {
      styleObj['text-align'] = attrs.align
    }
    attrs.align = undefined
  }

  // 转换 dir 属性
  if (attrs.dir) {
    styleObj.direction = attrs.dir
    attrs.dir = undefined
  }

  // 转换 font 标签的属性
  if (node.name === 'font') {
    if (attrs.color) {
      styleObj.color = attrs.color
      attrs.color = undefined
    }
    if (attrs.face) {
      styleObj['font-family'] = attrs.face
      attrs.face = undefined
    }
    if (attrs.size) {
      let size = parseInt(attrs.size)
      if (!isNaN(size)) {
        if (size < 1) {
          size = 1
        } else if (size > 7) {
          size = 7
        }
        styleObj['font-size'] = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', 'xxx-large'][size - 1]
      }
      attrs.size = undefined
    }
  }
  // #endif

  // 一些编辑器的自带 class
  if ((attrs.class || '').includes('align-center')) {
    styleObj['text-align'] = 'center'
  }

  Object.assign(styleObj, this.parseStyle(node))

  if (node.name !== 'table' && parseInt(styleObj.width) > windowWidth) {
    styleObj['max-width'] = '100%'
    styleObj['box-sizing'] = 'border-box'
  }

  // #ifndef APP-PLUS-NVUE
  if (config.blockTags[node.name]) {
    node.name = 'div'
  } else if (!config.trustTags[node.name] && !this.xml) {
    // 未知标签转为 span，避免无法显示
    node.name = 'span'
  }

  if (node.name === 'a' || node.name === 'ad'
    // #ifdef H5 || APP-PLUS
    || node.name === 'iframe' // eslint-disable-line
    // #endif
  ) {
    this.expose()
  } else if (node.name === 'video') {
    if ((styleObj.height || '').includes('auto')) {
      styleObj.height = undefined
    }
    /* #ifdef APP-PLUS */
    let str = '<video style="width:100%;height:100%"'
    for (const item in attrs) {
      if (attrs[item]) {
        str += ' ' + item + '="' + attrs[item] + '"'
      }
    }
    if (this.options.pauseVideo) {
      str += ' onplay="this.dispatchEvent(new CustomEvent(\'vplay\',{bubbles:!0}));for(var e=document.getElementsByTagName(\'video\'),t=0;t<e.length;t++)e[t]!=this&&e[t].pause()"'
    }
    str += '>'
    for (let i = 0; i < node.src.length; i++) {
      str += '<source src="' + node.src[i] + '">'
    }
    str += '</video>'
    node.html = str
    /* #endif */
  } else if ((node.name === 'ul' || node.name === 'ol') && node.c) {
    // 列表处理
    const types = {
      a: 'lower-alpha',
      A: 'upper-alpha',
      i: 'lower-roman',
      I: 'upper-roman'
    }
    if (types[attrs.type]) {
      attrs.style += ';list-style-type:' + types[attrs.type]
      attrs.type = undefined
    }
    for (let i = children.length; i--;) {
      if (children[i].name === 'li') {
        children[i].c = 1
      }
    }
  } else if (node.name === 'table') {
    // 表格处理
    // cellpadding、cellspacing、border 这几个常用表格属性需要通过转换实现
    let padding = parseFloat(attrs.cellpadding)
    let spacing = parseFloat(attrs.cellspacing)
    const border = parseFloat(attrs.border)
    const bordercolor = styleObj['border-color']
    const borderstyle = styleObj['border-style']
    if (node.c) {
      // padding 和 spacing 默认 2
      if (isNaN(padding)) {
        padding = 2
      }
      if (isNaN(spacing)) {
        spacing = 2
      }
    }
    if (border) {
      attrs.style += `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}`
    }
    if (node.flag && node.c) {
      // 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
      styleObj.display = 'grid'
      if (spacing) {
        styleObj['grid-gap'] = spacing + 'px'
        styleObj.padding = spacing + 'px'
      } else if (border) {
        // 无间隔的情况下避免边框重叠
        attrs.style += ';border-left:0;border-top:0'
      }

      const width = [] // 表格的列宽
      const trList = [] // tr 列表
      const cells = [] // 保存新的单元格
      const map = {}; // 被合并单元格占用的格子

      (function traversal (nodes) {
        for (let i = 0; i < nodes.length; i++) {
          if (nodes[i].name === 'tr') {
            trList.push(nodes[i])
          } else {
            traversal(nodes[i].children || [])
          }
        }
      })(children)

      for (let row = 1; row <= trList.length; row++) {
        let col = 1
        for (let j = 0; j < trList[row - 1].children.length; j++) {
          const td = trList[row - 1].children[j]
          if (td.name === 'td' || td.name === 'th') {
            // 这个格子被上面的单元格占用，则列号++
            while (map[row + '.' + col]) {
              col++
            }
            let style = td.attrs.style || ''
            let start = style.indexOf('width') ? style.indexOf(';width') : 0
            // 提取出 td 的宽度
            if (start !== -1) {
              let end = style.indexOf(';', start + 6)
              if (end === -1) {
                end = style.length
              }
              if (!td.attrs.colspan) {
                width[col] = style.substring(start ? start + 7 : 6, end)
              }
              style = style.substr(0, start) + style.substr(end)
            }
            // 设置竖直对齐
            style += ';display:flex'
            start = style.indexOf('vertical-align')
            if (start !== -1) {
              const val = style.substr(start + 15, 10)
              if (val.includes('middle')) {
                style += ';align-items:center'
              } else if (val.includes('bottom')) {
                style += ';align-items:flex-end'
              }
            } else {
              style += ';align-items:center'
            }
            // 设置水平对齐
            start = style.indexOf('text-align')
            if (start !== -1) {
              const val = style.substr(start + 11, 10)
              if (val.includes('center')) {
                style += ';justify-content: center'
              } else if (val.includes('right')) {
                style += ';justify-content: right'
              }
            }
            style = (border ? `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '') + ';' + style
            // 处理列合并
            if (td.attrs.colspan) {
              style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
              if (!td.attrs.rowspan) {
                style += `;grid-row-start:${row};grid-row-end:${row + 1}`
              }
              col += parseInt(td.attrs.colspan) - 1
            }
            // 处理行合并
            if (td.attrs.rowspan) {
              style += `;grid-row-start:${row};grid-row-end:${row + parseInt(td.attrs.rowspan)}`
              if (!td.attrs.colspan) {
                style += `;grid-column-start:${col};grid-column-end:${col + 1}`
              }
              // 记录下方单元格被占用
              for (let rowspan = 1; rowspan < td.attrs.rowspan; rowspan++) {
                for (let colspan = 0; colspan < (td.attrs.colspan || 1); colspan++) {
                  map[(row + rowspan) + '.' + (col - colspan)] = 1
                }
              }
            }
            if (style) {
              td.attrs.style = style
            }
            cells.push(td)
            col++
          }
        }
        if (row === 1) {
          let temp = ''
          for (let i = 1; i < col; i++) {
            temp += (width[i] ? width[i] : 'auto') + ' '
          }
          styleObj['grid-template-columns'] = temp
        }
      }
      node.children = cells
    } else {
      // 没有使用合并单元格的表格通过 table 布局实现
      if (node.c) {
        styleObj.display = 'table'
      }
      if (!isNaN(spacing)) {
        styleObj['border-spacing'] = spacing + 'px'
      }
      if (border || padding) {
        // 遍历
        (function traversal (nodes) {
          for (let i = 0; i < nodes.length; i++) {
            const td = nodes[i]
            if (td.name === 'th' || td.name === 'td') {
              if (border) {
                td.attrs.style = `border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'};${td.attrs.style || ''}`
              }
              if (padding) {
                td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
              }
            } else if (td.children) {
              traversal(td.children)
            }
          }
        })(children)
      }
    }
    // 给表格添加一个单独的横向滚动层
    if (this.options.scrollTable && !(attrs.style || '').includes('inline')) {
      const table = Object.assign({}, node)
      node.name = 'div'
      node.attrs = {
        style: 'overflow:auto'
      }
      node.children = [table]
      attrs = table.attrs
    }
  } else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
    for (let i = this.stack.length; i--;) {
      if (this.stack[i].name === 'table') {
        this.stack[i].flag = 1 // 指示含有合并单元格
        break
      }
    }
  } else if (node.name === 'ruby') {
    // 转换 ruby
    node.name = 'span'
    for (let i = 0; i < children.length - 1; i++) {
      if (children[i].type === 'text' && children[i + 1].name === 'rt') {
        children[i] = {
          name: 'div',
          attrs: {
            style: 'display:inline-block;text-align:center'
          },
          children: [{
            name: 'div',
            attrs: {
              style: 'font-size:50%;' + (children[i + 1].attrs.style || '')
            },
            children: children[i + 1].children
          }, children[i]]
        }
        children.splice(i + 1, 1)
      }
    }
  } else if (node.c) {
    (function traversal (node) {
      node.c = 2
      for (let i = node.children.length; i--;) {
        const child = node.children[i]
        // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
        if (child.name && (config.inlineTags[child.name] || ((child.attrs.style || '').includes('inline') && child.children)) && !child.c) {
          traversal(child)
        }
        // #endif
        if (!child.c || child.name === 'table') {
          node.c = 1
        }
      }
    })(node)
  }

  if ((styleObj.display || '').includes('flex') && !node.c) {
    for (let i = children.length; i--;) {
      const item = children[i]
      if (item.f) {
        item.attrs.style = (item.attrs.style || '') + item.f
        item.f = undefined
      }
    }
  }
  // flex 布局时部分样式需要提取到 rich-text 外层
  const flex = parent && ((parent.attrs.style || '').includes('flex') || (parent.attrs.style || '').includes('grid'))
    // #ifdef MP-WEIXIN
    // 检查基础库版本 virtualHost 是否可用
    && !(node.c && wx.getNFCAdapter) // eslint-disable-line
    // #endif
    // #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU || MP-TOUTIAO
    && !node.c // eslint-disable-line
  // #endif
  if (flex) {
    node.f = ';max-width:100%'
  }

  if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
    mergeNodes(children)
  }
  // #endif

  for (const key in styleObj) {
    if (styleObj[key]) {
      const val = `;${key}:${styleObj[key].replace(' !important', '')}`
      /* #ifndef APP-PLUS-NVUE */
      if (flex && ((key.includes('flex') && key !== 'flex-direction') || key === 'align-self' || key.includes('grid') || styleObj[key][0] === '-' || (key.includes('width') && val.includes('%')))) {
        node.f += val
        if (key === 'width') {
          attrs.style += ';width:100%'
        }
      } else /* #endif */ {
        attrs.style += val
      }
    }
  }
  attrs.style = attrs.style.substr(1) || undefined
  // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
  for (const key in attrs) {
    if (!attrs[key]) {
      delete attrs[key]
    }
  }
  // #endif
}

/**
 * @description 解析到文本
 * @param {String} text 文本内容
 */
Parser.prototype.onText = function (text) {
  if (!this.pre) {
    // 合并空白符
    let trim = ''
    let flag
    for (let i = 0, len = text.length; i < len; i++) {
      if (!blankChar[text[i]]) {
        trim += text[i]
      } else {
        if (trim[trim.length - 1] !== ' ') {
          trim += ' '
        }
        if (text[i] === '\n' && !flag) {
          flag = true
        }
      }
    }
    // 去除含有换行符的空串
    if (trim === ' ') {
      if (flag) return
      // #ifdef VUE3
      else {
        const parent = this.stack[this.stack.length - 1]
        if (parent && parent.name[0] === 't') return
      }
      // #endif
    }
    text = trim
  }
  const node = Object.create(null)
  node.type = 'text'
  // #ifdef (MP-BAIDU || MP-ALIPAY || MP-TOUTIAO) && VUE3
  node.attrs = {}
  // #endif
  node.text = decodeEntity(text)
  if (this.hook(node)) {
    // #ifdef MP-WEIXIN
    if (this.options.selectable === 'force' && system.includes('iOS') && !uni.canIUse('rich-text.user-select')) {
      this.expose()
    }
    // #endif
    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
    siblings.push(node)
  }
}

/**
 * @description html 词法分析器
 * @param {Object} handler 高层处理器
 */
function Lexer (handler) {
  this.handler = handler
}

/**
 * @description 执行解析
 * @param {String} content 要解析的文本
 */
Lexer.prototype.parse = function (content) {
  this.content = content || ''
  this.i = 0 // 标记解析位置
  this.start = 0 // 标记一个单词的开始位置
  this.state = this.text // 当前状态
  for (let len = this.content.length; this.i !== -1 && this.i < len;) {
    this.state()
  }
}

/**
 * @description 检查标签是否闭合
 * @param {String} method 如果闭合要进行的操作
 * @returns {Boolean} 是否闭合
 * @private
 */
Lexer.prototype.checkClose = function (method) {
  const selfClose = this.content[this.i] === '/'
  if (this.content[this.i] === '>' || (selfClose && this.content[this.i + 1] === '>')) {
    if (method) {
      this.handler[method](this.content.substring(this.start, this.i))
    }
    this.i += selfClose ? 2 : 1
    this.start = this.i
    this.handler.onOpenTag(selfClose)
    if (this.handler.tagName === 'script') {
      this.i = this.content.indexOf('</', this.i)
      if (this.i !== -1) {
        this.i += 2
        this.start = this.i
      }
      this.state = this.endTag
    } else {
      this.state = this.text
    }
    return true
  }
  return false
}

/**
 * @description 文本状态
 * @private
 */
Lexer.prototype.text = function () {
  this.i = this.content.indexOf('<', this.i) // 查找最近的标签
  if (this.i === -1) {
    // 没有标签了
    if (this.start < this.content.length) {
      this.handler.onText(this.content.substring(this.start, this.content.length))
    }
    return
  }
  const c = this.content[this.i + 1]
  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
    // 标签开头
    if (this.start !== this.i) {
      this.handler.onText(this.content.substring(this.start, this.i))
    }
    this.start = ++this.i
    this.state = this.tagName
  } else if (c === '/' || c === '!' || c === '?') {
    if (this.start !== this.i) {
      this.handler.onText(this.content.substring(this.start, this.i))
    }
    const next = this.content[this.i + 2]
    if (c === '/' && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
      // 标签结尾
      this.i += 2
      this.start = this.i
      this.state = this.endTag
      return
    }
    // 处理注释
    let end = '-->'
    if (c !== '!' || this.content[this.i + 2] !== '-' || this.content[this.i + 3] !== '-') {
      end = '>'
    }
    this.i = this.content.indexOf(end, this.i)
    if (this.i !== -1) {
      this.i += end.length
      this.start = this.i
    }
  } else {
    this.i++
  }
}

/**
 * @description 标签名状态
 * @private
 */
Lexer.prototype.tagName = function () {
  if (blankChar[this.content[this.i]]) {
    // 解析到标签名
    this.handler.onTagName(this.content.substring(this.start, this.i))
    while (blankChar[this.content[++this.i]]);
    if (this.i < this.content.length && !this.checkClose()) {
      this.start = this.i
      this.state = this.attrName
    }
  } else if (!this.checkClose('onTagName')) {
    this.i++
  }
}

/**
 * @description 属性名状态
 * @private
 */
Lexer.prototype.attrName = function () {
  let c = this.content[this.i]
  if (blankChar[c] || c === '=') {
    // 解析到属性名
    this.handler.onAttrName(this.content.substring(this.start, this.i))
    let needVal = c === '='
    const len = this.content.length
    while (++this.i < len) {
      c = this.content[this.i]
      if (!blankChar[c]) {
        if (this.checkClose()) return
        if (needVal) {
          // 等号后遇到第一个非空字符
          this.start = this.i
          this.state = this.attrVal
          return
        }
        if (this.content[this.i] === '=') {
          needVal = true
        } else {
          this.start = this.i
          this.state = this.attrName
          return
        }
      }
    }
  } else if (!this.checkClose('onAttrName')) {
    this.i++
  }
}

/**
 * @description 属性值状态
 * @private
 */
Lexer.prototype.attrVal = function () {
  const c = this.content[this.i]
  const len = this.content.length
  if (c === '"' || c === "'") {
    // 有冒号的属性
    this.start = ++this.i
    this.i = this.content.indexOf(c, this.i)
    if (this.i === -1) return
    this.handler.onAttrVal(this.content.substring(this.start, this.i))
  } else {
    // 没有冒号的属性
    for (; this.i < len; this.i++) {
      if (blankChar[this.content[this.i]]) {
        this.handler.onAttrVal(this.content.substring(this.start, this.i))
        break
      } else if (this.checkClose('onAttrVal')) return
    }
  }
  while (blankChar[this.content[++this.i]]);
  if (this.i < len && !this.checkClose()) {
    this.start = this.i
    this.state = this.attrName
  }
}

/**
 * @description 结束标签状态
 * @returns {String} 结束的标签名
 * @private
 */
Lexer.prototype.endTag = function () {
  const c = this.content[this.i]
  if (blankChar[c] || c === '>' || c === '/') {
    this.handler.onCloseTag(this.content.substring(this.start, this.i))
    if (c !== '>') {
      this.i = this.content.indexOf('>', this.i)
      if (this.i === -1) return
    }
    this.start = ++this.i
    this.state = this.text
  } else {
    this.i++
  }
}

export default Parser
lƿx8 <template>
  <view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
    <slot v-if="!nodes[0]" />
    <!-- #ifndef APP-PLUS-NVUE -->
    <node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]" name="span" />
    <!-- #endif -->
    <!-- #ifdef APP-PLUS-NVUE -->
    <web-view ref="web" src="/uni_modules/uv-parse/static/app-plus/uv-parse/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
    <!-- #endif -->
  </view>
</template>

<script>
/**
 * uv-parse v1.0.3
 * @description 富文本组件
 * @tutorial https://www.uvui.cn/components/parse.html
 * @property {String} container-style 容器的样式
 * @property {String} content 用于渲染的 html 字符串
 * @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
 * @property {String} domain 主域名，用于拼接链接
 * @property {String} error-img 图片出错时的占位图链接
 * @property {Boolean} lazy-load 是否开启图片懒加载
 * @property {string} loading-img 图片加载过程中的占位图链接
 * @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
 * @property {Boolean} preview-img 是否允许图片被点击时自动预览
 * @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
 * @property {Boolean | String} selectable 是否开启长按复制
 * @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
 * @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
 * @property {Object} tag-style 标签的默认样式
 * @property {Boolean | Number} use-anchor 是否使用锚点链接
 * @event {Function} load dom 结构加载完毕时触发
 * @event {Function} ready 所有图片加载完毕时触发
 * @event {Function} imgtap 图片被点击时触发
 * @event {Function} linktap 链接被点击时触发
 * @event {Function} play 音视频播放时触发
 * @event {Function} error 媒体加载出错时触发
 */
// #ifndef APP-PLUS-NVUE
import node from './node/node'
// #endif
import Parser from './parser'
const plugins=[]
// #ifdef APP-PLUS-NVUE
const dom = weex.requireModule('dom')
// #endif
export default {
  name: 'uv-parse',
  data () {
    return {
      nodes: [],
      // #ifdef APP-PLUS-NVUE
      height: 3
      // #endif
    }
  },
  props: {
    containerStyle: {
      type: String,
      default: ''
    },
    content: {
      type: String,
      default: ''
    },
    copyLink: {
      type: [Boolean, String],
      default: true
    },
    domain: String,
    errorImg: {
      type: String,
      default: ''
    },
    lazyLoad: {
      type: [Boolean, String],
      default: false
    },
    loadingImg: {
      type: String,
      default: ''
    },
    pauseVideo: {
      type: [Boolean, String],
      default: true
    },
    previewImg: {
      type: [Boolean, String],
      default: true
    },
    scrollTable: [Boolean, String],
    selectable: [Boolean, String],
    setTitle: {
      type: [Boolean, String],
      default: true
    },
    showImgMenu: {
      type: [Boolean, String],
      default: true
    },
    tagStyle: Object,
    useAnchor: [Boolean, Number]
  },
  // #ifdef VUE3
  emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
  // #endif
  // #ifndef APP-PLUS-NVUE
  components: {
    node
  },
  // #endif
  watch: {
    content (content) {
      this.setContent(content)
    }
  },
  created () {
    this.plugins = []
    for (let i = plugins.length; i--;) {
      this.plugins.push(new plugins[i](this))
    }
  },
  mounted () {
    if (this.content && !this.nodes.length) {
      this.setContent(this.content)
    }
  },
  beforeDestroy () {
    this._hook('onDetached')
  },
  methods: {
    /**
     * @description 将锚点跳转的范围限定在一个 scroll-view 内
     * @param {Object} page scroll-view 所在页面的示例
     * @param {String} selector scroll-view 的选择器
     * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
     */
    in (page, selector, scrollTop) {
      // #ifndef APP-PLUS-NVUE
      if (page && selector && scrollTop) {
        this._in = {
          page,
          selector,
          scrollTop
        }
      }
      // #endif
    },

    /**
     * @description 锚点跳转
     * @param {String} id 要跳转的锚点 id
     * @param {Number} offset 跳转位置的偏移量
     * @returns {Promise}
     */
    navigateTo (id, offset) {
      return new Promise((resolve, reject) => {
        if (!this.useAnchor) {
          reject(Error('Anchor is disabled'))
          return
        }
        offset = offset || parseInt(this.useAnchor) || 0
        // #ifdef APP-PLUS-NVUE
        if (!id) {
          dom.scrollToElement(this.$refs.web, {
            offset
          })
          resolve()
        } else {
          this._navigateTo = {
            resolve,
            reject,
            offset
          }
          this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
        }
        // #endif
        // #ifndef APP-PLUS-NVUE
        let deep = ' '
        // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
        deep = '>>>'
        // #endif
        const selector = uni.createSelectorQuery()
          // #ifndef MP-ALIPAY
          .in(this._in ? this._in.page : this)
          // #endif
          .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
        if (this._in) {
          selector.select(this._in.selector).scrollOffset()
            .select(this._in.selector).boundingClientRect()
        } else {
          // 获取 scroll-view 的位置和滚动距离
          selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
        }
        selector.exec(res => {
          if (!res[0]) {
            reject(Error('Label not found'))
            return
          }
          const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
          if (this._in) {
            // scroll-view 跳转
            this._in.page[this._in.scrollTop] = scrollTop
          } else {
            // 页面跳转
            uni.pageScrollTo({
              scrollTop,
              duration: 300
            })
          }
          resolve()
        })
        // #endif
      })
    },

    /**
     * @description 获取文本内容
     * @return {String}
     */
    getText (nodes) {
      let text = '';
      (function traversal (nodes) {
        for (let i = 0; i < nodes.length; i++) {
          const node = nodes[i]
          if (node.type === 'text') {
            text += node.text.replace(/&amp;/g, '&')
          } else if (node.name === 'br') {
            text += '\n'
          } else {
            // 块级标签前后加换行
            const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
            if (isBlock && text && text[text.length - 1] !== '\n') {
              text += '\n'
            }
            // 递归获取子节点的文本
            if (node.children) {
              traversal(node.children)
            }
            if (isBlock && text[text.length - 1] !== '\n') {
              text += '\n'
            } else if (node.name === 'td' || node.name === 'th') {
              text += '\t'
            }
          }
        }
      })(nodes || this.nodes)
      return text
    },

    /**
     * @description 获取内容大小和位置
     * @return {Promise}
     */
    getRect () {
      return new Promise((resolve, reject) => {
        uni.createSelectorQuery()
          // #ifndef MP-ALIPAY
          .in(this)
          // #endif
          .select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
      })
    },

    /**
     * @description 暂停播放媒体
     */
    pauseMedia () {
      for (let i = (this._videos || []).length; i--;) {
        this._videos[i].pause()
      }
      // #ifdef APP-PLUS
      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
      // #ifndef APP-PLUS-NVUE
      let page = this.$parent
      while (!page.$scope) page = page.$parent
      page.$scope.$getAppWebview().evalJS(command)
      // #endif
      // #ifdef APP-PLUS-NVUE
      this.$refs.web.evalJs(command)
      // #endif
      // #endif
    },

    /**
     * @description 设置媒体播放速率
     * @param {Number} rate 播放速率
     */
    setPlaybackRate (rate) {
      this.playbackRate = rate
      for (let i = (this._videos || []).length; i--;) {
        this._videos[i].playbackRate(rate)
      }
      // #ifdef APP-PLUS
      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
      // #ifndef APP-PLUS-NVUE
      let page = this.$parent
      while (!page.$scope) page = page.$parent
      page.$scope.$getAppWebview().evalJS(command)
      // #endif
      // #ifdef APP-PLUS-NVUE
      this.$refs.web.evalJs(command)
      // #endif
      // #endif
    },

    /**
     * @description 设置内容
     * @param {String} content html 内容
     * @param {Boolean} append 是否在尾部追加
     */
    setContent (content, append) {
      if (!append || !this.imgList) {
        this.imgList = []
      }
      const nodes = new Parser(this).parse(content)
      // #ifdef APP-PLUS-NVUE
      if (this._ready) {
        this._set(nodes, append)
      }
      // #endif
      this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)

      // #ifndef APP-PLUS-NVUE
      this._videos = []
      this.$nextTick(() => {
        this._hook('onLoad')
        this.$emit('load')
      })

      if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
        // 设置懒加载，每 350ms 获取高度，不变则认为加载完毕
        let height = 0
        const callback = rect => {
          if (!rect || !rect.height) rect = {}
          // 350ms 总高度无变化就触发 ready 事件
          if (rect.height === height) {
            this.$emit('ready', rect)
          } else {
            height = rect.height
            setTimeout(() => {
              this.getRect().then(callback).catch(callback)
            }, 350)
          }
        }
        this.getRect().then(callback).catch(callback)
      } else {
        // 未设置懒加载，等待所有图片加载完毕
        if (!this.imgList._unloadimgs) {
          this.getRect().then(rect => {
            this.$emit('ready', rect)
          }).catch(() => {
            this.$emit('ready', {})
          })
        }
      }
      // #endif
    },

    /**
     * @description 调用插件钩子函数
     */
    _hook (name) {
      for (let i = plugins.length; i--;) {
        if (this.plugins[i][name]) {
          this.plugins[i][name]()
        }
      }
    },

    // #ifdef APP-PLUS-NVUE
    /**
     * @description 设置内容
     */
    _set (nodes, append) {
      this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes).replace(/%22/g, '') + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
    },

    /**
     * @description 接收到 web-view 消息
     */
    _onMessage (e) {
      const message = e.detail.data[0]
      switch (message.action) {
        // web-view 初始化完毕
        case 'onJSBridgeReady':
          this._ready = true
          if (this.nodes) {
            this._set(this.nodes)
          }
          break
        // 内容 dom 加载完毕
        case 'onLoad':
          this.height = message.height
          this._hook('onLoad')
          this.$emit('load')
          break
        // 所有图片加载完毕
        case 'onReady':
          this.getRect().then(res => {
            this.$emit('ready', res)
          }).catch(() => {
            this.$emit('ready', {})
          })
          break
        // 总高度发生变化
        case 'onHeightChange':
          this.height = message.height
          break
        // 图片点击
        case 'onImgTap':
          this.$emit('imgtap', message.attrs)
          if (this.previewImg) {
            uni.previewImage({
              current: parseInt(message.attrs.i),
              urls: this.imgList
            })
          }
          break
        // 链接点击
        case 'onLinkTap': {
          const href = message.attrs.href
          this.$emit('linktap', message.attrs)
          if (href) {
            // 锚点跳转
            if (href[0] === '#') {
              if (this.useAnchor) {
                dom.scrollToElement(this.$refs.web, {
                  offset: message.offset
                })
              }
            } else if (href.includes('://')) {
              // 打开外链
              if (this.copyLink) {
                plus.runtime.openWeb(href)
              }
            } else {
              uni.navigateTo({
                url: href,
                fail () {
                  uni.switchTab({
                    url: href
                  })
                }
              })
            }
          }
          break
        }
        case 'onPlay':
          this.$emit('play')
          break
        // 获取到锚点的偏移量
        case 'getOffset':
          if (typeof message.offset === 'number') {
            dom.scrollToElement(this.$refs.web, {
              offset: message.offset + this._navigateTo.offset
            })
            this._navigateTo.resolve()
          } else {
            this._navigateTo.reject(Error('Label not found'))
          }
          break
        // 点击
        case 'onClick':
          this.$emit('tap')
          this.$emit('click')
          break
        // 出错
        case 'onError':
          this.$emit('error', {
            source: message.source,
            attrs: message.attrs
          })
      }
    }
    // #endif
  }
}
</script>

<style>
/* #ifndef APP-PLUS-NVUE */
/* 根节点样式 */
._root {
  padding: 1px 0;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}

/* 长按复制 */
._select {
  user-select: text;
}
/* #endif */
</style>
|R
xgC{
  "id": "uv-parse",
  "displayName": "uv-parse 富文本解析器EH4parse 该组件一般用于富文本解析场景，比如解析文章内容，商品详情，带原生HTML标签的各类字符g串等，此组件和uni-app官方的rich-text组件功能有重合之处，但是也有不同的地方+parseO!parse",
    "富文本	)XxF## Parse 富文本解析器parse**

该组件一般用于富文本解析场景，比如解析文章内容，商品详情，带原生`HTML`标签的各类符串等，此组件和`uni-app`官方的`rich-text`组件功能有重合之处，但是也有不同的地方。

该插件提供富文本的解析，该功能已经足够丰富。如果需要富文本的编辑，可使用`uniapp`官方提供的组件/parsesXx# 40000 app-plus .{3X*1U"7ZEʺx# 40000 uv-parse 
DJkJ9KxC 40000 js j9!N@x100644 local.html p<~gWf]oפxT 100644 handler.js '(J#<;*:>k100644 uni.webview.min.js Q2䡑.?y	]­xA'use strict'

// 等待初始化完毕
document.addEventListener('UniAppJSBridgeReady', () => {
    document.body.onclick = function () {
        return uni.postMessage({
            data: {
                action: 'onClick'
            }
        })
    }

    uni.postMessage({
        data: {
            action: 'onJSBridgeReady'
        }
    })
})
let options
let medias = []
/**
 * @description 获取标签的所有属性
 * @param {Element} ele
 */

function getAttrs(ele) {
    const attrs = Object.create(null)

    for (let i = ele.attributes.length; i--;) {
        attrs[ele.attributes[i].name] = ele.attributes[i].value
    }

    return attrs
}
/**
 * @description 图片加载出错
 */

function onImgError() {
    if (options[1]) {
        this.src = options[1]
        this.onerror = null
    } // 取消监听点击

    this.onclick = null
    this.ontouchstart = null
    uni.postMessage({
        data: {
            action: 'onError',
            source: 'img',
            attrs: getAttrs(this)
        }
    })
}
/**
 * @description 创建 dom 结构
 * @param {object[]} nodes 节点数组
 * @param {Element} parent 父节点
 * @param {string} namespace 命名空间
 */

function createDom(nodes, parent, namespace) {
    const _loop = function _loop(i) {
        const node = nodes[i]
        let ele = void 0

        if (!node.type || node.type == 'node') {
            let { name } = node // svg 需要设置 namespace

            if (name == 'svg') namespace = 'http://www.w3.org/2000/svg'
            if (name == 'html' || name == 'body') name = 'div' // 创建标签

            if (!namespace) ele = document.createElement(name); else ele = document.createElementNS(namespace, name) // 设置属性

            for (const item in node.attrs) {
                ele.setAttribute(item, node.attrs[item])
            } // 递归创建子节点

            if (node.children) createDom(node.children, ele, namespace) // 处理图片

            if (name == 'img') {
                if (!ele.src && ele.getAttribute('data-src')) ele.src = ele.getAttribute('data-src')

                if (!node.attrs.ignore) {
                    // 监听图片点击事件
                    ele.onclick = function (e) {
                        e.stopPropagation()
                        uni.postMessage({
                            data: {
                                action: 'onImgTap',
                                attrs: getAttrs(this)
                            }
                        })
                    }
                }

                if (options[2]) {
                    image = new Image()
                    image.src = ele.src
                    ele.src = options[2]

                    image.onload = function () {
                        ele.src = this.src
                    }

                    image.onerror = function () {
                        ele.onerror()
                    }
                }

                ele.onerror = onImgError
            } // 处理链接
            else if (name == 'a') {
                ele.addEventListener('click', function (e) {
                    e.stopPropagation()
                    e.preventDefault() // 阻止默认跳转

                    const href = this.getAttribute('href')
                    let offset
                    if (href && href[0] == '#') offset = (document.getElementById(href.substr(1)) || {}).offsetTop
                    uni.postMessage({
                        data: {
                            action: 'onLinkTap',
                            attrs: getAttrs(this),
                            offset
                        }
                    })
                }, true)
            } // 处理音视频
            else if (name == 'video' || name == 'audio') {
                medias.push(ele)

                if (!node.attrs.autoplay) {
                    if (!node.attrs.controls) ele.setAttribute('controls', 'true') // 空白图占位

                    if (!node.attrs.poster) ele.setAttribute('poster', "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'/>")
                }

                if (options[3]) {
                    ele.onplay = function () {
                        for (let _i = 0; _i < medias.length; _i++) {
                            if (medias[_i] != this) medias[_i].pause()
                        }
                    }
                }

                ele.onerror = function () {
                    uni.postMessage({
                        data: {
                            action: 'onError',
                            source: name,
                            attrs: getAttrs(this)
                        }
                    })
                }
            } // 处理表格
            else if (name == 'table' && options[4] && !ele.style.cssText.includes('inline')) {
                const div = document.createElement('div')
                div.style.overflow = 'auto'
                div.appendChild(ele)
                ele = div
            } else if (name == 'svg') namespace = void 0
        } else ele = document.createTextNode(node.text.replace(/&amp;/g, '&'))

        parent.appendChild(ele)
    }

    for (let i = 0; i < nodes.length; i++) {
        var image

        _loop(i)
    }
} // 设置 html 内容

window.setContent = function (nodes, opts, append) {
    const ele = document.getElementById('content') // 背景颜色

    if (opts[0]) document.body.bgColor = opts[0] // 长按复制

    if (!opts[5]) ele.style.userSelect = 'none'

    if (!append) {
        ele.innerHTML = '' // 不追加则先清空

        medias = []
    }

    options = opts
    const fragment = document.createDocumentFragment()
    createDom(nodes, fragment)
    ele.appendChild(fragment) // 触发事件

    let height = ele.scrollHeight
    uni.postMessage({
        data: {
            action: 'onLoad',
            height
        }
    })
    clearInterval(window.timer)
    let ready = false
    window.timer = setInterval(() => {
        if (ele.scrollHeight != height) {
            height = ele.scrollHeight
            uni.postMessage({
                data: {
                    action: 'onHeightChange',
                    height
                }
            })
        } else if (!ready) {
            ready = true
            uni.postMessage({
                data: {
                    action: 'onReady'
                }
            })
        }
    }, 350)
} // 回收计时器

window.onunload = function () {
    clearInterval(window.timer)
}
7FQbxq!(function (e, n) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = n() : typeof define === 'function' && define.amd ? define(n) : (e = e || self).uni = n() }(this, (() => {
    'use strict'

    try { const e = {}; Object.defineProperty(e, 'passive', { get() { !0 } }), window.addEventListener('test-passive', null, e) } catch (e) {} const n = Object.prototype.hasOwnProperty; function t(e, t) { return n.call(e, t) } const i = []; const a = function (e, n) { const t = { options: { timestamp: +new Date() }, name: e, arg: n }; if (window.__dcloud_weex_postMessage || window.__dcloud_weex_) { if (e === 'postMessage') { const a = { data: [n] }; return window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessage(a) : window.__dcloud_weex_.postMessage(JSON.stringify(a)) } const o = { type: 'WEB_INVOKE_APPSERVICE', args: { data: t, webviewIds: i } }; window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessageToService(o) : window.__dcloud_weex_.postMessageToService(JSON.stringify(o)) } if (!window.plus) return window.parent.postMessage({ type: 'WEB_INVOKE_APPSERVICE', data: t, pageId: '' }, '*'); if (i.length === 0) { const r = plus.webview.currentWebview(); if (!r) throw new Error('plus.webview.currentWebview() is undefined'); const d = r.parent(); let s = ''; s = d ? d.id : r.id, i.push(s) } if (plus.webview.getWebviewById('__uniapp__service'))plus.webview.postMessageToUniNView({ type: 'WEB_INVOKE_APPSERVICE', args: { data: t, webviewIds: i } }, '__uniapp__service'); else { const w = JSON.stringify(t); plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat('WEB_INVOKE_APPSERVICE', '",').concat(w, ',').concat(JSON.stringify(i), ');')) } }; const o = {
        navigateTo() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('navigateTo', { url: encodeURI(n) }) }, navigateBack() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.delta; a('navigateBack', { delta: parseInt(n) || 1 }) }, switchTab() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('switchTab', { url: encodeURI(n) }) }, reLaunch() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('reLaunch', { url: encodeURI(n) }) }, redirectTo() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; const n = e.url; a('redirectTo', { url: encodeURI(n) }) }, getEnv(e) { window.plus ? e({ plus: !0 }) : e({ h5: !0 }) }, postMessage() { const e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; a('postMessage', e.data || {}) }
    }; const r = /uni-app/i.test(navigator.userAgent); const d = /Html5Plus/i.test(navigator.userAgent); const s = /complete|loaded|interactive/; const w = window.my && navigator.userAgent.indexOf('AlipayClient') > -1; const u = window.swan && window.swan.webView && /swan/i.test(navigator.userAgent); const c = window.qq && window.qq.miniProgram && /QQ/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent); const g = window.tt && window.tt.miniProgram && /toutiaomicroapp/i.test(navigator.userAgent); const v = window.wx && window.wx.miniProgram && /micromessenger/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent); const p = window.qa && /quickapp/i.test(navigator.userAgent); for (var l, _ = function () { window.UniAppJSBridge = !0, document.dispatchEvent(new CustomEvent('UniAppJSBridgeReady', { bubbles: !0, cancelable: !0 })) }, f = [function (e) { if (r || d) return window.__dcloud_weex_postMessage || window.__dcloud_weex_ ? document.addEventListener('DOMContentLoaded', e) : window.plus && s.test(document.readyState) ? setTimeout(e, 0) : document.addEventListener('plusready', e), o }, function (e) { if (v) return window.WeixinJSBridge && window.WeixinJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener('WeixinJSBridgeReady', e), window.wx.miniProgram }, function (e) { if (c) return window.QQJSBridge && window.QQJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener('QQJSBridgeReady', e), window.qq.miniProgram }, function (e) {
            if (w) {
                document.addEventListener('DOMContentLoaded', e); const n = window.my; return {
                    navigateTo: n.navigateTo, navigateBack: n.navigateBack, switchTab: n.switchTab, reLaunch: n.reLaunch, redirectTo: n.redirectTo, postMessage: n.postMessage, getEnv: n.getEnv
                }
            }
        }, function (e) { if (u) return document.addEventListener('DOMContentLoaded', e), window.swan.webView }, function (e) { if (g) return document.addEventListener('DOMContentLoaded', e), window.tt.miniProgram }, function (e) {
            if (p) {
                window.QaJSBridge && window.QaJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener('QaJSBridgeReady', e); const n = window.qa; return {
                    navigateTo: n.navigateTo, navigateBack: n.navigateBack, switchTab: n.switchTab, reLaunch: n.reLaunch, redirectTo: n.redirectTo, postMessage: n.postMessage, getEnv: n.getEnv
                }
            }
        }, function (e) { return document.addEventListener('DOMContentLoaded', e), o }], m = 0; m < f.length && !(l = f[m](_)); m++);l || (l = {}); const E = typeof uni !== 'undefined' ? uni : {}; if (!E.navigateTo) for (const b in l)t(l, b) && (E[b] = l[b]); return E.webView = l, E
})))
 x<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><style>body,html{width:100%;height:100%;overflow:hidden}body{margin:0}video{width:300px;height:225px}img{max-width:100%;-webkit-touch-callout:none}@keyframes show{0%{opacity:0}100%{opacity:1}}</style></head><body><div id="content"></div><script type="text/javascript" src="./js/uni.webview.min.js"></script><script type="text/javascript" src="./js/handler.js"></script></body>~X	x e100644 changelog.md w-~EPrF40000 components c ӭ)N1:6\s@100644 package.json !_fBw!100644 readme.md ĬZIlMgR>3x<## 1.0.8（2023-08-14）
1. 取消scrollTop参数，使用clientY
## 1.0.7（2023-08-13）
1. 增加scrollTop参数，设置滚动条的位置。不设置如果页面出现滚动就需要传该值，会出现颜色面板无法进行选颜色的情况。
## 1.0.6（2023-08-04）
1. 修复颜色值错误的BUG
## 1.0.5（2023-08-02）
1. 更新依赖
## 1.0.4（2023-07-02）
uv-pick-color  由于弹出层uv-popup的修改，打开和关闭方法更改，详情参考文档：https://www.uvui.cn/components/pickColor.html
## 1.0.3（2023-06-12）
1. 修复在选择颜色时候百度小程序报错的BUG
## 1.0.2（2023-05-27）
1. 兼容非移动h5端不能选择的BUG
## 1.0.1（2023-05-24）
1.  去掉template中存在的this.导致头条小程序编译警告
## 1.0.0（2023-05-23）
uv-pick-color 新增颜色选择器
wx( 40000 uv-pick-color H$%w?xv 100644 colors.js πK &VJYǇ>100644 props.js 5Ws'y100644 uv-pick-color.vue $KA*s
;S'2xv/**
 * hsb 转 rgb
 * @param {Object} hsb 颜色模式  H(hues)表示色相，S(saturation)表示饱和度，B（brightness）表示亮度
 */
export function hsbToRgb(hsb) {
	let rgb = {};
	let h = hsb.h;
	let s = hsb.s * 255 / 100;
	let v = hsb.b * 255 / 100;
	if (s == 0) {
		rgb.r = rgb.g = rgb.b = v;
	} else {
		let t1 = v;
		let t2 = ((255 - s) * v) / 255;
		let t3 = ((t1 - t2) * (h % 60)) / 60;
		if (h == 360) h = 0;
		if (h < 60) {
			rgb.r = t1;
			rgb.b = t2;
			rgb.g = t2 + t3;
		} else if (h < 120) {
			rgb.g = t1;
			rgb.b = t2;
			rgb.r = t1 - t3;
		} else if (h < 180) {
			rgb.g = t1;
			rgb.r = t2;
			rgb.b = t2 + t3;
		} else if (h < 240) {
			rgb.b = t1;
			rgb.r = t2;
			rgb.g = t1 - t3;
		} else if (h < 300) {
			rgb.b = t1;
			rgb.g = t2;
			rgb.r = t2 + t3;
		} else if (h < 360) {
			rgb.r = t1;
			rgb.g = t2;
			rgb.b = t1 - t3;
		} else {
			rgb.r = 0;
			rgb.g = 0;
			rgb.b = 0;
		}
	}
	return {
		r: Math.round(rgb.r),
		g: Math.round(rgb.g),
		b: Math.round(rgb.b)
	};
}
/**
 * rgb转hsb
 * @param {Object} rgb 颜色rgb值
 */
export function rgbToHsb(rgb) {
	let hsb = {
		h: 0,
		s: 0,
		b: 0
	};
	let h = 0,
		s = 0,
		v = 0;
	let r = rgb.r,
		g = rgb.g,
		b = rgb.b;
	let min = Math.min(rgb.r, rgb.g, rgb.b);
	let max = Math.max(rgb.r, rgb.g, rgb.b);
	v = max / 255;
	if (max === 0) {
		s = 0;
	} else {
		s = 1 - (min / max);
	}
	if (max === min) {
		h = 0; //事实上，max===min的时候，h无论为多少都无所谓
	} else if (max === r && g >= b) {
		h = 60 * ((g - b) / (max - min)) + 0;
	} else if (max === r && g < b) {
		h = 60 * ((g - b) / (max - min)) + 360
	} else if (max === g) {
		h = 60 * ((b - r) / (max - min)) + 120
	} else if (max === b) {
		h = 60 * ((r - g) / (max - min)) + 240
	}
	hsb.h = parseInt(h);
	hsb.s = parseInt(s * 100);
	hsb.b = parseInt(v * 100);
	return hsb;
}
/**
 * rgb 转 二进制 hex
 * @param {Object} rgb
 */
export function rgbToHex(rgb) {
	let hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)];
	hex.map(function(str, i) {
		if (str.length == 1) {
			hex[i] = '0' + str;
		}
	});
	return hex.join('');
}
//预制颜色
export const colorList = [{
	r: 60,
	g: 156,
	b: 255,
	a: 1
}, {
	r: 245,
	g: 108,
	b: 108,
	a: 1
}, {
	r: 249,
	g: 174,
	b: 61,
	a: 1
}, {
	r: 90,
	g: 199,
	b: 37,
	a: 1
}, {
	r: 144,
	g: 147,
	b: 153,
	a: 1
}, {
	r: 48,
	g: 49,
	b: 51,
	a: 1
}, {
	r: 233,
	g: 30,
	b: 99,
	a: 1
}, {
	r: 156,
	g: 39,
	b: 176,
	a: 1
}, {
	r: 103,
	g: 58,
	b: 183,
	a: 1
}, {
	r: 63,
	g: 81,
	b: 181,
	a: 1
}, {
	r: 0,
	g: 188,
	b: 212,
	a: 1
}, {
	r: 0,
	g: 150,
	b: 136,
	a: 1
}, {
	r: 139,
	g: 195,
	b: 74,
	a: 1
}, {
	r: 205,
	g: 220,
	b: 57,
	a: 1
}, {
	r: 255,
	g: 235,
	b: 59,
	a: 1
}, {
	r: 255,
	g: 193,
	b: 7,
	a: 1
}, {
	r: 255,
	g: 152,
	b: 0,
	a: 1
}, {
	r: 255,
	g: 87,
	b: 34,
	a: 1
}, {
	r: 121,
	g: 85,
	b: 72,
	a: 1
}, {
	r: 158,
	g: 158,
	b: 158,
	a: 1
}, {
	r: 0,
	g: 0,
	b: 0,
	a: 0.5
}, {
	r: 0,
	g: 0,
	b: 0,
	a: 0
}]B1xexport default {
	props: {
		// 颜色选择器初始颜色
		color: {
			type: Object,
			default: () => {
				return { r: 0, g: 0, b: 0, a: 0 }
			}
		},
		// 预制颜色
		prefabColor: {
			type: Array,
			default: () => []
		},
		// 是否允许点击遮罩关闭
		closeOnClickOverlay: {
			type: Boolean,
			default: true
		},
		// 顶部标题
		title: {
			type: String,
			default: ''
		},
		// 取消按钮的文字
		cancelText: {
			type: String,
			default: '取消'
		},
		// 确认按钮的文字
		confirmText: {
			type: String,
			default: '确定'
		},
		// 取消按钮的颜色
		cancelColor: {
			type: String,
			default: '#909193'
		},
		// 确认按钮的颜色
		confirmColor: {
			type: String,
			default: '#3c9cff'
		},
		...uni.$uv?.props?.pickColor
	}
}OoUx	7<template>
	<!-- #ifndef APP-NVUE -->
	<uv-popup 
		ref="pickerColorPopup"
		mode="bottom"
		:close-on-click-overlay="closeOnClickOverlay"
		@change="popupChange">
		<view class="uv-pick-color">
			<uv-toolbar
				:show="showToolbar"
				:cancelColor="cancelColor"
				:confirmColor="confirmColor"
				:cancelText="cancelText"
				:confirmText="confirmText"
				:title="title"
				:show-border="true"
				@cancel="cancelHandler"
				@confirm="confirmHandler"></uv-toolbar>
			<view 
				class="uv-pick-color__box"
				:style="{
					background:`rgb(${bgcolor.r},${bgcolor.g},${bgcolor.b})`
				}"
			>
				<!-- #ifdef H5 -->
				<view
					class="uv-pick-color__box__bg drag-box"
					@tap.stop.prevent="touchstart($event, 0)"
					@touchstart.stop.prevent="touchstart($event, 0)"
					@touchmove.stop.prevent="touchmove($event, 0)"
					@touchend.stop.prevent="touchend($event, 0)"
				>
				<!-- #endif -->
				<!-- #ifndef H5 -->
				<view
					class="uv-pick-color__box__bg drag-box"
					@touchstart.stop.prevent="touchstart($event, 0)"
					@touchmove.stop.prevent="touchmove($event, 0)"
					@touchend.stop.prevent="touchend($event, 0)"
				>
				<!-- #endif -->
					<view class="uv-pick-color__box__bg-mask"></view>
					<view 
						class="uv-pick-color__box__bg-pointer"
						:style="[pointerStyle]"
					>
					</view>
				</view>
			</view>
			<view class="uv-pick-color__control">
				<view class="uv-pick-color__control__alpha">
					<view 
						class="uv-pick-color__control__alpha--color"
						:style="{ background:`rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})` }"
					></view>
				</view>
				<view class="uv-pick-color__control__item">
					<!-- #ifdef H5 -->
					<view
						class="uv-pick-color__control__item__drag drag-box"
						@tap.stop="touchstart($event, 1)"
						@touchstart.stop="touchstart($event, 1)"
						@touchmove.stop="touchmove($event, 1)"
						@touchend.stop="touchend($event, 1)"
					>
					<!-- #endif -->
					<!-- #ifndef H5 -->
					<view
						class="uv-pick-color__control__item__drag drag-box"
						@touchstart.stop="touchstart($event, 1)"
						@touchmove.stop="touchmove($event, 1)"
						@touchend.stop="touchend($event, 1)"
					>
					<!-- #endif -->
						<view class="uv-pick-color__control__item__drag--hue"></view>
						<view 
							class="uv-pick-color__control__item__drag--circle"
							:style="{ 
								left: $uv.getPx(site[1].left - 10,true)
							}"
						></view>
					</view>
					<!-- #ifdef H5 -->
					<view
						class="uv-pick-color__control__item__drag drag-box"
						@tap.stop="touchstart($event, 2)"
						@touchstart.stop="touchstart($event, 2)"
						@touchmove.stop="touchmove($event, 2)"
						@touchend.stop="touchend($event, 2)"
					>
					<!-- #endif -->
					<!-- #ifndef H5 -->
					<view
						class="uv-pick-color__control__item__drag drag-box"
						@touchstart.stop="touchstart($event, 2)"
						@touchmove.stop="touchmove($event, 2)"
						@touchend.stop="touchend($event, 2)"
					>
					<!-- #endif -->
						<view class="uv-pick-color__control__item__drag--alpha"></view>
						<view 
							class="uv-pick-color__control__item__drag--circle"
							:style="{ 
								left: $uv.getPx(site[2].left - 10,true)
							}"
						></view>
					</view>
				</view>
			</view>
			<view class="uv-pick-color__result">
				<view 
					class="uv-pick-color__result__select"
					hover-class="uv-hover-class"
					@click.stop="select"
				>
					<text class="text">切换</text>
					<text class="text">模式</text>
				</view>
				<view class="uv-pick-color__result__item" v-if="mode">
					<view class="uv-pick-color__result__item--value uv-border">
						<text>{{hex}}</text>
					</view>
					<view class="uv-pick-color__result__item--hex">
						<text>HEX</text>
					</view>
				</view>
				<template v-else>
					<view class="uv-pick-color__result__item">
						<view class="uv-pick-color__result__item--value uv-border">
							<text>{{rgba.r}}</text>
						</view>
						<view class="uv-pick-color__result__item--rgba">
							<text>R</text>
						</view>
					</view>
					<view class="uv-pick-color__result__gap"></view>
					<view class="uv-pick-color__result__item">
						<view class="uv-pick-color__result__item--value uv-border">
							<text>{{rgba.g}}</text>
						</view>
						<view class="uv-pick-color__result__item--rgba">
							<text>G</text>
						</view>
					</view>
					<view class="uv-pick-color__result__gap"></view>
					<view class="uv-pick-color__result__item">
						<view class="uv-pick-color__result__item--value uv-border">
							<text>{{rgba.b}}</text>
						</view>
						<view class="uv-pick-color__result__item--rgba">
							<text>B</text>
						</view>
					</view>
					<view class="uv-pick-color__result__gap"></view>
					<view class="uv-pick-color__result__item">
						<view class="uv-pick-color__result__item--value uv-border">
							<text>{{rgba.a}}</text>
						</view>
						<view class="uv-pick-color__result__item--rgba">
							<text>A</text>
						</view>
					</view>
				</template>
			</view>
			<view class="uv-pick-color__prefab">
				<view 
					class="uv-pick-color__prefab__item"
					v-for="(item,index) in colorList"
					:key="index"
				>
					<view 
						class="uv-pick-color__prefab__item--color"
						:style="{ background:`rgba(${item.r},${item.g},${item.b},${item.a})` }"
						@click.stop="setColorBySelect(item)"
					></view>
				</view>
			</view>
		</view>
	</uv-popup>
	<!-- #endif -->
	<!-- #ifdef APP-NVUE -->
	<view>
		<text>nvue暂不支持uv-pick-color组件</text>
	</view>
	<!-- #endif -->
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
	import { rgbToHsb, hsbToRgb, rgbToHex, colorList } from './colors.js';
	import props from './props.js';
	export default {
		name: 'uv-pick-color',
		emits: ['confirm', 'cancel', 'close', 'change'],
		mixins: [mpMixin, mixin, props],
		computed: {
			pointerStyle() {
				const style = {};
				style.top = this.$uv.addUnit(this.site[0].top - 8);
				style.left = this.$uv.addUnit(this.site[0].left - 8);
				return style;
			}
		},
		data() {
			return {
				showToolbar: false,
				// rgba 颜色
				rgba: {
					r: 0,
					g: 0,
					b: 0,
					a: 1
				},
				// hsb 颜色
				hsb: {
					h: 0,
					s: 0,
					b: 0
				},
				site: [{
					top: 0,
					left: 0
				}, {
					left: 0
				}, {
					left: 0
				}],
				index: 0,
				bgcolor: {
					r: 255,
					g: 0,
					b: 0,
					a: 1
				},
				hex: '#000000',
				mode: true,
				colorList: colorList
			};
		},
		watch: {
			prefabColor(newVal) {
				this.colorList = newVal;
			}
		},
		created() {
			// #ifdef APP-NVUE
			return this.$uv.error('nvue暂不支持uv-pick-color组件');
			// #endif
			this.rgba = this.color;
			if (this.prefabColor.length) this.colorList = this.prefabColor;
		},
		methods: {
			open() {
				this.$refs.pickerColorPopup.open();
				this.showToolbar = true;
				this.$nextTick(async () => {
					await this.$uv.sleep(350);
					this.getSelectorQuery();
				})
			},
			close() {
				this.$refs.pickerColorPopup.close();
			},
			popupChange(e) {
				if(!e.show) this.$emit('close');
			},
			// 点击工具栏的取消按钮
			cancelHandler() {
				this.$emit('cancel');
				this.close();
			},
			// 点击工具栏的确定按钮
			confirmHandler() {
				this.$emit('confirm', {
					rgba: this.rgba,
					hex: this.hex
				})
				this.close();
			},
			// 初始化
			init() {
				// hsb 颜色
				this.hsb = rgbToHsb(this.rgba);
				this.setValue(this.rgba);
			},
			async getSelectorQuery() {
				const data = await this.$uvGetRect('.drag-box',true);
				this.position = data;
				this.setColorBySelect(this.rgba);
			},
			// 选择模式
			select() {
				this.mode = !this.mode;
			},
			touchstart(e, index) {
				const { clientX, clientY } = e.touches[0];
				this.pageX = clientX;
				this.pageY = clientY;
				this.setPosition(clientX, clientY, index);
			},
			touchmove(e, index) {
				const { clientX, clientY } = e.touches[0];
				this.moveX = clientX;
				this.moveY = clientY;
				this.setPosition(clientX, clientY, index);
			},
			touchend(e, index) {},
			/**
			 * 设置位置
			 */
			setPosition(x, y, index) {
				this.index = index;
				const { top, left, width, height } = this.position[index];
				// 设置最大最小值
				this.site[index].left = Math.max(0, Math.min(parseInt(x - left), width));
				if (index === 0) {
					this.site[index].top = Math.max(0, Math.min(parseInt(y - top), height));
					// 设置颜色
					this.hsb.s = parseInt((100 * this.site[index].left) / width);
					this.hsb.b = parseInt(100 - (100 * this.site[index].top) / height);
					this.setColor();
					this.setValue(this.rgba);
				} else {
					this.setControl(index, this.site[index].left);
				}
			},
			/**
			 * 设置 rgb 颜色
			 */
			setColor() {
				const rgb = hsbToRgb(this.hsb);
				this.rgba.r = rgb.r;
				this.rgba.g = rgb.g;
				this.rgba.b = rgb.b;
			},
			/**
			 * 设置二进制颜色
			 * @param {Object} rgb
			 */
			setValue(rgb) {
				this.hex = `#${(rgbToHex(rgb))}`;
			},
			setControl(index, x) {
				const {
					top,
					left,
					width,
					height
				} = this.position[index];

				if (index === 1) {
					this.hsb.h = parseInt((360 * x) / width);
					this.bgcolor = hsbToRgb({
						h: this.hsb.h,
						s: 100,
						b: 100
					});
					this.setColor()
				} else {
					this.rgba.a = +(x / width).toFixed(1);
				}
				this.setValue(this.rgba);
			},
			setColorBySelect(getrgb) {
				const { r, g, b, a } = getrgb;
				let rgb = {};
				rgb = {
					r: r ? parseInt(r) : 0,
					g: g ? parseInt(g) : 0,
					b: b ? parseInt(b) : 0,
					a: a ? a : 0
				};
				this.rgba = rgb;
				this.hsb = rgbToHsb(rgb);
				this.changeViewByHsb();
			},
			changeViewByHsb() {
				const [a, b, c] = this.position;
				this.site[0].left = parseInt(this.hsb.s * a.width / 100);
				this.site[0].top = parseInt((100 - this.hsb.b) * a.height / 100);
				this.setColor(this.hsb.h);
				this.setValue(this.rgba);
				this.bgcolor = hsbToRgb({
					h: this.hsb.h,
					s: 100,
					b: 100
				});
				this.site[1].left = this.hsb.h / 360 * b.width;
				this.site[2].left = this.rgba.a * c.width;
			}
		}
	};
</script>
<style scoped lang="scss">
	$show-border: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	$height: 400rpx;
	/* #ifndef APP-NVUE */
	.uv-pick-color {
		&__box {
			position: relative;
			height: $height;
			background: rgb(255, 0, 0);
			margin: 20rpx;
			&__bg {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
				&-mask {
					position: absolute;
					top: 0;
					left: 0;
					right: 0;
					bottom: 0;
					height: $height;
					background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
				}
				&-pointer {
					position: absolute;
					top: -8px;
					left: -8px;
					z-index: 2;
					width: 16px;
					height: 16px;
					border: 1px #fff solid;
					border-radius: 8px;
				}
			}
		}
		&__control {
			@include flex;
			padding: 10rpx 20rpx;
			&__alpha {
				width: 100rpx;
				height: 100rpx;
				border-radius: 50rpx;
				background-color: #fff;
				background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
				background-size: 36rpx 36rpx;
				background-position: 0 0, 18rpx 18rpx;
				border: 1px #eee solid;
				overflow: hidden;
				&--color {
					width: 100%;
					height: 100%;
				}
			}
			&__item {
				flex: 1;
				@include flex(column);
				justify-content: space-between;
				height: 100rpx;
				padding: 6rpx 0 6rpx 30rpx;
			}
			&__item__drag {
				position: relative;
				height: 16px;
				background-color: #fff;
				background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
				linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
				background-size: 32rpx 32rpx;
				background-position: 0 0, 16rpx 16rpx;
				&--hue {
					width: 100%;
					height: 100%;
					background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
				}
				&--alpha {
					width: 100%;
					height: 100%;
					background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0));
				}
				&--circle {
					position: absolute;
					top: -2px;
					width: 20px;
					height: 20px;
					box-sizing: border-box;
					border-radius: 10px;
					background: #fff;
					box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
				}
			}
		}
		&__result {
			@include flex;
			padding: 20rpx;
			text-align: center;
			&__select {
				@include flex(column);
				justify-content: center;
				width: 100rpx;
				height: 100rpx;
				margin-right: 10px;
				border-radius: 10rpx;
				box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
				font-size: 14px;
				color: #999;
			}
			&__item {
				flex: 1;
				height: 100rpx;
				&--value {
					height: 50rpx;
					line-height: 50rpx;
					border-radius: 4rpx;
					font-size: 28rpx;
					color: #999;
				}
				&--hex,
				&--rgba {
					height: 50rpx;
					line-height: 50rpx;
					font-size: 30rpx;
				}
			}
			&__gap {
				width: 10px;
				height: 10px;
			}
		}
		&__prefab {
			@include flex;
			margin: 0 -8rpx;
			padding: 0 20rpx 20rpx;
			flex-wrap: wrap;
			&__item {
				width: 50rpx;
				height: 50rpx;
				margin: 8rpx;
				border-radius: 6rpx;
				background-color: #fff;
				background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
					linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
				background-size: 36rpx 36rpx;
				background-position: 0 0, 18rpx 18rpx;
				border: 1px #eee solid;
				&--color {
					width: 100%;
					height: 100%;
					border-radius: 6rpx;
				}
			}
		}
	}
	/* #endif */
</style>x{
  "id": "uv-pick-colopick-color 颜色KQ8",
  "description": "该组件为颜色选择器，支持预制颜色，初始化颜色，简单配置，开箱即用",
  "key7uv-pick-coloT"颜色",
    "coloropup",
			"uv-toolbau^,yz	x e100644 changelog.md S+=	R2I1jB40000 components ܼCe:A1'6100644 package.json bp,oMrpj100644 readme.md Wu1+\>Mb6CH<[xI## 1.0.14（2023-12-29）
1. 修复上个版本引出的BUG
## 1.0.13（2023-12-26）
1. 修复抖音小程序滚到底不触发change的BUG
## 1.0.12（2023-11-20）
1. 修复issues反馈的问题uv-picker在组合式API的自定义组件中，columns动态赋值无法显示选项：https://gitee.com/climblee/uv-ui/issues/I8H0GQ
## 1.0.11（2023-10-11）
1. 将immediate-change默认值改为true，该值在于change回调的及时性，微信小程序生效
## 1.0.10（2023-08-25）
1. 增加round属性设置弹窗圆角，默认为0
## 1.0.9（2023-08-24）
1. 修复cli项目不返回值的问题
## 1.0.8（2023-08-04）
1. 优化
## 1.0.7（2023-08-02）
1. 改组件中删除uv-toolbar组件，请单独下载uv-toolbar组件
## 1.0.6（2023-07-02）
uv-picker  由于弹出层uv-popup的修改，打开和关闭方法更改，详情参考文档：https://www.uvui.cn/components/picker.html
## 1.0.5（2023-06-26）
1. 增加color参数
2. 增加activeColor参数
## 1.0.4（2023-06-15）
1. 修改支付宝报错的BUG
## 1.0.3（2023-06-12）
1. setColumnValues的使用统一化，避免某些平台报错
2. 取消change回调回传的组件实例，直接统一通过ref的方式调取setColumnValues方法
## 1.0.2（2023-05-23）
1. uv-toolbar组件新增下边框属性 
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-picker 选择器
Mx$ 40000 uv-picker t$b`VXzz{t?xM 100644 props.js Ti 2Fcrz100644 uv-picker.vue ȮhU@4B05Gz"|"(x&窗	B\// 对象数组，设置每一列的数据
		columns: {
			type: Array,
			default: () => []f定'zA字颜色
		cQ&N	!// 选中文字的颜色
		activeP'N	k6选项对象中，需要展示的属性键名
		keyNam#text'@各列的默认索引
		defaultIndex: {
			type: Array,
			default: () => [],
		},
		// 是否在手指松开时立即触发 change 事件。若不开启则会在滚动动画结束后触发 change 事件，只在微信2.21.1及以上有效
		immediateChangP	#	picker
	}
}Ux'C<template>
	<uv-popup
		ref="pickerPopup"
		mode="bottom"
		:round="round"
		:close-on-click-overlay="closeOnClickOverlay"
		@change="popupChange"
	>
		<view class="uv-picker">
			<uv-toolbar
				v-if="showToolbar"
				:cancelColor="cancelColor"
				:confirmColor="confirmColor"
				:cancelText="cancelText"
				:confirmText="confirmText"
				:title="title"
				@cancel="cancel"
				@confirm="confirm"
			></uv-toolbar>
			<!-- #ifdef MP-TOUTIAO -->
			<picker-view
				class="uv-picker__view"
				:indicatorStyle="`height: ${$uv.addUnit(itemHeight)}`"
				:value="innerIndex"
				:immediateChange="immediateChange"
				:style="{
					height: `${$uv.addUnit(visibleItemCount * itemHeight)}`
				}"
				@pickend="changeHandler"
			>
			<!-- #endif -->
			<!-- #ifndef MP-TOUTIAO -->
			<picker-view
				class="uv-picker__view"
				:indicatorStyle="`height: ${$uv.addUnit(itemHeight)}`"
				:value="innerIndex"
				:immediateChange="immediateChange"
				:style="{
					height: `${$uv.addUnit(visibleItemCount * itemHeight)}`
				}"
				@change="changeHandler"
			>
			<!-- #endif -->
			<!-- @pickend在这里为了解决抖音等滚到底不触发change兼容性问题 -->
				<picker-view-column
					v-for="(item, index) in innerColumns"
					:key="index"
					class="uv-picker__view__column"
				>
					<text
						v-if="$uv.test.array(item)"
						class="uv-picker__view__column__item uv-line-1"
						v-for="(item1, index1) in item"
						:key="index1"
						:style="[{
								height: $uv.addUnit(itemHeight),
								lineHeight: $uv.addUnit(itemHeight),
								fontWeight: index1 === innerIndex[index] ? 'bold' : 'normal'
							},textStyle(index,index1)]"
					>{{ getItemText(item1) }}</text>
				</picker-view-column>
			</picker-view>
			<view
				v-if="loading"
				class="uv-picker--loading"
			>
				<uv-loading-icon mode="circle"></uv-loading-icon>
			</view>
		</view>
	</uv-popup>
</template>

<script>
/**
 * uv-picker
 * @description 选择器
 * @property {Boolean}			showToolbar			是否显示顶部的操作栏（默认 true ）
 * @property {String}			title				顶部标题
 * @property {Array}			columns				对象数组，设置每一列的数据
 * @property {Boolean}			loading				是否显示加载中状态（默认 false ）
 * @property {String | Number}	itemHeight			各列中，单个选项的高度（默认 44 ）
 * @property {String}			cancelText			取消按钮的文字（默认 '取消' ）
 * @property {String}			confirmText			确认按钮的文字（默认 '确定' ）
 * @property {String}			cancelColor			取消按钮的颜色（默认 '#909193' ）
 * @property {String}			confirmColor		确认按钮的颜色（默认 '#3c9cff' ）
 * @property {String}			color		文字颜色（默认 '' ）
 * @property {String}			activeColor		选中文字的颜色（默认 '' ）
 * @property {String | Number}	visibleItemCount	每列中可见选项的数量（默认 5 ）
 * @property {String}			keyName				选项对象中，需要展示的属性键名（默认 'text' ）
 * @property {Boolean}			closeOnClickOverlay	是否允许点击遮罩关闭选择器（默认 false ）
 * @property {Array}			defaultIndex		各列的默认索引
 * @property {Boolean}			immediateChange		是否在手指松开时立即触发change事件（默认 false ）
 * @event {Function} close		关闭选择器时触发
 * @event {Function} cancel		点击取消按钮触发
 * @event {Function} change		当选择值变化时触发
 * @event {Function} confirm	点击确定按钮，返回当前选择的值
 */
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import props from './props.js';
export default {
	name: 'uv-picker',
	emits: ['confirm','cancel','close','change'],
	mixins: [mpMixin, mixin, props],
	computed: {
		// 为了解决支付宝不生效
		textStyle(){
			return (index,index1) => {
				const style = {};
				// #ifndef APP-NVUE 
				style.display = 'block';
				// #endif
				if(this.color) {
					style.color = this.color;
				}
				if(this.activeColor && index1 === this.innerIndex[index]) {
					style.color = this.activeColor;
				}
				return style;
			}
		}
	},
	data() {
		return {
			// 上一次选择的列索引
			lastIndex: [],
			// 索引值 ，对应picker-view的value
			innerIndex: [],
			// 各列的值
			innerColumns: [],
			// 上一次的变化列索引
			columnIndex: 0,
		}
	},
	watch: {
		// 监听默认索引的变化，重新设置对应的值
		defaultIndex: {
			immediate: true,
			handler(n) {
				this.setIndexs(n, true)
			}
		},
		// 监听columns参数的变化
		columns: {
			deep: true,
			immediate: true,
			handler(n) {
				this.setColumns(n)
			}
		},
	},
	methods: {
		open() {
			this.$refs.pickerPopup.open();
		},
		close() {
			this.$refs.pickerPopup.close();
		},
		popupChange(e) {
			if(!e.show) this.$emit('close');
		},
		// 获取item需要显示的文字，判别为对象还是文本
		getItemText(item) {
			if (this.$uv.test.object(item)) {
				return item[this.keyName]
			} else {
				return item
			}
		},
		// 点击工具栏的取消按钮
		cancel() {
			this.$emit('cancel');
			this.close();
		},
		// 点击工具栏的确定按钮
		confirm() {
			// 在这里使用deepClone拷贝后，vue3会自动转换成原始对象，这样处理是因为cli项目可能出现不返回值的情况
			this.$emit('confirm', this.$uv.deepClone({
				indexs: this.innerIndex,
				value: this.innerColumns.map((item, index) => item[this.innerIndex[index]]),
				values: this.innerColumns
			}));
			if(this.closeOnClickConfirm) {
				this.close();
			}
		},
		// 选择器某一列的数据发生变化时触发
		changeHandler(e) {
			const {
				value
			} = e.detail
			let index = 0,
				columnIndex = 0
			// 通过对比前后两次的列索引，得出当前变化的是哪一列
			for (let i = 0; i < value.length; i++) {
				let item = value[i]
				if (item !== (this.lastIndex[i] || 0)) { // 把undefined转为合法假值0
					// 设置columnIndex为当前变化列的索引
					columnIndex = i
					// index则为变化列中的变化项的索引
					index = item
					break // 终止循环，即使少一次循环，也是性能的提升
				}
			}
			this.columnIndex = columnIndex
			const values = this.innerColumns
			// 将当前的各项变化索引，设置为"上一次"的索引变化值
			this.setLastIndex(value)
			this.setIndexs(value)

			this.$emit('change', {
				value: this.innerColumns.map((item, index) => item[value[index]]),
				index,
				indexs: value,
				// values为当前变化列的数组内容
				values,
				columnIndex
			})
		},
		// 设置index索引，此方法可被外部调用设置
		setIndexs(index, setLastIndex) {
			this.innerIndex = this.$uv.deepClone(index)
			if (setLastIndex) {
				this.setLastIndex(index)
			}
		},
		// 记录上一次的各列索引位置
		setLastIndex(index) {
			// 当能进入此方法，意味着当前设置的各列默认索引，即为“上一次”的选中值，需要记录，是因为changeHandler中
			// 需要拿前后的变化值进行对比，得出当前发生改变的是哪一列
			this.lastIndex = this.$uv.deepClone(index)
		},
		// 设置对应列选项的所有值
		setColumnValues(columnIndex, values) {
			// 替换innerColumns数组中columnIndex索引的值为values，使用的是数组的splice方法
			this.innerColumns.splice(columnIndex, 1, values)
			// 拷贝一份原有的innerIndex做临时变量，将大于当前变化列的所有的列的默认索引设置为0
			let tmpIndex = this.$uv.deepClone(this.innerIndex)
			for (let i = 0; i < this.innerColumns.length; i++) {
				if (i > this.columnIndex) {
					tmpIndex[i] = 0
				}
			}
			// 一次性赋值，不能单个修改，否则无效
			this.setIndexs(tmpIndex)
		},
		// 获取对应列的所有选项
		getColumnValues(columnIndex) {
			// 进行同步阻塞，因为外部得到change事件之后，可能需要执行setColumnValues更新列的值
			// 索引如果在外部change的回调中调用getColumnValues的话，可能无法得到变更后的列值，这里进行一定延时，保证值的准确性
			(async () => {
				await this.$uv.sleep()
			})()
			return this.innerColumns[columnIndex]
		},
		// 设置整体各列的columns的值
		setColumns(columns) {
			this.innerColumns = this.$uv.deepClone(columns)
			// 如果在设置各列数据时，没有被设置默认的各列索引defaultIndex，那么用0去填充它，数组长度为列的数量
			if (this.innerIndex.length === 0) {
				this.innerIndex = new Array(columns.length).fill(0)
			}
		},
		// 获取各列选中值对应的索引
		getIndexs() {
			return this.innerIndex
		},
		// 获取各列选中的值
		getValues() {
			// 进行同步阻塞，因为外部得到change事件之后，可能需要执行setColumnValues更新列的值
			// 索引如果在外部change的回调中调用getValues的话，可能无法得到变更后的列值，这里进行一定延时，保证值的准确性
			(async () => {
				await this.$uv.sleep()
			})()
			return this.innerColumns.map((item, index) => item[this.innerIndex[index]])
		}
	},
}
</script>

<style lang="scss" scoped>
	$show-lines: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-picker {
		position: relative;

		&__view {

			&__column {
				@include flex;
				flex: 1;
				justify-content: center;

				&__item {
					@include flex;
					justify-content: center;
					align-items: center;
					font-size: 16px;
					text-align: center;
					/* #ifndef APP-NVUE */
					display: block;
					/* #endif */
					color: $uv-main-color;

					&--disabled {
						/* #ifndef APP-NVUE */
						cursor: not-allowed;
						/* #endif */
						opacity: 0.35;
					}
				}
			}
		}

		&--loading {
			position: absolute;
			top: 0;
			right: 0;
			left: 0;
			bottom: 0;
			@include flex;
			justify-content: center;
			align-items: center;
			background-color: rgba(255, 255, 255, 0.87);
			z-index: 1000;
		}
	}
</style>
RfW"x '{
  "id": "uvpicker KRb4",
  "description": "uv-picker 此选择器用于单列，多列，多列联动的选择场景....uvN(picker",
    "联动*opup",
			"uv-loading-icon",
			"uv-toolba_Z	x e100644 changelog.md %7S] {f40000 components giyzr W$[`100644 package.json SΗwD;E}"100644 readme.md "J7a39Dզrk?2x!## 1.0.7（2023-11-20）
修复issues问题：https://gitee.com/climblee/uv-ui/issues/I8HDLO
## 1.0.6（2023-10-13）
1. 优化vue，内容有背景色，设置圆角被遮挡的情况
## 1.0.5（2023-09-10）
1. 修复H5默认层级过高的问题
2. 修复全局设置prop无效的问题
## 1.0.4（2023-08-08）
1. 修复修改zIndex不生效的BUG
## 1.0.3（2023-07-02）
uv-popup  弹出层，代码重构优化，性能翻倍，小程序体验性能更加，避免卡顿。打开和关闭方法更改，详情参考文档：https://www.uvui.cn/components/popup.html
## 1.0.2（2023-06-11）
1. 修复zIndex层级问题
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
1. 新增uv-popup组件
@&x# 40000 uv-popup V!*4Z^Y2R`ExO 100644 keypress.js bݤa]Y#sAma+100644 uv-popup.vue ?$U!}!HEx_// #ifdef H5
export default {
  name: 'Keypress',
  props: {
    disable: {
      type: Boolean,
      default: false
    }
  },
  mounted () {
    const keyNames = {
      esc: ['Esc', 'Escape'],
      tab: 'Tab',
      enter: 'Enter',
      space: [' ', 'Spacebar'],
      up: ['Up', 'ArrowUp'],
      left: ['Left', 'ArrowLeft'],
      right: ['Right', 'ArrowRight'],
      down: ['Down', 'ArrowDown'],
      delete: ['Backspace', 'Delete', 'Del']
    }
    const listener = ($event) => {
      if (this.disable) {
        return
      }
      const keyName = Object.keys(keyNames).find(key => {
        const keyName = $event.key
        const value = keyNames[key]
        return value === keyName || (Array.isArray(value) && value.includes(keyName))
      })
      if (keyName) {
        // 避免和其他按键事件冲突
        setTimeout(() => {
          this.$emit(keyName, {})
        }, 0)
      }
    }
    document.addEventListener('keyup', listener)
    // this.$once('hook:beforeDestroy', () => {
    //   document.removeEventListener('keyup', listener)
    // })
  },
	render: () => {}
}
// #endif
#ZJcx61<template>
	<view 
		v-if="showPopup" 
		class="uv-popup" 
		:class="[popupClass, isDesktop ? 'fixforpc-z-index' : '']"
		:style="[{zIndex: zIndex}]"
	>
		<view @touchstart="touchstart">
			<!-- 遮罩层 -->
			<uv-overlay
				key="1"
				v-if="maskShow && overlay"
				:show="showTrans"
				:duration="duration"
				:custom-style="overlayStyle"
				:opacity="overlayOpacity"
			  :zIndex="zIndex"
				@click="onTap"
			></uv-overlay>
			<uv-transition 
				key="2" 
				:mode="ani" 
				name="content" 
				:custom-style="transitionStyle" 
				:duration="duration"
				:show="showTrans" 
				@click="onTap"
			>
				<view 
					class="uv-popup__content" 
					:style="[contentStyle]" 
					:class="[popupClass]" 
					@click="clear"
				>
					<uv-status-bar v-if="safeAreaInsetTop"></uv-status-bar>
					<slot />
					<uv-safe-bottom v-if="safeAreaInsetBottom"></uv-safe-bottom>
					<view
						v-if="closeable"
						@tap.stop="close"
						class="uv-popup__content__close"
						:class="['uv-popup__content__close--' + closeIconPos]"
						hover-class="uv-popup__content__close--hover"
						hover-stay-time="150"
					>
						<uv-icon
							name="close"
							color="#909399"
							size="18"
							bold
						></uv-icon>
					</view>
				</view>
			</uv-transition>
		</view>
		<!-- #ifdef H5 -->
		<keypress v-if="maskShow" @esc="onTap" />
		<!-- #endif -->
	</view>
</template>

<script>
	// #ifdef H5
	import keypress from './keypress.js'
	// #endif
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	/**
	* PopUp 弹出层
	* @description 弹出层组件，为了解决遮罩弹层的问题
	* @tutorial https://www.uvui.cn/components/popup.html
	* @property {String} mode = [top|center|bottom|left|right] 弹出方式
	* 	@value top 顶部弹出
	* 	@value center 中间弹出
	* 	@value bottom 底部弹出
	* 	@value left		左侧弹出
	* 	@value right  右侧弹出
	* @property {Number} duration 动画时长，默认300
	* @property {Boolean} overlay 是否显示遮罩，默认true
	* @property {Boolean} overlayOpacity 遮罩透明度，默认0.5 
	* @property {Object} overlayStyle 遮罩自定义样式
	* @property {Boolean} closeOnClickOverlay = [true|false] 蒙版点击是否关闭弹窗，默认true
	* @property {Number | String} zIndex 弹出层的层级
	* @property {Boolean} safeAreaInsetTop 是否留出顶部安全区（状态栏高度），默认false
	* @property {Boolean} safeAreaInsetBottom 是否为留出底部安全区适配，默认true
	* @property {Boolean} closeable 是否显示关闭图标，默认false
	* @property {Boolean} closeIconPos 自定义关闭图标位置，`top-left`-左上角，`top-right`-右上角，`bottom-left`-左下角，`bottom-right`-右下角，默认top-right
	* @property {String}  bgColor 主窗口背景色
	* @property {String}  maskBackgroundColor 蒙版颜色
	* @property {Boolean} customStyle 自定义样式
	* @event {Function} change 打开关闭弹窗触发，e={show: false}
	* @event {Function} maskClick 点击遮罩触发
	*/
	export default {
		name: 'uv-popup',
		components: {
			// #ifdef H5
			keypress
			// #endif
		},
		mixins: [mpMixin, mixin],
		emits: ['change', 'maskClick'],
		props: {
			// 弹出层类型，可选值，top: 顶部弹出层；bottom：底部弹出层；center：全屏弹出层
			// message: 消息提示 ; dialog : 对话框
			mode: {
				type: String,
				default: 'center'
			},
			// 动画时长，单位ms
			duration: {
				type: [String, Number],
				default: 300
			},
			// 层级
			zIndex: {
				type: [String, Number],
				// #ifdef H5
				default: 997
				// #endif
				// #ifndef H5
				default: 10075
				// #endif
			},
			bgColor: {
				type: String,
				default: '#ffffff'
			},
			safeArea: {
				type: Boolean,
				default: true
			},
			// 是否显示遮罩
			overlay: {
				type: Boolean,
				default: true
			},
			// 点击遮罩是否关闭弹窗
			closeOnClickOverlay: {
				type: Boolean,
				default: true
			},
			// 遮罩的透明度，0-1之间
			overlayOpacity: {
				type: [Number, String],
				default: 0.4
			},
			// 自定义遮罩的样式
			overlayStyle: {
				type: [Object, String],
				default: ''
			},
			// 是否为iPhoneX留出底部安全距离
			safeAreaInsetBottom: {
				type: Boolean,
				default: true
			},
			// 是否留出顶部安全距离（状态栏高度）
			safeAreaInsetTop: {
				type: Boolean,
				default: false
			},
			// 是否显示关闭图标
			closeable: {
				type: Boolean,
				default: false
			},
			// 自定义关闭图标位置，top-left为左上角，top-right为右上角，bottom-left为左下角，bottom-right为右下角
			closeIconPos: {
				type: String,
				default: 'top-right'
			},
			// mode=center，也即中部弹出时，是否使用缩放模式
			zoom: {
				type: Boolean,
				default: true
			},
			round: {
				type: [Number, String],
				default: 0
			},
			...uni.$uv?.props?.popup
		},
		watch: {
			/**
			 * 监听type类型
			 */
			type: {
				handler: function(type) {
					if (!this.config[type]) return
					this[this.config[type]](true)
				},
				immediate: true
			},
			isDesktop: {
				handler: function(newVal) {
					if (!this.config[newVal]) return
					this[this.config[this.mode]](true)
				},
				immediate: true
			},
			// H5 下禁止底部滚动
			showPopup(show) {
				// #ifdef H5
				// fix by mehaotian 处理 h5 滚动穿透的问题
				document.getElementsByTagName('body')[0].style.overflow = show ? 'hidden' : 'visible'
				// #endif
			}
		},
		data() {
			return {
				ani: [],
				showPopup: false,
				showTrans: false,
				popupWidth: 0,
				popupHeight: 0,
				config: {
					top: 'top',
					bottom: 'bottom',
					center: 'center',
					left: 'left',
					right: 'right',
					message: 'top',
					dialog: 'center',
					share: 'bottom'
				},
				transitionStyle: {
					position: 'fixed',
					left: 0,
					right: 0
				},
				maskShow: true,
				mkclick: true,
				popupClass: this.isDesktop ? 'fixforpc-top' : 'top',
				direction: ''
			}
		},
		computed: {
			isDesktop() {
				return this.popupWidth >= 500 && this.popupHeight >= 500
			},
			bg() {
				if (this.bgColor === '' || this.bgColor === 'none' || this.$uv.getPx(this.round)>0) {
					return 'transparent'
				}
				return this.bgColor
			},
			contentStyle() {
				const style = {};
				if (this.bgColor) {
					style.backgroundColor = this.bg
				}
				if(this.round) {
					const value = this.$uv.addUnit(this.round)
					const mode = this.direction?this.direction:this.mode
					style.backgroundColor = this.bgColor
					if(mode === 'top') {
						style.borderBottomLeftRadius = value
						style.borderBottomRightRadius = value
					} else if(mode === 'bottom') {
						style.borderTopLeftRadius = value
						style.borderTopRightRadius = value
					} else if(mode === 'center') {
						style.borderRadius = value
					} 
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		// #ifndef VUE3
		// TODO vue2
		destroyed() {
			this.setH5Visible()
		},
		// #endif
		// #ifdef VUE3
		// TODO vue3
		unmounted() {
			this.setH5Visible()
		},
		// #endif
		created() {
			// TODO 处理 message 组件生命周期异常的问题
			this.messageChild = null
			// TODO 解决头条冒泡的问题
			this.clearPropagation = false
		},
		methods: {
			setH5Visible() {
				// #ifdef H5
				// fix by mehaotian 处理 h5 滚动穿透的问题
				document.getElementsByTagName('body')[0].style.overflow = 'visible'
				// #endif
			},
			/**
			 * 公用方法，不显示遮罩层
			 */
			closeMask() {
				this.maskShow = false
			},
			// TODO nvue 取消冒泡
			clear(e) {
				// #ifndef APP-NVUE
				e.stopPropagation()
				// #endif
				this.clearPropagation = true
			},

			open(direction) {
				// fix by mehaotian 处理快速打开关闭的情况
				if (this.showPopup) {
					return
				}
				let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
				if (!(direction && innerType.indexOf(direction) !== -1)) {
					direction = this.mode
				}else {
					this.direction = direction;
				}
				if (!this.config[direction]) {
					return this.$uv.error(`缺少类型：${direction}`);
				}
				this[this.config[direction]]()
				this.$emit('change', {
					show: true,
					type: direction
				})
			},
			close(type) {
				this.showTrans = false
				this.$emit('change', {
					show: false,
					type: this.mode
				})
				clearTimeout(this.timer)
				// // 自定义关闭事件
				this.timer = setTimeout(() => {
					this.showPopup = false
				}, 300)
			},
			// TODO 处理冒泡事件，头条的冒泡事件有问题 ，先这样兼容
			touchstart() {
				this.clearPropagation = false
			},
			onTap() {
				if (this.clearPropagation) {
					// fix by mehaotian 兼容 nvue
					this.clearPropagation = false
					return
				}
				this.$emit('maskClick')
				if (!this.closeOnClickOverlay) return
				this.close()
			},
			/**
			 * 顶部弹出样式处理
			 */
			top(type) {
				this.popupClass = this.isDesktop ? 'fixforpc-top' : 'top'
				this.ani = ['slide-top']
				this.transitionStyle = {
					position: 'fixed',
					zIndex: this.zIndex,
					left: 0,
					right: 0,
					backgroundColor: this.bg
				}
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return
				this.showPopup = true
				this.showTrans = true
				this.$nextTick(() => {
					if (this.messageChild && this.mode === 'message') {
						this.messageChild.timerClose()
					}
				})
			},
			/**
			 * 底部弹出样式处理
			 */
			bottom(type) {
				this.popupClass = 'bottom'
				this.ani = ['slide-bottom']
				this.transitionStyle = {
					position: 'fixed',
					zIndex: this.zIndex,
					left: 0,
					right: 0,
					bottom: 0,
					backgroundColor: this.bg
				}
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return
				this.showPopup = true
				this.showTrans = true
			},
			/**
			 * 中间弹出样式处理
			 */
			center(type) {
				this.popupClass = 'center'
				this.ani = this.zoom?['zoom-in', 'fade']:['fade'];
				this.transitionStyle = {
					position: 'fixed',
					zIndex: this.zIndex,
					/* #ifndef APP-NVUE */
					display: 'flex',
					flexDirection: 'column',
					/* #endif */
					bottom: 0,
					left: 0,
					right: 0,
					top: 0,
					justifyContent: 'center',
					alignItems: 'center'
				}
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return
				this.showPopup = true
				this.showTrans = true
			},
			left(type) {
				this.popupClass = 'left'
				this.ani = ['slide-left']
				this.transitionStyle = {
					position: 'fixed',
					zIndex: this.zIndex,
					left: 0,
					bottom: 0,
					top: 0,
					backgroundColor: this.bg,
					/* #ifndef APP-NVUE */
					display: 'flex',
					flexDirection: 'column'
					/* #endif */
				}
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return
				this.showPopup = true
				this.showTrans = true
			},
			right(type) {
				this.popupClass = 'right'
				this.ani = ['slide-right']
				this.transitionStyle = {
					position: 'fixed',
					zIndex: this.zIndex,
					bottom: 0,
					right: 0,
					top: 0,
					backgroundColor: this.bg,
					/* #ifndef APP-NVUE */
					display: 'flex',
					flexDirection: 'column'
					/* #endif */
				}
				// TODO 兼容 type 属性 ，后续会废弃
				if (type) return
				this.showPopup = true
				this.showTrans = true
			}
		}
	}
</script>
<style lang="scss" scoped>
	.uv-popup {
		position: fixed;
		/* #ifndef APP-NVUE */
		z-index: 99;

		/* #endif */
		&.top,
		&.left,
		&.right {
			/* #ifdef H5 */
			top: var(--window-top);
			/* #endif */
			/* #ifndef H5 */
			top: 0;
			/* #endif */
		}

		.uv-popup__content {
			/* #ifndef APP-NVUE */
			display: block;
			overflow: hidden;
			/* #endif */
			position: relative;

			&.left,
			&.right {
				/* #ifdef H5 */
				padding-top: var(--window-top);
				/* #endif */
				/* #ifndef H5 */
				padding-top: 0;
				/* #endif */
				flex: 1;
			}
			&__close {
				position: absolute;

				&--hover {
					opacity: 0.4;
				}
			}
			
			&__close--top-left {
				top: 15px;
				left: 15px;
			}
			
			&__close--top-right {
				top: 15px;
				right: 15px;
			}
			
			&__close--bottom-left {
				bottom: 15px;
				left: 15px;
			}
			
			&__close--bottom-right {
				right: 15px;
				bottom: 15px;
			}
		}
	}

	.fixforpc-z-index {
		/* #ifndef APP-NVUE */
		z-index: 999;
		/* #endif */
	}

	.fixforpc-top {
		top: 0;
	}
</style>
 J xd{
  "id": "uv-popup",
  "displayName": "uv-popup 弹出层 全面兼容vue3+2、app、h5、小程序k7",
  "description": "uv-popup 弹出层容器，用于展示弹窗、信息提示等内容，支持上、下、左、右和中B部弹出。组件只提供容器，内部内容由用户自定义popup!!popup",
    "弹出层\X,
			"uv-icon:safe-bottoms
aBx## Popup 弹出层

> **组件名：uv-popup**

弹出层容器，用于展示弹窗、信息提示等内容，支持上、下左、右和中部弹出。组件只提供容器，内部内容由用户自定义。

该组件已经放弃原来`uview2.x`写法，参照了官方`uni-popup`的写法进行重构。在小程序端的性能大大提升，打开和关闭避免延迟K调用方法与之前相比也有所差异，具体请查看文档。

# (pop1d76	x e100644 changelog.md pغ;%]fCҐc 40000 components k!|\DѲ100644 package.json ^tKfh|:100644 readme.md J%SCzFr2<~R?xy## 1.0.5（2023-12-19）
1. 优化
## 1.0.4（2023-07-17）
1. 优化文档
2. 优化其他
## 1.0.3（2023-06-26）
1. H5增加属性h5SaveTip 保存二维码时候是否显示提示
## 1.0.2（2023-06-01）
1. 修复点击触发两次事件的BUG 
## 1.0.1（2023-05-23）
1. 修复在部分平台不显示加载效果的BUG
## 1.0.0（2023-05-17）
1. 新增uv-qrcode组件
TCx$ 40000 uv-qrcode SE[s6־g"1Bt2#Nx #100644 cache.js ؗhs?'aTQ40000 gcanvas SڣE%!r/T100644 props.js U[je#80D3B100644 qrcode.js "7K6rj˶@&100644 queue.js k)˜tj[
J'100644 uv-qrcode.vue ݌abKөfR:YUx! export const cacheImageList = [];*x O40000 bridge @k
\?kH:!40000 context-2d +󇾨ziHRCWxϑ40000 context-webgl yK}$	Bde4q40000 env ɢtA~a'rs100644 index.js JՈAy(_6*'e2Gx* 100644 bridge-weex.js 'nÇh_!6J!|)׵x%const isWeex = typeof WXEnvironment !== 'undefined';
const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform);
const isWeexAndroid = isWeex && !isWeexIOS;

import GLmethod from '../context-webgl/GLmethod';

const GCanvasModule =
    (typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) :
        (typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {};

let isDebugging = false;

let isComboDisabled = false;

const logCommand = (function () {
    const methodQuery = [];
    Object.keys(GLmethod).forEach(key => {
        methodQuery[GLmethod[key]] = key;
    })
    const queryMethod = (id) => {
        return methodQuery[parseInt(id)] || 'NotFoundMethod';
    }
    const logCommand = (id, cmds) => {
        const mId = cmds.split(',')[0];
        const mName = queryMethod(mId);
        console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`);
    }
    return logCommand;
})();

function joinArray(arr, sep) {
    let res = '';
    for (let i = 0; i < arr.length; i++) {
        if (i !== 0) {
            res += sep;
        }
        res += arr[i];
    }
    return res;
}

const commandsCache = {}

const GBridge = {

    callEnable: (ref, configArray) => {

        commandsCache[ref] = [];

        return GCanvasModule.enable({
            componentId: ref,
            config: configArray
        });
    },

    callEnableDebug: () => {
        isDebugging = true;
    },

    callEnableDisableCombo: () => {
        isComboDisabled = true;
    },

    callSetContextType: function (componentId, context_type) {
        GCanvasModule.setContextType(context_type, componentId);
    },

    callReset: function(id){
        GCanvasModule.resetComponent && canvasModule.resetComponent(componentId);
    },

    render: isWeexIOS ? function (componentId) {
        return GCanvasModule.extendCallNative({
            contextId: componentId,
            type: 0x60000001
        });
    } : function (componentId) {
        return callGCanvasLinkNative(componentId, 0x60000001, 'render');
    },

    render2d: isWeexIOS ? function (componentId, commands, callback) {

        if (isDebugging) {
            console.log('>>> >>> render2d ===');
            console.log('>>> commands: ' + commands);
        }
		
        GCanvasModule.render([commands, callback?true:false], componentId, callback);

    } : function (componentId, commands,callback) {

        if (isDebugging) {
            console.log('>>> >>> render2d ===');
            console.log('>>> commands: ' + commands);
        }

        callGCanvasLinkNative(componentId, 0x20000001, commands);
		if(callback){
		callback();
		}
    },

    callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) {

        throw 'should not be here anymore ' + cmdArgs;

    } : function (componentId, cmdArgs) {

        throw 'should not be here anymore ' + cmdArgs;

    },


    flushNative: isWeexIOS ? function (componentId) {

        const cmdArgs = joinArray(commandsCache[componentId], ';');
        commandsCache[componentId] = [];

        if (isDebugging) {
            console.log('>>> >>> flush native ===');
            console.log('>>> commands: ' + cmdArgs);
        }

        const result = GCanvasModule.extendCallNative({
            "contextId": componentId,
            "type": 0x60000000,
            "args": cmdArgs
        });

        const res = result && result.result;

        if (isDebugging) {
            console.log('>>> result: ' + res);
        }

        return res;

    } : function (componentId) {

        const cmdArgs = joinArray(commandsCache[componentId], ';');
        commandsCache[componentId] = [];

        if (isDebugging) {
            console.log('>>> >>> flush native ===');
            console.log('>>> commands: ' + cmdArgs);
        }

        const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs);

        if (isDebugging) {
            console.log('>>> result: ' + result);
        }

        return result;
    },

    callNative: function (componentId, cmdArgs, cache) {

        if (isDebugging) {
            logCommand(componentId, cmdArgs);
        }

        commandsCache[componentId].push(cmdArgs);

        if (!cache || isComboDisabled) {
            return GBridge.flushNative(componentId);
        } else {
            return undefined;
        }
    },

    texImage2D(componentId, ...args) {
        if (isWeexIOS) {
            if (args.length === 6) {
                const [target, level, internalformat, format, type, image] = args;
                GBridge.callNative(
                    componentId,
                    GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src
                )
            } else if (args.length === 9) {
                const [target, level, internalformat, width, height, border, format, type, image] = args;
                GBridge.callNative(
                    componentId,
                    GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' +
                    + format + ',' + type + ',' + (image ? image.src : 0)
                )
            }
        } else if (isWeexAndroid) {
            if (args.length === 6) {
                const [target, level, internalformat, format, type, image] = args;
                GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src);
            } else if (args.length === 9) {
                const [target, level, internalformat, width, height, border, format, type, image] = args;
                GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0));
            }
        }
    },

    texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
        if (isWeexIOS) {
            if (arguments.length === 8) {
                GBridge.callNative(
                    componentId,
                    GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src
                )
            }
        } else if (isWeexAndroid) {
            GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src);
        }
    },

    bindImageTexture(componentId, src, imageId) {
        GCanvasModule.bindImageTexture([src, imageId], componentId);
    },

    perloadImage([url, id], callback) {
        GCanvasModule.preLoadImage([url, id], function (image) {
            image.url = url;
            image.id = id;
            callback(image);
        });
    },
	
	measureText(text, fontStyle, componentId) {
	    return GCanvasModule.measureText([text, fontStyle], componentId);
	},
	
	getImageData (componentId, x, y, w, h, callback) {
		GCanvasModule.getImageData([x, y,w,h],componentId,callback);
	},
	
	putImageData (componentId, data, x, y, w, h, callback) {
		GCanvasModule.putImageData([x, y,w,h,data],componentId,callback);
	},
	
	toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){ 
		GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback);
	}
}

export default GBridge;תx 5100644 FillStyleLinearGradient.js >Al!O2a100644 FillStylePattern.js nOdo @S)I)Ci100644 FillStyleRadialGradient.js wYe	>BHggV@100644 RenderingContext.js 2
˒
+w9M=xclass FillStyleLinearGradient {

    constructor(x0, y0, x1, y1) {
        this._start_pos = { _x: x0, _y: y0 };
        this._end_pos = { _x: x1, _y: y1 };
        this._stop_count = 0;
        this._stops = [0, 0, 0, 0, 0];
    }

    addColorStop = function (pos, color) {
        if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
            this._stops[this._stop_count] = { _pos: pos, _color: color };
            this._stop_count++;
        }
    }
}

export default FillStyleLinearGradient;4f	x eclass FillStylePattern {
    constructor(img, pattern) {
        this._style = pattern;
        this._img = img;
    }
}

export default FillStylePattern;7&1,xb class FillStyleRadialGradient { r0, x1, y1, r>/, _r: rl-, _r: raRadialGradient;XR |xDimport FillStylePattern from './FillStylePattern';
import FillStyleLinearGradient from './FillStyleLinearGradient';
import FillStyleRadialGradient from './FillStyleRadialGradient';
import GImage from '../env/image.js';
import {
	ArrayBufferToBase64,
	Base64ToUint8ClampedArray
} from '../env/tool.js';

export default class CanvasRenderingContext2D {

	_drawCommands = '';

	_globalAlpha = 1.0;

	_fillStyle = 'rgb(0,0,0)';
	_strokeStyle = 'rgb(0,0,0)';

	_lineWidth = 1;
	_lineCap = 'butt';
	_lineJoin = 'miter';

	_miterLimit = 10;

	_globalCompositeOperation = 'source-over';

	_textAlign = 'start';
	_textBaseline = 'alphabetic';

	_font = '10px sans-serif';

	_savedGlobalAlpha = [];

	timer = null;
	componentId = null;

	_notCommitDrawImageCache = [];
	_needRedrawImageCache = [];
	_redrawCommands = '';
	_autoSaveContext = true;
	// _imageMap = new GHashMap();
	// _textureMap = new GHashMap();

	constructor() {
		this.className = 'CanvasRenderingContext2D';
		//this.save()
	}

	setFillStyle(value) {
		this.fillStyle = value;
	}

	set fillStyle(value) {
		this._fillStyle = value;

		if (typeof(value) == 'string') {
			this._drawCommands = this._drawCommands.concat("F" + value + ";");
		} else if (value instanceof FillStylePattern) {
			const image = value._img;
			if (!image.complete) {
				image.onload = () => {
					var index = this._needRedrawImageCache.indexOf(image);
					if (index > -1) {
						this._needRedrawImageCache.splice(index, 1);
						CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
						this._redrawflush(true);
					}
				}
				this._notCommitDrawImageCache.push(image);
			} else {
				CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
			}

			//CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
			this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
		} else if (value instanceof FillStyleLinearGradient) {
			var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
				value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
				value._stop_count;
			for (var i = 0; i < value._stop_count; ++i) {
				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
			}
			this._drawCommands = this._drawCommands.concat(command + ";");
		} else if (value instanceof FillStyleRadialGradient) {
			var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
				.toFixed(2) + "," +
				value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," +
				value._stop_count;
			for (var i = 0; i < value._stop_count; ++i) {
				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
			}
			this._drawCommands = this._drawCommands.concat(command + ";");
		}
	}

	get fillStyle() {
		return this._fillStyle;
	}

	get globalAlpha() {
		return this._globalAlpha;
	}

	setGlobalAlpha(value) {
		this.globalAlpha = value;
	}

	set globalAlpha(value) {
		this._globalAlpha = value;
		this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";");
	}


	get strokeStyle() {
		return this._strokeStyle;
	}

	setStrokeStyle(value) {
		this.strokeStyle = value;
	}

	set strokeStyle(value) {

		this._strokeStyle = value;

		if (typeof(value) == 'string') {
			this._drawCommands = this._drawCommands.concat("S" + value + ";");
		} else if (value instanceof FillStylePattern) {
			CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
			this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
		} else if (value instanceof FillStyleLinearGradient) {
			var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
				value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
				value._stop_count;

			for (var i = 0; i < value._stop_count; ++i) {
				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
			}
			this._drawCommands = this._drawCommands.concat(command + ";");
		} else if (value instanceof FillStyleRadialGradient) {
			var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
				.toFixed(2) + "," +
				value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," +
				value._stop_count;

			for (var i = 0; i < value._stop_count; ++i) {
				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
			}
			this._drawCommands = this._drawCommands.concat(command + ";");
		}
	}

	get lineWidth() {
		return this._lineWidth;
	}

	setLineWidth(value) {
		this.lineWidth = value;
	}

	set lineWidth(value) {
		this._lineWidth = value;
		this._drawCommands = this._drawCommands.concat("W" + value + ";");
	}

	get lineCap() {
		return this._lineCap;
	}

	setLineCap(value) {
		this.lineCap = value;
	}

	set lineCap(value) {
		this._lineCap = value;
		this._drawCommands = this._drawCommands.concat("C" + value + ";");
	}

	get lineJoin() {
		return this._lineJoin;
	}

	setLineJoin(value) {
		this.lineJoin = value
	}

	set lineJoin(value) {
		this._lineJoin = value;
		this._drawCommands = this._drawCommands.concat("J" + value + ";");
	}

	get miterLimit() {
		return this._miterLimit;
	}

	setMiterLimit(value) {
		this.miterLimit = value
	}

	set miterLimit(value) {
		this._miterLimit = value;
		this._drawCommands = this._drawCommands.concat("M" + value + ";");
	}

	get globalCompositeOperation() {
		return this._globalCompositeOperation;
	}

	set globalCompositeOperation(value) {

		this._globalCompositeOperation = value;
		let mode = 0;
		switch (value) {
			case "source-over":
				mode = 0;
				break;
			case "source-atop":
				mode = 5;
				break;
			case "source-in":
				mode = 0;
				break;
			case "source-out":
				mode = 2;
				break;
			case "destination-over":
				mode = 4;
				break;
			case "destination-atop":
				mode = 4;
				break;
			case "destination-in":
				mode = 4;
				break;
			case "destination-out":
				mode = 3;
				break;
			case "lighter":
				mode = 1;
				break;
			case "copy":
				mode = 2;
				break;
			case "xor":
				mode = 6;
				break;
			default:
				mode = 0;
		}

		this._drawCommands = this._drawCommands.concat("B" + mode + ";");
	}

	get textAlign() {
		return this._textAlign;
	}

	setTextAlign(value) {
		this.textAlign = value
	}

	set textAlign(value) {

		this._textAlign = value;
		let Align = 0;
		switch (value) {
			case "start":
				Align = 0;
				break;
			case "end":
				Align = 1;
				break;
			case "left":
				Align = 2;
				break;
			case "center":
				Align = 3;
				break;
			case "right":
				Align = 4;
				break;
			default:
				Align = 0;
		}

		this._drawCommands = this._drawCommands.concat("A" + Align + ";");
	}

	get textBaseline() {
		return this._textBaseline;
	}

	setTextBaseline(value) {
		this.textBaseline = value
	}

	set textBaseline(value) {
		this._textBaseline = value;
		let baseline = 0;
		switch (value) {
			case "alphabetic":
				baseline = 0;
				break;
			case "middle":
				baseline = 1;
				break;
			case "top":
				baseline = 2;
				break;
			case "hanging":
				baseline = 3;
				break;
			case "bottom":
				baseline = 4;
				break;
			case "ideographic":
				baseline = 5;
				break;
			default:
				baseline = 0;
				break;
		}

		this._drawCommands = this._drawCommands.concat("E" + baseline + ";");
	}

	get font() {
		return this._font;
	}

	setFontSize(size) {
		var str = this._font;
		var strs = str.trim().split(/\s+/);
		for (var i = 0; i < strs.length; i++) {
			var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold",
				"bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900",
				"normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
				"semi-expanded", "expanded", "extra-expanded", "ultra-expanded"
			];

			if (-1 == values.indexOf(strs[i].trim())) {
				if (typeof size === 'string') {
					strs[i] = size;
				} else if (typeof size === 'number') {
					strs[i] = String(size) + 'px';
				}
				break;
			}
		}
		this.font = strs.join(" ");
	}

	set font(value) {
		this._font = value;
		this._drawCommands = this._drawCommands.concat("j" + value + ";");
	}

	setTransform(a, b, c, d, tx, ty) {
		this._drawCommands = this._drawCommands.concat("t" +
			(a === 1 ? "1" : a.toFixed(2)) + "," +
			(b === 0 ? "0" : b.toFixed(2)) + "," +
			(c === 0 ? "0" : c.toFixed(2)) + "," +
			(d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
	}

	transform(a, b, c, d, tx, ty) {
		this._drawCommands = this._drawCommands.concat("f" +
			(a === 1 ? "1" : a.toFixed(2)) + "," +
			(b === 0 ? "0" : b.toFixed(2)) + "," +
			(c === 0 ? "0" : c.toFixed(2)) + "," +
			(d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";");
	}

	resetTransform() {
		this._drawCommands = this._drawCommands.concat("m;");
	}

	scale(a, d) {
		this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," +
			d.toFixed(2) + ";");
	}

	rotate(angle) {
		this._drawCommands = this._drawCommands
			.concat("r" + angle.toFixed(6) + ";");
	}

	translate(tx, ty) {
		this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
	}

	save() {
		this._savedGlobalAlpha.push(this._globalAlpha);
		this._drawCommands = this._drawCommands.concat("v;");
	}

	restore() {
		this._drawCommands = this._drawCommands.concat("e;");
		this._globalAlpha = this._savedGlobalAlpha.pop();
	}

	createPattern(img, pattern) {
		if (typeof img === 'string') {
			var imgObj = new GImage();
			imgObj.src = img;
			img = imgObj;
		}
		return new FillStylePattern(img, pattern);
	}

	createLinearGradient(x0, y0, x1, y1) {
		return new FillStyleLinearGradient(x0, y0, x1, y1);
	}

	createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
		return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1);
	};

	createCircularGradient = function(x0, y0, r0) {
		return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0);
	};

	strokeRect(x, y, w, h) {
		this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";");
	}


	clearRect(x, y, w, h) {
		this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w +
			"," + h + ";");
	}

	clip() {
		this._drawCommands = this._drawCommands.concat("p;");
	}

	resetClip() {
		this._drawCommands = this._drawCommands.concat("q;");
	}

	closePath() {
		this._drawCommands = this._drawCommands.concat("o;");
	}

	moveTo(x, y) {
		this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";");
	}

	lineTo(x, y) {
		this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";");
	}

	quadraticCurveTo = function(cpx, cpy, x, y) {
		this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";");
	}

	bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) {
		this._drawCommands = this._drawCommands.concat(
			"z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," +
			x.toFixed(2) + "," + y.toFixed(2) + ";");
	}

	arcTo(x1, y1, x2, y2, radius) {
		this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";");
	}

	beginPath() {
		this._drawCommands = this._drawCommands.concat("b;");
	}


	fillRect(x, y, w, h) {
		this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w +
			"," + h + ";");
	}

	rect(x, y, w, h) {
		this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";");
	}

	fill() {
		this._drawCommands = this._drawCommands.concat("L;");
	}

	stroke(path) {
		this._drawCommands = this._drawCommands.concat("x;");
	}

	arc(x, y, radius, startAngle, endAngle, anticlockwise) {

		let ianticlockwise = 0;
		if (anticlockwise) {
			ianticlockwise = 1;
		}

		this._drawCommands = this._drawCommands.concat(
			"y" + x.toFixed(2) + "," + y.toFixed(2) + "," +
			radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise +
			";"
		);
	}

	fillText(text, x, y) {
		let tmptext = text.replace(/!/g, "!!");
		tmptext = tmptext.replace(/,/g, "!,");
		tmptext = tmptext.replace(/;/g, "!;");
		this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;");
	}

	strokeText = function(text, x, y) {
		let tmptext = text.replace(/!/g, "!!");
		tmptext = tmptext.replace(/,/g, "!,");
		tmptext = tmptext.replace(/;/g, "!;");
		this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;");
	}

	measureText(text) {
		return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId);
	}

	isPointInPath = function(x, y) {
		throw new Error('GCanvas not supported yet');
	}

	drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
		if (typeof image === 'string') {
			var imgObj = new GImage();
			imgObj.src = image;
			image = imgObj;
		}
		if (image instanceof GImage) {
			if (!image.complete) {
				imgObj.onload = () => {
					var index = this._needRedrawImageCache.indexOf(image);
					if (index > -1) {
						this._needRedrawImageCache.splice(index, 1);
						CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
						this._redrawflush(true);
					}
				}
				this._notCommitDrawImageCache.push(image);
			} else {
				CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
			}
			var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh];
			var args = [];
			for (var arg in srcArgs) {
				if (typeof(srcArgs[arg]) != 'undefined') {
					args.push(srcArgs[arg]);
				}
			}
			this.__drawImage.apply(this, args);
			//this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
		}
	}

	__drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
		const numArgs = arguments.length;

		function drawImageCommands() {

			if (numArgs === 3) {
				const x = parseFloat(sx) || 0.0;
				const y = parseFloat(sy) || 0.0;

				return ("d" + image._id + ",0,0," +
					image.width + "," + image.height + "," +
					x + "," + y + "," + image.width + "," + image.height + ";");
			} else if (numArgs === 5) {
				const x = parseFloat(sx) || 0.0;
				const y = parseFloat(sy) || 0.0;
				const width = parseInt(sw) || image.width;
				const height = parseInt(sh) || image.height;

				return ("d" + image._id + ",0,0," +
					image.width + "," + image.height + "," +
					x + "," + y + "," + width + "," + height + ";");
			} else if (numArgs === 9) {
				sx = parseFloat(sx) || 0.0;
				sy = parseFloat(sy) || 0.0;
				sw = parseInt(sw) || image.width;
				sh = parseInt(sh) || image.height;
				dx = parseFloat(dx) || 0.0;
				dy = parseFloat(dy) || 0.0;
				dw = parseInt(dw) || image.width;
				dh = parseInt(dh) || image.height;

				return ("d" + image._id + "," +
					sx + "," + sy + "," + sw + "," + sh + "," +
					dx + "," + dy + "," + dw + "," + dh + ";");
			}
		}
		this._drawCommands += drawImageCommands();
	}

	_flush(reserve, callback) {
		const commands = this._drawCommands;
		this._drawCommands = '';
		CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
		this._needRender = false;
	}

	_redrawflush(reserve, callback) {
		const commands = this._redrawCommands;
		CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
		if (this._needRedrawImageCache.length == 0) {
			this._redrawCommands = '';
		}
	}

	draw(reserve, callback) {
		if (!reserve) {
			this._globalAlpha = this._savedGlobalAlpha.pop();
			this._savedGlobalAlpha.push(this._globalAlpha);
			this._redrawCommands = this._drawCommands;
			this._needRedrawImageCache = this._notCommitDrawImageCache;
			if (this._autoSaveContext) {
				this._drawCommands = ("v;" + this._drawCommands);
				this._autoSaveContext = false;
			} else {
				this._drawCommands = ("e;X;v;" + this._drawCommands);
			}
		} else {
			this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache);
			this._redrawCommands += this._drawCommands;
			if (this._autoSaveContext) {
				this._drawCommands = ("v;" + this._drawCommands);
				this._autoSaveContext = false;
			}
		}
		this._notCommitDrawImageCache = [];
		if (this._flush) {
			this._flush(reserve, callback);
		}
	}

	getImageData(x, y, w, h, callback) {
		CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) {
			res.data = Base64ToUint8ClampedArray(res.data);
			if (typeof(callback) == 'function') {
				callback(res);
			}
		});
	}

	putImageData(data, x, y, w, h, callback) {
		if (data instanceof Uint8ClampedArray) {
			data = ArrayBufferToBase64(data);
			CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) {
				if (typeof(callback) == 'function') {
					callback(res);
				}
			});
		}
	}

	toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
		CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight,
			fileType, quality,
			function(res) {
				if (typeof(callback) == 'function') {
					callback(res);
				}
			});
	}
}
կ#x?100644 ActiveInfo.js m.ZGݧ]100644 Buffer.js H vJX!߂wgS.2100644 Framebuffer.js (m?=K{*M<G|100644 GLenum.js UDeOQM~J;100644 GLmethod.js e4/&@5FP%>?100644 GLtype.js iZ>o{L`i100644 Program.js oV͹U705 銓,100644 Renderbuffer.js *gDMXSNƂ100644 RenderingContext.js _TFq7wN100644 Shader.js caYʰWa100644 ShaderPrecisionFormat.js  li(fkna100644 Texture.js Mn(J><100644 UniformLocation.js ưX[s{1100644 classUtils.js qk䃕ϢWaE	!px +export default class WebGLActiveInfo {
    className = 'WebGLActiveInfo';

    constructor({
        type, name, size
    }) {
        this.type = type;
        this.name = name;
        this.size = size;
    }
}vj><xQimport {getTransferedObjectUUID} from './classUtils';

const name = 'WebGLBuffer';

function uuid(id) {
    return getTransferedObjectUUID(name, id);
}

export default class WebGLBuffer {
    className = name;

    constructor(id) {
        this.id = id;
    }

    static uuid = uuid;

    uuid() {
        return uuid(this.id);
    }
}ix]import {getTransferedObjectUUID} from './classUtils';

const name = 'WebGLRenderBuffer';

function uuid(id) {
    return getTransferedObjectUUID(name, id);
}

export default class WebGLRenderbuffer {
    className = name;

    constructor(id) {
        this.id = id;
    }

    static uuid = uuid;

    uuid() {
        return uuid(this.id);
    }
}Ȟmjx JFramePiFrames9	x!Bexport default {
    "DEPTH_BUFFER_BIT": 256,
    "STENCIL_BUFFER_BIT": 1024,
    "COLOR_BUFFER_BIT": 16384,
    "POINTS": 0,
    "LINES": 1,
    "LINE_LOOP": 2,
    "LINE_STRIP": 3,
    "TRIANGLES": 4,
    "TRIANGLE_STRIP": 5,
    "TRIANGLE_FAN": 6,
    "ZERO": 0,
    "ONE": 1,
    "SRC_COLOR": 768,
    "ONE_MINUS_SRC_COLOR": 769,
    "SRC_ALPHA": 770,
    "ONE_MINUS_SRC_ALPHA": 771,
    "DST_ALPHA": 772,
    "ONE_MINUS_DST_ALPHA": 773,
    "DST_COLOR": 774,
    "ONE_MINUS_DST_COLOR": 775,
    "SRC_ALPHA_SATURATE": 776,
    "FUNC_ADD": 32774,
    "BLEND_EQUATION": 32777,
    "BLEND_EQUATION_RGB": 32777,
    "BLEND_EQUATION_ALPHA": 34877,
    "FUNC_SUBTRACT": 32778,
    "FUNC_REVERSE_SUBTRACT": 32779,
    "BLEND_DST_RGB": 32968,
    "BLEND_SRC_RGB": 32969,
    "BLEND_DST_ALPHA": 32970,
    "BLEND_SRC_ALPHA": 32971,
    "CONSTANT_COLOR": 32769,
    "ONE_MINUS_CONSTANT_COLOR": 32770,
    "CONSTANT_ALPHA": 32771,
    "ONE_MINUS_CONSTANT_ALPHA": 32772,
    "BLEND_COLOR": 32773,
    "ARRAY_BUFFER": 34962,
    "ELEMENT_ARRAY_BUFFER": 34963,
    "ARRAY_BUFFER_BINDING": 34964,
    "ELEMENT_ARRAY_BUFFER_BINDING": 34965,
    "STREAM_DRAW": 35040,
    "STATIC_DRAW": 35044,
    "DYNAMIC_DRAW": 35048,
    "BUFFER_SIZE": 34660,
    "BUFFER_USAGE": 34661,
    "CURRENT_VERTEX_ATTRIB": 34342,
    "FRONT": 1028,
    "BACK": 1029,
    "FRONT_AND_BACK": 1032,
    "TEXTURE_2D": 3553,
    "CULL_FACE": 2884,
    "BLEND": 3042,
    "DITHER": 3024,
    "STENCIL_TEST": 2960,
    "DEPTH_TEST": 2929,
    "SCISSOR_TEST": 3089,
    "POLYGON_OFFSET_FILL": 32823,
    "SAMPLE_ALPHA_TO_COVERAGE": 32926,
    "SAMPLE_COVERAGE": 32928,
    "NO_ERROR": 0,
    "INVALID_ENUM": 1280,
    "INVALID_VALUE": 1281,
    "INVALID_OPERATION": 1282,
    "OUT_OF_MEMORY": 1285,
    "CW": 2304,
    "CCW": 2305,
    "LINE_WIDTH": 2849,
    "ALIASED_POINT_SIZE_RANGE": 33901,
    "ALIASED_LINE_WIDTH_RANGE": 33902,
    "CULL_FACE_MODE": 2885,
    "FRONT_FACE": 2886,
    "DEPTH_RANGE": 2928,
    "DEPTH_WRITEMASK": 2930,
    "DEPTH_CLEAR_VALUE": 2931,
    "DEPTH_FUNC": 2932,
    "STENCIL_CLEAR_VALUE": 2961,
    "STENCIL_FUNC": 2962,
    "STENCIL_FAIL": 2964,
    "STENCIL_PASS_DEPTH_FAIL": 2965,
    "STENCIL_PASS_DEPTH_PASS": 2966,
    "STENCIL_REF": 2967,
    "STENCIL_VALUE_MASK": 2963,
    "STENCIL_WRITEMASK": 2968,
    "STENCIL_BACK_FUNC": 34816,
    "STENCIL_BACK_FAIL": 34817,
    "STENCIL_BACK_PASS_DEPTH_FAIL": 34818,
    "STENCIL_BACK_PASS_DEPTH_PASS": 34819,
    "STENCIL_BACK_REF": 36003,
    "STENCIL_BACK_VALUE_MASK": 36004,
    "STENCIL_BACK_WRITEMASK": 36005,
    "VIEWPORT": 2978,
    "SCISSOR_BOX": 3088,
    "COLOR_CLEAR_VALUE": 3106,
    "COLOR_WRITEMASK": 3107,
    "UNPACK_ALIGNMENT": 3317,
    "PACK_ALIGNMENT": 3333,
    "MAX_TEXTURE_SIZE": 3379,
    "MAX_VIEWPORT_DIMS": 3386,
    "SUBPIXEL_BITS": 3408,
    "RED_BITS": 3410,
    "GREEN_BITS": 3411,
    "BLUE_BITS": 3412,
    "ALPHA_BITS": 3413,
    "DEPTH_BITS": 3414,
    "STENCIL_BITS": 3415,
    "POLYGON_OFFSET_UNITS": 10752,
    "POLYGON_OFFSET_FACTOR": 32824,
    "TEXTURE_BINDING_2D": 32873,
    "SAMPLE_BUFFERS": 32936,
    "SAMPLES": 32937,
    "SAMPLE_COVERAGE_VALUE": 32938,
    "SAMPLE_COVERAGE_INVERT": 32939,
    "COMPRESSED_TEXTURE_FORMATS": 34467,
    "DONT_CARE": 4352,
    "FASTEST": 4353,
    "NICEST": 4354,
    "GENERATE_MIPMAP_HINT": 33170,
    "BYTE": 5120,
    "UNSIGNED_BYTE": 5121,
    "SHORT": 5122,
    "UNSIGNED_SHORT": 5123,
    "INT": 5124,
    "UNSIGNED_INT": 5125,
    "FLOAT": 5126,
    "DEPTH_COMPONENT": 6402,
    "ALPHA": 6406,
    "RGB": 6407,
    "RGBA": 6408,
    "LUMINANCE": 6409,
    "LUMINANCE_ALPHA": 6410,
    "UNSIGNED_SHORT_4_4_4_4": 32819,
    "UNSIGNED_SHORT_5_5_5_1": 32820,
    "UNSIGNED_SHORT_5_6_5": 33635,
    "FRAGMENT_SHADER": 35632,
    "VERTEX_SHADER": 35633,
    "MAX_VERTEX_ATTRIBS": 34921,
    "MAX_VERTEX_UNIFORM_VECTORS": 36347,
    "MAX_VARYING_VECTORS": 36348,
    "MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661,
    "MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660,
    "MAX_TEXTURE_IMAGE_UNITS": 34930,
    "MAX_FRAGMENT_UNIFORM_VECTORS": 36349,
    "SHADER_TYPE": 35663,
    "DELETE_STATUS": 35712,
    "LINK_STATUS": 35714,
    "VALIDATE_STATUS": 35715,
    "ATTACHED_SHADERS": 35717,
    "ACTIVE_UNIFORMS": 35718,
    "ACTIVE_ATTRIBUTES": 35721,
    "SHADING_LANGUAGE_VERSION": 35724,
    "CURRENT_PROGRAM": 35725,
    "NEVER": 512,
    "LESS": 513,
    "EQUAL": 514,
    "LEQUAL": 515,
    "GREATER": 516,
    "NOTEQUAL": 517,
    "GEQUAL": 518,
    "ALWAYS": 519,
    "KEEP": 7680,
    "REPLACE": 7681,
    "INCR": 7682,
    "DECR": 7683,
    "INVERT": 5386,
    "INCR_WRAP": 34055,
    "DECR_WRAP": 34056,
    "VENDOR": 7936,
    "RENDERER": 7937,
    "VERSION": 7938,
    "NEAREST": 9728,
    "LINEAR": 9729,
    "NEAREST_MIPMAP_NEAREST": 9984,
    "LINEAR_MIPMAP_NEAREST": 9985,
    "NEAREST_MIPMAP_LINEAR": 9986,
    "LINEAR_MIPMAP_LINEAR": 9987,
    "TEXTURE_MAG_FILTER": 10240,
    "TEXTURE_MIN_FILTER": 10241,
    "TEXTURE_WRAP_S": 10242,
    "TEXTURE_WRAP_T": 10243,
    "TEXTURE": 5890,
    "TEXTURE_CUBE_MAP": 34067,
    "TEXTURE_BINDING_CUBE_MAP": 34068,
    "TEXTURE_CUBE_MAP_POSITIVE_X": 34069,
    "TEXTURE_CUBE_MAP_NEGATIVE_X": 34070,
    "TEXTURE_CUBE_MAP_POSITIVE_Y": 34071,
    "TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072,
    "TEXTURE_CUBE_MAP_POSITIVE_Z": 34073,
    "TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074,
    "MAX_CUBE_MAP_TEXTURE_SIZE": 34076,
    "TEXTURE0": 33984,
    "TEXTURE1": 33985,
    "TEXTURE2": 33986,
    "TEXTURE3": 33987,
    "TEXTURE4": 33988,
    "TEXTURE5": 33989,
    "TEXTURE6": 33990,
    "TEXTURE7": 33991,
    "TEXTURE8": 33992,
    "TEXTURE9": 33993,
    "TEXTURE10": 33994,
    "TEXTURE11": 33995,
    "TEXTURE12": 33996,
    "TEXTURE13": 33997,
    "TEXTURE14": 33998,
    "TEXTURE15": 33999,
    "TEXTURE16": 34000,
    "TEXTURE17": 34001,
    "TEXTURE18": 34002,
    "TEXTURE19": 34003,
    "TEXTURE20": 34004,
    "TEXTURE21": 34005,
    "TEXTURE22": 34006,
    "TEXTURE23": 34007,
    "TEXTURE24": 34008,
    "TEXTURE25": 34009,
    "TEXTURE26": 34010,
    "TEXTURE27": 34011,
    "TEXTURE28": 34012,
    "TEXTURE29": 34013,
    "TEXTURE30": 34014,
    "TEXTURE31": 34015,
    "ACTIVE_TEXTURE": 34016,
    "REPEAT": 10497,
    "CLAMP_TO_EDGE": 33071,
    "MIRRORED_REPEAT": 33648,
    "FLOAT_VEC2": 35664,
    "FLOAT_VEC3": 35665,
    "FLOAT_VEC4": 35666,
    "INT_VEC2": 35667,
    "INT_VEC3": 35668,
    "INT_VEC4": 35669,
    "BOOL": 35670,
    "BOOL_VEC2": 35671,
    "BOOL_VEC3": 35672,
    "BOOL_VEC4": 35673,
    "FLOAT_MAT2": 35674,
    "FLOAT_MAT3": 35675,
    "FLOAT_MAT4": 35676,
    "SAMPLER_2D": 35678,
    "SAMPLER_CUBE": 35680,
    "VERTEX_ATTRIB_ARRAY_ENABLED": 34338,
    "VERTEX_ATTRIB_ARRAY_SIZE": 34339,
    "VERTEX_ATTRIB_ARRAY_STRIDE": 34340,
    "VERTEX_ATTRIB_ARRAY_TYPE": 34341,
    "VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922,
    "VERTEX_ATTRIB_ARRAY_POINTER": 34373,
    "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975,
    "IMPLEMENTATION_COLOR_READ_TYPE": 35738,
    "IMPLEMENTATION_COLOR_READ_FORMAT": 35739,
    "COMPILE_STATUS": 35713,
    "LOW_FLOAT": 36336,
    "MEDIUM_FLOAT": 36337,
    "HIGH_FLOAT": 36338,
    "LOW_INT": 36339,
    "MEDIUM_INT": 36340,
    "HIGH_INT": 36341,
    "FRAMEBUFFER": 36160,
    "RENDERBUFFER": 36161,
    "RGBA4": 32854,
    "RGB5_A1": 32855,
    "RGB565": 36194,
    "DEPTH_COMPONENT16": 33189,
    "STENCIL_INDEX8": 36168,
    "DEPTH_STENCIL": 34041,
    "RENDERBUFFER_WIDTH": 36162,
    "RENDERBUFFER_HEIGHT": 36163,
    "RENDERBUFFER_INTERNAL_FORMAT": 36164,
    "RENDERBUFFER_RED_SIZE": 36176,
    "RENDERBUFFER_GREEN_SIZE": 36177,
    "RENDERBUFFER_BLUE_SIZE": 36178,
    "RENDERBUFFER_ALPHA_SIZE": 36179,
    "RENDERBUFFER_DEPTH_SIZE": 36180,
    "RENDERBUFFER_STENCIL_SIZE": 36181,
    "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048,
    "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049,
    "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050,
    "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051,
    "COLOR_ATTACHMENT0": 36064,
    "DEPTH_ATTACHMENT": 36096,
    "STENCIL_ATTACHMENT": 36128,
    "DEPTH_STENCIL_ATTACHMENT": 33306,
    "NONE": 0,
    "FRAMEBUFFER_COMPLETE": 36053,
    "FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054,
    "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055,
    "FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057,
    "FRAMEBUFFER_UNSUPPORTED": 36061,
    "FRAMEBUFFER_BINDING": 36006,
    "RENDERBUFFER_BINDING": 36007,
    "MAX_RENDERBUFFER_SIZE": 34024,
    "INVALID_FRAMEBUFFER_OPERATION": 1286,
    "UNPACK_FLIP_Y_WEBGL": 37440,
    "UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441,
    "CONTEXT_LOST_WEBGL": 37442,
    "UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443,
    "BROWSER_DEFAULT_WEBGL": 37444
};
pxnlet i = 1;

const GLmethod = {};

GLmethod.activeTexture = i++;         //1
GLmethod.attachShader = i++;
GLmethod.bindAttribLocation = i++;
GLmethod.bindBuffer = i++;
GLmethod.bindFramebuffer = i++;
GLmethod.bindRenderbuffer = i++;
GLmethod.bindTexture = i++;
GLmethod.blendColor = i++;
GLmethod.blendEquation = i++;
GLmethod.blendEquationSeparate = i++; //10
GLmethod.blendFunc = i++;
GLmethod.blendFuncSeparate = i++;
GLmethod.bufferData = i++;
GLmethod.bufferSubData = i++;
GLmethod.checkFramebufferStatus = i++;
GLmethod.clear = i++;
GLmethod.clearColor = i++;
GLmethod.clearDepth = i++;
GLmethod.clearStencil = i++;
GLmethod.colorMask = i++;              //20
GLmethod.compileShader = i++;
GLmethod.compressedTexImage2D = i++;
GLmethod.compressedTexSubImage2D = i++;
GLmethod.copyTexImage2D = i++;
GLmethod.copyTexSubImage2D = i++;
GLmethod.createBuffer = i++;
GLmethod.createFramebuffer = i++;
GLmethod.createProgram = i++;
GLmethod.createRenderbuffer = i++;
GLmethod.createShader = i++;           //30
GLmethod.createTexture = i++;
GLmethod.cullFace = i++;
GLmethod.deleteBuffer = i++;
GLmethod.deleteFramebuffer = i++;
GLmethod.deleteProgram = i++;
GLmethod.deleteRenderbuffer = i++;
GLmethod.deleteShader = i++;
GLmethod.deleteTexture = i++;
GLmethod.depthFunc = i++;
GLmethod.depthMask = i++;              //40
GLmethod.depthRange = i++;
GLmethod.detachShader = i++;
GLmethod.disable = i++;
GLmethod.disableVertexAttribArray = i++;
GLmethod.drawArrays = i++;
GLmethod.drawArraysInstancedANGLE = i++;
GLmethod.drawElements = i++;
GLmethod.drawElementsInstancedANGLE = i++;
GLmethod.enable = i++;
GLmethod.enableVertexAttribArray = i++;    //50
GLmethod.flush = i++;
GLmethod.framebufferRenderbuffer = i++;
GLmethod.framebufferTexture2D = i++;
GLmethod.frontFace = i++;
GLmethod.generateMipmap = i++;
GLmethod.getActiveAttrib = i++;
GLmethod.getActiveUniform = i++;
GLmethod.getAttachedShaders = i++;
GLmethod.getAttribLocation = i++;
GLmethod.getBufferParameter = i++;         //60
GLmethod.getContextAttributes = i++;
GLmethod.getError = i++;
GLmethod.getExtension = i++;
GLmethod.getFramebufferAttachmentParameter = i++;
GLmethod.getParameter = i++;
GLmethod.getProgramInfoLog = i++;
GLmethod.getProgramParameter = i++;
GLmethod.getRenderbufferParameter = i++;
GLmethod.getShaderInfoLog = i++;
GLmethod.getShaderParameter = i++;         //70
GLmethod.getShaderPrecisionFormat = i++;
GLmethod.getShaderSource = i++;
GLmethod.getSupportedExtensions = i++;
GLmethod.getTexParameter = i++;
GLmethod.getUniform = i++;
GLmethod.getUniformLocation = i++;
GLmethod.getVertexAttrib = i++;
GLmethod.getVertexAttribOffset = i++;
GLmethod.isBuffer = i++;
GLmethod.isContextLost = i++;              //80
GLmethod.isEnabled = i++;
GLmethod.isFramebuffer = i++;
GLmethod.isProgram = i++;
GLmethod.isRenderbuffer = i++;
GLmethod.isShader = i++;
GLmethod.isTexture = i++;
GLmethod.lineWidth = i++;
GLmethod.linkProgram = i++;
GLmethod.pixelStorei = i++;
GLmethod.polygonOffset = i++;              //90
GLmethod.readPixels = i++;
GLmethod.renderbufferStorage = i++;
GLmethod.sampleCoverage = i++;
GLmethod.scissor = i++;
GLmethod.shaderSource = i++;
GLmethod.stencilFunc = i++;
GLmethod.stencilFuncSeparate = i++;
GLmethod.stencilMask = i++;
GLmethod.stencilMaskSeparate = i++;
GLmethod.stencilOp = i++;                  //100
GLmethod.stencilOpSeparate = i++;
GLmethod.texImage2D = i++;
GLmethod.texParameterf = i++;
GLmethod.texParameteri = i++;
GLmethod.texSubImage2D = i++;
GLmethod.uniform1f = i++;
GLmethod.uniform1fv = i++;
GLmethod.uniform1i = i++;
GLmethod.uniform1iv = i++;
GLmethod.uniform2f = i++;                  //110
GLmethod.uniform2fv = i++;
GLmethod.uniform2i = i++;
GLmethod.uniform2iv = i++;
GLmethod.uniform3f = i++;
GLmethod.uniform3fv = i++;
GLmethod.uniform3i = i++;
GLmethod.uniform3iv = i++;
GLmethod.uniform4f = i++;
GLmethod.uniform4fv = i++;
GLmethod.uniform4i = i++;                  //120
GLmethod.uniform4iv = i++;
GLmethod.uniformMatrix2fv = i++;
GLmethod.uniformMatrix3fv = i++;
GLmethod.uniformMatrix4fv = i++;
GLmethod.useProgram = i++;
GLmethod.validateProgram = i++;
GLmethod.vertexAttrib1f = i++; //new
GLmethod.vertexAttrib2f = i++; //new
GLmethod.vertexAttrib3f = i++; //new
GLmethod.vertexAttrib4f = i++; //new       //130
GLmethod.vertexAttrib1fv = i++; //new
GLmethod.vertexAttrib2fv = i++; //new
GLmethod.vertexAttrib3fv = i++; //new
GLmethod.vertexAttrib4fv = i++; //new
GLmethod.vertexAttribPointer = i++;
GLmethod.viewport = i++;

export default GLmethod;>0bxLconst GLtype = {};

[
    "GLbitfield",    
    "GLboolean",
    "GLbyte",
    "GLclampf",
    "GLenum",
    "GLfloat",
    "GLint",
    "GLintptr",
    "GLsizei",
    "GLsizeiptr",
    "GLshort",
    "GLubyte",
    "GLuint",
    "GLushort"
].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1));

export default GLtype;



XpxSimport {getTransferedObjectUUID} from './classUtils';

const name = 'WebGLProgram';

function uuid(id) {
    return getTransferedObjectUUID(name, id);
}

export default class WebGLProgram {
    className = name;

    constructor(id) {
        this.id = id;
    }

    static uuid = uuid;

    uuid() {
        return uuid(this.id);
    }
}ʔjxrpimport GLenum from './GLenum';
import ActiveInfo from './ActiveInfo';
import Buffer from './Buffer';
import Framebuffer from './Framebuffer';
import Renderbuffer from './Renderbuffer';
import Texture from './Texture';
import Program from './Program';
import Shader from './Shader';
import ShaderPrecisionFormat from './ShaderPrecisionFormat';
import UniformLocation from './UniformLocation';
import GLmethod from './GLmethod';

const processArray = (array, checkArrayType = false) => {

    function joinArray(arr, sep) {
        let res = '';
        for (let i = 0; i < arr.length; i++) {
            if (i !== 0) {
                res += sep;
            }
            res += arr[i];
        }
        return res;
    }

    let type = 'Float32Array';
    if (checkArrayType) {
        if (array instanceof Uint8Array) {
            type = 'Uint8Array'
        } else if (array instanceof Uint16Array) {
            type = 'Uint16Array';
        } else if (array instanceof Uint32Array) {
            type = 'Uint32Array';
        } else if (array instanceof Float32Array) {
            type = 'Float32Array';
        } else {
            throw new Error('Check array type failed. Array type is ' + typeof array);
        }
    }

    const ArrayTypes = {
        Uint8Array: 1,
        Uint16Array: 2,
        Uint32Array: 4,
        Float32Array: 14
    };
    return ArrayTypes[type] + ',' + btoa(joinArray(array, ','))
}

export default class WebGLRenderingContext {

    // static GBridge = null;

    className = 'WebGLRenderingContext';

    constructor(canvas, type, attrs) {
        this._canvas = canvas;
        this._type = type;
        this._version = 'WebGL 1.0';
        this._attrs = attrs;
        this._map = new Map();

        Object.keys(GLenum)
            .forEach(name => Object.defineProperty(this, name, {
                value: GLenum[name]
            }));
    }

    get canvas() {
        return this._canvas;
    }

    activeTexture = function (textureUnit) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.activeTexture + ',' + textureUnit,
            true
        );
    }

    attachShader = function (progarm, shader) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.attachShader + ',' + progarm.id + ',' + shader.id,
            true
        );
    }

    bindAttribLocation = function (program, index, name) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.bindAttribLocation + ',' + program.id + ',' + index + ',' + name,
            true
        )
    }

    bindBuffer = function (target, buffer) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.bindBuffer + ',' + target + ',' + (buffer ? buffer.id : 0),
            true
        );
    }

    bindFramebuffer = function (target, framebuffer) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.bindFramebuffer + ',' + target + ',' + (framebuffer ? framebuffer.id : 0),
            true
        )
    }

    bindRenderbuffer = function (target, renderBuffer) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.bindRenderbuffer + ',' + target + ',' + (renderBuffer ? renderBuffer.id : 0),
            true
        )
    }

    bindTexture = function (target, texture) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.bindTexture + ',' + target + ',' + (texture ? texture.id : 0),
            true
        )
    }

    blendColor = function (r, g, b, a) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.blendColor + ',' + target + ',' + r + ',' + g + ',' + b + ',' + a,
            true
        )
    }

    blendEquation = function (mode) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.blendEquation + ',' + mode,
            true
        )
    }

    blendEquationSeparate = function (modeRGB, modeAlpha) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.blendEquationSeparate + ',' + modeRGB + ',' + modeAlpha,
            true
        )
    }


    blendFunc = function (sfactor, dfactor) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.blendFunc + ',' + sfactor + ',' + dfactor,
            true
        );
    }

    blendFuncSeparate = function (srcRGB, dstRGB, srcAlpha, dstAlpha) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.blendFuncSeparate + ',' + srcRGB + ',' + dstRGB + ',' + srcAlpha + ',' + dstAlpha,
            true
        );
    }

    bufferData = function (target, data, usage) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.bufferData + ',' + target + ',' + processArray(data, true) + ',' + usage,
            true
        )
    }

    bufferSubData = function (target, offset, data) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.bufferSubData + ',' + target + ',' + offset + ',' + processArray(data, true),
            true
        )
    }

    checkFramebufferStatus = function (target) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.checkFramebufferStatus + ',' + target
        );
        return Number(result);
    }

    clear = function (mask) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.clear + ',' + mask
        );
        this._canvas._needRender = true;
    }

    clearColor = function (r, g, b, a) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.clearColor + ',' + r + ',' + g + ',' + b,
            true
        )
    }

    clearDepth = function (depth) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.clearDepth + ',' + depth,
            true
        )
    }

    clearStencil = function (s) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.clearStencil + ',' + s
        );
    }

    colorMask = function (r, g, b, a) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.colorMask + ',' + r + ',' + g + ',' + b + ',' + a
        )
    }

    compileShader = function (shader) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.compileShader + ',' + shader.id,
            true
        )
    }

    compressedTexImage2D = function (target, level, internalformat, width, height, border, pixels) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.compressedTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' +
            width + ',' + height + ',' + border + ',' + processArray(pixels),
            true
        )
    }

    compressedTexSubImage2D = function (target, level, xoffset, yoffset, width, height, format, pixels) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.compressedTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' +
            width + ',' + height + ',' + format + ',' + processArray(pixels),
            true
        )
    }


    copyTexImage2D = function (target, level, internalformat, x, y, width, height, border) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.copyTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' + x + ',' + y + ',' +
            width + ',' + height + ',' + border,
            true
        );
    }

    copyTexSubImage2D = function (target, level, xoffset, yoffset, x, y, width, height) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.copyTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' + x + ',' + y + ',' +
            width + ',' + height
        );
    }

    createBuffer = function () {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.createBuffer + ''
        );
        const buffer = new Buffer(result);
        this._map.set(buffer.uuid(), buffer);
        return buffer;
    }

    createFramebuffer = function () {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.createFramebuffer + ''
        );
        const framebuffer = new Framebuffer(result);
        this._map.set(framebuffer.uuid(), framebuffer);
        return framebuffer;
    }


    createProgram = function () {
        const id = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.createProgram + ''
        );
        const program = new Program(id);
        this._map.set(program.uuid(), program);
        return program;
    }

    createRenderbuffer = function () {
        const id = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.createRenderbuffer + ''
        )
        const renderBuffer = new Renderbuffer(id);
        this._map.set(renderBuffer.uuid(), renderBuffer);
        return renderBuffer;
    }

    createShader = function (type) {
        const id = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.createShader + ',' + type
        )
        const shader = new Shader(id, type);
        this._map.set(shader.uuid(), shader);
        return shader;
    }

    createTexture = function () {
        const id = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.createTexture + ''
        );
        const texture = new Texture(id);
        this._map.set(texture.uuid(), texture);
        return texture;
    }

    cullFace = function (mode) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.cullFace + ',' + mode,
            true
        )
    }


    deleteBuffer = function (buffer) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.deleteBuffer + ',' + buffer.id,
            true
        )
    }

    deleteFramebuffer = function (framebuffer) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.deleteFramebuffer + ',' + framebuffer.id,
            true
        )
    }

    deleteProgram = function (program) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.deleteProgram + ',' + program.id,
            true
        )
    }

    deleteRenderbuffer = function (renderbuffer) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.deleteRenderbuffer + ',' + renderbuffer.id,
            true
        )
    }

    deleteShader = function (shader) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.deleteShader + ',' + shader.id,
            true
        )
    }

    deleteTexture = function (texture) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.deleteTexture + ',' + texture.id,
            true
        )
    }

    depthFunc = function (func) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.depthFunc + ',' + func
        )
    }

    depthMask = function (flag) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.depthMask + ',' + Number(flag),
            true
        )
    }

    depthRange = function (zNear, zFar) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.depthRange + ',' + zNear + ',' + zFar,
            true
        )
    }

    detachShader = function (program, shader) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.detachShader + ',' + program.id + ',' + shader.id,
            true
        )
    }

    disable = function (cap) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.disable + ',' + cap,
            true
        )
    }

    disableVertexAttribArray = function (index) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.disableVertexAttribArray + ',' + index,
            true
        );
    }

    drawArrays = function (mode, first, count) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.drawArrays + ',' + mode + ',' + first + ',' + count
        )
        this._canvas._needRender = true;
    }

    drawElements = function (mode, count, type, offset) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.drawElements + ',' + mode + ',' + count + ',' + type + ',' + offset + ';'
        );
        this._canvas._needRender = true;
    }

    enable = function (cap) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.enable + ',' + cap,
            true
        );
    }

    enableVertexAttribArray = function (index) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.enableVertexAttribArray + ',' + index,
            true
        )
    }


    flush = function () {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.flush + ''
        )
    }

    framebufferRenderbuffer = function (target, attachment, textarget, texture, level) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.framebufferRenderbuffer + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
            true
        )
    }

    framebufferTexture2D = function (target, attachment, textarget, texture, level) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.framebufferTexture2D + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
            true
        )
    }

    frontFace = function (mode) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.frontFace + ',' + mode,
            true
        )
    }

    generateMipmap = function (target) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.generateMipmap + ',' + target,
            true
        )
    }

    getActiveAttrib = function (progarm, index) {
        const resultString = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getActiveAttrib + ',' + progarm.id + ',' + index
        )
        const [type, size, name] = resultString.split(',');
        return new ActiveInfo({
            type: Number(type),
            size: Number(size),
            name
        });
    }

    getActiveUniform = function (progarm, index) {
        const resultString = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getActiveUniform + ',' + progarm.id + ',' + index
        );
        const [type, size, name] = resultString.split(',');
        return new ActiveInfo({
            type: Number(type),
            size: Number(size),
            name
        })
    }

    getAttachedShaders = function (progarm) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getAttachedShaders + ',' + progarm.id
        );
        const [type, ...ids] = result;
        return ids.map(id => this._map.get(Shader.uuid(id)));
    }

    getAttribLocation = function (progarm, name) {
        return WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getAttribLocation + ',' + progarm.id + ',' + name
        )
    }

    getBufferParameter = function (target, pname) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getBufferParameter + ',' + target + ',' + pname
        );
        const [type, res] = getBufferParameter;
        return res;
    }

    getError = function () {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getError + ''
        )
        return result;
    }

    getExtension = function (name) {
        return null;
    }

    getFramebufferAttachmentParameter = function (target, attachment, pname) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getFramebufferAttachmentParameter + ',' + target + ',' + attachment + ',' + pname
        )
        switch (pname) {
            case GLenum.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
                return this._map.get(Renderbuffer.uuid(result)) || this._map.get(Texture.uuid(result)) || null;
            default:
                return result;
        }
    }

    getParameter = function (pname) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getParameter + ',' + pname
        )
        switch (pname) {
            case GLenum.VERSION:
                return this._version;
            case GLenum.ARRAY_BUFFER_BINDING: // buffer
            case GLenum.ELEMENT_ARRAY_BUFFER_BINDING: // buffer
                return this._map.get(Buffer.uuid(result)) || null;
            case GLenum.CURRENT_PROGRAM: // program
                return this._map.get(Program.uuid(result)) || null;
            case GLenum.FRAMEBUFFER_BINDING: // framebuffer
                return this._map.get(Framebuffer.uuid(result)) || null;
            case GLenum.RENDERBUFFER_BINDING: // renderbuffer
                return this._map.get(Renderbuffer.uuid(result)) || null;
            case GLenum.TEXTURE_BINDING_2D: // texture
            case GLenum.TEXTURE_BINDING_CUBE_MAP: // texture
                return this._map.get(Texture.uuid(result)) || null;
            case GLenum.ALIASED_LINE_WIDTH_RANGE: // Float32Array
            case GLenum.ALIASED_POINT_SIZE_RANGE: // Float32Array
            case GLenum.BLEND_COLOR: // Float32Array
            case GLenum.COLOR_CLEAR_VALUE: // Float32Array
            case GLenum.DEPTH_RANGE: // Float32Array
            case GLenum.MAX_VIEWPORT_DIMS: // Int32Array
            case GLenum.SCISSOR_BOX: // Int32Array
            case GLenum.VIEWPORT: // Int32Array            
            case GLenum.COMPRESSED_TEXTURE_FORMATS: // Uint32Array
            default:
                const [type, ...res] = result.split(',');
                if (res.length === 1) {
                    return Number(res[0]);
                } else {
                    return res.map(Number);
                }
        }
    }

    getProgramInfoLog = function (progarm) {
        return WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getProgramInfoLog + ',' + progarm.id
        )
    }

    getProgramParameter = function (program, pname) {
        const res = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getProgramParameter + ',' + program.id + ',' + pname
        );

        const [type, result] = res.split(',').map(i => parseInt(i));

        if (type === 1) {
            return Boolean(result);
        } else if (type === 2) {
            return result;
        } else {
            throw new Error('Unrecongized program paramater ' + res + ', type: ' + typeof res);
        }
    }


    getRenderbufferParameter = function (target, pname) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getRenderbufferParameter + ',' + target + ',' + pname
        )
        return result;
    }


    getShaderInfoLog = function (shader) {
        return WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getShaderInfoLog + ',' + shader.id
        );
    }

    getShaderParameter = function (shader, pname) {
        return WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getShaderParameter + ',' + shader.id + ',' + pname
        )
    }

    getShaderPrecisionFormat = function (shaderType, precisionType) {
        const [rangeMin, rangeMax, precision] = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getShaderPrecisionFormat + ',' + shaderType + ',' + precisionType
        );
        const shaderPrecisionFormat = new ShaderPrecisionFormat({
            rangeMin: Number(rangeMin),
            rangeMax: Number(rangeMax),
            precision: Number(precision)
        });
        return shaderPrecisionFormat;
    }

    getShaderSource = function (shader) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getShaderSource + ',' + shader.id
        );
        return result;
    }

    getSupportedExtensions = function () {
        return Object.keys({});
    }

    getTexParameter = function (target, pname) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getTexParameter + ',' + target + ',' + pname
        )
        return result;
    }

    getUniformLocation = function (program, name) {
        const id = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getUniformLocation + ',' + program.id + ',' + name
        );
        if (id === -1) {
            return null;
        } else {
            return new UniformLocation(Number(id));
        }
    }

    getVertexAttrib = function (index, pname) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getVertexAttrib + ',' + index + ',' + pname
        );
        switch (pname) {
            case GLenum.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
                return this._map.get(Buffer.uuid(result)) || null;
            case GLenum.CURRENT_VERTEX_ATTRIB: // Float32Array
            default:
                return result;
        }
    }

    getVertexAttribOffset = function (index, pname) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.getVertexAttribOffset + ',' + index + ',' + pname
        )
        return Number(result);
    }

    isBuffer = function (buffer) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.isBuffer + ',' + buffer.id
        )
        return Boolean(result);
    }

    isContextLost = function () {
        return false;
    }

    isEnabled = function (cap) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.isEnabled + ',' + cap
        )
        return Boolean(result);
    }

    isFramebuffer = function (framebuffer) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.isFramebuffer + ',' + framebuffer.id
        )
        return Boolean(result);
    }

    isProgram = function (program) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.isProgram + ',' + program.id
        )
        return Boolean(result);
    }

    isRenderbuffer = function (renderBuffer) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.isRenderbuffer + ',' + renderbuffer.id
        )
        return Boolean(result);
    }

    isShader = function (shader) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.isShader + ',' + shader.id
        )
        return Boolean(result);
    }

    isTexture = function (texture) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.isTexture + ',' + texture.id
        );
        return Boolean(result);
    }

    lineWidth = function (width) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.lineWidth + ',' + width,
            true
        )
    }

    linkProgram = function (program) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.linkProgram + ',' + program.id,
            true
        );
    }


    pixelStorei = function (pname, param) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.pixelStorei + ',' + pname + ',' + Number(param)
        )
    }

    polygonOffset = function (factor, units) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.polygonOffset + ',' + factor + ',' + units
        )
    }

    readPixels = function (x, y, width, height, format, type, pixels) {
        const result = WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.readPixels + ',' + x + ',' + y + ',' + width + ',' + height + ',' + format + ',' + type
        )
        return result;
    }

    renderbufferStorage = function (target, internalFormat, width, height) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.renderbufferStorage + ',' + target + ',' + internalFormat + ',' + width + ',' + height,
            true
        )
    }

    sampleCoverage = function (value, invert) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.sampleCoverage + ',' + value + ',' + Number(invert),
            true
        )
    }

    scissor = function (x, y, width, height) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.scissor + ',' + x + ',' + y + ',' + width + ',' + height,
            true
        )
    }

    shaderSource = function (shader, source) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.shaderSource + ',' + shader.id + ',' + source
        )
    }

    stencilFunc = function (func, ref, mask) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.stencilFunc + ',' + func + ',' + ref + ',' + mask,
            true
        )
    }

    stencilFuncSeparate = function (face, func, ref, mask) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.stencilFuncSeparate + ',' + face + ',' + func + ',' + ref + ',' + mask,
            true
        )
    }

    stencilMask = function (mask) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.stencilMask + ',' + mask,
            true
        )
    }

    stencilMaskSeparate = function (face, mask) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.stencilMaskSeparate + ',' + face + ',' + mask,
            true
        )
    }

    stencilOp = function (fail, zfail, zpass) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.stencilOp + ',' + fail + ',' + zfail + ',' + zpass
        )
    }

    stencilOpSeparate = function (face, fail, zfail, zpass) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.stencilOp + ',' + face + ',' + fail + ',' + zfail + ',' + zpass,
            true
        )
    }

    texImage2D = function (...args) {
        WebGLRenderingContext.GBridge.texImage2D(this._canvas.id, ...args);
    }


    texParameterf = function (target, pname, param) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.texParameterf + ',' + target + ',' + pname + ',' + param,
            true
        )
    }

    texParameteri = function (target, pname, param) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.texParameteri + ',' + target + ',' + pname + ',' + param
        )
    }

    texSubImage2D = function (...args) {
        WebGLRenderingContext.GBridge.texSubImage2D(this._canvas.id, ...args);
    }

    uniform1f = function (location, v0) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform1f + ',' + location.id + ',' + v0
        )
    }

    uniform1fv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform1fv + ',' + location.id + ',' + processArray(value),
            true
        )
    }

    uniform1i = function (location, v0) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform1i + ',' + location.id + ',' + v0,
            // true
        )
    }

    uniform1iv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform1iv + ',' + location.id + ',' + processArray(value),
            true
        )
    }

    uniform2f = function (location, v0, v1) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform2f + ',' + location.id + ',' + v0 + ',' + v1,
            true
        )
    }

    uniform2fv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform2fv + ',' + location.id + ',' + processArray(value),
            true
        )
    }

    uniform2i = function (location, v0, v1) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform2i + ',' + location.id + ',' + v0 + ',' + v1,
            true
        )
    }

    uniform2iv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform2iv + ',' + location.id + ',' + processArray(value),
            true
        )
    }

    uniform3f = function (location, v0, v1, v2) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform3f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
            true
        )
    }

    uniform3fv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform3fv + ',' + location.id + ',' + processArray(value),
            true
        )
    }

    uniform3i = function (location, v0, v1, v2) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform3i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
            true
        )
    }

    uniform3iv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform3iv + ',' + location.id + ',' + processArray(value),
            true
        )
    }

    uniform4f = function (location, v0, v1, v2, v3) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform4f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
            true
        )
    }

    uniform4fv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform4fv + ',' + location.id + ',' + processArray(value),
            true
        )
    }

    uniform4i = function (location, v0, v1, v2, v3) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform4i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
            true
        )
    }

    uniform4iv = function (location, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniform4iv + ',' + location.id + ',' + processArray(value, true),
            true
        )
    }

    uniformMatrix2fv = function (location, transpose, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniformMatrix2fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
            true
        )
    }

    uniformMatrix3fv = function (location, transpose, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniformMatrix3fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
            true
        )
    }

    uniformMatrix4fv = function (location, transpose, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.uniformMatrix4fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
            true
        );
    }

    useProgram = function (progarm) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.useProgram + ',' + progarm.id + '',
            true
        )
    }


    validateProgram = function (program) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.validateProgram + ',' + program.id,
            true
        )
    }

    vertexAttrib1f = function (index, v0) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib1f + ',' + index + ',' + v0,
            true
        )
    }

    vertexAttrib2f = function (index, v0, v1) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib2f + ',' + index + ',' + v0 + ',' + v1,
            true
        )
    }

    vertexAttrib3f = function (index, v0, v1, v2) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib3f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2,
            true
        )
    }

    vertexAttrib4f = function (index, v0, v1, v2, v3) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib4f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
            true
        )
    }

    vertexAttrib1fv = function (index, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib1fv + ',' + index + ',' + processArray(value),
            true
        )
    }

    vertexAttrib2fv = function (index, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib2fv + ',' + index + ',' + processArray(value),
            true
        )
    }

    vertexAttrib3fv = function (index, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib3fv + ',' + index + ',' + processArray(value),
            true
        )
    }

    vertexAttrib4fv = function (index, value) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttrib4fv + ',' + index + ',' + processArray(value),
            true
        )
    }

    vertexAttribPointer = function (index, size, type, normalized, stride, offset) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.vertexAttribPointer + ',' + index + ',' + size + ',' + type + ',' + Number(normalized) + ',' + stride + ',' + offset,
            true
        )
    }

    viewport = function (x, y, width, height) {
        WebGLRenderingContext.GBridge.callNative(
            this._canvas.id,
            GLmethod.viewport + ',' + x + ',' + y + ',' + width + ',' + height,
            true
        )
    }
}ޛd-xR JShadNeShad.8, type) {
        this.id = id;
        this.type = typeT'vxexport default class WebGLShaderPrecisionFormat {
    className = 'WebGLShaderPrecisionFormat';

    constructor({
        rangeMin, rangeMax, precision
    }) {
        this.rangeMin = rangeMin;
        this.rangeMax = rangeMax;
        this.precision = precision;
    }
}4Vzxsimport {getTransferedObjectUUID} from './classUtils';

const name = 'WebGLTexture';

function uuid(id) {
    return getTransferedObjectUUID(name, id);
}

export default class WebGLTexture {
    className = name;

    constructor(id, type) {
        this.id = id;
        this.type = type;
    }

    static uuid = uuid;

    uuid() {
        return uuid(this.id);
    }
}swx|import {getTransferedObjectUUID} from './classUtils';

const name = 'WebGLUniformLocation';

function uuid(id) {
    return getTransferedObjectUUID(name, id);
}

export default class WebGLUniformLocation {
    className = name;

    constructor(id, type) {
        this.id = id;
        this.type = type;
    }

    static uuid = uuid;

    uuid() {
        return uuid(this.id);
    }
}kyǿx_ export function getTransferedObjectUUID(name, id) {
    return `${name.toLowerCase()}-${id}`;
}x!Qxl 100644 canvas.js ٻH	,W`CV"100644 image.js >g!`v
B9100644 tool.js 9IR<EӤ񦊕ml,txDimport GContext2D from '../context-2d/RenderingContext';
import GContextWebGL from '../context-webgl/RenderingContext';

export default class GCanvas {

    // static GBridge = null;

    id = null;

    _needRender = true;

    constructor(id, { disableAutoSwap }) {
        this.id = id;

        this._disableAutoSwap = disableAutoSwap;
        if (disableAutoSwap) {
            this._swapBuffers = () => {
                GCanvas.GBridge.render(this.id);
            }
        }
    }

    getContext(type) {

        let context = null;

        if (type.match(/webgl/i)) {
            context = new GContextWebGL(this);

            context.componentId = this.id;

            if (!this._disableAutoSwap) {
                const render = () => {
                    if (this._needRender) {
                        GCanvas.GBridge.render(this.id);
                        this._needRender = false;
                    }
                }
                setInterval(render, 16);
            }

            GCanvas.GBridge.callSetContextType(this.id, 1); // 0 for 2d; 1 for webgl
        } else if (type.match(/2d/i)) {
            context = new GContext2D(this);

            context.componentId = this.id;

//             const render = ( callback ) => {
// 
//                 const commands = context._drawCommands;
//                 context._drawCommands = '';
// 
//                 GCanvas.GBridge.render2d(this.id, commands, callback);
//                 this._needRender = false;
//             }
// 			//draw方法触发
// 			context._flush = render;
//             //setInterval(render, 16);

            GCanvas.GBridge.callSetContextType(this.id, 0);
        } else {
            throw new Error('not supported context ' + type);
        }

        return context;

    }

    reset() {
        GCanvas.GBridge.callReset(this.id);
    }


}w{xOlet incId = 1;

const noop = function () { };

class GImage {

    static GBridge = null;

    constructor() {
        this._id = incId++;
        this._width = 0;
        this._height = 0;
        this._src = undefined;
        this._onload = noop;
        this._onerror = noop;
        this.complete = false;
    }

    get width() {
        return this._width;
    }
    set width(v) {
        this._width = v;
    }

    get height() {
        return this._height;
    }

    set height(v) {
        this._height = v;
    }

    get src() {
        return this._src;
    }

    set src(v) {

        if (v.startsWith('//')) {
            v = 'http:' + v;
        }

        this._src = v;

        GImage.GBridge.perloadImage([this._src, this._id], (data) => {
            if (typeof data === 'string') {
                data = JSON.parse(data);
            }
            if (data.error) {
                var evt = { type: 'error', target: this };
                this.onerror(evt);
            } else {
                this.complete = true;
                this.width = typeof data.width === 'number' ? data.width : 0;
                this.height = typeof data.height === 'number' ? data.height : 0;
                var evt = { type: 'load', target: this };
                this.onload(evt);
            }
        });
    }

    addEventListener(name, listener) {
        if (name === 'load') {
            this.onload = listener;
        } else if (name === 'error') {
            this.onerror = listener;
        }
    }

    removeEventListener(name, listener) {
        if (name === 'load') {
            this.onload = noop;
        } else if (name === 'error') {
            this.onerror = noop;
        }
    }

    get onload() {
        return this._onload;
    }

    set onload(v) {
        this._onload = v;
    }

    get onerror() {
        return this._onerror;
    }

    set onerror(v) {
        this._onerror = v;
    }
}

export default GImage;]	*x^
export function ArrayBufferToBase64 (buffer) {
    var binary = '';
    var bytes = new Uint8ClampedArray(buffer);
    for (var len = bytes.byteLength, i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return btoa(binary);
}
	
export function Base64ToUint8ClampedArray(base64String) {
	const padding = '='.repeat((4 - base64String.length % 4) % 4);
	const base64 = (base64String + padding)
		.replace(/\-/g, '+')
		.replace(/_/g, '/');

	const rawData = atob(base64);
	const outputArray = new Uint8ClampedArray(rawData.length);

	for (let i = 0; i < rawData.length; ++i) {
		outputArray[i] = rawData.charCodeAt(i);
	}
	return outputArray;
}!Px import GCanvas from './env/canvas';
import GImage from './env/image';

import GWebGLRenderingContext from './context-webgl/RenderingContext';
import GContext2D from './context-2d/RenderingContext';

import GBridgeWeex from './bridge/bridge-weex';

export let Image = GImage;

export let WeexBridge = GBridgeWeex;

export function enable(el, { bridge, debug, disableAutoSwap, disableComboCommands } = {}) {

    const GBridge = GImage.GBridge = GCanvas.GBridge = GWebGLRenderingContext.GBridge = GContext2D.GBridge = bridge;

    GBridge.callEnable(el.ref, [
        0,      // renderMode: 0--RENDERMODE_WHEN_DIRTY, 1--RENDERMODE_CONTINUOUSLY
        -1,     // hybridLayerType:  0--LAYER_TYPE_NONE 1--LAYER_TYPE_SOFTWARE 2--LAYER_TYPE_HARDWARE
        false,  // supportScroll
        false,  // newCanvasMode
        1,      // compatible
        'white',// clearColor
        false   // sameLevel: newCanvasMode = true && true => GCanvasView and Webview is same level
    ]);

    if (debug === true) {
        GBridge.callEnableDebug();
    }
    if (disableComboCommands) {
        GBridge.callEnableDisableCombo();
    }

    var canvas = new GCanvas(el.ref, { disableAutoSwap });
    canvas.width = el.style.width;
    canvas.height = el.style.height;

    return canvas;
};Lvxhexport default {
	props: {
		//二维码内容
		value: {
			type: [String, Number]
		},
		//选项
		options: {
			type: Object,
			default: () => {
				return {};
			}
		},
		//二维码大小
		size: {
			type: [String, Number],
			default: 200
		},
		//导出的文件类型
		fileType: {
			type: String,
			default: 'png'
		},
		//是否初始化组件后就开始生成
		start: {
			type: Boolean,
			default: true
		},
		//是否数据发生改变自动重绘
		auto: {
			type: Boolean,
			default: true
		},
		//隐藏组件
		hide: {
			type: Boolean,
			default: false
		},
		/**
		 * canvas 类型，微信小程序默认使用2d，非2d微信官方已放弃维护，问题比较多
		 * 注意：微信小程序type2d手机上正常，PC上微信内打开小程序toDataURL报错，看后期微信官方团队会不会做兼容，不兼容的话只能在自行判断在PC使用非2d，或者直接提示用户请在手机上操作，微信团队的海报中心小程序就是这么做的
		 */
		type: {
			type: String,
			default: () => {
				// #ifdef MP-WEIXIN
				return '2d';
				// #endif
				// #ifndef MP-WEIXIN
				return 'normal';
				// #endif
			}
		},
		//队列绘制，主要针对NVue端
		queue: {
			type: Boolean,
			default: false
		},
		//是否队列加载图片，可减少canvas发起的网络资源请求，节省服务器资源
		isQueueLoadImage: {
			type: Boolean,
			default: false
		},
		//loading态
		loading: {
			type: Boolean,
			default: undefined
		},
		//H5保存即自动下载（在支持的环境下），默认false为仅弹层提示用户需要长按图片保存，不会自动下载
		h5SaveIsDownload: {
			type: Boolean,
			default: false
		},
		//H5下载名称
		h5DownloadName: {
			type: String,
			default: 'uvQRCode'
		},
		// H5保存二维码时候是否显示提示
		h5SaveTip: {
			type: Boolean,
			default: true
		}
	}
}cxWt//---------------------------------------------------------------------
// uQRCode二维码生成插件 v4.0.6
// 
// uQRCode是一款基于Javascript环境开发的二维码生成插件，适用所有Javascript运行环境的前端应用和Node.js。
// 
// Copyright (c) Sansnn uQRCode All rights reserved.
// 
// Licensed under the Apache License, Version 2.0.
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// github地址：
//   https://github.com/Sansnn/uQRCode
// 
// npm地址：
//   https://www.npmjs.com/package/uqrcodejs
// 
// uni-app插件市场地址：
//   https://ext.dcloud.net.cn/plugin?id=1287
// 
// 复制使用请保留本段注释，感谢支持开源！
// 
//---------------------------------------------------------------------

//---------------------------------------------------------------------
// 当前文件格式为 es，将 bundle 保留为 ES 模块文件，适用于其他打包工具以及支持 <script type=module> 标签的浏览器（别名: esm，module）
// 如需在其他环境使用，请获取环境对应的格式文件
// 格式说明：
// amd - 异步模块定义，适用于 RequireJS 等模块加载器
// cjs - CommonJS，适用于 Node 环境和其他打包工具（别名：commonjs）
// es - 将 bundle 保留为 ES 模块文件，适用于其他打包工具以及支持 <script type=module> 标签的浏览器（别名: esm，module）
// umd - 通用模块定义，生成的包同时支持 amd、cjs 和 iife 三种格式
//---------------------------------------------------------------------

function o(o){this.mode=r.MODE_8BIT_BYTE,this.data=o;}function e(o,e){this.typeNumber=o,this.errorCorrectLevel=e,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=new Array;}o.prototype={getLength:function(o){return this.data.length},write:function(o){for(var e=0;e<this.data.length;e++)o.put(this.data.charCodeAt(e),8);}},e.prototype={addData:function(e){var r=new o(e);this.dataList.push(r),this.dataCache=null;},isDark:function(o,e){if(o<0||this.moduleCount<=o||e<0||this.moduleCount<=e)throw new Error(o+","+e);return this.modules[o][e]},getModuleCount:function(){return this.moduleCount},make:function(){if(this.typeNumber<1){var o=1;for(o=1;o<40;o++){for(var e=v.getRSBlocks(o,this.errorCorrectLevel),r=new p,t=0,i=0;i<e.length;i++)t+=e[i].dataCount;for(i=0;i<this.dataList.length;i++){var n=this.dataList[i];r.put(n.mode,4),r.put(n.getLength(),h.getLengthInBits(n.mode,o)),n.write(r);}if(r.getLengthInBits()<=8*t)break}this.typeNumber=o;}this.makeImpl(!1,this.getBestMaskPattern());},makeImpl:function(o,r){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var t=0;t<this.moduleCount;t++){this.modules[t]=new Array(this.moduleCount);for(var i=0;i<this.moduleCount;i++)this.modules[t][i]=null;}this.setupPositionProbePattern(0,0),this.setupPositionProbePattern(this.moduleCount-7,0),this.setupPositionProbePattern(0,this.moduleCount-7),this.setupPositionAdjustPattern(),this.setupTimingPattern(),this.setupTypeInfo(o,r),this.typeNumber>=7&&this.setupTypeNumber(o),null==this.dataCache&&(this.dataCache=e.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,r);},setupPositionProbePattern:function(o,e){for(var r=-1;r<=7;r++)if(!(o+r<=-1||this.moduleCount<=o+r))for(var t=-1;t<=7;t++)e+t<=-1||this.moduleCount<=e+t||(this.modules[o+r][e+t]=0<=r&&r<=6&&(0==t||6==t)||0<=t&&t<=6&&(0==r||6==r)||2<=r&&r<=4&&2<=t&&t<=4);},getBestMaskPattern:function(){for(var o=0,e=0,r=0;r<8;r++){this.makeImpl(!0,r);var t=h.getLostPoint(this);(0==r||o>t)&&(o=t,e=r);}return e},createMovieClip:function(o,e,r){var t=o.createEmptyMovieClip(e,r);this.make();for(var i=0;i<this.modules.length;i++)for(var n=1*i,a=0;a<this.modules[i].length;a++){var d=1*a;this.modules[i][a]&&(t.beginFill(0,100),t.moveTo(d,n),t.lineTo(d+1,n),t.lineTo(d+1,n+1),t.lineTo(d,n+1),t.endFill());}return t},setupTimingPattern:function(){for(var o=8;o<this.moduleCount-8;o++)null==this.modules[o][6]&&(this.modules[o][6]=o%2==0);for(var e=8;e<this.moduleCount-8;e++)null==this.modules[6][e]&&(this.modules[6][e]=e%2==0);},setupPositionAdjustPattern:function(){for(var o=h.getPatternPosition(this.typeNumber),e=0;e<o.length;e++)for(var r=0;r<o.length;r++){var t=o[e],i=o[r];if(null==this.modules[t][i])for(var n=-2;n<=2;n++)for(var a=-2;a<=2;a++)this.modules[t+n][i+a]=-2==n||2==n||-2==a||2==a||0==n&&0==a;}},setupTypeNumber:function(o){for(var e=h.getBCHTypeNumber(this.typeNumber),r=0;r<18;r++){var t=!o&&1==(e>>r&1);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=t;}for(r=0;r<18;r++){t=!o&&1==(e>>r&1);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=t;}},setupTypeInfo:function(o,e){for(var r=this.errorCorrectLevel<<3|e,t=h.getBCHTypeInfo(r),i=0;i<15;i++){var n=!o&&1==(t>>i&1);i<6?this.modules[i][8]=n:i<8?this.modules[i+1][8]=n:this.modules[this.moduleCount-15+i][8]=n;}for(i=0;i<15;i++){n=!o&&1==(t>>i&1);i<8?this.modules[8][this.moduleCount-i-1]=n:i<9?this.modules[8][15-i-1+1]=n:this.modules[8][15-i-1]=n;}this.modules[this.moduleCount-8][8]=!o;},mapData:function(o,e){for(var r=-1,t=this.moduleCount-1,i=7,n=0,a=this.moduleCount-1;a>0;a-=2)for(6==a&&a--;;){for(var d=0;d<2;d++)if(null==this.modules[t][a-d]){var u=!1;n<o.length&&(u=1==(o[n]>>>i&1)),h.getMask(e,t,a-d)&&(u=!u),this.modules[t][a-d]=u,-1==--i&&(n++,i=7);}if((t+=r)<0||this.moduleCount<=t){t-=r,r=-r;break}}}},e.PAD0=236,e.PAD1=17,e.createData=function(o,r,t){for(var i=v.getRSBlocks(o,r),n=new p,a=0;a<t.length;a++){var d=t[a];n.put(d.mode,4),n.put(d.getLength(),h.getLengthInBits(d.mode,o)),d.write(n);}var u=0;for(a=0;a<i.length;a++)u+=i[a].dataCount;if(n.getLengthInBits()>8*u)throw new Error("code length overflow. ("+n.getLengthInBits()+">"+8*u+")");for(n.getLengthInBits()+4<=8*u&&n.put(0,4);n.getLengthInBits()%8!=0;)n.putBit(!1);for(;!(n.getLengthInBits()>=8*u||(n.put(e.PAD0,8),n.getLengthInBits()>=8*u));)n.put(e.PAD1,8);return e.createBytes(n,i)},e.createBytes=function(o,e){for(var r=0,t=0,i=0,n=new Array(e.length),a=new Array(e.length),d=0;d<e.length;d++){var u=e[d].dataCount,s=e[d].totalCount-u;t=Math.max(t,u),i=Math.max(i,s),n[d]=new Array(u);for(var g=0;g<n[d].length;g++)n[d][g]=255&o.buffer[g+r];r+=u;var l=h.getErrorCorrectPolynomial(s),c=new f(n[d],l.getLength()-1).mod(l);a[d]=new Array(l.getLength()-1);for(g=0;g<a[d].length;g++){var m=g+c.getLength()-a[d].length;a[d][g]=m>=0?c.get(m):0;}}var v=0;for(g=0;g<e.length;g++)v+=e[g].totalCount;var p=new Array(v),C=0;for(g=0;g<t;g++)for(d=0;d<e.length;d++)g<n[d].length&&(p[C++]=n[d][g]);for(g=0;g<i;g++)for(d=0;d<e.length;d++)g<a[d].length&&(p[C++]=a[d][g]);return p};for(var r={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},t={L:1,M:0,Q:3,H:2},i=0,n=1,a=2,d=3,u=4,s=5,g=6,l=7,h={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(o){for(var e=o<<10;h.getBCHDigit(e)-h.getBCHDigit(h.G15)>=0;)e^=h.G15<<h.getBCHDigit(e)-h.getBCHDigit(h.G15);return (o<<10|e)^h.G15_MASK},getBCHTypeNumber:function(o){for(var e=o<<12;h.getBCHDigit(e)-h.getBCHDigit(h.G18)>=0;)e^=h.G18<<h.getBCHDigit(e)-h.getBCHDigit(h.G18);return o<<12|e},getBCHDigit:function(o){for(var e=0;0!=o;)e++,o>>>=1;return e},getPatternPosition:function(o){return h.PATTERN_POSITION_TABLE[o-1]},getMask:function(o,e,r){switch(o){case i:return (e+r)%2==0;case n:return e%2==0;case a:return r%3==0;case d:return (e+r)%3==0;case u:return (Math.floor(e/2)+Math.floor(r/3))%2==0;case s:return e*r%2+e*r%3==0;case g:return (e*r%2+e*r%3)%2==0;case l:return (e*r%3+(e+r)%2)%2==0;default:throw new Error("bad maskPattern:"+o)}},getErrorCorrectPolynomial:function(o){for(var e=new f([1],0),r=0;r<o;r++)e=e.multiply(new f([1,c.gexp(r)],0));return e},getLengthInBits:function(o,e){if(1<=e&&e<10)switch(o){case r.MODE_NUMBER:return 10;case r.MODE_ALPHA_NUM:return 9;case r.MODE_8BIT_BYTE:case r.MODE_KANJI:return 8;default:throw new Error("mode:"+o)}else if(e<27)switch(o){case r.MODE_NUMBER:return 12;case r.MODE_ALPHA_NUM:return 11;case r.MODE_8BIT_BYTE:return 16;case r.MODE_KANJI:return 10;default:throw new Error("mode:"+o)}else {if(!(e<41))throw new Error("type:"+e);switch(o){case r.MODE_NUMBER:return 14;case r.MODE_ALPHA_NUM:return 13;case r.MODE_8BIT_BYTE:return 16;case r.MODE_KANJI:return 12;default:throw new Error("mode:"+o)}}},getLostPoint:function(o){for(var e=o.getModuleCount(),r=0,t=0;t<e;t++)for(var i=0;i<e;i++){for(var n=0,a=o.isDark(t,i),d=-1;d<=1;d++)if(!(t+d<0||e<=t+d))for(var u=-1;u<=1;u++)i+u<0||e<=i+u||0==d&&0==u||a==o.isDark(t+d,i+u)&&n++;n>5&&(r+=3+n-5);}for(t=0;t<e-1;t++)for(i=0;i<e-1;i++){var s=0;o.isDark(t,i)&&s++,o.isDark(t+1,i)&&s++,o.isDark(t,i+1)&&s++,o.isDark(t+1,i+1)&&s++,0!=s&&4!=s||(r+=3);}for(t=0;t<e;t++)for(i=0;i<e-6;i++)o.isDark(t,i)&&!o.isDark(t,i+1)&&o.isDark(t,i+2)&&o.isDark(t,i+3)&&o.isDark(t,i+4)&&!o.isDark(t,i+5)&&o.isDark(t,i+6)&&(r+=40);for(i=0;i<e;i++)for(t=0;t<e-6;t++)o.isDark(t,i)&&!o.isDark(t+1,i)&&o.isDark(t+2,i)&&o.isDark(t+3,i)&&o.isDark(t+4,i)&&!o.isDark(t+5,i)&&o.isDark(t+6,i)&&(r+=40);var g=0;for(i=0;i<e;i++)for(t=0;t<e;t++)o.isDark(t,i)&&g++;return r+=10*(Math.abs(100*g/e/e-50)/5)}},c={glog:function(o){if(o<1)throw new Error("glog("+o+")");return c.LOG_TABLE[o]},gexp:function(o){for(;o<0;)o+=255;for(;o>=256;)o-=255;return c.EXP_TABLE[o]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},m=0;m<8;m++)c.EXP_TABLE[m]=1<<m;for(m=8;m<256;m++)c.EXP_TABLE[m]=c.EXP_TABLE[m-4]^c.EXP_TABLE[m-5]^c.EXP_TABLE[m-6]^c.EXP_TABLE[m-8];for(m=0;m<255;m++)c.LOG_TABLE[c.EXP_TABLE[m]]=m;function f(o,e){if(null==o.length)throw new Error(o.length+"/"+e);for(var r=0;r<o.length&&0==o[r];)r++;this.num=new Array(o.length-r+e);for(var t=0;t<o.length-r;t++)this.num[t]=o[t+r];}function v(o,e){this.totalCount=o,this.dataCount=e;}function p(){this.buffer=new Array,this.length=0;}function C(o){return o.setFillStyle=o.setFillStyle||function(e){o.fillStyle=e;},o.setFontSize=o.setFontSize||function(e){o.font=`${e}px`;},o.setTextAlign=o.setTextAlign||function(e){o.textAlign=e;},o.setTextBaseline=o.setTextBaseline||function(e){o.textBaseline=e;},o.setGlobalAlpha=o.setGlobalAlpha||function(e){o.globalAlpha=e;},o.setStrokeStyle=o.setStrokeStyle||function(e){o.strokeStyle=e;},o.setShadow=o.setShadow||function(e,r,t,i){o.shadowOffsetX=e,o.shadowOffsetY=r,o.shadowBlur=t,o.shadowColor=i;},o.draw=o.draw||function(o,e){e&&e();},o.clearRect=o.clearRect||function(e,r,t,i){o.draw(!1);},o}function b(o,e){var r=this.data="",t=this.size=200;this.useDynamicSize=!1,this.dynamicSize=t;var i=this.typeNumber=-1;this.errorCorrectLevel=b.errorCorrectLevel.H;var n=this.margin=0;this.areaColor="#FFFFFF",this.backgroundColor="rgba(255,255,255,0)",this.backgroundImageSrc=void 0;var a=this.backgroundImageWidth=void 0,d=this.backgroundImageHeight=void 0,u=this.backgroundImageX=void 0,s=this.backgroundImageY=void 0;this.backgroundImageAlpha=1,this.backgroundImageBorderRadius=0;var g=this.backgroundPadding=0;this.foregroundColor="#000000",this.foregroundImageSrc=void 0;var l=this.foregroundImageWidth=void 0,h=this.foregroundImageHeight=void 0,c=this.foregroundImageX=void 0,m=this.foregroundImageY=void 0,f=this.foregroundImagePadding=0;this.foregroundImageBackgroundColor="#FFFFFF";var v=this.foregroundImageBorderRadius=0,p=this.foregroundImageShadowOffsetX=0,k=this.foregroundImageShadowOffsetY=0,y=this.foregroundImageShadowBlur=0;this.foregroundImageShadowColor="#808080";var w=this.foregroundPadding=0,I=this.positionProbeBackgroundColor=void 0,B=this.positionProbeForegroundColor=void 0,S=this.separatorColor=void 0,P=this.positionAdjustBackgroundColor=void 0,L=this.positionAdjustForegroundColor=void 0,D=this.timingBackgroundColor=void 0,A=this.timingForegroundColor=void 0,E=this.typeNumberBackgroundColor=void 0,T=this.typeNumberForegroundColor=void 0,N=this.darkBlockColor=void 0;this.base=void 0,this.modules=[],this.moduleCount=0,this.drawModules=[];var M=this.canvasContext=void 0;this.loadImage,this.drawReserve=!1,this.isMaked=!1,Object.defineProperties(this,{data:{get(){if(""===r||void 0===r)throw console.error("[uQRCode]: data must be set!"),new b.Error("data must be set!");return r},set(o){r=String(o);}},size:{get:()=>t,set(o){t=Number(o);}},typeNumber:{get:()=>i,set(o){i=Number(o);}},margin:{get:()=>n,set(o){n=Number(o);}},backgroundImageWidth:{get(){return void 0===a?this.dynamicSize:this.useDynamicSize?this.dynamicSize/this.size*a:a},set(o){a=Number(o);}},backgroundImageHeight:{get(){return void 0===d?this.dynamicSize:this.useDynamicSize?this.dynamicSize/this.size*d:d},set(o){d=Number(o);}},backgroundImageX:{get(){return void 0===u?0:this.useDynamicSize?this.dynamicSize/this.size*u:u},set(o){u=Number(o);}},backgroundImageY:{get(){return void 0===s?0:this.useDynamicSize?this.dynamicSize/this.size*s:s},set(o){s=Number(o);}},backgroundPadding:{get:()=>g,set(o){g=o>1?1:o<0?0:o;}},foregroundImageWidth:{get(){return void 0===l?(this.dynamicSize-2*this.margin)/4:this.useDynamicSize?this.dynamicSize/this.size*l:l},set(o){l=Number(o);}},foregroundImageHeight:{get(){return void 0===h?(this.dynamicSize-2*this.margin)/4:this.useDynamicSize?this.dynamicSize/this.size*h:h},set(o){h=Number(o);}},foregroundImageX:{get(){return void 0===c?this.dynamicSize/2-this.foregroundImageWidth/2:this.useDynamicSize?this.dynamicSize/this.size*c:c},set(o){c=Number(o);}},foregroundImageY:{get(){return void 0===m?this.dynamicSize/2-this.foregroundImageHeight/2:this.useDynamicSize?this.dynamicSize/this.size*m:m},set(o){m=Number(o);}},foregroundImagePadding:{get(){return this.useDynamicSize?this.dynamicSize/this.size*f:f},set(o){f=Number(o);}},foregroundImageBorderRadius:{get(){return this.useDynamicSize?this.dynamicSize/this.size*v:v},set(o){v=Number(o);}},foregroundImageShadowOffsetX:{get(){return this.useDynamicSize?this.dynamicSize/this.size*p:p},set(o){p=Number(o);}},foregroundImageShadowOffsetY:{get(){return this.useDynamicSize?this.dynamicSize/this.size*k:k},set(o){k=Number(o);}},foregroundImageShadowBlur:{get(){return this.useDynamicSize?this.dynamicSize/this.size*y:y},set(o){y=Number(o);}},foregroundPadding:{get:()=>w,set(o){w=o>1?1:o<0?0:o;}},positionProbeBackgroundColor:{get(){return I||this.backgroundColor},set(o){I=o;}},positionProbeForegroundColor:{get(){return B||this.foregroundColor},set(o){B=o;}},separatorColor:{get(){return S||this.backgroundColor},set(o){S=o;}},positionAdjustBackgroundColor:{get(){return P||this.backgroundColor},set(o){P=o;}},positionAdjustForegroundColor:{get(){return L||this.foregroundColor},set(o){L=o;}},timingBackgroundColor:{get(){return D||this.backgroundColor},set(o){D=o;}},timingForegroundColor:{get(){return A||this.foregroundColor},set(o){A=o;}},typeNumberBackgroundColor:{get(){return E||this.backgroundColor},set(o){E=o;}},typeNumberForegroundColor:{get(){return T||this.foregroundColor},set(o){T=o;}},darkBlockColor:{get(){return N||this.foregroundColor},set(o){N=o;}},canvasContext:{get(){if(void 0===M)throw console.error("[uQRCode]: use drawCanvas, you need to set the canvasContext!"),new b.Error("use drawCanvas, you need to set the canvasContext!");return M},set(o){M=C(o);}}}),b.plugins.forEach((o=>o(b,this,!1))),o&&this.setOptions(o),e&&(this.canvasContext=C(e));}f.prototype={get:function(o){return this.num[o]},getLength:function(){return this.num.length},multiply:function(o){for(var e=new Array(this.getLength()+o.getLength()-1),r=0;r<this.getLength();r++)for(var t=0;t<o.getLength();t++)e[r+t]^=c.gexp(c.glog(this.get(r))+c.glog(o.get(t)));return new f(e,0)},mod:function(o){if(this.getLength()-o.getLength()<0)return this;for(var e=c.glog(this.get(0))-c.glog(o.get(0)),r=new Array(this.getLength()),t=0;t<this.getLength();t++)r[t]=this.get(t);for(t=0;t<o.getLength();t++)r[t]^=c.gexp(c.glog(o.get(t))+e);return new f(r,0).mod(o)}},v.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],v.getRSBlocks=function(o,e){var r=v.getRsBlockTable(o,e);if(null==r)throw new Error("bad rs block @ typeNumber:"+o+"/errorCorrectLevel:"+e);for(var t=r.length/3,i=new Array,n=0;n<t;n++)for(var a=r[3*n+0],d=r[3*n+1],u=r[3*n+2],s=0;s<a;s++)i.push(new v(d,u));return i},v.getRsBlockTable=function(o,e){switch(e){case t.L:return v.RS_BLOCK_TABLE[4*(o-1)+0];case t.M:return v.RS_BLOCK_TABLE[4*(o-1)+1];case t.Q:return v.RS_BLOCK_TABLE[4*(o-1)+2];case t.H:return v.RS_BLOCK_TABLE[4*(o-1)+3];default:return}},p.prototype={get:function(o){var e=Math.floor(o/8);return 1==(this.buffer[e]>>>7-o%8&1)},put:function(o,e){for(var r=0;r<e;r++)this.putBit(1==(o>>>e-r-1&1));},getLengthInBits:function(){return this.length},putBit:function(o){var e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),o&&(this.buffer[e]|=128>>>this.length%8),this.length++;}},e.errorCorrectLevel=t,b.errorCorrectLevel=e.errorCorrectLevel,b.Error=function(o){this.errMsg="[uQRCode]: "+o;},b.plugins=[],b.use=function(o){"function"==typeof o&&b.plugins.push(o);},b.prototype.loadImage=function(o){return Promise.resolve(o)},b.prototype.setOptions=function(o){var e,r,t,i,n,a,d,u,s,g,l,h,c,m,f,v,p,C,b,k,y,w,I,B,S,P,L,D,A,E,T,N,M,z,R,_,O,F,x,H,X,Y,j,W,G,K,Q,U,$,J,q,V,Z,oo,eo,ro;o&&(Object.keys(o).forEach((e=>{this[e]=o[e];})),function(o={},e={},r=!1){let t;t=r?o:{...o};for(let o in e){var i=e[o];null!=i&&(i.constructor==Object?t[o]=this.deepReplace(t[o],i):i.constructor!=String||i?t[o]=i:t[o]=t[o]);}}(this,{data:o.data||o.text,size:o.size,useDynamicSize:o.useDynamicSize,typeNumber:o.typeNumber,errorCorrectLevel:o.errorCorrectLevel,margin:o.margin,areaColor:o.areaColor,backgroundColor:o.backgroundColor||(null===(e=o.background)||void 0===e?void 0:e.color),backgroundImageSrc:o.backgroundImageSrc||(null===(r=o.background)||void 0===r||null===(t=r.image)||void 0===t?void 0:t.src),backgroundImageWidth:o.backgroundImageWidth||(null===(i=o.background)||void 0===i||null===(n=i.image)||void 0===n?void 0:n.width),backgroundImageHeight:o.backgroundImageHeight||(null===(a=o.background)||void 0===a||null===(d=a.image)||void 0===d?void 0:d.height),backgroundImageX:o.backgroundImageX||(null===(u=o.background)||void 0===u||null===(s=u.image)||void 0===s?void 0:s.x),backgroundImageY:o.backgroundImageY||(null===(g=o.background)||void 0===g||null===(l=g.image)||void 0===l?void 0:l.y),backgroundImageAlpha:o.backgroundImageAlpha||(null===(h=o.background)||void 0===h||null===(c=h.image)||void 0===c?void 0:c.alpha),backgroundImageBorderRadius:o.backgroundImageBorderRadius||(null===(m=o.background)||void 0===m||null===(f=m.image)||void 0===f?void 0:f.borderRadius),backgroundPadding:o.backgroundPadding,foregroundColor:o.foregroundColor||(null===(v=o.foreground)||void 0===v?void 0:v.color),foregroundImageSrc:o.foregroundImageSrc||(null===(p=o.foreground)||void 0===p||null===(C=p.image)||void 0===C?void 0:C.src),foregroundImageWidth:o.foregroundImageWidth||(null===(b=o.foreground)||void 0===b||null===(k=b.image)||void 0===k?void 0:k.width),foregroundImageHeight:o.foregroundImageHeight||(null===(y=o.foreground)||void 0===y||null===(w=y.image)||void 0===w?void 0:w.height),foregroundImageX:o.foregroundImageX||(null===(I=o.foreground)||void 0===I||null===(B=I.image)||void 0===B?void 0:B.x),foregroundImageY:o.foregroundImageY||(null===(S=o.foreground)||void 0===S||null===(P=S.image)||void 0===P?void 0:P.y),foregroundImagePadding:o.foregroundImagePadding||(null===(L=o.foreground)||void 0===L||null===(D=L.image)||void 0===D?void 0:D.padding),foregroundImageBackgroundColor:o.foregroundImageBackgroundColor||(null===(A=o.foreground)||void 0===A||null===(E=A.image)||void 0===E?void 0:E.backgroundColor),foregroundImageBorderRadius:o.foregroundImageBorderRadius||(null===(T=o.foreground)||void 0===T||null===(N=T.image)||void 0===N?void 0:N.borderRadius),foregroundImageShadowOffsetX:o.foregroundImageShadowOffsetX||(null===(M=o.foreground)||void 0===M||null===(z=M.image)||void 0===z?void 0:z.shadowOffsetX),foregroundImageShadowOffsetY:o.foregroundImageShadowOffsetY||(null===(R=o.foreground)||void 0===R||null===(_=R.image)||void 0===_?void 0:_.shadowOffsetY),foregroundImageShadowBlur:o.foregroundImageShadowBlur||(null===(O=o.foreground)||void 0===O||null===(F=O.image)||void 0===F?void 0:F.shadowBlur),foregroundImageShadowColor:o.foregroundImageShadowColor||(null===(x=o.foreground)||void 0===x||null===(H=x.image)||void 0===H?void 0:H.shadowColor),foregroundPadding:o.foregroundPadding,positionProbeBackgroundColor:o.positionProbeBackgroundColor||(null===(X=o.positionProbe)||void 0===X?void 0:X.backgroundColor)||(null===(Y=o.positionDetection)||void 0===Y?void 0:Y.backgroundColor),positionProbeForegroundColor:o.positionProbeForegroundColor||(null===(j=o.positionProbe)||void 0===j?void 0:j.foregroundColor)||(null===(W=o.positionDetection)||void 0===W?void 0:W.foregroundColor),separatorColor:o.separatorColor||(null===(G=o.separator)||void 0===G?void 0:G.color),positionAdjustBackgroundColor:o.positionAdjustBackgroundColor||(null===(K=o.positionAdjust)||void 0===K?void 0:K.backgroundColor)||(null===(Q=o.alignment)||void 0===Q?void 0:Q.backgroundColor),positionAdjustForegroundColor:o.positionAdjustForegroundColor||(null===(U=o.positionAdjust)||void 0===U?void 0:U.foregroundColor)||(null===($=o.alignment)||void 0===$?void 0:$.foregroundColor),timingBackgroundColor:o.timingBackgroundColor||(null===(J=o.timing)||void 0===J?void 0:J.backgroundColor),timingForegroundColor:o.timingForegroundColor||(null===(q=o.timing)||void 0===q?void 0:q.foregroundColor),typeNumberBackgroundColor:o.typeNumberBackgroundColor||(null===(V=o.typeNumber)||void 0===V?void 0:V.backgroundColor)||(null===(Z=o.versionInformation)||void 0===Z?void 0:Z.backgroundColor),typeNumberForegroundColor:o.typeNumberForegroundColor||(null===(oo=o.typeNumber)||void 0===oo?void 0:oo.foregroundColor)||(null===(eo=o.versionInformation)||void 0===eo?void 0:eo.foregroundColor),darkBlockColor:o.darkBlockColor||(null===(ro=o.darkBlock)||void 0===ro?void 0:ro.color)},!0));},b.prototype.make=function(){let{foregroundColor:o,backgroundColor:r,typeNumber:t,errorCorrectLevel:i,data:n,size:a,margin:d,useDynamicSize:u}=this;if(o===r)throw console.error("[uQRCode]: foregroundColor and backgroundColor cannot be the same!"),new b.Error("foregroundColor and backgroundColor cannot be the same!");var s=new e(t,i);s.addData(function(o){o=o.toString();for(var e,r="",t=0;t<o.length;t++)(e=o.charCodeAt(t))>=1&&e<=127?r+=o.charAt(t):e>2047?(r+=String.fromCharCode(224|e>>12&15),r+=String.fromCharCode(128|e>>6&63),r+=String.fromCharCode(128|e>>0&63)):(r+=String.fromCharCode(192|e>>6&31),r+=String.fromCharCode(128|e>>0&63));return r}(n)),s.make(),this.base=s,this.typeNumber=s.typeNumber,this.modules=s.modules,this.moduleCount=s.moduleCount,this.dynamicSize=u?Math.ceil((a-2*d)/s.moduleCount)*s.moduleCount+2*d:a,function(o){let{dynamicSize:e,margin:r,backgroundColor:t,backgroundPadding:i,foregroundColor:n,foregroundPadding:a,modules:d,moduleCount:u}=o,s=(e-2*r)/u,g=s,l=0;i>0&&(l=g*i/2,g-=2*l);let h=s,c=0;a>0&&(c=h*a/2,h-=2*c);for(var m=0;m<u;m++)for(var f=0;f<u;f++){var v=f*s+r,p=m*s+r;if(d[m][f]){var C=c,b=v+c,k=p+c,y=h,w=h;d[m][f]={type:["foreground"],color:n,isBlack:!0,isDrawn:!1,destX:v,destY:p,destWidth:s,destHeight:s,x:b,y:k,width:y,height:w,paddingTop:C,paddingRight:C,paddingBottom:C,paddingLeft:C};}else C=l,b=v+l,k=p+l,y=g,w=g,d[m][f]={type:["background"],color:t,isBlack:!1,isDrawn:!1,destX:v,destY:p,destWidth:s,destHeight:s,x:b,y:k,width:y,height:w,paddingTop:C,paddingRight:C,paddingBottom:C,paddingLeft:C};}}(this),function(o){let{modules:e,moduleCount:r,positionProbeBackgroundColor:t,positionProbeForegroundColor:i}=o,n=r-7;[[0,0,1],[1,0,1],[2,0,1],[3,0,1],[4,0,1],[5,0,1],[6,0,1],[0,1,1],[1,1,0],[2,1,0],[3,1,0],[4,1,0],[5,1,0],[6,1,1],[0,2,1],[1,2,0],[2,2,1],[3,2,1],[4,2,1],[5,2,0],[6,2,1],[0,3,1],[1,3,0],[2,3,1],[3,3,1],[4,3,1],[5,3,0],[6,3,1],[0,4,1],[1,4,0],[2,4,1],[3,4,1],[4,4,1],[5,4,0],[6,4,1],[0,5,1],[1,5,0],[2,5,0],[3,5,0],[4,5,0],[5,5,0],[6,5,1],[0,6,1],[1,6,1],[2,6,1],[3,6,1],[4,6,1],[5,6,1],[6,6,1]].forEach((o=>{var r=e[o[0]][o[1]],a=e[o[0]+n][o[1]],d=e[o[0]][o[1]+n];d.type.push("positionProbe"),a.type.push("positionProbe"),r.type.push("positionProbe"),r.color=1==o[2]?i:t,a.color=1==o[2]?i:t,d.color=1==o[2]?i:t;}));}(this),function(o){let{modules:e,moduleCount:r,separatorColor:t}=o;[[7,0],[7,1],[7,2],[7,3],[7,4],[7,5],[7,6],[7,7],[0,7],[1,7],[2,7],[3,7],[4,7],[5,7],[6,7]].forEach((o=>{var i=e[o[0]][o[1]],n=e[r-o[0]-1][o[1]],a=e[o[0]][r-o[1]-1];a.type.push("separator"),n.type.push("separator"),i.type.push("separator"),i.color=t,n.color=t,a.color=t;}));}(this),function(o){let{typeNumber:e,modules:r,moduleCount:t,foregroundColor:i,backgroundColor:n,positionAdjustForegroundColor:a,positionAdjustBackgroundColor:d,timingForegroundColor:u,timingBackgroundColor:s}=o;const g=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]][e-1];if(g){const o=[[-2,-2,1],[-1,-2,1],[0,-2,1],[1,-2,1],[2,-2,1],[-2,-1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[2,-1,1],[-2,0,1],[-1,0,0],[0,0,1],[1,0,0],[2,0,1],[-2,1,1],[-1,1,0],[0,1,0],[1,1,0],[2,1,1],[-2,2,1],[-1,2,1],[0,2,1],[1,2,1],[2,2,1]],e=g.length;for(let l=0;l<e;l++)for(let h=0;h<e;h++){let{x:e,y:c}={x:g[l],y:g[h]};e<9&&c<9||e>t-9-1&&c<9||c>t-9-1&&e<9||o.forEach((o=>{var t=r[e+o[0]][c+o[1]];t.type.push("positionAdjust"),t.type.includes("timing")?1==o[2]?t.color=a==i?u:a:t.color=a==i&&d==n?s:d:t.color=1==o[2]?a:d;}));}}}(this),function(o){let{modules:e,moduleCount:r,timingForegroundColor:t,timingBackgroundColor:i}=o,n=r-16;for(let o=0;o<n;o++){var a=e[6][8+o],d=e[8+o][6];a.type.push("timing"),d.type.push("timing"),a.color=1&o^1?t:i,d.color=1&o^1?t:i;}}(this),function(o){let{modules:e,moduleCount:r,darkBlockColor:t}=o;var i=e[r-7-1][8];i.type.push("darkBlock"),i.color=t;}(this),function(o){let{typeNumber:e,modules:r,moduleCount:t,typeNumberBackgroundColor:i,typeNumberForegroundColor:n}=o;if(e<7)return r;const a=[0,0,0,0,0,0,0,"000111110010010100","001000010110111100","001001101010011001","001010010011010011","001011101111110110","001100011101100010","001101100001000111","001110011000001101","001111100100101000","010000101101111000","010001010001011101","010010101000010111","010011010100110010","010100100110100110","010101011010000011","010110100011001001","010111011111101100","011000111011000100","011001000111100001","011010111110101011","011011000010001110","011100110000011010","011101001100111111","011110110101110101","011111001001010000","100000100111010101","100001011011110000","100010100010111010","100011011110011111","100100101100001011","100101010000101110","100110101001100100","100111010101000001","101000110001101001"];let d=a[e]+a[e],u=[t-11,t-10,t-9];[[5,u[2]],[5,u[1]],[5,u[0]],[4,u[2]],[4,u[1]],[4,u[0]],[3,u[2]],[3,u[1]],[3,u[0]],[2,u[2]],[2,u[1]],[2,u[0]],[1,u[2]],[1,u[1]],[1,u[0]],[0,u[2]],[0,u[1]],[0,u[0]],[u[2],5],[u[1],5],[u[0],5],[u[2],4],[u[1],4],[u[0],4],[u[2],3],[u[1],3],[u[0],3],[u[2],2],[u[1],2],[u[0],2],[u[2],1],[u[1],1],[u[0],1],[u[2],0],[u[1],0],[u[0],0]].forEach(((o,e)=>{var t=r[o[0]][o[1]];t.type.push("typeNumber"),t.color="1"==d[e]?n:i;}));}(this),this.isMaked=!0,this.drawModules=[];},b.prototype.getDrawModules=function(){if(this.drawModules&&this.drawModules.length>0)return this.drawModules;let o=this.drawModules=[],{modules:e,moduleCount:r,dynamicSize:t,areaColor:i,backgroundImageSrc:n,backgroundImageX:a,backgroundImageY:d,backgroundImageWidth:u,backgroundImageHeight:s,backgroundImageAlpha:g,backgroundImageBorderRadius:l,foregroundImageSrc:h,foregroundImageX:c,foregroundImageY:m,foregroundImageWidth:f,foregroundImageHeight:v,foregroundImagePadding:p,foregroundImageBackgroundColor:C,foregroundImageBorderRadius:b,foregroundImageShadowOffsetX:k,foregroundImageShadowOffsetY:y,foregroundImageShadowBlur:w,foregroundImageShadowColor:I}=this;i&&o.push({name:"area",type:"area",color:i,x:0,y:0,width:t,height:t}),n&&o.push({name:"backgroundImage",type:"image",imageSrc:n,mappingName:"backgroundImageSrc",x:a,y:d,width:u,height:s,alpha:g,borderRadius:l});for(var B=0;B<r;B++)for(var S=0;S<r;S++){var P=e[B][S];P.isDrawn||(P.type.includes("foreground")?o.push({name:"foreground",type:"tile",color:P.color,destX:P.destX,destY:P.destY,destWidth:P.destWidth,destHeight:P.destHeight,x:P.x,y:P.y,width:P.width,height:P.height,paddingTop:P.paddingTop,paddingRight:P.paddingRight,paddingBottom:P.paddingBottom,paddingLeft:P.paddingLeft,rowIndex:B,colIndex:S}):o.push({name:"background",type:"tile",color:P.color,destX:P.destX,destY:P.destY,destWidth:P.destWidth,destHeight:P.destHeight,x:P.x,y:P.y,width:P.width,height:P.height,paddingTop:P.paddingTop,paddingRight:P.paddingRight,paddingBottom:P.paddingBottom,paddingLeft:P.paddingLeft,rowIndex:B,colIndex:S}),P.isDrawn=!0);}return h&&o.push({name:"foregroundImage",type:"image",imageSrc:h,mappingName:"foregroundImageSrc",x:c,y:m,width:f,height:v,padding:p,backgroundColor:C,borderRadius:b,shadowOffsetX:k,shadowOffsetY:y,shadowBlur:w,shadowColor:I}),o},b.prototype.isBlack=function(o,e){var r=this.moduleCount;return !(0>o||0>e||o>=r||e>=r)&&this.modules[o][e].isBlack},b.prototype.drawCanvas=function(){let{isMaked:o,canvasContext:e,useDynamicSize:r,dynamicSize:t,foregroundColor:i,foregroundPadding:n,backgroundColor:a,backgroundPadding:d,drawReserve:u,margin:s}=this;if(!o)return console.error("[uQRCode]: please execute the make method first!"),Promise.reject(new b.Error("please execute the make method first!"));let g=this.getDrawModules(),l=async(o,r)=>{try{e.clearRect(0,0,t,t),e.draw(!1);for(var i=0;i<g.length;i++){var n=g[i];switch(e.save(),n.type){case"area":e.setFillStyle(n.color),e.fillRect(n.x,n.y,n.width,n.height);break;case"tile":var a=n.x,d=n.y,s=n.width,l=n.height;e.setFillStyle(n.color),e.fillRect(a,d,s,l);break;case"image":if("backgroundImage"===n.name){a=Math.round(n.x),d=Math.round(n.y),s=Math.round(n.width),l=Math.round(n.height);s<2*(c=Math.round(n.borderRadius))&&(c=s/2),l<2*c&&(c=l/2),e.setGlobalAlpha(n.alpha),c>0&&(e.beginPath(),e.moveTo(a+c,d),e.arcTo(a+s,d,a+s,d+l,c),e.arcTo(a+s,d+l,a,d+l,c),e.arcTo(a,d+l,a,d,c),e.arcTo(a,d,a+s,d,c),e.closePath(),e.setStrokeStyle("rgba(0,0,0,0)"),e.stroke(),e.clip());try{var h=await this.loadImage(n.imageSrc);e.drawImage(h,a,d,s,l);}catch(o){throw console.error(`[uQRCode]: ${n.mappingName} invalid!`),new b.Error(`${n.mappingName} invalid!`)}}else if("foregroundImage"===n.name){a=Math.round(n.x),d=Math.round(n.y),s=Math.round(n.width),l=Math.round(n.height);var c,m=Math.round(n.padding);s<2*(c=Math.round(n.borderRadius))&&(c=s/2),l<2*c&&(c=l/2);var f=a-m,v=d-m,p=s+2*m,C=l+2*m,k=Math.round(p/s*c);p<2*k&&(k=p/2),C<2*k&&(k=C/2),e.save(),e.setShadow(n.shadowOffsetX,n.shadowOffsetY,n.shadowBlur,n.shadowColor),k>0?(e.beginPath(),e.moveTo(f+k,v),e.arcTo(f+p,v,f+p,v+C,k),e.arcTo(f+p,v+C,f,v+C,k),e.arcTo(f,v+C,f,v,k),e.arcTo(f,v,f+p,v,k),e.closePath(),e.setFillStyle(n.backgroundColor),e.fill()):(e.setFillStyle(n.backgroundColor),e.fillRect(f,v,p,C)),e.restore(),e.save(),k>0?(e.beginPath(),e.moveTo(f+k,v),e.arcTo(f+p,v,f+p,v+C,k),e.arcTo(f+p,v+C,f,v+C,k),e.arcTo(f,v+C,f,v,k),e.arcTo(f,v,f+p,v,k),e.closePath(),e.setFillStyle(m>0?n.backgroundColor:"rgba(0,0,0,0)"),e.fill()):(e.setFillStyle(m>0?n.backgroundColor:"rgba(0,0,0,0)"),e.fillRect(f,v,p,C)),e.restore(),c>0&&(e.beginPath(),e.moveTo(a+c,d),e.arcTo(a+s,d,a+s,d+l,c),e.arcTo(a+s,d+l,a,d+l,c),e.arcTo(a,d+l,a,d,c),e.arcTo(a,d,a+s,d,c),e.closePath(),e.setStrokeStyle("rgba(0,0,0,0)"),e.stroke(),e.clip());try{h=await this.loadImage(n.imageSrc);e.drawImage(h,a,d,s,l);}catch(o){throw console.error(`[uQRCode]: ${n.mappingName} invalid!`),new b.Error(`${n.mappingName} invalid!`)}}}u&&e.draw(!0),e.restore();}e.draw(!0),setTimeout(o,150);}catch(o){if(!(o instanceof b.Error))throw o;r(o);}};return new Promise(((o,e)=>{l(o,e);}))},b.prototype.draw=function(){return this.drawCanvas()},b.prototype.register=function(o){o&&o(b,this,!0);};export{b as default};L Nxfunction Queue() {
  let waitingQueue = this.waitingQueue = [];
  let isRunning = this.isRunning = false; // 记录是否有未完成的任务

  function execute(task, resolve, reject) {
    task()
      .then((data) => {
        resolve(data);
      })
      .catch((e) => {
        reject(e);
      })
      .finally(() => {
        // 等待任务队列中如果有任务，则触发它；否则设置isRunning = false,表示无任务状态
        if (waitingQueue.length) {
          const next = waitingQueue.shift();
          execute(next.task, next.resolve, next.reject);
        } else {
          isRunning = false;
        }
      });
  }
  this.exec = function(task) {
    return new Promise((resolve, reject) => {
      if (isRunning) {
        waitingQueue.push({
          task,
          resolve,
          reject
        });
      } else {
        isRunning = true;
        execute(task, resolve, reject);
      }
    });
  }
}

/* 队列实例，某些平台一起使用多个组件时需要通过队列逐一绘制，否则部分绘制方法异常，nvue端的iOS gcanvas尤其明显，在不通过队列绘制时会出现图片丢失的情况 */
export const queueDraw = new Queue();
export const queueLoadImage = new Queue();!xg<template>
	<view class="uqrcode"
		:class="{ 'uqrcode-hide': hide }"
		:style="{ width: `${templateOptions.width}px`, height: `${templateOptions.height}px` }">
		<view class="uqrcode-canvas-wrapper">
			<!-- 画布 -->
			<!-- #ifndef APP-NVUE -->
			<canvas class="uqrcode-canvas"
				:id="canvasId"
				:canvas-id="canvasId"
				:type="canvasType"
				:style="{
          width: `${templateOptions.canvasWidth}px`,
          height: `${templateOptions.canvasHeight}px`,
          transform: templateOptions.canvasTransform
        }"
				v-if="templateOptions.canvasDisplay"
				@click="onClick"></canvas>
			<!-- #endif -->

			<!-- nvue用gcanvas -->
			<!-- #ifdef APP-NVUE -->
			<gcanvas class="uqrcode-canvas"
				ref="gcanvas"
				:style="{
          width: `${templateOptions.canvasWidth}px`,
          height: `${templateOptions.canvasHeight}px`
        }"
				v-if="templateOptions.canvasDisplay"
				@click="onClick"></gcanvas>
			<!-- #endif -->
		</view>

		<!-- 加载效果 -->
		<view class="uqrcode-makeing"
			v-if="loading === undefined || !loading ? makeing : loading">
			<slot name="loading">
				<image class="uqrcode-makeing-image"
					:style="{ width: `${templateOptions.size / 4}px`, height: `${templateOptions.size / 4}px` }"
					src="data:image/gif;base64,R0lGODlhAAEAAfIEAOHh4SSsWuDg4N3d3f///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDYuMC1jMDAyIDc5LjE2NDQ4OCwgMjAyMC8wNy8xMC0yMjowNjo1MyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIyLjAgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODhGMzM4RDEwMTExRUM4MDhCRkVBQkE2QUZDQzkwIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjAyODhGMzM5RDEwMTExRUM4MDhCRkVBQkE2QUZDQzkwIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4OEYzMzZEMTAxMTFFQzgwOEJGRUFCQTZBRkNDOTAiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDI4OEYzMzdEMTAxMTFFQzgwOEJGRUFCQTZBRkNDOTAiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX08/Lx8O/u7ezr6uno5+bl5OPi4eDf3t3c29rZ2NfW1dTT0tHQz87NzMvKycjHxsXEw8LBwL++vby7urm4t7a1tLOysbCvrq2sq6qpqKempaSjoqGgn56dnJuamZiXlpWUk5KRkI+OjYyLiomIh4aFhIOCgYB/fn18e3p5eHd2dXRzcnFwb25tbGtqaWhnZmVkY2JhYF9eXVxbWllYV1ZVVFNSUVBPTk1MS0pJSEdGRURDQkFAPz49PDs6OTg3NjU0MzIxMC8uLSwrKikoJyYlJCMiISAfHh0cGxoZGBcWFRQTEhEQDw4NDAsKCQgHBgUEAwIBAAAh+QQFFAAEACwAAAAAAAEAAQAD/0i63P4wykmrvTjrzbv/YCiOZGmeaKqubOu+cCzPdG3feK7vfO//wKBwSCwaj8ikcslsOp/QqHRKrVqv2Kx2y+16v+CweEwum8/otHrNbrvf8Lh8Tq/b7/i8fs/v+/+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanigCqq6ytrieusbISAbW2t7i5uru8vb66bLLCrLDDw7S/ycrLzLXBxsLF0LHIzdbXzc/Trybb1BHY4eK92t6r0uaq1ePs4+Xp6PDg7fTh7+bx+PP1/Mz33vkA7utH0Ne/bQERDizIMNfBaQkhLmxIMcBDaBExTqzI8P+isYwfN3Ik6PFYt3TnRI7kVzLaSZQA1q0s2HLWS5QyZ/ar+a0ETHUqdbLjyc3nz5xC6RFtBdIkhKQ01/yMeVPeU6g7pR6tqu8q1npLiXEV6PVru7ApjcJEquyEPa1rxyosm83EWzVTm7qk688uNrRA1eIMatDvNcBUBVt9cJdEYzR55Urku8ztX7iDFXdlfLnE4zORNZPlfNiwNcR6bVJua7ou3q2i55I+3brv67ixJ8927bhzmtAkgDv4HIJ4GeEikDMw/oH5GOUgoCtw3oF6GOkesFvfsP0L9g7afY/o7uU7h/ClPYsHDTt4++Hri8c//j55/eXzm+d/fj96/+n/+1UX4HX/ZVcgeRggyIV5G6BHmycMauAgb5xEmMGEtnViIQYYVvbJhhd0yBqEBYJ34ICUgGiBiMmAomIFLP7iYonnnZiehjQ2aOODOE7l449MERbVai1iBuSRO67EVpG3IenkYvDptKSMRj5pZUhENjRlYU1e6aVqu420JTlVfmlmYGFyNCYviJ2ZWZoVrblLm25uFuVMcgJTZp1X5gmWkGzuyeeTfioF6JyCDopkoWcdqmeXilrJ6FCOOpRopD9O6k6luNCJ6V5wUqSpRZd+mqSYnN7iqalFhaplqrasyqpYWXYEqzOlzmpnA0mNKquuiblqa61kQgrsqWreSqqx/8e+eaeSyqIi7bTUVmvttdhmq+223Hbr7bejCCDuuOSWa+656Kar7rrnSjDAu/DGK++89NZr77340vsru/z2224E+QYs8MAEw7uvvwj3627BDDfM8MEJR5zuwg5XbHG9EEusMbkUX+zxxRlvvHHHH5f8cK4ip+wvySa3HHDIKifMsss0Y4xyzDijO3PNPBt8c85Aj7tzzzzDHPS6QxNNs9FHTwyw0lAPwHTT/0IQNdRTU11u0ld/nLXWQj/dddE/g50y12Nb/LXZaKft8Npgt+32ycyafbTccxMMt9Z45y3w3lT37Xe+qEnGruDxzihxalU/ULHiETNuLuI+k7i44f9Ii013j5Fjri7l70Ius+dOW/32hxpLvrXmBYuOsOocs6436pfndrjsA7u+Muk64/437Z3bnrnpDeuuMO+NO/A48KML/7nvLzP/OvKTQ0+49Ls7X7rjp1sevHu1c1889sdr3zvxm1eYOvWro986+fzCHrb7s3vfPPjfK9895/ePMLL1+DKe3c6Hv/fZb4DPM5++4IfA9hWwfvxrIAH9tz/1STCBD8wdAy8oNfYlboMXlF/oQChBEXbwgByMnQLnJcAUmrCFHDTh4FhYNrZ5cIY2q5sLb4hDGuowhjzs4Qd/GMIgCnGERCyhEY8IOAxS8IgVZE8Kk2cfKI4viQ2UIRPAaxi3JQqxiXcDoBXtVbgVOlB/YzTgb9ZnRhWKL40axCIVQ/A/+sExgFwU1wvFeMchrjF8T8xfA/oYxz8Kko5sfCMh71XGDJZPkYvMoSH7V8VDLiCS15Nj9do4P0hiUl6NDCQlGfBJRoLrlKhMpSpXycpWuvKVsIylLGdJy1ra8pa4zKUud8nLXvryl8AMpjCHScxiGvOYyEymMpfJzGY685nQjKY0p0nNalrzmtjMpja3yc1uevOb4AynOMdJhwQAACH5BAUUAAQALDIAMgCcAJwAAAP/KLrcTjDKSWt0OFsIuv9gKI5kaZ6Ztq1s6iorKs90/apsTt1pbP/AIA+mK16Gj41wyWwan8ikpUmtRp/GaMNn7Xq3WJ2Wwf2arWHxmDg9u6np3JpdeduX8da8fO8j83xXSn6EQ4CDa4GFi2CHO3uIjJJkjo+JkZOTlZZjipmFmxNzAp6ffqESo6Wmd6hHl22sjK4ckLGyoLSqmLh9tAS7t72+urZ1QL+LycacNcuEz528M9HErsHHP9WtxbDZNtt24YbTMuNu5zerJulm7S7rJe9e8zjfzt2n+VrxJPVo+wQJo/GvSsFG9wgGFLeQ3EBqDdFFVFcOxUEnE1/0G3GR/0lHOs0UXss10ltIiCX1peRX8cRHIS83iniJLVRNUcgyfonZkp1Oej/tnTT3K87NSkdfgSuaJukhp8ByMsUCNQ/UIFPDVDXKDKe2rFC6IhWrFB/YIlubkq319awak5uuSnWrB+5Yu2VF0pUpBZXctnt7jhqMl63KhMMIU3z4hm9ixY4xMn6sGENkj4IpVyaVuctlzdImn/kMWiDixp1L/z08VPVm0lhTuw59WqLo2YNhz22NO7dsOL9789ANmLfwwlGhBT8Obzke58wtQ499O/qf6bu9WvddHWj37RqxF9cOHrky8ZvTs/wOkH2IwPDjy59Pv779+/jz69/Pv7////8ABijggAQWaOCBCCao4FQDNOjggxBGKOGEFFZooYQrBKDhhhx26OGHIIYo4ogfXmjiiSim6GCGJLbo4oswaqjijDTSyGKMOOYYY4089ljhjToGKWSJPhZpJJBDJimkkUz2iKSSUO7Y5JQqPhnllSRSqeWJVmLpJZFbhjlhl1+WKaOYaEJIpplfpulmg2uyieWbbsYpZ5R0pmnnnUrmieaefA7pp5iABhrkoGEWamiOiG6p6KJSNjrlo5C+KCmVlFba4qWTbqCpl5w2memnIvLIkwVB6mdqUBh6qqOqNZ5aQar5rbpSiqMGAKuNrEaY664zykoBrfjZ6lesruYIbJX/vaqZLI7L4trsg7/WiuytKFZb7LXH8orqq9Z6222wz8YYbbbTrlgujOdymS6c677YronCTkDsfcbaxO2w4G4rrr7/2tsvvvvGVbAE99qXr8EBIzywwgc7srDDyoZLLrbufluxv6EOUFTC9XWsLi0g0ycyvCQ/HPLJH6tsMsu/lDzfyR7H7PLMMKe8McEit7wzxD3b/PPKQesMrcWh+kxqnzm7sjSeTaPyNJQ0Kz31oVGHcnWSVQu9tY5dG/01jmE7PTbYWW9yNtpFm712pDQ3HMHbZEf8lN0E0A03sxjTG6/eIU4sMd6AW4q3VYQXvunhXMkNgeKLOw6I4I9DPiLlGZMnbnngjKsl+ealdq6V5qB7iDnin5f+YQIAIfkEBRQABAAsMgAyAJwAnAAAA/84utxOMMpJa3Q4Wyi6/2AojmRpnpm2rWzqKisqz3T9qmxO3Wls/8AgD6YrXoaPjXDJbBqfyKSlSa1Gn8Zow2fterdYnZbB/ZqtYfGYOD27qencml1525fx1rx87yPzfFdKfoRDgINrgYWLYIc7e4iMkmSOj4mRk5OVlmOKmYWbE3MDnp9+oRKjpaZ3qEeXbayMrhyQsbKgtKqYuH20BLu3vb66tnVAv4vJxpw1y4TPnbwz0cSuwcc/1a3FsNk223bhhtMy427nN6sm6WbtLusl717zON/O3af5WvEk9Wj7BAmj8a9KwUb3CAYUt5DcQGoN0UVUVw7FQScTX/QbcZH/SUc6zRReyzXSW0iIJfWl5FfxxEchLzeKeIktVE1RyDJ+idmSnU56P+2dNPcrzs1KR1+BK5om6SGnwHIyxQI1D9QgU8NUNcoMp7asULoiFasUH9giW5uSrfX1rBqTm65KdasH7li7ZUXSlSkFldy2e3uOGoyXrcqEwwhTfPiGb2LFjjEyfqwYQ2SPgilXJpW5y2XN0iaf+QxaIOLGnUv/PTxU9WbSWFO7Dn1aoujZg2HPbY07t2w4v3vz0A2Yt/DCUaEFPw5vOR7nzC1Dj307+p/pu71a910daPftGrEX1w4euTLxm9Oz/A6QfYjA8OPLn0+/vv37+PPr38+/v////wAGKOCABBZo4IEIJqjgVAE06OCDEEYo4YQUVmihhMQBoOGGHHbo4YcghsjhhSSWaOKJDmYo4oostqghijDGGKOKLtZo44sy5qgjhTTe6OOKOwYpZAA9/mikh0MmKWORRzYJgJJQnsikk0ZGaeWFU1Lp45VcTpilljZ2KeaDX4Lp4pholmkmi2iOqeaaIrYp5ptwgihnl3TWieSdV+ap54h8WunnnzgGCuWghBoaJaJ/KnooeoTW6KiSjOo5aZKV1pnjL5tCp1+nroBaG4ufLkmLqMaJWOqMp5rqXoerwsipq6OuGCuKs7L6Koe3StmqrrWqmh+qmxCbipG9mpirrP+eDktrKMbmVWOyJS6La7P4RXuItsn5SC2J1vq664bfYvkrs+NqWK6F4SqL7X3c5sHtketW2G6179oXbxzzIusssNA+S56N9fJ47rXpAlCwlweLG2yIC7fJU7aXkhnUhxGnebGHGbu5Maz/Vkzkx7yGXPHE8IrcIMr6qjzySgSbfCnL9bn8sl/+UqwyTZHeaDPPPUvqMtBBt/gzyUVvOTTSSYe5NMxNr3k01FGDOTXOVWv6NNZZS721TV3DaXO/YZu5bxpkl63l2WGkrbaTbGPh9ttHxv3E3HT/aLcReOfts8CV9O230AAXC7i0gxOOLiqCJ87m4dtC3q3jThceuOQElP+YAAAh+QQFFAAEACwyADIAnACcAAAD/xi63E4wyklrdDhbOLr/YCiOZGmKWcpsbEuoMHvOdG17sOruVJ7Kt6Aw6NPwjq/iYzNsOkvKJXIXbQCfWGx1NaVuFdesWPgFd13lQHjMpqXP6PK6TSe94ay7pc6HyvEbehV9hCGCgBOHE4WMHYqIEI8RjYySiJYElIWYeJiahJxwnp98oWejpHSmXaipbKtTra5isEiys1p/kIm6g7hjtUe3v03BPMM0uxTFvcpJX3M1zhLM0NORzYtD1xxDxl7We9vc1Vvcz+ZM49flVefIM+ftUe/Z1OvT80r14b5C8t7sQYJ3AiAZgZcQZsLnTF8RfunE/SMXsJ8zgiYMElHYSf9hE403vsWxqG0iu4oRp2EsAdKGyBYrSbSs8TKPR4bKHPqA6E6dyXwoe16LOWKmG46ibv5sGJQeN6IijM6oGUhpkHMdSe6CGgJrUq0Drd7wegppWbDdlpIFl/KiWBtrY5ll9VZaXGFz5aJdqPZu1b1Z25a86petUJV1kxUeKXhr4niLYaaZTFmKP03RjlbePDkzIc8nOIt+3Ae0idGonUrE7HNj6tc6WlMy7Qe2bcvLSNG2c7v3gt1tgKPw7Vv4GOMgiBeX3Qj5B+W9nWOR7gi6bepOsFu/zpyR9u2vsX/srhn8aPE47x00f578Z/eh2bdfPRv+afmi0fed1BQ/VzH/3/lXmX6E0eeSgAPaV0eACP6XBXaRRSjhhBRWaOGFGGao4YYcdujhhyCGKOKIJJZo4okopqjiimQB4OKLMMYo44w01mjjjTMSKMCOPPbo449ABinkkDgWaeSROOpI5JJMNonkk1BGqaSTVFYZ5ZVY3jillVx2meWXSG7p5Zhkgmmmi2KWqeaZbBqZ5ppwtilnjG/GaeecbNZ55554Yqknn4D2eeSfgRYqaI2EGqrooS8muiijkDr6KKSCSjoppXNaeimmeSq46aec2qgpqKH66SmpqJYKwKipqjroqa3yKVWSsP64oaknSVmrj7deOauWu/bYq665QgmhhrgCRexl/1UOayxFy+bGpbNP/ipqsDxSGya0zxropLavFlsttjuC6ya343rbpLlFWosouQKwS6u426rLpLzA0hsus1Tie62+59q7pL/vAtwuvATT6K7CCCPrK7r18vutw9Hm9LDARCacI8T7SmulxjIuvDHGQ4JMJ8cBS7wuxa6GjPK9LLcMo8i2xiwzmi8PbPPNNPO6s8w9C/tzy0FnO7SrRZd7tKpJx7t0qU2bzGjUT4fadKxYn2xw1lwfvHXXYDP8ddhkN5pz2WhfjTbQZ68dttpuM9123De7PDbddZvJatZUk4x3xbsk6/Hfa/atMuGCWww4f4gXPrfYhzferbKTDy554hmBXxz55R0rXvlgnGvO1OJphS665+luTncCADs=">
				</image>
			</slot>
		</view>

		<!-- 错误处理 -->
		<view class="uqrcode-error"
			v-if="isError"
			@click="onClick">
			<slot name="error"
				:error="error">
				<text class="uqrcode-error-message">{{ error.errMsg }}</text>
			</slot>
		</view>

		<!-- H5保存提示 -->
		<!-- #ifdef H5 -->
		<view class="uqrcode-h5-save"
			v-if="isH5Save">
			<slot name="h5save"
				:tempFilePath="tempFilePath">
				<image class="uqrcode-h5-save-image"
					:src="tempFilePath"></image>
				<text class="uqrcode-h5-save-text">{{ h5SaveIsDownload ? '若保存失败，' : '' }}请长按二维码进行保存</text>
			</slot>
			<view class="uqrcode-h5-save-close"
				@click.stop="isH5Save = false">
				<view class="uqrcode-h5-save-close-before"></view>
				<view class="uqrcode-h5-save-close-after"></view>
			</view>
		</view>
		<!-- #endif -->
	</view>
</template>

<script>
	import props from './props.js';
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef VUE3
	import { toRaw } from 'vue';
	// #endif
	/* 引入uvQRCode核心js */
	import UQRCode from './qrcode';
	/* 引入nvue所需模块 */
	// #ifdef APP-NVUE
	import { enable, WeexBridge } from './gcanvas';
	const modal = weex.requireModule('modal');
	// #endif
	/* 引入队列 */
	import { queueDraw, queueLoadImage } from './queue';
	/* 引入缓存图片 */
	import { cacheImageList } from './cache';
	let instance = null;
	/**
	 * qrcode 二维码
	 * @description 二维码生成插件，可扩展性高，它支持自定义渲染二维码，可通过uQRCode API得到二维码绘制关键信息后，使用canvas、svg或js操作dom的方式绘制二维码图案。还可自定义二维码样式，如随机颜色、圆点、方块、块与块之间的间距等。
	 * @tutorial https://www.uvui.cn/components/qrcode.html
	 * @property {String}	 value	 二维码内容 (start为true时必填 )
	 * @property {Object}	 options  二维码配置选项 (data|size|margin...)
	 * @property {String}	 fileType  导出的文件类型  (jpg | png)  
	 * @property {String}	 start  是否初始化组件后就开始生成 (默认 true)
	 * @property {String}	 auto  是否数据发生改变自动重绘 (默认 false)
	 * @property {String}	 hide  隐藏组件。如果只需要导出二维码作为图片使用，可设置为true，不能在组件或组件父级元素设置v-if="false"、v-show="false"、style="display:none;"等实现隐藏效果，这样会导致导出二维码空白  (默认 false)
	 * @property {String}	 type  canvas组件类型。微信小程序默认2d (默认 undefined)
	 * @property {String}	 queue  队列绘制 (默认 false)
	 * @property {String}	 isQueueLoadImage  是否队列加载图片，选择true将通过队列缓存所需要加载的图片。优点是加载重复资源可减少资源请求次数，节省网络资源，缺点是会转化为同步请求，资源不重复且多的情况下，等待时间会更久。总之，请求重复资源较多则选择true，请求不重复资源较多则选择false (默认 false)
	 * @property {String}	 loading  loading态 (默认 false)
	 * @property {String}	 h5SaveIsDownload  H5保存即自动下载（在支持的环境下），默认false为仅弹层提示用户需要长按图片保存，不会自动下载 (默认 false)
	 * @property {String}	 h5DownloadName  H5下载名称 
	 * @property {String}	 h5SaveTip  H5保存二维码时候是否显示提示
	 * @example <uv-qrcode ref="uvqrcode" size="400rpx" canvas-id="qrcode" value="https://www.uvui.cn"></uv-qrcode>
	 */
	export default {
		name: 'uv-qrcode',
		mixins: [mpMixin,mixin,props],
		emits: ['click','change','complete'],
		data() {
			return {
				canvasId: "",
				canvas: undefined,
				canvasType: undefined,
				canvasContext: undefined,
				makeDelegate: undefined,
				drawDelegate: undefined,
				toTempFilePathDelegate: undefined,
				makeExecuted: false,
				makeing: false,
				drawing: false,
				isError: false,
				error: undefined,
				isH5Save: false,
				tempFilePath: '',
				templateOptions: {
					size: 0,
					width: 0, // 组件宽度
					height: 0,
					canvasWidth: 0, // canvas宽度
					canvasHeight: 0,
					canvasTransform: '',
					canvasDisplay: false
				},
				uqrcodeOptions: {
					data: ''
				},
				plugins: [],
				makeingPattern: [
					[
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true]
					],
					[
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, false, false, false],
						[true, true, true, true, true, true, false, true, true, true],
						[true, true, true, true, true, true, false, true, true, true],
						[true, true, true, true, true, true, false, true, true, true]
					],
					[
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, true, true, true, true, false, false, false],
						[true, true, true, true, true, true, true, false, false, false],
						[true, true, true, true, true, true, true, false, false, false],
						[true, true, true, false, false, false, false, true, true, true],
						[true, true, true, false, false, false, false, true, true, true]
					],
					[
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, false, false, false, false, false, false, false],
						[true, true, true, false, false, false, false, false, false, false],
						[true, true, true, false, false, false, false, false, false, false],
						[true, true, true, false, false, false, false, false, false, false],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true],
						[true, true, true, true, true, true, true, true, true, true]
					]
				]
			};
		},
		watch: {
			type: {
				handler(val) {
					const types = ['2d'];
					if (types.includes(val)) {
						this.canvasType = val;
					} else {
						this.canvasType = undefined;
					}
				},
				immediate: true
			},
			value: {
				handler() {
					if (this.auto) {
						this.remake();
					}
				}
			},
			size: {
				handler() {
					if (this.auto) {
						this.remake();
					}
				}
			},
			options: {
				handler() {
					if (this.auto) {
						this.remake();
					}
				},
				deep: true
			},
			makeing: {
				handler(val) {
					if (!val) {
						if (typeof this.toTempFilePathDelegate === 'function') {
							this.toTempFilePathDelegate();
						}
					}
				}
			}
		},
		created() {
			this.canvasId = this.$uv.guid();
		},
		mounted() {
			this.templateOptions.size = this.$uv.getPx(this.size);
			this.templateOptions.width = this.templateOptions.size;
			this.templateOptions.height = this.templateOptions.size;
			this.templateOptions.canvasWidth = this.templateOptions.size;
			this.templateOptions.canvasHeight = this.templateOptions.size;
			if (this.canvasType == '2d') {
				// #ifndef MP-WEIXIN
				this.templateOptions.canvasTransform = `scale(${this.templateOptions.size / this.templateOptions.canvasWidth}, ${this.templateOptions.size /
        this.templateOptions.canvasHeight})`;
				// #endif
			} else {
				this.templateOptions.canvasTransform = `scale(${this.templateOptions.size / this.templateOptions.canvasWidth}, ${this.templateOptions.size /
        this.templateOptions.canvasHeight})`;
			}
			if (this.start) {
				this.$nextTick(()=>{
					this.make();
				})
			}
		},
		methods: {
			/**
			 * 获取模板选项
			 */
			getTemplateOptions() {
				var size = this.$uv.getPx(this.size);
				return deepReplace(this.templateOptions, {
					size,
					width: size,
					height: size
				});
			},
			/**
			 * 获取插件选项
			 */
			getUqrcodeOptions() {
				return deepReplace(this.options, {
					data: String(this.value),
					size: Number(this.templateOptions.size)
				});
			},
			/**
			 * 重置画布
			 */
			resetCanvas(callback) {
				this.templateOptions.canvasDisplay = false;
				this.$nextTick(() => {
					this.templateOptions.canvasDisplay = true;
					this.$nextTick(() => {
						callback && callback();
					});
				});
			},
			/**
			 * 绘制二维码
			 */
			async draw(callback = {}, isDrawDelegate = false) {
				if (typeof callback.success != 'function') {
					callback.success = () => {};
				}
				if (typeof callback.fail != 'function') {
					callback.fail = () => {};
				}
				if (typeof callback.complete != 'function') {
					callback.complete = () => {};
				}

				if (this.drawing) {
					if (!isDrawDelegate) {
						this.drawDelegate = () => {
							this.draw(callback, true);
						};
						return;
					}
				} else {
					this.drawing = true;
				}

				if (!this.canvasId) {
					console.error('[uQRCode]: canvasId must be set!');
					this.isError = true;
					this.drawing = false;
					callback.fail({
						errMsg: '[uQRCode]: canvasId must be set!'
					});
					callback.complete({
						errMsg: '[uQRCode]: canvasId must be set!'
					});
					return;
				}
				if (!this.value) {
					console.error('[uQRCode]: value must be set!');
					this.isError = true;
					this.drawing = false;
					callback.fail({
						errMsg: '[uQRCode]: value must be set!'
					});
					callback.complete({
						errMsg: '[uQRCode]: value must be set!'
					});
					return;
				}

				/* 组件数据 */
				this.templateOptions = this.getTemplateOptions();
				/* uQRCode选项 */
				this.uqrcodeOptions = this.getUqrcodeOptions();
				/* 纠错等级兼容字母写法 */
				if (typeof this.uqrcodeOptions.errorCorrectLevel === 'string') {
					this.uqrcodeOptions.errorCorrectLevel = UQRCode.errorCorrectLevel[this.uqrcodeOptions.errorCorrectLevel];
				}
				/* nvue不支持动态修改gcanvas尺寸，除nvue外，默认使用useDynamicSize */
				// #ifndef APP-NVUE
				if (typeof this.options.useDynamicSize === 'undefined') {
					this.uqrcodeOptions.useDynamicSize = true;
				}
				// #endif
				// #ifdef APP-NVUE
				if (typeof this.options.useDynamicSize === 'undefined') {
					this.uqrcodeOptions.useDynamicSize = false;
				}
				// if (typeof this.options.drawReserve === 'undefined') {
				//   this.uqrcodeOptions.drawReserve = true;
				// }
				// #endif

				/* 获取uQRCode实例 */
				const qr = instance = new UQRCode();
				/* 注册扩展 */
				this.plugins.forEach(p => qr.register(p.plugin));
				/* 设置uQRCode选项 */
				qr.setOptions(this.uqrcodeOptions);
				/* 调用制作二维码方法 */
				qr.make();

				/* 获取canvas上下文 */
				let canvasContext = null;
				// #ifndef APP-NVUE
				if (this.canvasType === '2d') {
					// #ifdef MP-WEIXIN
					/* 微信小程序获取canvas2d上下文方式 */
					const canvas = (this.canvas = await new Promise(resolve => {
						uni
							.createSelectorQuery()
							.in(this) // 在组件内使用需要
							.select(`#${this.canvasId}`)
							.fields({
								node: true,
								size: true
							})
							.exec(res => {
								resolve(res[0].node);
							});
					}));
					canvasContext = this.canvasContext = canvas.getContext('2d');
					/* 2d的组件设置宽高与实际canvas绘制宽高不是一个，打个比方，组件size=200，canvas.width设置为100，那么绘制出来就是100=200，组件size=400，canvas.width设置为800，绘制大小还是800=400，所以无需理会下方返回的dynamicSize是多少，按dpr重新赋值给canvas即可 */
					this.templateOptions.canvasWidth = qr.size;
					this.templateOptions.canvasHeight = qr.size;
					this.templateOptions.canvasTransform = '';
					/* 使用dynamicSize+scale，可以解决小块间出现白线问题，dpr可以解决模糊问题 */
					const dpr = uni.getSystemInfoSync().pixelRatio;
					canvas.width = qr.dynamicSize * dpr;
					canvas.height = qr.dynamicSize * dpr;
					canvasContext.scale(dpr, dpr);
					/* 微信小程序获取图像方式 */
					qr.loadImage = this.getLoadImage(function(src) {
						/* 小程序下获取网络图片信息需先配置download域名白名单才能生效 */
						return new Promise((resolve, reject) => {
							const img = canvas.createImage();
							img.src = src;
							img.onload = () => {
								resolve(img);
							};
							img.onerror = err => {
								reject(err);
							};
						});
					});
					// #endif
					// #ifndef MP-WEIXIN
					/* 非微信小程序不支持2d，切换回uniapp获取canvas上下文方式 */
					canvasContext = this.canvasContext = uni.createCanvasContext(this.canvasId, this);
					/* 使用dynamicSize，可以解决小块间出现白线问题，再通过scale缩放至size，使其达到所设尺寸 */
					this.templateOptions.canvasWidth = qr.dynamicSize;
					this.templateOptions.canvasHeight = qr.dynamicSize;
					this.templateOptions.canvasTransform = `scale(${this.templateOptions.size / this.templateOptions.canvasWidth}, ${this.templateOptions.size /
          this.templateOptions.canvasHeight})`;
					/* uniapp获取图像方式 */
					qr.loadImage = this.getLoadImage(function(src) {
						return new Promise((resolve, reject) => {
							if (src.startsWith('http')) {
								uni.getImageInfo({
									src,
									success: res => {
										resolve(res.path);
									},
									fail: err => {
										reject(err);
									}
								});
							} else {
								if (src.startsWith('.')) {
									console.error('[uQRCode]: 本地图片路径仅支持绝对路径！');
									throw new Error('[uQRCode]: local image path only supports absolute path!');
								} else {
									resolve(src);
								}
							}
						});
					});
					// #endif
				} else {
					/* uniapp获取canvas上下文方式 */
					canvasContext = this.canvasContext = uni.createCanvasContext(this.canvasId, this);
					/* 使用dynamicSize，可以解决小块间出现白线问题，再通过scale缩放至size，使其达到所设尺寸 */
					this.templateOptions.canvasWidth = qr.dynamicSize;
					this.templateOptions.canvasHeight = qr.dynamicSize;
					this.templateOptions.canvasTransform = `scale(${this.templateOptions.size / this.templateOptions.canvasWidth}, ${this.templateOptions.size /
          this.templateOptions.canvasHeight})`;
					/* uniapp获取图像方式 */
					qr.loadImage = this.getLoadImage(function(src) {
						return new Promise((resolve, reject) => {
							/* getImageInfo在微信小程序的bug：本地路径返回路径会把开头的/或../移除，导致路径错误，解决方法：限制只能使用绝对路径 */
							if (src.startsWith('http')) {
								uni.getImageInfo({
									src,
									success: res => {
										resolve(res.path);
									},
									fail: err => {
										reject(err);
									}
								});
							} else {
								if (src.startsWith('.')) {
									console.error('[uQRCode]: 本地图片路径仅支持绝对路径！');
									throw new Error('[uQRCode]: local image path only supports absolute path!');
								} else {
									resolve(src);
								}
							}
						});
					});
				}
				// #endif
				// #ifdef APP-NVUE
				/* NVue获取canvas上下文方式 */
				const gcanvas = this.$refs['gcanvas'];
				const canvas = enable(gcanvas, {
					bridge: WeexBridge
				});
				canvasContext = this.canvasContext = canvas.getContext('2d');
				/* NVue获取图像方式 */
				qr.loadImage = this.getLoadImage(function(src) {
					return new Promise((resolve, reject) => {
						/* getImageInfo在nvue的bug：获取同一个路径的图片信息，同一时间第一次获取成功，后续失败，猜测是写入本地时产生文件写入冲突，所以没有返回，特别是对于网络资源 --- 已实现队列绘制，已解决此问题 */
						if (src.startsWith('.')) {
							console.error('[uQRCode]: 本地图片路径仅支持绝对路径！');
							throw new Error('[uQRCode]: local image path only supports absolute path!');
						} else {
							uni.getImageInfo({
								src,
								success: res => {
									resolve(res.path);
								},
								fail: err => {
									reject(err);
								}
							});
						}
					});
				});
				// #endif

				/* 设置uQRCode实例的canvas上下文 */
				qr.canvasContext = canvasContext;
				/* 延时等待页面重新绘制完毕 */
				setTimeout(() => {
					/* 从插件获取具体要调用哪一个扩展函数 */
					var plugin = this.plugins.find(p => p.name == qr.style);
					var drawCanvasName = plugin ? plugin.drawCanvas : 'drawCanvas';
					/* 虽然qr[drawCanvasName]是直接返回Promise的，但由于js内部this指向问题，故不能直接exec(qr[drawCanvasName])此方式执行，需要改成exec(() => qr[drawCanvasName]())才能正确获取this */
					var drawCanvas;
					if (this.queue) {
						drawCanvas = () => queueDraw.exec(() => qr[drawCanvasName]());
						// drawCanvas = () => queueDraw.exec(() => new Promise((resolve, reject) => {
						//   setTimeout(() => {
						//     qr[drawCanvasName]().then(resolve).catch(reject);
						//   }, 1000);
						// }));
					} else {
						drawCanvas = () => qr[drawCanvasName]();
					}
					/* 调用绘制方法将二维码图案绘制到canvas上 */
					drawCanvas()
						.then(() => {
							if (this.drawDelegate) {
								/* 高频重绘纠正 */
								let delegate = this.drawDelegate;
								this.drawDelegate = undefined;
								delegate();
							} else {
								this.drawing = false;
								callback.success();
							}
						})
						.catch(err => {
							console.log(err);
							if (this.drawDelegate) {
								/* 高频重绘纠正 */
								let delegate = this.drawDelegate;
								this.drawDelegate = undefined;
								delegate();
							} else {
								this.drawing = false;
								this.isError = true;
								callback.fail(err);
							}
						})
						.finally(() => {
							callback.complete();
						});
				}, 300);
			},
			/**
			 * 生成二维码
			 */
			make(callback = {}) {
				this.makeExecuted = true;
				this.makeing = true;
				this.isError = false;

				if (typeof callback.success != 'function') {
					callback.success = () => {};
				}
				if (typeof callback.fail != 'function') {
					callback.fail = () => {};
				}
				if (typeof callback.complete != 'function') {
					callback.complete = () => {};
				}

				this.resetCanvas(() => {
					clearTimeout(this.makeDelegate);
					this.makeDelegate = setTimeout(() => {
						this.draw({
							success: () => {
								setTimeout(() => {
									callback.success();
									this.complete(true);
								}, 300);
							},
							fail: err => {
								callback.fail(err);
								this.error = err;
								this.complete(false, err.errMsg);
							},
							complete: () => {
								callback.complete();
								this.makeing = false;
							}
						});
					}, 300);
				});
			},
			/**
			 * 重新生成
			 */
			remake(callback) {
				this.$emit('change');
				this.make(callback);
			},
			/**
			 * 生成完成
			 */
			complete(success = true, errMsg = '') {
				if (success) {
					this.$emit('complete', {
						success
					});
				} else {
					this.$emit('complete', {
						success,
						errMsg
					});
				}
			},
			/**
			 * 导出临时路径
			 */
			toTempFilePath(callback = {}) {
				if (typeof callback.success != 'function') {
					callback.success = () => {};
				}
				if (typeof callback.fail != 'function') {
					callback.fail = () => {};
				}
				if (typeof callback.complete != 'function') {
					callback.complete = () => {};
				}

				if (!this.makeExecuted) {
					console.error('[uQRCode]: make() 方法从未调用！请先成功调用 make() 后再进行操作。');
					var err = {
						errMsg: '[uQRCode]: make() method has never been executed! please execute make() successfully before operating.'
					};
					callback.fail(err);
					callback.complete(err);
					return;
				}

				if (this.isError) {
					callback.fail(this.error);
					callback.complete(this.error);
					return;
				}

				if (this.makeing) {
					/* 如果还在生成状态，那当前操作将托管到委托，监听生成完成后再通过委托复调当前方法 */
					this.toTempFilePathDelegate = () => {
						this.toTempFilePath(callback);
					};
					return;
				} else {
					this.toTempFilePathDelegate = null;
				}

				// #ifndef APP-NVUE
				if (this.canvasType === '2d') {
					// #ifdef MP-WEIXIN
					try {
						let dataURL = null;
						// #ifdef VUE3
						dataURL = toRaw(this.canvas)
							.toDataURL();
						// #endif
						// #ifndef VUE3
						dataURL = this.canvas.toDataURL();
						// #endif
						callback.success({
							tempFilePath: dataURL
						});
						callback.complete({
							tempFilePath: dataURL
						});
					} catch (e) {
						callback.fail(e);
						callback.complete(e);
					}
					// #endif
				} else {
					uni.canvasToTempFilePath({
							canvasId: this.canvasId,
							fileType: this.fileType,
							width: Number(this.templateOptions.canvasWidth),
							height: Number(this.templateOptions.canvasHeight),
							destWidth: Number(this.templateOptions.size),
							destHeight: Number(this.templateOptions.size),
							success: res => {
								callback.success(res);
							},
							fail: err => {
								callback.fail(err);
							},
							complete: () => {
								callback.complete();
							}
						},
						this
					);
				}
				// #endif
				// #ifdef APP-NVUE
				const dpr = uni.getSystemInfoSync().pixelRatio;
				this.canvasContext.toTempFilePath(
					0,
					0,
					this.templateOptions.canvasWidth * dpr,
					this.templateOptions.canvasHeight * dpr,
					this.templateOptions.size * dpr,
					this.templateOptions.size * dpr,
					'',
					1,
					res => {
						callback.success(res);
						callback.complete(res);
					}
				);
				// #endif
			},
			/**
			 * 保存
			 */
			save(callback = {}) {
				if (typeof callback.success != 'function') {
					callback.success = () => {};
				}
				if (typeof callback.fail != 'function') {
					callback.fail = () => {};
				}
				if (typeof callback.complete != 'function') {
					callback.complete = () => {};
				}

				this.toTempFilePath({
					success: res => {
						// #ifndef H5
						if (this.canvasType === '2d') {
							// #ifdef MP-WEIXIN
							/* 需要将 data:image/png;base64, 这段去除 writeFile 才能正常打开文件，否则是损坏文件，无法打开 */
							const reg = new RegExp('^data:image/png;base64,', 'g');
							const dataURL = res.tempFilePath.replace(reg, '');
							const fs = wx.getFileSystemManager();
							const tempFilePath = `${wx.env.USER_DATA_PATH}/${new Date().getTime()}${
                Math.random()
                  .toString()
                  .split('.')[1]
              }.png`;
							fs.writeFile({
								filePath: tempFilePath, // 要写入的文件路径 (本地路径)
								data: dataURL, // base64图片
								encoding: 'base64',
								success: res1 => {
									uni.saveImageToPhotosAlbum({
										filePath: tempFilePath,
										success: res2 => {
											callback.success(res2);
										},
										fail: err2 => {
											callback.fail(err2);
										},
										complete: () => {
											callback.complete();
										}
									});
								},
								fail: err => {
									callback.fail(err);
								},
								complete: () => {
									callback.complete();
								}
							});
							// #endif
						} else {
							uni.saveImageToPhotosAlbum({
								filePath: res.tempFilePath,
								success: res1 => {
									callback.success(res1);
								},
								fail: err1 => {
									callback.fail(err1);
								},
								complete: () => {
									callback.complete();
								}
							});
						}
						// #endif

						// #ifdef H5
						/* 可以在电脑浏览器下载，移动端iOS不行，安卓微信浏览器不行，安卓外部浏览器可以 */
						this.isH5Save = this.h5SaveTip;
						this.tempFilePath = res.tempFilePath;
						if (this.h5SaveIsDownload) {
							const aEle = document.createElement('a');
							aEle.download = this.h5DownloadName; // 设置下载的文件名，默认是'下载'
							aEle.href = res.tempFilePath;
							document.body.appendChild(aEle);
							aEle.click();
							aEle.remove(); // 下载之后把创建的元素删除
						}
						callback.success({
							errMsg: 'ok'
						});
						callback.complete({
							errMsg: 'ok'
						});
						// #endif
					},
					fail: err => {
						callback.fail(err);
						callback.complete(err);
					}
				});
			},
			/**
			 * 注册click事件
			 */
			onClick(e) {
				this.$emit('click', e);
			},
			/**
			 * 获取实例
			 */
			getInstance() {
				return instance;
			},
			/**
			 * 注册扩展，组件仅支持注册type为style的drawCanvas扩展
			 * @param {Object} plugin
			 */
			registerStyle(plugin) {
				if (plugin.Type != 'style') {
					console.warn('[uQRCode]: registerStyle 仅支持注册 style 类型的扩展！');
					return {
						errMsg: 'registerStyle 仅支持注册 style 类型的扩展！'
					};
				}
				if (typeof plugin === 'function') {
					this.plugins.push({
						plugin,
						name: plugin.Name,
						drawCanvas: plugin.DrawCanvas
					});
				}
			},
			getLoadImage(loadImage) {
				var that = this;
				if (typeof loadImage == 'function') {
					return function(src) {
						/* 判断是否是队列加载图片的 */
						if (that.isQueueLoadImage) {
							/* 解决iOS APP||NVUE同时绘制多个二维码导致图片丢失需使用队列 */
							return queueLoadImage.exec(() => {
								return new Promise((resolve, reject) => {
									setTimeout(() => {
										const cache = cacheImageList.find(x => x.src == src);
										if (cache) {
											resolve(cache.img);
										} else {
											loadImage(src)
												.then(img => {
													cacheImageList.push({
														src,
														img
													});
													resolve(img);
												})
												.catch(err => {
													reject(err);
												});
										}
									}, 10);
								});
							});
						} else {
							return loadImage(src);
						}
					};
				} else {
					return function(src) {
						return Promise.resolve(src);
					};
				}
			}
		}
	};

	/**
	 * 对象属性深度替换
	 * @param {Object} o 原始对象/默认对象/被替换的对象
	 * @param {Object} r 从这个对象里取值替换到o对象里
	 * @return {Object} 替换后的新对象
	 */
	function deepReplace(o = {}, r = {}, c = false) {
		let obj;
		if (c) {
			// 从源替换
			obj = o;
		} else {
			// 不替换源，copy一份备份来替换
			obj = {
				...o
			};
		}
		for (let k in r) {
			var vr = r[k];
			if (vr != undefined) {
				if (vr.constructor == Object) {
					obj[k] = this.deepReplace(obj[k], vr);
				} else if (vr.constructor == String && !vr) {
					obj[k] = obj[k];
				} else {
					obj[k] = vr;
				}
			}
		}
		return obj;
	}
</script>

<style scoped>
	.uqrcode {
		position: relative;
	}
	.uqrcode-hide {
		position: fixed;
		left: 7500rpx;
	}
	.uqrcode-canvas {
		transform-origin: top left;
	}
	.uqrcode-makeing {
		position: absolute;
		top: 0;
		right: 0;
		bottom: 0;
		left: 0;
		z-index: 10;
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		justify-content: center;
		align-items: center;
	}
	.uqrcode-makeing-image {
		/* #ifndef APP-NVUE */
		display: block;
		max-width: 120px;
		max-height: 120px;
		/* #endif */
	}
	.uqrcode-error {
		position: absolute;
		top: 0;
		right: 0;
		bottom: 0;
		left: 0;
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		justify-content: center;
		align-items: center;
	}
	.uqrcode-error-message {
		font-size: 12px;
		color: #939291;
	}
	/* #ifdef H5 */
	.uqrcode-h5-save {
		position: fixed;
		top: 0;
		right: 0;
		bottom: 0;
		left: 0;
		z-index: 100;
		background-color: rgba(0, 0, 0, 0.68);
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
	}
	.uqrcode-h5-save-image {
		width: 512rpx;
		height: 512rpx;
		padding: 32rpx;
	}
	.uqrcode-h5-save-text {
		margin-top: 20rpx;
		font-size: 32rpx;
		font-weight: 700;
		color: #ffffff;
	}
	.uqrcode-h5-save-close {
		position: relative;
		margin-top: 72rpx;
		width: 60rpx;
		height: 60rpx;
		border: 2rpx solid #ffffff;
		border-radius: 60rpx;
		padding: 10rpx;
	}
	.uqrcode-h5-save-close-before {
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%) rotate(45deg);
		width: 40rpx;
		height: 4rpx;
		background: #ffffff;
	}
	.uqrcode-h5-save-close-after {
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%) rotate(-45deg);
		width: 40rpx;
		height: 4rpx;
		background: #ffffff;
	}
	/* #endif */
</style> xD<{
  "id": "uv-qrcode",
  "displayName": "uv-qrcode 二维码EH5",
  "description": "该组件是超级强大二维码生成功能，可扩展性高。自定义二维码样式，如随机颜N色、圆点、方块、块与块之间的间距等等，具体请查看文档+qrcode",
    "qrcodeO!	二维码	ҳx}## QRCode 二维码生成器qrcode**

超级强大二维码生成组件，可扩展性高。自定义二维码样式，如随机颜色、圆点、方块、块与块之间的间距等等，具体请在下方查看文档。

灵活配置，开箱即用，文档全面，支持自定二维码风格/qrcodev,mall style="font-size:14px;font-weight:700;"P#mallvԪ	x e100644 changelog.md FZ@3Fm40000 components q4Q738<|ڋ100644 package.json $`ʯ..VE^100644 readme.md &_B AKNw=QJxP## 1.0.13（2023-12-19）
1. 修复在group设置labelColor不生效的BUG
## 1.0.12（2023-11-04）
1. 修复label文字较多不分行的问题
## 1.0.11（2023-10-11）
1. 优化：https://gitee.com/climblee/uv-ui/issues/I872VD
## 1.0.10（2023-09-01）
1. 修复点击空隙处无效的问题
2. label支持插槽下可点击
## 1.0.9（2023-08-27）
1. 优化
## 1.0.8（2023-08-26）
1. 修复v-model 绑定布尔值控制台报警
## 1.0.7（2023-08-26）
1. 修复设置 labelSize 属性设置无效的问题：https://gitee.com/climblee/uv-ui/issues/I7W6UN
## 1.0.6（2023-08-04）
1. 修复name为数字0时不能选中的BUG
## 1.0.5（2023-07-13）
1.  修复  uv-radio设置value属性不生效的BUG 
## 1.0.4（2023-07-05）
修复vue3模式下，动态修改v-model绑定的值无效的BUG
## 1.0.3（2023-06-06）
1. 修正语法问题
## 1.0.2（2023-06-06）
1.  uv-radio-group 兼容自定义样式customStyle,方便通过样式调整整体位置等
2.  .uv-radio-group--row增加flex-wrap: wrap;允许换行
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-radio 单选框
t L(xL 40000 uv-radio-group ںILxW L;40000 uv-radio lVؚۚ2`ROhxR 100644 props.js Zh+KцX8H]100644 uv-radio-group.vue k0i:db̦|&T!&+x2A, Boolean],
			default: ''\<, Boolean],
			default: ''
		},
		// 是否禁用全部radio[=Pcircle'=文本
		label2'
		},
		// label的颜色 （默认 '#303133' ）DUUcheckbox(默认 false ) 铃e_	与文字的对齐方式A?radioGroup
	}
}KzQSx"!!radio)2radioRroup 单选框父组件
	 * @description 单选框用于有一个选择，用户只能选择其中一个的场景。搭uv-radio使用.
radio.htmla 	 | Boolean}	value h所有radio1/F			shape			外观形状，shape-方形，circle-圆形(默认 circle )a@,时的颜色，应用到所有子Radio组件1$(默认 '#c8c9cc' )a			name			标识符a *			size			组件整体的大小，单位pxQ*xa}						label			文本a			labelColor		label的T.0 		, /checkbox)S		2FT/			iconPlacement	图标与文字的对齐方式 （默认 'left' ）
     * @property {Object}						customStyle		组件的样，对象形式
	 * @event {Function} change 任一个radio状态发生变化时触发
	 * @example <uv-radio-group v-model="value"></uv-radio1+radiodlradio
radio	Lconst value = this.value ||

bradioradio)radio0C"// 所有子radio中，被操作组件实例的checked的值无需修改
					if (childInstance !== child) {
						child.checked = false
					}
				})
				const {
					name
				} = childInstance
				// 通过emit事件，设置父组件通过v-model双@8name~Fname~&name)
			},n.uv-radio-group {
		flex: 1;
ojFDxL 100644 props.js ^*U+[|RwX 100644 uv-radio.vue <6wHUǷio'dMx export default {
	props: {
		// radio的名称
		name: {
			type: [String, Number, Boolean],
			default: ''
		},
		// 形状，square为方形，circle为圆型
		shape: {
			type: String,
			default: ''
		},
		// 是否禁用
		disabled: {
			type: [String, Boolean],
			default: ''
		},
		// 是否禁止点击提示语选中单选框
		labelDisabled: {
			type: [String, Boolean],
			default: ''
		},
		// 选中状态下的颜色，如设置此值，将会覆盖parent的activeColor值
		activeColor: {
			type: String,
			default: ''
		},
		// 未选中的颜色
		inactiveColor: {
			type: String,
			default: ''
		},
		// 图标的大小，单位px
		iconSize: {
			type: [String, Number],
			default: ''
		},
		// label的字体大小，px单位
		labelSize: {
			type: [String, Number],
			default: ''
		},
		// label提示文字，因为nvue下，直接slot进来的文字，由于特殊的结构，无法修改样式
		label: {
			type: [String, Number, Boolean],
			default: ''
		},
		// 整体的大小
		size: {
			type: [String, Number],
			default: ''
		},
		// 图标颜色
		iconColor: {
			type: String,
			default: ''
		},
		// label的颜色
		labelColor: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.radio
	}
}Ux /<template>
	<view
	  class="uv-radio"
		@tap.stop="wrapperClickHandler"
	  :style="[radioStyle]"
	  :class="[`uv-radio-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'uv-border-bottom']"
	>
		<view
		  class="uv-radio__icon-wrap"
		  @tap.stop="iconClickHandler"
		  :class="iconClasses"
		  :style="[iconWrapStyle]"
		>
			<slot name="icon">
				<uv-icon
				  class="uv-radio__icon-wrap__icon"
				  name="checkbox-mark"
				  :size="elIconSize"
				  :color="elIconColor"
				/>
			</slot>
		</view>
		<view
			class="uv-radio__label-wrap" 
			@tap.stop="labelClickHandler">
			<slot>
				<text
					:style="{
						color: elDisabled ? elInactiveColor : elLabelColor,
						fontSize: elLabelSize,
						lineHeight: elLabelSize
					}"
				>{{label}}</text>
			</slot>
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * radio 单选框
	 * @description 单选框用于有一个选择，用户只能选择其中一个的场景。搭配uv-radio-group使用
	 * @tutorial https://www.uvui.cn/components/radio.html
	 * @property {String | Number}	name			radio的名称
	 * @property {String}			shape			形状，square为方形，circle为圆型
	 * @property {Boolean}			disabled		是否禁用
	 * @property {String | Boolean}	labelDisabled	是否禁止点击提示语选中单选框
	 * @property {String}			activeColor		选中时的颜色，如设置parent的active-color将失效
	 * @property {String}			inactiveColor	未选中的颜色
	 * @property {String | Number}	iconSize		图标大小，单位px
	 * @property {String | Number}	labelSize		label字体大小，单位px
	 * @property {String | Number}	label			label提示文字，因为nvue下，直接slot进来的文字，由于特殊的结构，无法修改样式
	 * @property {String | Number}	size			整体的大小
	 * @property {String}			iconColor		图标颜色
	 * @property {String}			labelColor		label的颜色
	 * @property {Object}			customStyle		组件的样式，对象形式
	 * 
	 * @event {Function} change 某个radio状态发生变化时触发(选中状态)
	 * @example <uv-radio :labelDisabled="false">门掩黄昏，无计留春住</uv-radio>
	 */
	export default {
		name: "uv-radio",

		mixins: [mpMixin, mixin, props],
		data() {
			return {
				checked: false,
				// 当你看到这段代码的时候，
				// 父组件的默认值，因为头条小程序不支持在computed中使用this.parent.shape的形式
				// 故只能使用如此方法
				parentData: {
					iconSize: 12,
					labelSize: 14,
					labelColor: '#303133',
					labelDisabled: null,
					disabled: null,
					shape: null,
					activeColor: null,
					inactiveColor: null,
					size: 18,
					value: null,
					modelValue: null,
					iconColor: null,
					placement: 'row',
					borderBottom: false,
					iconPlacement: 'left'
				}
			}
		},
		computed: {
			// 是否禁用，如果父组件uv-raios-group禁用的话，将会忽略子组件的配置
			elDisabled() {
				return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
			},
			// 是否禁用label点击
			elLabelDisabled() {
				return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
					false;
			},
			// 组件尺寸，对应size的值，默认值为21px
			elSize() {
				return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
			},
			// 组件的勾选图标的尺寸，默认12px
			elIconSize() {
				return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
			},
			// 组件选中激活时的颜色
			elActiveColor() {
				return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
			},
			// 组件选未中激活时的颜色
			elInactiveColor() {
				return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
					'#c8c9cc');
			},
			// label的颜色
			elLabelColor() {
				return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
			},
			// 组件的形状
			elShape() {
				return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
			},
			// label大小
			elLabelSize() {
				return this.$uv.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
					'15'))
			},
			elIconColor() {
				const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
					'#ffffff');
				// 图标的颜色
				if (this.elDisabled) {
					// disabled状态下，已勾选的radio图标改为elInactiveColor
					return this.checked ? this.elInactiveColor : 'transparent'
				} else {
					return this.checked ? iconColor : 'transparent'
				}
			},
			iconClasses() {
				let classes = []
				// 组件的形状
				classes.push('uv-radio__icon-wrap--' + this.elShape)
				if (this.elDisabled) {
					classes.push('uv-radio__icon-wrap--disabled')
				}
				if (this.checked && this.elDisabled) {
					classes.push('uv-radio__icon-wrap--disabled--checked')
				}
				// 支付宝，头条小程序无法动态绑定一个数组类名，否则解析出来的结果会带有","，而导致失效
				// #ifdef MP-ALIPAY || MP-TOUTIAO
				classes = classes.join(' ')
				// #endif
				return classes
			},
			iconWrapStyle() {
				// radio的整体样式
				const style = {}
				style.backgroundColor = this.checked && !this.elDisabled ? this.elActiveColor : '#ffffff'
				style.borderColor = this.checked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
				style.width = this.$uv.addUnit(this.elSize)
				style.height = this.$uv.addUnit(this.elSize)
				// 如果是图标在右边的话，移除它的右边距
				if (this.parentData.iconPlacement === 'right') {
					style.marginRight = 0
				}
				return style
			},
			radioStyle() {
				const style = {}
				if (this.parentData.borderBottom && this.parentData.placement === 'row') {
					this.$uv.error('检测到您将borderBottom设置为true，需要同时将uv-radio-group的placement设置为column才有效')
				}
				// 当父组件设置了显示下边框并且排列形式为纵向时，给内容和边框之间加上一定间隔
				if (this.parentData.borderBottom && this.parentData.placement === 'column') {
					// ios像素密度高，需要多一点的距离
					style.paddingBottom = this.$uv.os() === 'ios' ? '12px' : '8px'
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		created() {
			this.init()
		},
		methods: {
			init() {
				// 支付宝小程序不支持provide/inject，所以使用这个方法获取整个父组件，在created定义，避免循环引用
				this.updateParentData()
				if (!this.parent) {
					this.$uv.error('uv-radio必须搭配uv-radio-group组件使用')
				}
				// 设置初始化时，是否默认选中的状态
				this.$nextTick(()=>{
					let parentValue = null;
					// #ifdef VUE2
					parentValue = this.parentData.value;
					// #endif
					// #ifdef VUE3
					parentValue = this.parentData.modelValue;
					// #endif
					this.checked = this.name === parentValue
				})
			},
			updateParentData() {
				this.getParentData('uv-radio-group')
			},
			// 点击图标
			iconClickHandler(e) {
				this.preventEvent(e)
				// 如果整体被禁用，不允许被点击
				if (!this.elDisabled) {
					this.setRadioCheckedStatus()
				}
			},
			// 横向两端排列时，点击组件即可触发选中事件
			wrapperClickHandler(e) {
				this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
			},
			// 点击label
			labelClickHandler(e) {
				this.preventEvent(e)
				// 如果按钮整体被禁用或者label被禁用，则不允许点击文字修改状态
				if (!this.elLabelDisabled && !this.elDisabled) {
					this.setRadioCheckedStatus()
				}
			},
			emitEvent() {
				// uv-radio的checked不为true时(意味着未选中)，才发出事件，避免多次点击触发事件
				if (!this.checked) {
					this.$emit('change', this.name)
					// 尝试调用uv-form的验证方法，进行一定延迟，否则微信小程序更新可能会不及时
					this.$nextTick(() => {
						this.$uv.formValidate(this, 'change')
					})
				}
			},
			// 改变组件选中状态
			// 这里的改变的依据是，更改本组件的checked值为true，同时通过父组件遍历所有uv-radio实例
			// 将本组件外的其他uv-radio的checked都设置为false(都被取消选中状态)，因而只剩下一个为选中状态
			setRadioCheckedStatus() {
				this.emitEvent()
				// 将本组件标记为选中状态
				this.checked = true
				typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-border: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-radio-label-wrap-padding-right: 6px !default;
	$uv-radio-wrap-font-size: 20px !default;
	$uv-radio-wrap-border-width: 1px !default;
	$uv-radio-wrap-border-color: #c8c9cc !default;
	$uv-radio-line-height: 0 !default;
	$uv-radio-circle-border-radius: 100% !default;
	$uv-radio-square-border-radius: 3px !default;
	$uv-radio-checked-color: #fff !default;
	$uv-radio-checked-background-color: red !default;
	$uv-radio-checked-border-color: #2979ff !default;
	$uv-radio-disabled-background-color: #ebedf0 !default;
	$uv-radio-disabled--checked-color: #c8c9cc !default;
	$uv-radio-label-margin-left: 5px !default;
	$uv-radio-label-margin-right: 12px !default;
	$uv-radio-label-color: $uv-content-color !default;
	$uv-radio-label-font-size: 15px !default;
	$uv-radio-label-disabled-color: #c8c9cc !default;
	.uv-radio {
		/* #ifndef APP-NVUE */
		@include flex(row);
		/* #endif */
		overflow: hidden;
		flex-direction: row;
		align-items: center;
		&-label--left {
			flex-direction: row
		}
		&-label--right {
			flex-direction: row-reverse;
			justify-content: space-between
		}
		&__icon-wrap {
			/* #ifndef APP-NVUE */
			box-sizing: border-box;
			// nvue下，border-color过渡有问题
			transition-property: border-color, background-color, color;
			transition-duration: 0.2s;
			/* #endif */
			color: $uv-content-color;
			@include flex;
			align-items: center;
			justify-content: center;
			color: transparent;
			text-align: center;
			font-size: $uv-radio-wrap-font-size;
			border-width: $uv-radio-wrap-border-width;
			border-color: $uv-radio-wrap-border-color;
			border-style: solid;
			/* #ifdef MP-TOUTIAO */
			// 头条小程序兼容性问题，需要设置行高为0，否则图标偏下
			&__icon {
				line-height: $uv-radio-line-height;
			}
			/* #endif */
			&--circle {
				border-radius: $uv-radio-circle-border-radius;
			}
			&--square {
				border-radius: $uv-radio-square-border-radius;
			}
			&--checked {
				color: $uv-radio-checked-color;
				background-color: $uv-radio-checked-background-color;
				border-color: $uv-radio-checked-border-color;
			}
			&--disabled {
				background-color: $uv-radio-disabled-background-color !important;
			}
			&--disabled--checked {
				color: $uv-radio-disabled--checked-color !important;
			}
		}
		&__label {
			/* #ifndef APP-NVUE */
			word-wrap: break-word;
			/* #endif */
			margin-left: $uv-radio-label-margin-left;
			margin-right: $uv-radio-label-margin-right;
			color: $uv-radio-label-color;
			font-size: $uv-radio-label-font-size;
			&--disabled {
				color: $uv-radio-label-disabled-color;
			}
		}
		&__label-wrap {
			flex: 1;
			padding-left: $uv-radio-label-wrap-padding-right;
		}
	}
</style>09Xx 9:{
  "id": "uv-radio",
  "displayName": "uv-radio 单选框EH13Nradio 单选框用于有一个选择，用户只能选择其中一个的场景+radioO!radio",
    "单选框	^x |## Radio 单选框Yradio**

单选框用于有一个选择，用户只能选择其中一个的场景。	

# 7(radio{PFê	x e100644 changelog.md +"nPUdDLu40000 components oM8 H2r;֦100644 package.json  MWuvM&100644 readme.md jO_m3gtƑԢk>!x## 1.0.7（2023-08-24）
1. 修复支付宝不能选半星的BUG
## 1.0.6（2023-08-23）
1. 修复支付宝报错的BUG
## 1.0.5（2023-07-13）
优化代码
## 1.0.4（2023-07-13）
1. 修复value/v-model更改不生效的BUG
## 1.0.3（2023-06-05）
1. 修复只读或禁止状态下设置value无效的问题
## 1.0.2（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.1（2023-05-12）
1. 修复vue3中双向绑定问题
## 1.0.0（2023-05-10）
uv-rate 评分
Vsx" 40000 uv-rate Dgok@00CޫxK 100644 props.js nJjhelj3XWG100644 uv-rate.vue HUd{1[;whٺBx%export default {
	props: {
		value: {
			type: [Boolean, String, Number],
			default: false
		},
		modelValue: {
			type: [Boolean, String, Number],
			default: false
		},
		// 是否为加载中状态
		loading: {
			type: Boolean,
			default: false
		},
		// 是否为禁用装填
		disabled: {
			type: Boolean,
			default: false
		},
		// 开关尺寸，单位px
		size: {
			type: [String, Number],
			default: 25
		},
		// 打开时的背景颜色
		activeColor: {
			type: String,
			default: '#2979ff'
		},
		// 关闭时的背景颜色
		inactiveColor: {
			type: String,
			default: '#fff'
		},
		// switch打开时的值
		activeValue: {
			type: [String, Number, Boolean],
			default: true
		},
		// switch关闭时的值
		inactiveValue: {
			type: [String, Number, Boolean],
			default: false
		},
		// 是否开启异步变更，开启后需要手动控制输入值
		asyncChange: {
			type: Boolean,
			default: false
		},
		// 圆点与外边框的距离
		space: {
			type: [String, Number],
			default: 0
		},
		...uni.$uv?.props?.switch
	}
},%2xT	0c#// 要显示的星星数量
		count5
		},
		// 是否不可选中=是否只读
		readonly~2星星的大小c=18
		},
		// 未选中时的9b2b2b2'
		},
		// 选中的7;FA3534'
		},
		// 星星之间的间距，单位px
		gutter54
		},
		// 最少能选择的星星个数
		minCount*1
		},
		// 是否允许半星
		allowHalf~2'选中时的图标(星星)
		activeIcon0"Astar-fill'
		},
		// 未选中时的图标(星星)
		inactiveIcon0"Estar'
		},
		// 是否可以通过滑动手势选择评分
		touchabl}0	rate
	}
}xg$<template>
	<view 
		class="uv-rate"
		:id="elId"
		ref="uv-rate"
		:style="[$uv.addStyle(customStyle)]"
	>
		<view class="uv-rate__content"
			@touchmove.stop="touchMove"
			@touchend.stop="touchEnd">
			<view class="uv-rate__content__item"
				v-for="(item, index) in Number(count)"
				:key="index"
				:class="[elClass]">
				<view class="uv-rate__content__item__icon-wrap"
					ref="uv-rate__content__item__icon-wrap"
					@tap.stop="clickHandler($event, index + 1)">
					<uv-icon 
						:name="Math.floor(activeIndex) > index? activeIcon : inactiveIcon"
						:color="disabled ? '#c8c9cc' : Math.floor(activeIndex) > index ? activeColor : inactiveColor"
						:custom-style="{
              'padding-left': $uv.addUnit(gutter / 2),
							'padding-right': $uv.addUnit(gutter / 2)
            }"
						:size="size"
					></uv-icon>
				</view>
				<view v-if="allowHalf"
					@tap.stop="clickHandler($event, index + 1)"
					class="uv-rate__content__item__icon-wrap uv-rate__content__item__icon-wrap--half"
					:style="[{ width: $uv.addUnit(rateWidth / 2)}]"
					ref="uv-rate__content__item__icon-wrap">
					<uv-icon 
						:name=" Math.ceil(activeIndex) > index ? activeIcon : inactiveIcon "
						:color=" disabled ? '#c8c9cc' : Math.ceil(activeIndex) > index ? activeColor : inactiveColor "
						:custom-style="{
							'padding-left': $uv.addUnit(gutter / 2),
							'padding-right': $uv.addUnit(gutter / 2)
            }"
						:size="size">
					</uv-icon>
				</view>
			</view>
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const dom = weex.requireModule("dom");
	// #endif
	/**
	 * rate 评分
	 * @description 该组件一般用于满意度调查，星型评分的场景
	 * @tutorial https://www.uvui.cn/components/rate.html
	 * @property {String | Number}	value			用于v-model双向绑定选中的星星数量 (默认 1 )
	 * @property {String | Number}	count			最多可选的星星数量 （默认 5 ）
	 * @property {Boolean}			disabled		是否禁止用户操作 （默认 false ）
	 * @property {Boolean}			readonly		是否只读 （默认 false ）
	 * @property {String | Number}	size			星星的大小，单位px （默认 18 ）
	 * @property {String}			inactiveColor	未选中星星的颜色 （默认 '#b2b2b2' ）
	 * @property {String}			activeColor		选中的星星颜色 （默认 '#FA3534' ）
	 * @property {String | Number}	gutter			星星之间的距离 （默认 4 ）
	 * @property {String | Number}	minCount		最少选中星星的个数 （默认 1 ）
	 * @property {Boolean}			allowHalf		是否允许半星选择 （默认 false ）
	 * @property {String}			activeIcon		选中时的图标名，只能为uvui的内置图标 （默认 'star-fill' ）
	 * @property {String}			inactiveIcon	未选中时的图标名，只能为uvui的内置图标 （默认 'star' ）
	 * @property {Boolean}			touchable		是否可以通过滑动手势选择评分 （默认 'false' ）
	 * @property {Object}			customStyle		组件的样式，对象形式
	 * @event {Function} change 选中的星星发生变化时触发
	 * @example <uv-rate :count="count" :value="2"></uv-rate>
	 */
	export default {
		name: "uv-rate",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 生成一个唯一id，否则一个页面多个评分组件，会造成冲突
				elId: '',
				elClass: '',
				rateBoxLeft: 0, // 评分盒子左边到屏幕左边的距离，用于滑动选择时计算距离
				activeIndex: 0,
				rateWidth: 0, // 每个星星的宽度
				// 标识是否正在滑动，由于iOS事件上touch比click先触发，导致快速滑动结束后，接着触发click，导致事件混乱而出错
				moving: false
			}
		},
		watch: {
			value(newVal){
				this.activeIndex = newVal;
			},
			modelValue(newVal){
				this.activeIndex = newVal;
			}
		},
		created() {
			this.activeIndex = Number(this.value || this.modelValue);
			this.elId = this.$uv.guid();
			this.elClass = this.$uv.guid();
		},
		mounted() {
			this.init();
		},
		methods: {
			init() {
				this.$uv.sleep(200).then(() => {
					this.getRateItemRect();
					this.getRateIconWrapRect();
				})
			},
			// 获取评分组件盒子的布局信息
			async getRateItemRect() {
				await this.$uv.sleep();
				// uvui封装的获取节点的方法，详见文档
				// #ifndef APP-NVUE
				this.$uvGetRect("#" + this.elId).then((res) => {
					this.rateBoxLeft = res.left;
				});
				// #endif
				// #ifdef APP-NVUE
				dom.getComponentRect(this.$refs["uv-rate"], (res) => {
					this.rateBoxLeft = res.size.left;
				});
				// #endif
			},
			// 获取单个星星的尺寸
			getRateIconWrapRect() {
				// uvui封装的获取节点的方法，详见文档
				// #ifndef APP-NVUE
				this.$uvGetRect("." + this.elClass).then((res) => {
					this.rateWidth = res.width;
				});
				// #endif
				// #ifdef APP-NVUE
				dom.getComponentRect(this.$refs["uv-rate__content__item__icon-wrap"][0],
					(res) => {
						this.rateWidth = res.size.width;
					});
				// #endif
			},
			// 手指滑动
			touchMove(e) {
				// 如果禁止通过手动滑动选择，返回
				if (!this.touchable) {
					return;
				}
				this.preventEvent(e);
				const x = e.changedTouches && e.changedTouches[0].pageX || e.detail && e.detail.pageX;
				this.getActiveIndex(x);
			},
			// 停止滑动
			touchEnd(e) {
				// 如果禁止通过手动滑动选择，返回
				if (!this.touchable) {
					return;
				}
				this.preventEvent(e);
				const x = e.changedTouches && e.changedTouches[0].pageX || e.detail && e.detail.pageX;
				this.getActiveIndex(x);
			},
			// 通过点击，直接选中
			clickHandler(e, index) {
				// ios上，moving状态取消事件触发
				if (this.$uv.os() === "ios" && this.moving) {
					return;
				}
				this.preventEvent(e);
				let x = 0;
				// 点击时，在nvue上，无法获得点击的坐标，所以无法实现点击半星选择
				// #ifndef APP-NVUE
				x = e.changedTouches && e.changedTouches[0].pageX || e.detail && e.detail.pageX;
				// #endif
				// #ifdef APP-NVUE
				// nvue下，无法通过点击获得坐标信息，这里通过元素的位置尺寸值模拟坐标
				x = index * this.rateWidth + this.rateBoxLeft;
				// #endif
				this.getActiveIndex(x, true);
			},
			// 发出事件
			changeEvent() {
				this.$emit("change", this.activeIndex);
				this.$emit("input", this.activeIndex);
				this.$emit("update:modelValue", this.activeIndex);
			},
			// 获取当前激活的评分图标
			getActiveIndex(x, isClick = false) {
				if (this.disabled || this.readonly) {
					return;
				}
				// 判断当前操作的点的x坐标值，是否在允许的边界范围内
				const allRateWidth = this.rateWidth * this.count + this.rateBoxLeft;
				// 如果小于第一个图标的左边界，设置为最小值，如果大于所有图标的宽度，则设置为最大值
				x = this.$uv.range(this.rateBoxLeft, allRateWidth, x) - this.rateBoxLeft
				// 滑动点相对于评分盒子左边的距离
				const distance = x;
				// 滑动的距离，相当于多少颗星星
				let index;
				// 判断是否允许半星
				if (this.allowHalf) {
					index = Math.floor(distance / this.rateWidth);
					// 取余，判断小数的区间范围
					const decimal = distance % this.rateWidth;
					if (decimal <= this.rateWidth / 2 && decimal > 0) {
						index += 0.5;
					} else if (decimal > this.rateWidth / 2) {
						index++;
					}
				} else {
					index = Math.floor(distance / this.rateWidth);
					// 取余，判断小数的区间范围
					const decimal = distance % this.rateWidth;
					// 非半星时，只有超过了图标的一半距离，才认为是选择了这颗星
					if (isClick) {
						if (decimal > 0) index++;
					} else {
						if (decimal > this.rateWidth / 2) index++;
					}
				}
				this.activeIndex = Math.min(index, this.count);
				// 对最少颗星星的限制
				if (this.activeIndex < this.minCount) {
					this.activeIndex = this.minCount;
				}
				this.changeEvent();
				// 设置延时为了让click事件在touchmove之前触发
				setTimeout(() => {
					this.moving = true;
				}, 10);
				// 一定时间后，取消标识为移动中状态，是为了让click事件无效
				setTimeout(() => {
					this.moving = false;
				}, 10);
			}
		}
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-rate-margin: 0 !default;
	$uv-rate-padding: 0 !default;
	$uv-rate-item-icon-wrap-half-top: 0 !default;
	$uv-rate-item-icon-wrap-half-left: 0 !default;
	.uv-rate {
		@include flex;
		align-items: center;
		margin: $uv-rate-margin;
		padding: $uv-rate-padding;
		/* #ifndef APP-NVUE */
		touch-action: none;
		/* #endif */
		&__content {
			@include flex;
			&__item {
				position: relative;
				&__icon-wrap {
					&--half {
						position: absolute;
						overflow: hidden;
						top: $uv-rate-item-icon-wrap-half-top;
						left: $uv-rate-item-icon-wrap-half-left;
					}
				}
			}
		}
	}
	.uv-icon {
		/* #ifndef APP-NVUE */
		box-sizing: border-box;
		/* #endif */
	}
</style>T> 
!x X5{
  "id": "uv-rate",
  "displayName": "uv-rate 评分E^?该组件为星型评分，可用于满意度调查等场景....rateO!rate",
    "评分	NmZx ~o## Rate 评分

> **组件名：uv-rate**

该组件为星型评分，可用于满意度调查等场景。	

# (rate{GX	x e100644 changelog.md @,,#@^#40000 components 9ƅܠY,ys|1100644 package.json wgOBŜL 2100644 readme.md yG2qn)5y=x' 40000 uv-read-more 6p`ݠxP 100644 props.js ƑU%O&{Qt100644 uv-read-more.vue }iș?u+%{A"Zx[export default {
	props: {
		// 默认的显示占位高度
		showHeight: {
			type: [String, Number],
			default: 400
		},
		// 展开后是否显示"收起"按钮
		toggle: {
			type: Boolean,
			default: false
		},
		// 关闭时的提示文字
		closeText: {
			type: String,
			default: '展开阅读全文'
		},
		// 展开时的提示文字
		openText: {
			type: String,
			default: '收起'
		},
		// 提示的文字颜色
		color: {
			type: String,
			default: '#2979ff'
		},
		// 提示文字的大小
		fontSize: {
			type: [String, Number],
			default: 14
		},
		// 是否显示阴影
		// 此参数不能写在props/readMore.js中进行默认配置，因为使用了条件编译，在外部js中
		// uni无法准确识别当前是否处于nvue还是非nvue下
		shadowStyle: {
			type: Object,
			default: () => ({
				// #ifndef APP-NVUE
				backgroundImage: 'linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, #fff 80%)',
				// #endif
				// #ifdef APP-NVUE
				// nvue上不支持设置复杂的backgroundImage属性
				backgroundImage: 'linear-gradient(to top, #fff, rgba(255, 255, 255, 0.5))',
				// #endif
				paddingTop: '100px',
				marginTop: '-100px'
			})
		},
		// 段落首行缩进的字符个数
		textIndent: {
			type: String,
			default: '2em'
		},
		// open和close事件时，将此参数返回在回调参数中
		name: {
			type: [String, Number],
			default: ''
		},
		...uni.$uv?.props?.readMore
	}
}Ix[<template>
	<view class="uv-read-more">
		<view
		    class="uv-read-more__content"
		    :style="{
				height: isLongContent && status === 'close' ? $uv.addUnit(showHeight) : $uv.addUnit(contentHeight,'px'),
				textIndent: textIndent
			}"
		>
			<view
			    class="uv-read-more__content__inner"
			    ref="uv-read-more__content__inner"
			    :class="[elId]"
			>
				<slot></slot>
			</view>
		</view>
		<view
		    class="uv-read-more__toggle"
		    :style="[innerShadowStyle]"
		    v-if="isLongContent"
		>
			<slot name="toggle">
				<view
				    class="uv-read-more__toggle__text"
				    @tap="toggleReadMore"
				>
					<uv-text
					    :text="status === 'close' ? closeText : openText"
					    :color="color"
					    :size="fontSize"
					    :lineHeight="fontSize"
					    margin="0 5px 0 0"
					></uv-text>
					<view class="uv-read-more__toggle__icon">
						<uv-icon
						    :color="color"
						    :size="fontSize + 2"
						    :name="status === 'close' ? 'arrow-down' : 'arrow-up'"
						></uv-icon>
					</view>
				</view>
			</slot>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	import props from './props.js';
	/**
	 * readMore 阅读更多
	 * @description 该组件一般用于内容较长，预先收起一部分，点击展开全部内容的场景。
	 * @tutorial https://www.uvui.cn/components/readMore.html
	 * @property {String | Number}	showHeight	内容超出此高度才会显示展开全文按钮，单位px（默认 400 ）
	 * @property {Boolean}			toggle		展开后是否显示收起按钮（默认 false ）
	 * @property {String}			closeText	关闭时的提示文字（默认 '展开阅读全文' ）
	 * @property {String}			openText	展开时的提示文字（默认 '收起' ）
	 * @property {String}			color		提示文字的颜色（默认 '#2979ff' ）
	 * @property {String | Number}	fontSize	提示文字的大小，单位px （默认 14 ）
	 * @property {Object}			shadowStyle	显示阴影的样式
	 * @property {String}			textIndent	段落首行缩进的字符个数 （默认 '2em' ）
	 * @property {String | Number}	name		用于在 open 和 close 事件中当作回调参数返回
	 * @event {Function} open 内容被展开时触发
	 * @event {Function} close 内容被收起时触发
	 * @example <uv-read-more><rich-text :nodes="content"></rich-text></uv-read-more>
	 */
	export default {
		name: 'uv-read-more',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				isLongContent: false, // 是否需要隐藏一部分内容
				status: 'close', // 当前隐藏与显示的状态，close-收起状态，open-展开状态
				elId: '', // 生成唯一class
				contentHeight: 100, // 内容高度
			}
		},
		computed: {
			// 展开后无需阴影，收起时才需要阴影样式
			innerShadowStyle() {
				if (this.status === 'open') return {}
				else return this.shadowStyle
			}
		},
		created() {
			this.elId = this.$uv.guid();
		},
		mounted() {
			this.init()
		},
		methods: {
			async init() {
				this.getContentHeight().then(height => {
					this.contentHeight = height
					// 判断高度，如果真实内容高度大于占位高度，则显示收起与展开的控制按钮
					if (height > this.$uv.getPx(this.showHeight)) {
						this.isLongContent = true
						this.status = 'close'
					}
				})
			},
			// 获取内容的高度
			async getContentHeight() {
				// 延时一定时间再获取节点
				await this.$uv.sleep(30)
				return new Promise(resolve => {
					// #ifndef APP-NVUE
					this.$uvGetRect('.' + this.elId).then(res => {
						resolve(res.height)
					})
					// #endif

					// #ifdef APP-NVUE
					const ref = this.$refs['uv-read-more__content__inner']
					dom.getComponentRect(ref, (res) => {
						resolve(res.size.height)
					})
					// #endif
				})
			},
			// 展开或者收起
			toggleReadMore() {
				this.status = this.status === 'close' ? 'open' : 'close'
				// 如果toggle为false，隐藏"收起"部分的内容
				if (this.toggle == false) this.isLongContent = false
				// 发出打开或者收齐的事件
				this.$emit(this.status, this.name)
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
.uv-read-more {

	&__content {
		overflow: hidden;
		color: $uv-content-color;
		font-size: 15px;
		text-align: left;
	}

	&__toggle {
		@include flex;
		justify-content: center;

		&__text {
			@include flex;
			align-items: center;
			justify-content: center;
			margin-top: 5px;
		}
	}
}
</style>
SIjx ${
  "id": "uv-reread-more 展开阅读?igread-more 该组件一般用于内容较长，预先收起一部分，点击展开全部内容的场景*reJ(read",
    "展开阅读icon",
			"uv-text
Gq]	x e100644 changelog.md 9S14r6+dN40000 components ^ȻƂ2l100644 package.json KMV{ju!y100644 readme.md {G`	Q+up@:]xw## 1.0.4（2023-08-29）
1. nvue修复设置align不生效的BUG
## 1.0.3（2023-08-24）
1. 修复在nvue不能换行的问题
## 1.0.2（2023-05-24）
1. 去掉多余的data-index属性，避免警告
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-text 文本组件
x ˚row layout布局
xB 40000 uv-col P-5!"$ը_wot40000 uv-row 桒O6P_W99
VrxJ 100644 props.js ~!Ii`J100644 uv-col.vue r[9
?=uy"V+xKexport default {
	props: {
		// 占父容器宽度的多少等分，总分为12份
		span: {
			type: [String, Number],
			default: 12
		},
		// 指定栅格左侧的间隔数(总12栏)
		offset: {
			type: [String, Number],
			default: 0
		},
		// 水平排列方式，可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
		justify: {
			type: String,
			default: 'start'
		},
		// 垂直对齐方式，可选值为top、center、bottom、stretch
		align: {
			type: String,
			default: 'stretch'
		},
		// 文字对齐方式
		textAlign: {
			type: String,
			default: 'left'
		},
		...uni.$uv?.props?.col
	}
}R ^x&<template>
	<view
	    class="uv-col"
		ref="uv-col"
	    :class="[
			'uv-col-' + span
		]"
	    :style="[colStyle]"
	    @tap="clickHandler"
	>
		<slot></slot>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * CodeInput 栅格系统的列 
	 * @description 该组件一般用于Layout 布局 通过基础的 12 分栏，迅速简便地创建布局
	 * @tutorial https://www.uvui.cn/components/Layout.html
	 * @property {String | Number}	span		栅格占据的列数，总12等份 (默认 12 ) 
	 * @property {String | Number}	offset		分栏左边偏移，计算方式与span相同 (默认 0 ) 
	 * @property {String}			justify		水平排列方式，可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)  (默认 'start' ) 
	 * @property {String}			align		垂直对齐方式，可选值为top、center、bottom、stretch (默认 'stretch' ) 
	 * @property {String}			textAlign	文字水平对齐方式 (默认 'left' ) 
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * @event {Function}	click	col被点击，会阻止事件冒泡到row
	 * @example	 <uv-col  span="3" offset="3" > <view class="demo-layout bg-purple"></view> </uv-col>
	 */
	export default {
		name: 'uv-col',
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				width: 0,
				parentData: {
					gutter: 0
				},
				gridNum: 12
			}
		},
		computed: {
			uJustify() {
				if (this.justify == 'end' || this.justify == 'start') return 'flex-' + this.justify
				else if (this.justify == 'around' || this.justify == 'between') return 'space-' + this.justify
				else return this.justify
			},
			uAlignItem() {
				if (this.align == 'top') return 'flex-start'
				if (this.align == 'bottom') return 'flex-end'
				else return this.align
			},
			colStyle() {
				const style = {
					// 这里写成"padding: 0 10px"的形式是因为nvue的需要
					paddingLeft: this.$uv.addUnit(this.$uv.getPx(this.parentData.gutter)/2),
					paddingRight: this.$uv.addUnit(this.$uv.getPx(this.parentData.gutter)/2),
					alignItems: this.uAlignItem,
					justifyContent: this.uJustify,
					textAlign: this.textAlign,
					// #ifndef APP-NVUE
					// 在非nvue上，使用百分比形式
					flex: `0 0 ${100 / this.gridNum * this.span}%`,
					marginLeft: 100 / 12 * this.offset + '%',
					// #endif
					// #ifdef APP-NVUE
					// 在nvue上，由于无法使用百分比单位，这里需要获取父组件的宽度，再计算得出该有对应的百分比尺寸
					width: this.$uv.addUnit(Math.floor(this.width / this.gridNum * Number(this.span))),
					marginLeft: this.$uv.addUnit(Math.floor(this.width / this.gridNum * Number(this.offset))),
					// #endif
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		mounted() {
			this.init()
		},
		methods: {
			async init() {
				// 支付宝小程序不支持provide/inject，所以使用这个方法获取整个父组件，在created定义，避免循环引用
				this.updateParentData()
				this.width = await this.parent.getComponentWidth()
			},
			updateParentData() {
				this.getParentData('uv-row')
			},
			clickHandler(e) {
				this.$emit('click');
			}
		},
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-col {
		padding: 0;
		/* #ifndef APP-NVUE */
		box-sizing:border-box;
		/* #endif */
		/* #ifdef MP */
		display: block;
		/* #endif */
	}

	// nvue下百分比无效
	/* #ifndef APP-NVUE */
	.uv-col-0 {
		width: 0;
	}

	.uv-col-1 {
		width: calc(100%/12);
	}

	.uv-col-2 {
		width: calc(100%/12 * 2);
	}

	.uv-col-3 {
		width: calc(100%/12 * 3);
	}

	.uv-col-4 {
		width: calc(100%/12 * 4);
	}

	.uv-col-5 {
		width: calc(100%/12 * 5);
	}

	.uv-col-6 {
		width: calc(100%/12 * 6);
	}

	.uv-col-7 {
		width: calc(100%/12 * 7);
	}

	.uv-col-8 {
		width: calc(100%/12 * 8);
	}

	.uv-col-9 {
		width: calc(100%/12 * 9);
	}

	.uv-col-10 {
		width: calc(100%/12 * 10);
	}

	.uv-col-11 {
		width: calc(100%/12 * 11);
	}

	.uv-col-12 {
		width: calc(100%/12 * 12);
	}

	/* #endif */
</style>
r^$ߪxJ 100644 props.js Yp=TF100644 uv-row.vue x뾐٬O2'lJP1xexport default {
	props: {
		// 给col添加间距，左右边距各占一半
		gutter: {
			type: [String, Number],
			default: 0
		},
		// 水平排列方式，可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
		justify: {
			type: String,
			default: 'start'
		},
		// 垂直对齐方式，可选值为top、center、bottom
		align: {
			type: String,
			default: 'center'
		},
		...uni.$uv?.props?.row
	}
}S> xs<template>
	<view
	    class="uv-row"
		ref="uv-row"
	    :style="[rowStyle]"
	    @tap="clickHandler"
	>
		<slot />
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	import props from './props.js';
	/**
	 * Row 栅格系统中的行
	 * @description 通过基础的 12 分栏，迅速简便地创建布局 
	 * @tutorial https://www.uvui.cn/components/layout.html
	 * @property {String | Number}	gutter		栅格间隔，左右各为此值的一半，单位px  (默认 0 )
	 * @property {String}			justify		水平排列方式(微信小程序暂不支持) 可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)  (默认 'start' )
	 * @property {String}			align		垂直排列方式 (默认 'center' )
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * 
	 * @event {Function} click row被点击
	 * @example <uv-row justify="space-between" customStyle="margin-bottom: 10px"></uv-row>
	 */
	export default {
		name: "uv-row",
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				
			}
		},
		computed: {
			uJustify() {
				if (this.justify == 'end' || this.justify == 'start') return 'flex-' + this.justify
				else if (this.justify == 'around' || this.justify == 'between') return 'space-' + this.justify
				else return this.justify
			},
			uAlignItem() {
				if (this.align == 'top') return 'flex-start'
				if (this.align == 'bottom') return 'flex-end'
				else return this.align
			},
			rowStyle() {
				const style = {
					alignItems: this.uAlignItem,
					justifyContent: this.uJustify
				}
				// 通过给uv-row左右两边的负外边距，消除uv-col在有gutter时，第一个和最后一个元素的左内边距和右内边距造成的影响
				if(this.gutter) {
					style.marginLeft = this.$uv.addUnit(-Number(this.gutter)/2)
					style.marginRight = this.$uv.addUnit(-Number(this.gutter)/2)
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		methods: {
			clickHandler(e) {
				this.$emit('click')
			},
			async getComponentWidth() {
				// 延时一定时间，以确保节点渲染完成
				await this.$uv.sleep()
				return new Promise(resolve => {
					// uvui封装的获取节点的方法，详见文档
					// #ifndef APP-NVUE
					this.$uvGetRect('.uv-row').then(res => {
						resolve(res.width)
					})
					// #endif
					// #ifdef APP-NVUE
					// nvue的dom模块用于获取节点
					dom.getComponentRect(this.$refs['uv-row'], (res) => {
						resolve(res.size.width)
					})
					// #endif
				})
			},
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-row {
		@include flex;
	}
</style>
clx ?9{
  "id": "uv-row",
  "displayName": "uv-row layout布局?JT1",
  "description": "uv-row 通过基础的 12 分栏，迅速简便地创建布局row!!layout",
    "布局\t	[Rxl ## Layout 布局 >row**

通过基础的 12 分栏，迅速简便地创建布局.layoutZXr7	x e100644 changelog.md VZXa&V*c?[U40000 components S;#d-E-Yk100644 package.json [P%9O4&100644 readme.md x&3N\t=sfL>'xz## 1.0.4（2023-09-14）
1. 飞书小程序支持
## 1.0.3（2023-08-14）
1. 修复百度报错的BUG
## 1.0.2（2023-07-02）
uv-safe-bottom 修复，在百度程序，抖音小程序不生效的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-safe-bottom 底部安全区组件
^x) 40000 uv-safe-bottom )̆cbP5F_>r6gx. 100644 uv-safe-bottom.vue CJ f\|e5y$rkɹpx	<template>
	<view
		class="uv-safe-bottom"
		:style="[style]"
		:class="[!isNvue && 'uv-safe-area-inset-bottom']"
	>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	/**
	 * SafeBottom 底部安全区
	 * @description 这个适配，主要是针对IPhone X等一些底部带指示条的机型，指示条的操作区域与页面底部存在重合，容易导致用户误操作，因此我们需要针对这些机型进行底部安全区适配。
	 * @tutorial https://www.uvui.cn/components/safeAreaInset.html
	 * @property {type}		prop_name
	 * @property {Object}	customStyle	定义需要用到的外部样式
	 *
	 * @event {Function()}
	 * @example <uv-status-bar></uv-status-bar>
	 */
	export default {
		name: "uv-safe-bottom",
		mixins: [mpMixin, mixin],
		data() {
			return {
				safeAreaBottomHeight: 0,
				isNvue: false,
			};
		},
		computed: {
			style() {
				const style = {};
				// #ifdef APP-NVUE || MP-TOUTIAO || MP-LARK
				// nvue下，高度使用js计算填充
				style.height = this.$uv.addUnit(this.$uv.sys()?.safeAreaInsets?.bottom, 'px');
				// #endif
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			},
		},
		mounted() {
			// #ifdef APP-NVUE
			// 标识为是否nvue
			this.isNvue = true;
			// #endif
		},
	};
</script>

<style lang="scss" scoped>
	.uv-safe-bottom {
		/* #ifndef APP-NVUE */
		width: 100%;
		/* #endif */
	}
	/* #ifndef APP-NVUE */
	// 历遍生成4个方向的底部安全区
	@each $d in top, right, bottom, left {
		.uv-safe-area-inset-#{$d} {
			padding-#{$d}: 0;
			padding-#{$d}: constant(safe-area-inset-#{$d});  
			padding-#{$d}: env(safe-area-inset-#{$d});  
		}
	}
	/* #endif */
</style>
ԳxxqK{
  "id": "uv-safe-bottom",
  "displayName": "uv-safe-bottom 底部安全匑>K4",
  "description": "这个适配，主要是针对IPhone X等一些底部带指示条的机型，指示条的操作区域与面底部存在重合，容易导致用户误操作，因此我们需要针对这些机型进行底部安全区适配。",
  safe-bottom!!bottom",
    "底部安全匳[t	Xݾx0## SafeBottom 底部安全区afe-bottom**

这个适配，主要是针对IPhone X等一些底部带指示条的机型，指示条的操作区域与页面底o部存在重合，容易导致用户误操作，因此我们需要针对这些机型进行底部安全区适配&guide/safeAreaInsetݥ^@	x e100644 changelog.md '%~Q|^	d.40000 components 5UrA$P0Ha100644 package.json *`;*;~100644 readme.md O]8ؙ[	?ضxV## 1.0.5（2023-11-15）
1. 修复微信报错的BUG
## 1.0.4（2023-11-14）
1. 兼容全局设置rpx
## 1.0.3（2023-08-19）
1.  修复报错导致不能移动指示器的BUG
## 1.0.2（2023-08-08）
1. 修复vue2编译报错的BUG
## 1.0.1（2023-07-21）
1. 优化
## 1.0.0（2023-07-21）
1. 新增uv-scroll-liast 横向滚动表组件
k_x) 40000 uv-scroll-list OknG}-1RO/6u	x a100644 nvue.js k})T]vGCU100644 props.js 7mGҘ̥100644 scrollWxs.wxs zX749jbB|U100644 uv-scroll-list.vue RCENL_s
DCx0// 引入bindingx，此库类似于微信小程序wxs，目的是让js运行在视图层，减少视图层和逻辑层的通信折损
const BindingX = uni.requireNativePlugin('bindingx')
export default {
	methods: {
		// 此处不写注释，请自行体会
		nvueScrollHandler(e) {
			if (this.indicator) {
				const anchor = this.$refs['uv-scroll-list__scroll-view'].ref
				const element = this.$refs['uv-scroll-list__indicator__line__bar'].ref
				const scrollLeft = e.contentOffset.x
				const contentSize = e.contentSize.width
				const { scrollWidth } = this
				const barAllMoveWidth = this.indicatorWidth - this.indicatorBarWidth
				// 在安卓和iOS上，需要除的倍数不一样，iOS需要除以2
				const actionNum = this.$uv.os() === 'ios' ? 2 : 1
				const expression = `(x / ${actionNum}) / ${contentSize - scrollWidth} * ${this.$uv.getPx(this.$uv.addUnit(barAllMoveWidth))}`
				BindingX.bind({
					anchor,
					eventType: 'scroll',
					props: [{
						element,
						property: 'transform.translateX',
						expression
					}]
				})
			}
		}
	}
}ʛ$)xeexport default {
	props: {
		// 指示器的整体宽度
		indicatorWidth: {
			type: [String, Number],
			default: 50
		},
		// 滑块的宽度
		indicatorBarWidth: {
			type: [String, Number],
			default: 20
		},
		// 是否显示面板指示器
		indicator: {
			type: Boolean,
			default: true
		},
		// 指示器非激活颜色
		indicatorColor: {
			type: String,
			default: '#f2f2f2'
		},
		// 指示器的激活颜色
		indicatorActiveColor: {
			type: String,
			default: '#3c9cff'
		},
		// 指示器样式，可通过bottom，left，right进行定位
		indicatorStyle: {
			type: [String, Object],
			default: ''
		},
		...uni.$uv?.props?.scrollList
	}
}{x
Dfunction scroll(event, ownerInstance) {
	// detail中含有scroll-view的信息，比如scroll-view的实际宽度，当前时间点scroll-view的移动距离等
	var detail = event.detail
	var scrollWidth = detail.scrollWidth
	var scrollLeft = detail.scrollLeft
	// 获取当前组件的dataset，说白了就是祸国殃民的腾xun搞出来的垃ji
	var dataset = event.currentTarget.dataset
	// 此为scroll-view外部包裹元素的宽度
	// 某些HX版本(3.1.18)，发现view元素中大写的data-scrollWidth，在wxs中，变成了全部小写，所以这里需要特别处理
	var scrollComponentWidth = dataset.scrollWidth || dataset.scrollwidth || 0
	// 指示器和滑块的宽度
	var indicatorWidth = dataset.indicatorWidth || dataset.indicatorwidth || 0
	var barWidth = dataset.barWidth || dataset.barwidth || 0
	// 此处的计算理由为：scroll-view的滚动距离与目标滚动距离(scroll-view的实际宽度减去包裹元素的宽度)之比，等于滑块当前移动距离与总需
	// 滑动距离(指示器的总宽度减去滑块宽度)的比值
	var x = scrollLeft / (scrollWidth - scrollComponentWidth) * (indicatorWidth - barWidth)
	setBarStyle(ownerInstance, x, dataset.unit)
}

// 由于webview的无能，无法保证scroll-view在滑动过程中，一直触发scroll事件，会导致
// 无法监听到某些滚动值，当在首尾临界值无法监听到时，这是致命的，因为错失这些值会导致滑块无法回到起点和终点
// 所以这里需要对临界值做监听并处理
function scrolltolower(event, ownerInstance) {
	ownerInstance.callMethod('scrollEvent', 'right')
	// 获取当前组件的dataset
	var dataset = event.currentTarget.dataset
	// 指示器和滑块的宽度
	var indicatorWidth = dataset.indicatorWidth || dataset.indicatorwidth || 0
	var barWidth = dataset.barWidth || dataset.barwidth || 0
	// scroll-view滚动到右边终点时，将滑块也设置为到右边的终点，它所需移动的距离为：指示器宽度 - 滑块宽度
	setBarStyle(ownerInstance, indicatorWidth - barWidth, dataset.unit)
}

function scrolltoupper(event, ownerInstance) {
	var dataset = event.currentTarget.dataset
	ownerInstance.callMethod('scrollEvent', 'left')
	// 滚动到左边时，将滑块设置为0的偏移距离，回到起点
	setBarStyle(ownerInstance, 0, dataset.unit)
}

function setBarStyle(ownerInstance, x, unit) {
	ownerInstance.selectComponent('.uv-scroll-list__indicator__line__bar') && ownerInstance.selectComponent('.uv-scroll-list__indicator__line__bar').setStyle({
		transform: unit == 'rpx' ? 'translateX(' + x + 'rpx)' : 'translateX(' + x + 'px)'
	})
}

module.exports = {
	scroll: scroll,
	scrolltolower: scrolltolower,
	scrolltoupper: scrolltoupper
}?Hx<template>
	<view
		class="uv-scroll-list"
		ref="uv-scroll-list"
	>
		<!-- #ifdef APP-NVUE -->
		<!-- nvue使用bindingX实现，以得到更好的性能 -->
		<scroller
			class="uv-scroll-list__scroll-view"
			ref="uv-scroll-list__scroll-view"
			scroll-direction="horizontal"
			:show-scrollbar="false"
			:offset-accuracy="1"
			@scroll="nvueScrollHandler"
		>
			<view class="uv-scroll-list__scroll-view__content">
				<slot />
			</view>
		</scroller>
		<!-- #endif -->
		<!-- #ifndef APP-NVUE -->
		<!-- #ifdef MP-WEIXIN || APP-VUE || H5 || MP-QQ -->
		<!-- 以上平台，支持wxs -->
		<scroll-view
			class="uv-scroll-list__scroll-view"
			scroll-x
			@scroll="wxs.scroll"
			@scrolltoupper="wxs.scrolltoupper"
			@scrolltolower="wxs.scrolltolower"
			:data-scrollWidth="scrollWidth"
			:data-barWidth="$uv.getPx(indicatorBarWidth)"
			:data-indicatorWidth="$uv.getPx(indicatorWidth)"
			:show-scrollbar="false"
			:upper-threshold="0"
			:lower-threshold="0"
			:data-unit="$uv.unit"
		>
			<!-- #endif -->
			<!-- #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ -->
			<!-- 非以上平台，只能使用普通js实现 -->
			<scroll-view
				class="uv-scroll-list__scroll-view"
				scroll-x
				@scroll="scrollHandler"
				@scrolltoupper="scrolltoupperHandler"
				@scrolltolower="scrolltolowerHandler"
				:show-scrollbar="false"
				:upper-threshold="0"
				:lower-threshold="0"
			>
				<!-- #endif -->
				<view class="uv-scroll-list__scroll-view__content">
					<slot />
				</view>
			</scroll-view>
			<!-- #endif -->
			<view
				class="uv-scroll-list__indicator"
				v-if="indicator"
				:style="[$uv.addStyle(indicatorStyle)]"
			>
				<view
					class="uv-scroll-list__indicator__line"
					:style="[lineStyle]"
				>
					<view
						class="uv-scroll-list__indicator__line__bar"
						:style="[barStyle]"
						ref="uv-scroll-list__indicator__line__bar"
					></view>
				</view>
			</view>
			<!-- 避免报错 -->
			<!-- #ifdef H5 -->
			<view v-else class="uv-scroll-list__indicator__line__bar"></view>
			<!-- #endif -->
	</view>
</template>
<script src="./scrollWxs.wxs" module="wxs" lang="wxs"></script>
<script>
	/**
	 * scrollList 横向滚动列表
	 * @description 该组件一般用于同时展示多个商品、分类的场景，也可以完成左右滑动的列表。
	 * @tutorial https://www.uviewui.com/components/scrollList.html
	 * @property {String | Number}	indicatorWidth			指示器的整体宽度 (默认 50 )
	 * @property {String | Number}	indicatorBarWidth		滑块的宽度 (默认 20 )
	 * @property {Boolean}			indicator				是否显示面板指示器 (默认 true )
	 * @property {String}			indicatorColor			指示器非激活颜色 (默认 '#f2f2f2' )
	 * @property {String}			indicatorActiveColor	指示器的激活颜色 (默认 '#3c9cff' )
	 * @property {String | Object}	indicatorStyle			指示器样式，可通过bottom，left，right进行定位
	 * @event {Function} left	滑动到左边时触发
	 * @event {Function} right	滑动到右边时触发
	 * @example
	 */
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	import nvueMixin from "./nvue.js"
	// #endif
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	export default {
		name: 'uv-scroll-list',
		// #ifndef APP-NVUE
		mixins: [mpMixin, mixin, props],
		// #endif
		// #ifdef APP-NVUE
		mixins: [mpMixin, mixin, nvueMixin, props],
		// #endif
		data() {
			return {
				scrollInfo: {
					scrollLeft: 0,
					scrollWidth: 0
				},
				scrollWidth: 0
			}
		},
		computed: {
			// 指示器为线型的样式
			barStyle() {
				const style = {}
				// #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ
				// 此为普通js方案，只有在非nvue和不支持wxs方案的端才使用、
				// 此处的计算理由为：scroll-view的滚动距离与目标滚动距离(scroll-view的实际宽度减去包裹元素的宽度)之比，等于滑块当前移动距离与总需
				// 滑动距离(指示器的总宽度减去滑块宽度)的比值
				const scrollLeft = this.scrollInfo.scrollLeft,
					scrollWidth = this.scrollInfo.scrollWidth,
					barAllMoveWidth = this.indicatorWidth - this.indicatorBarWidth
				const x = scrollLeft / (scrollWidth - this.scrollWidth) * this.$uv.getPx(this.$uv.addUnit(barAllMoveWidth))
				style.transform = `translateX(${ x }px)`
				// #endif
				// 设置滑块的宽度和背景色，是每个平台都需要的
				style.width = this.$uv.addUnit(this.indicatorBarWidth)
				style.backgroundColor = this.indicatorActiveColor
				return style
			},
			lineStyle() {
				const style = {}
				// 指示器整体的样式，需要设置其宽度和背景色
				style.width = this.$uv.addUnit(this.indicatorWidth)
				style.backgroundColor = this.indicatorColor
				return style
			}
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				this.getComponentWidth()
			},
			// #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ
			// scroll-view触发滚动事件
			scrollHandler(e) {
				this.scrollInfo = e.detail
			},
			scrolltoupperHandler() {
				this.scrollEvent('left')
				this.scrollInfo.scrollLeft = 0
			},
			scrolltolowerHandler() {
				this.scrollEvent('right')
				// 在普通js方案中，滚动到右边时，通过设置this.scrollInfo，模拟出滚动到右边的情况
				// 因为上方是用过computed计算的，设置后，会自动调整滑块的位置
				this.scrollInfo.scrollLeft = this.$uv.getPx(this.indicatorWidth) - this.$uv.getPx(this.indicatorBarWidth)
			},
			// #endif
			scrollEvent(status) {
				this.$emit(status)
			},
			// 获取组件的宽度
			async getComponentWidth() {
				// 延时一定时间，以获取dom尺寸
				await this.$uv.sleep(30)
				// #ifndef APP-NVUE
				this.$uvGetRect('.uv-scroll-list').then(size => {
					this.scrollWidth = size.width
				})
				// #endif
				// #ifdef APP-NVUE
				const ref = this.$refs['uv-scroll-list']
				ref && dom.getComponentRect(ref, (res) => {
					this.scrollWidth = res.size.width
				})
				// #endif
			},
		}
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-scroll-list {
		padding-bottom: 10px;
		&__scroll-view {
			@include flex;
			&__content {
				@include flex;
			}
		}
		&__indicator {
			@include flex;
			justify-content: center;
			margin-top: 15px;
			&__line {
				width: 60px;
				height: 4px;
				border-radius: 100px;
				overflow: hidden;
				&__bar {
					width: 20px;
					height: 4px;
					border-radius: 100px;
				}
			}
		}
	}
</style>VOKx  ## ScrollList 横向滚动列表
scroll-lis=同时展示多个商品、分类的场景，也可以完成左右滑动的列表，往往数量不确定，数量较多支持0右滚动。灵活配置，开箱即用。

# (
scrollList/d[I	x e100644 changelog.md e`mP\%ߌ}B40000 components еOp*.qIyNX100644 package.json 7	gy7!ru100644 readme.md yޣuɘﴀnqV=$:xQ## 1.0.11（2023-11-10）
1. 调整清除按钮样式的marginLeft，避免微信上多数情况触发不了的BUG
## 1.0.10（2023-11-04）
1. 修复设置disabled情况下，@click回调事件触发不了的bug
## 1.0.9（2023-08-18）
1. 修复boxStyle失效的BUG
## 1.0.8（2023-08-07）
修复值为null或undefined时显示错误的bug
## 1.0.7（2023-08-05）
1.  修复在vue2模式下，v-model设置为0时不生效的BUG
## 1.0.6（2023-07-26）
1. 增加boxStyle参数，方便控制输入框部分的样式
## 1.0.5（2023-07-26）
1. 增加prefix和suffix  前置和后置插槽
## 1.0.4（2023-07-13）
1. 修复value值清空不生效的BUG
## 1.0.3（2023-07-13）
1. 修复value/v-model更改不生效的BUG
## 1.0.2（2023-07-03）
去除无用的插槽
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-search 搜索
-⎤x$ 40000 uv-search ew\)`.\Y)xM 100644 props.js 3P&+?/>W100644 uv-search.vue !oNLz>IYZC'3x
export default {
	props: {
		value: {
			type: [String, Number],
			default: ''
		},
		modelValue: {
			type: [String, Number],
			default: ''
		},
		// 搜索框形状，round-圆形，square-方形
		shape: {
			type: String,
			default: 'round'
		},
		// 搜索框背景色，默认值#f2f2f2
		bgColor: {
			type: String,
			default: '#f2f2f2'
		},
		// 占位提示文字
		placeholder: {
			type: String,
			default: '请输入关键字'
		},
		// 是否启用清除控件
		clearabled: {
			type: Boolean,
			default: true
		},
		// 是否自动聚焦
		focus: {
			type: Boolean,
			default: false
		},
		// 是否在搜索框右侧显示取消按钮
		showAction: {
			type: Boolean,
			default: true
		},
		// 右边控件的样式
		actionStyle: {
			type: Object,
			default: () => ({})
		},
		// 取消按钮文字
		actionText: {
			type: String,
			default: '搜索'
		},
		// 输入框内容对齐方式，可选值为 left|center|right
		inputAlign: {
			type: String,
			default: 'left'
		},
		// input输入框的样式，可以定义文字颜色，大小等，对象形式
		inputStyle: {
			type: Object,
			default: () => ({})
		},
		// 是否禁用输入框
		disabled: {
			type: Boolean,
			default: false
		},
		// 边框颜色
		borderColor: {
			type: String,
			default: 'transparent'
		},
		// 搜索图标的颜色，默认同输入框字体颜色
		searchIconColor: {
			type: String,
			default: '#909399'
		},
		// 输入框字体颜色
		color: {
			type: String,
			default: '#606266'
		},
		// placeholder的颜色
		placeholderColor: {
			type: String,
			default: '#909399'
		},
		// 左边输入框的图标，可以为uvui图标名称或图片路径
		searchIcon: {
			type: String,
			default: 'search'
		},
		searchIconSize: {
			type: [Number, String],
			default: 22
		},
		// 组件与其他上下左右元素之间的距离，带单位的字符串形式，如"30px"、"30px 20px"等写法
		margin: {
			type: String,
			default: '0'
		},
		// 开启showAction时，是否在input获取焦点时才显示
		animation: {
			type: Boolean,
			default: false
		},
		// 输入框最大能输入的长度，-1为不限制长度(来自uniapp文档)
		maxlength: {
			type: [String, Number],
			default: -1
		},
		// 搜索框高度，单位px
		height: {
			type: [String, Number],
			default: 32
		},
		// 搜索框左侧文本
		label: {
			type: [String, Number, null],
			default: null
		},
		// 搜索框扩展样式
		boxStyle: {
			type: [String, Object],
			default: () => ({})
		},
		...uni.$uv?.props?.search
	}
}x(`<template>
	<view
	  class="uv-search"
	  @tap="clickHandler"
	  :style="[{
			margin: margin,
		}, $uv.addStyle(customStyle)]"
	>
		<view
		  class="uv-search__content"
		  :style="[{
				backgroundColor: bgColor,
				borderRadius: shape == 'round' ? '100px' : '4px',
				borderColor: borderColor,
			},$uv.addStyle(boxStyle)]"
		>
			<view class="uv-search__content__disabled" v-if="disabled"></view>
			<slot name="prefix">
				<view class="uv-search__content__icon">
					<uv-icon
						@tap="clickIcon"
					  :size="searchIconSize"
					  :name="searchIcon"
					  :color="searchIconColor ? searchIconColor : color"
					></uv-icon>
				</view>
			</slot>
			<input
			  confirm-type="search"
			  @blur="blur"
			  :value="keyword"
			  @confirm="search"
			  @input="inputChange"
			  :disabled="disabled"
			  @focus="getFocus"
			  :focus="focus"
			  :maxlength="maxlength"
			  placeholder-class="uv-search__content__input--placeholder"
			  :placeholder="placeholder"
			  :placeholder-style="`color: ${placeholderColor}`"
			  class="uv-search__content__input"
			  type="text"
			  :style="[{
					textAlign: inputAlign,
					color: color,
					backgroundColor: bgColor,
					height: $uv.addUnit(height)
				}, inputStyle]"
			/>
			<view
			  class="uv-search__content__icon uv-search__content__close"
			  v-if="keyword && clearabled && focused"
			  @tap="clear"
			>
				<uv-icon
				  name="close"
				  size="11"
				  color="#ffffff"
					customStyle="line-height: 12px"
				></uv-icon>
			</view>
			<slot name="suffix"></slot>
		</view>
		<text
		  :style="[actionStyle]"
		  class="uv-search__action"
		  :class="[(showActionBtn || show) && 'uv-search__action--active']"
		  @tap.stop.prevent="custom"
		>{{ actionText }}</text>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * search 搜索框
	 * @description 搜索组件，集成了常见搜索框所需功能，用户可以一键引入，开箱即用。
	 * @tutorial https://www.uvui.cn/components/search.html
	 * @property {String}			value/v-model				输入框初始值
	 * @property {String}			shape				搜索框形状，round-圆形，square-方形（默认 'round' ）
	 * @property {String}			bgColor				搜索框背景颜色（默认 '#f2f2f2' ）
	 * @property {String}			placeholder			占位文字内容（默认 '请输入关键字' ）
	 * @property {Boolean}			clearabled			是否启用清除控件（默认 true ）
	 * @property {Boolean}			focus				是否自动获得焦点（默认 false ）
	 * @property {Boolean}			showAction			是否显示右侧控件（默认 true ）
	 * @property {Object}			actionStyle			右侧控件的样式，对象形式
	 * @property {String}			actionText			右侧控件文字（默认 '搜索' ）
	 * @property {String}			inputAlign			输入框内容水平对齐方式 （默认 'left' ）
	 * @property {Object}			inputStyle			自定义输入框样式，对象形式
	 * @property {Boolean}			disabled			是否启用输入框（默认 false ）
	 * @property {String}			borderColor			边框颜色，配置了颜色，才会有边框 (默认 'transparent' )
	 * @property {String}			searchIconColor		搜索图标的颜色，默认同输入框字体颜色 (默认 '#909399' )
	 * @property {Number | String}	searchIconSize 搜索图标的字体，默认22
	 * @property {String}			color				输入框字体颜色（默认 '#606266' ）
	 * @property {String}			placeholderColor	placeholder的颜色（默认 '#909399' ）
	 * @property {String}			searchIcon			输入框左边的图标，可以为uvui图标名称或图片路径  (默认 'search' )
	 * @property {String}			margin				组件与其他上下左右元素之间的距离，带单位的字符串形式，如"30px"   (默认 '0' )
	 * @property {Boolean} 			animation			是否开启动画，见上方说明（默认 false ）
	 * @property {String | Number}	maxlength			输入框最大能输入的长度，-1为不限制长度  (默认 '-1' )
	 * @property {String | Number}	height				输入框高度，单位px（默认 64 ）
	 * @property {String | Number}	label				搜索框左边显示内容
	 * @property {Object} boxStyle 自定义内容框样式，设置padding 
	 * @property {Object}			customStyle			定义需要用到的外部样式
	 *
	 * @event {Function} change 输入框内容发生变化时触发
	 * @event {Function} search 用户确定搜索时触发，用户按回车键，或者手机键盘右下角的"搜索"键时触发
	 * @event {Function} custom 用户点击右侧控件时触发
	 * @event {Function} clear 用户点击清除按钮时触发
	 * @example <uv-search placeholder="日照香炉生紫烟" v-model="keyword"></uv-search>
	 */
	export default {
		name: "uv-search",
		emits: ['click', 'input', 'change', 'clear', 'search', 'custom', 'focus', 'blur', 'clickIcon', 'update:modelValue'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				keyword: '',
				showClear: false, // 是否显示右边的清除图标
				show: false,
				// 标记input当前状态是否处于聚焦中，如果是，才会显示右侧的清除控件
				focused: this.focus
			};
		},
		created() {
			// #ifndef VUE3
			this.keyword = this.value;
			// #endif
			// #ifdef VUE3
			this.keyword = this.modelValue;
			// #endif
		},
		watch: {
			value(nVal){
				this.keyword = nVal;
			},
			modelValue(nVal){
				this.keyword = nVal;
			}
		},
		computed: {
			showActionBtn() {
				return !this.animation && this.showAction
			}
		},
		methods: {
			keywordChange(){
				this.$emit('input', this.keyword)
				this.$emit('update:modelValue', this.keyword)
				this.$emit('change', this.keyword);
			},
			// 目前HX2.6.9 v-model双向绑定无效，故监听input事件获取输入框内容的变化
			inputChange(e) {
				this.keyword = e.detail.value;
				this.keywordChange();
			},
			// 清空输入
			// 也可以作为用户通过this.$refs形式调用清空输入框内容
			clear() {
				this.keyword = '';
				this.$nextTick(() => {
					this.$emit('clear');
				})
				this.keywordChange();
			},
			// 确定搜索
			search(e) {
				this.$emit('search', e.detail.value);
				try {
					// 收起键盘
					uni.hideKeyboard();
				} catch (e) {}
			},
			// 点击右边自定义按钮的事件
			custom() {
				this.$emit('custom', this.keyword);
				try {
					// 收起键盘
					uni.hideKeyboard();
				} catch (e) {}
			},
			// 获取焦点
			getFocus() {
				this.focused = true;
				// 开启右侧搜索按钮展开的动画效果
				if (this.animation && this.showAction) this.show = true;
				this.$emit('focus', this.keyword);
			},
			// 失去焦点
			blur() {
				// 最开始使用的是监听图标@touchstart事件，自从hx2.8.4后，此方法在微信小程序出错
				// 这里改为监听点击事件，手点击清除图标时，同时也发生了@blur事件，导致图标消失而无法点击，这里做一个延时
				setTimeout(() => {
					this.focused = false;
				}, 100)
				this.show = false;
				this.$emit('blur', this.keyword);
			},
			// 点击搜索框，只有disabled=true时才发出事件，因为禁止了输入，意味着是想跳转真正的搜索页
			clickHandler() {
				if (this.disabled) this.$emit('click');
			},
			// 点击左边图标
			clickIcon() {
				this.$emit('clickIcon');
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-search-content-padding: 0 10px !default;
	$uv-search-label-color: $uv-main-color !default;
	$uv-search-label-font-size: 14px !default;
	$uv-search-label-margin: 0 4px !default;
	$uv-search-close-size: 20px !default;
	$uv-search-close-radius: 100px !default;
	$uv-search-close-bgColor: #C6C7CB !default;
	$uv-search-close-transform: scale(0.82) !default;
	$uv-search-input-font-size: 14px !default;
	$uv-search-input-margin: 0 15px 0 5px !default;
	$uv-search-input-color: $uv-main-color !default;
	$uv-search-input-placeholder-color: $uv-tips-color !default;
	$uv-search-action-font-size: 14px !default;
	$uv-search-action-color: $uv-main-color !default;
	$uv-search-action-width: 0 !default;
	$uv-search-action-active-width: 40px !default;
	$uv-search-action-margin-left: 5px !default;
	/* #ifdef H5 */
	// iOS15在H5下，hx的某些版本，input type=search时，会多了一个搜索图标，进行移除
	[type="search"]::-webkit-search-decoration {
		display: none;
	}
	/* #endif */
	.uv-search {
		@include flex(row);
		align-items: center;
		flex: 1;
		&__content {
			position: relative;	
			@include flex;
			align-items: center;
			padding: $uv-search-content-padding;
			flex: 1;
			justify-content: space-between;
			border-width: 1px;
			border-color: transparent;
			border-style: solid;
			overflow: hidden;
			&__icon {
				@include flex;
				align-items: center;
			}
			&__label {
				color: $uv-search-label-color;
				font-size: $uv-search-label-font-size;
				margin: $uv-search-label-margin;
			}
			&__close {
				width: $uv-search-close-size;
				height: $uv-search-close-size;
				border-top-left-radius: $uv-search-close-radius;
				border-top-right-radius: $uv-search-close-radius;
				border-bottom-left-radius: $uv-search-close-radius;
				border-bottom-right-radius: $uv-search-close-radius;
				background-color: $uv-search-close-bgColor;
				@include flex(row);
				align-items: center;
				justify-content: center;
				transform: $uv-search-close-transform;
			}
			&__input {
				flex: 1;
				font-size: $uv-search-input-font-size;
				line-height: 1;
				margin: $uv-search-input-margin;
				color: $uv-search-input-color;
				&--placeholder {
					color: $uv-search-input-placeholder-color;
				}
			}
			&__disabled {
				position: absolute;
				left: 0;
				top: 0;
				bottom: 0;
				right: 0;
				z-index: 2;
			}
		}
		&__action {
			font-size: $uv-search-action-font-size;
			color: $uv-search-action-color;
			width: $uv-search-action-width;
			overflow: hidden;
			transition-property: width;
			transition-duration: 0.3s;
			/* #ifndef APP-NVUE */
			white-space: nowrap;
			/* #endif */
			text-align: center;
			&--active {
				width: $uv-search-action-active-width;
				margin-left: $uv-search-action-margin-left;
			}
		}
	}
</style>'Kx9{
  "id": "uv-search",
  "displayName": "uv-search 搜索EH11",
  "description": "搜索组件，集成了常见搜索框所需功能，支持前后插槽，用户可以一键引入，
箱即用.searchO!search",
    "搜索loading-icon
	x e100644 changelog.md ׍TCfw0ms>40000 components 3%aWϦY;100644 package.json 8	i,bY.'_2E?T100644 readme.md 1L
ٔ)V<5HнL<ʱ,x>## 1.0.2（2023-11-02）
1. **`uv-skeleton`不再维护，强烈推荐使用新版本`uv-skeletons`**
2. 推荐大家使用新版骨架屏，作者已经运用到大量实战中了，绝对正品：[https://ext.dcloud.net.cn/plugin?name=uv-skeletons](https://ext.dcloud.net.cn/plugin?name=uv-skeletons)
3. 新版本`uv-skeletons`的优点：灵活度非常高，直接配置数组就可以完成想要的布局，作者已经运用到大量实战中。鼓励老用户迁移新版本，有任何问题可以加Q群549833913交流。
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-skeleton 骨架屏
x& 40000 uv-skeleton ?9{!a7y,RxO 100644 props.js ~|Z҂g`=D{100644 uv-skeleton.vue !$%,<2ϦК Ixdexport default {
	props: {
		// 是否展示骨架组件
		loading: {
			type: Boolean,
			default: true
		},
		// 是否开启动画效果
		animate: {
			type: Boolean,
			default: true
		},
		// 段落占位图行数
		rows: {
			type: [String, Number],
			default: 0
		},
		// 段落占位图的宽度
		rowsWidth: {
			type: [String, Number, Array],
			default: '100%'
		},
		// 段落占位图的高度
		rowsHeight: {
			type: [String, Number, Array],
			default: 18
		},
		// 段落占位图的左边距
		rowsLeft: {
			type: [String, Number, Array],
			default: 0
		},
		// 是否展示标题占位图
		title: {
			type: Boolean,
			default: true
		},
		// 段落标题的宽度
		titleWidth: {
			type: [String, Number],
			default: '50%'
		},
		// 段落标题的高度
		titleHeight: {
			type: [String, Number],
			default: 18
		},
		// 是否展示头像占位图
		avatar: {
			type: Boolean,
			default: false
		},
		// 头像占位图大小
		avatarSize: {
			type: [String, Number],
			default: 32
		},
		// 头像占位图的形状，circle-圆形，square-方形
		avatarShape: {
			type: String,
			default: 'circle'
		},
		...uni.$uv?.props?.skeleton
	}
}cx<template>
	<view class="uv-skeleton">
		<view
		    class="uv-skeleton__wrapper"
		    ref="uv-skeleton__wrapper"
		    v-if="loading"
			style="display: flex; flex-direction: row;"
		>
			<view
			    class="uv-skeleton__wrapper__avatar"
			    v-if="avatar"
			    :class="[`uv-skeleton__wrapper__avatar--${avatarShape}`, animate && 'animate']"
			    :style="{
						height: $uv.addUnit(avatarSize),
						width: $uv.addUnit(avatarSize)
					}"
			></view>
			<view
			    class="uv-skeleton__wrapper__content"
			    ref="uv-skeleton__wrapper__content"
				style="flex: 1;"
			>
				<view
				    class="uv-skeleton__wrapper__content__title"
				    v-if="title"
				    :style="{
							width: uTitleWidth,
							height: $uv.addUnit(titleHeight),
						}"
				    :class="[animate && 'animate']"
				></view>
				<view
				    class="uv-skeleton__wrapper__content__rows"
				    :class="[animate && 'animate']"
				    v-for="(item, index) in rowsArray"
				    :key="index"
				    :style="{
							 width: item.width,
							 height: item.height,
							 marginTop: item.marginTop,
							 marginLeft: item.marginLeft
						}"
				>
		
				</view>
			</view>
		</view>
		<slot v-else />
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	// 由于weex为阿里的KPI业绩考核的产物，所以不支持百分比单位，这里需要通过dom查询组件的宽度
	const dom = uni.requireNativePlugin('dom')
	const animation = uni.requireNativePlugin('animation')
	// #endif
	/**
	 * Skeleton 骨架屏
	 * @description 骨架屏一般用于页面在请求远程数据尚未完成时，页面用灰色块预显示本来的页面结构，给用户更好的体验。
	 * @tutorial https://www.uvui.cn/components/skeleton.html
	 * @property {Boolean}					loading		是否显示骨架占位图，设置为false将会展示子组件内容 (默认 true )
	 * @property {Boolean}					animate		是否开启动画效果 (默认 true )
	 * @property {String | Number}			rows		段落占位图行数 (默认 0 )
	 * @property {String | Number | Array}	rowsWidth	段落占位图的宽度，可以为百分比，数值，带单位字符串等，可通过数组传入指定每个段落行的宽度 (默认 '100%' )
	 * @property {String | Number | Array}	rowsHeight	段落的高度 (默认 18 )
	 * @property {String | Number | Array}	rowsLeft	段落的左边距 (默认 0 )
	 * @property {Boolean}					title		是否展示标题占位图 (默认 true )
	 * @property {String | Number}			titleWidth	标题的宽度 (默认 '50%' )
	 * @property {String | Number}			titleHeight	标题的高度 (默认 18 )
	 * @property {Boolean}					avatar		是否展示头像占位图 (默认 false )
	 * @property {String | Number}			avatarSize	头像占位图大小 (默认 32 )
	 * @property {String}					avatarShape	头像占位图的形状，circle-圆形，square-方形 (默认 'circle' )
	 * @example <uv-skeleton :loading="true" :animate="true"></uv-skeleton>
	 */
	export default {
		name: 'uv-skeleton',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				width: 0,
			}
		},
		watch: {
			loading() {
				this.getComponentWidth()
			}
		},
		computed: {
			rowsArray() {
				if (/%$/.test(this.rowsHeight)) {
					this.$uv.error('rowsHeight参数不支持百分比单位')
				}
				const rows = []
				for (let i = 0; i < this.rows; i++) {
					let item = {},
						// 需要预防超出数组边界的情况
						rowWidth = this.$uv.test.array(this.rowsWidth) ? (this.rowsWidth[i] || (i === this.row - 1 ? '70%' : '100%')) : i ===
						this.rows - 1 ? '70%' : this.rowsWidth,
						rowHeight = this.$uv.test.array(this.rowsHeight) ? (this.rowsHeight[i] || '18px') : this.rowsHeight,
						rowLeft = this.$uv.test.array(this.rowsLeft) ? (this.rowsLeft[i] || 0) : this.rowsLeft;
					// 如果有title占位图，第一个段落占位图的外边距需要大一些，如果没有title占位图，第一个段落占位图则无需外边距
					// 之所以需要这么做，是因为weex的无能，以提升性能为借口不支持css的一些伪类
					item.marginTop = !this.title && i === 0 ? 0 : this.title && i === 0 ? '20px' : '12px'
					// 如果设置的为百分比的宽度，转换为px值，因为nvue不支持百分比单位
					if (/%$/.test(rowWidth)) {
						// 通过parseInt提取出百分比单位中的数值部分，除以100得到百分比的小数值
						item.width = this.$uv.addUnit(this.width * parseInt(rowWidth) / 100)
					} else {
						item.width = this.$uv.addUnit(rowWidth)
					}
					item.height = this.$uv.addUnit(rowHeight)
					item.marginLeft = this.$uv.addUnit(rowLeft)
					rows.push(item)
				}
				// console.log(rows);
				return rows
			},
			uTitleWidth() {
				let tWidth = 0
				if (/%$/.test(this.titleWidth)) {
					// 通过parseInt提取出百分比单位中的数值部分，除以100得到百分比的小数值
					tWidth = this.$uv.addUnit(this.width * parseInt(this.titleWidth) / 100)
				} else {
					tWidth = this.$uv.addUnit(this.titleWidth)
				}
				return this.$uv.addUnit(tWidth)
			},
			
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				this.getComponentWidth()
				// #ifdef APP-NVUE
				this.loading && this.animate && this.setNvueAnimation()
				// #endif
			},
			async setNvueAnimation() {
				// #ifdef APP-NVUE
				// 为了让opacity:1的状态保持一定时间，这里做一个延时
				await this.$uv.sleep(500)
				const skeleton = this.$refs['uv-skeleton__wrapper'];
				skeleton && this.loading && this.animate && animation.transition(skeleton, {
					styles: {
						opacity: 0.5
					},
					duration: 600,
				}, () => {
					// 这里无需判断是否loading和开启动画状态，因为最终的状态必须达到opacity: 1，否则可能
					// 会停留在opacity: 0.5的状态中
					animation.transition(skeleton, {
						styles: {
							opacity: 1
						},
						duration: 600,
					}, () => {
						// 只有在loading中时，才执行动画
						this.loading && this.animate && this.setNvueAnimation()
					})
				})
				// #endif
			},
			// 获取组件的宽度
			async getComponentWidth() {
				// 延时一定时间，以获取dom尺寸
				await this.$uv.sleep(20)
				// #ifndef APP-NVUE
				this.$uvGetRect('.uv-skeleton__wrapper__content').then(size => {
					this.width = size.width
				})
				// #endif

				// #ifdef APP-NVUE
				const ref = this.$refs['uv-skeleton__wrapper__content']
				ref && dom.getComponentRect(ref, (res) => {
					this.width = res.size.width
				})
				// #endif
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	@mixin background {
		/* #ifdef APP-NVUE */
		background-color: #F1F2F4;
		/* #endif */
		/* #ifndef APP-NVUE */
		background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
		background-size: 400% 100%;
		/* #endif */
	}

	.uv-skeleton {
		flex: 1;
		
		&__wrapper {
			@include flex(row);
			
			&__avatar {
				@include background;
				margin-right: 15px;
			
				&--circle {
					border-radius: 100px;
				}
			
				&--square {
					border-radius: 4px;
				}
			}
			
			&__content {
				flex: 1;
			
				&__rows,
				&__title {
					@include background;
					border-radius: 3px;
				}
			}
		}
	}

	/* #ifndef APP-NVUE */
	.animate {
		animation: skeleton 1.8s ease infinite
	}

	@keyframes skeleton {
		0% {
			background-position: 100% 50%
		}

		100% {
			background-position: 0 50%
		}
	}

	/* #endif */
</style>
?Iux!@{
  "id": "uv-skeleton",
  "displayName": "uv-skeleton 骨架屏?J2",
  "description": "骨架屏一般用于页面在请求远程数据尚未完成时，页面用灰色块预显示本来的页$面结构，给用户更好的体验skeleton!!skeleton",
    "骨架屏\t	1Äzx 3## Skeleton 骨架屏keleton**

骨架屏一般用于页面在请求远程数据尚未完成时，页面用灰色块预显示本来的页面结构给用户更好的体验2keletonZ4}*	x e100644 changelog.md ՍHleu40000 components e|T'#0r100644 package.json 6)u#8r=p!DO100644 readme.md 9rv:b
G!4=wxs ## 1.0.1（2023-11-15）
1. 修复支付宝小程序报错的BUG
## 1.0.0（2023-10-30）
1. 新版骨架屏上线
8x' 40000 uv-skeletons #ֺ7. f$U8o̒ժЬx, 100644 uv-skeletons.vue +"Cٟ㑁pE\`.xI<template>
	<view class="uv-skeleton">
		<view v-if="loading">
			<view v-for="(item, index) in elements" :key="index">
				<!-- 横向并列布局 -->
				<view class="uv-skeleton__group" :style="[style(item)]" v-if="item.type=='flex'">
					<view v-for="(item2,index2) in item.children" :class="[item2.clas]" :style="[style(item2)]" :key="index2">
						<view v-for="(item3,index3) in item2.elements" :key="index3">
							<!-- 垂直高度站位 -->
							<view :style="{height: $uv.addUnit(item3.height,'rpx')}" v-if="item3.type=='gap'"></view>
							<view :class="[item3.clas, roundClass, animateClass]" :style="[style(item3)]" v-else ref="skeleton"></view>
						</view>
					</view>
				</view>
				<!-- 自定义骨架屏内容 -->
				<!-- ps 自定义扩展说明： -->
				<!-- 如果你需要自定义模板，可以参照这个custom的写法，增加一个skeleton配置类型，编写布局和样式就可以了 -->
				<!-- 注意事项：为了保证骨架效果和动态效果的一致，扩展时，在你希望实际展示在页面中的元素上加上 :class="[style, animateClass]" 和 :style="[style(item)]" 和 ref="skeleton" -->
				<view :class="[item.clas, animateClass]" :style="[style(item)]" ref="skeleton" v-else-if="item.type == 'custom'"></view>
				<!-- 垂直高度站位 -->
				<view :style="{height: $uv.addUnit(item.height,'rpx')}" v-else-if="item.type=='gap'"></view>
				<!-- 其他基本单位 line avatar 等 -->
				<view :class="[item.clas, roundClass, animateClass]" :style="[style(item)]" v-else ref="skeleton"></view>
			</view>
		</view>
		<view v-else>
			<slot />
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	const animation = weex.requireModule('animation');
	// #endif
	export default {
		name: 'uv-skeletons',
		mixins: [mpMixin, mixin],
		props: {
			// 是否显示骨架
			loading: {
				type: Boolean,
				default: true
			},
			// 骨架内容 具体说明参考文档：
			skeleton: {
				type: Array,
				default: () => []
			},
			// 是否开启动画效果
			animate: {
				type: Boolean,
				default: true
			},
			// 是否圆角骨架风格
			round: {
				type: Boolean,
				default: false
			},
			...uni.$uv?.props?.skeleton
		},
		data() {
			return {
				elements: [],
				opacity: 0.5,
				duration: 600
			}
		},
		computed: {
			animateClass() {
				return this.animate ? 'uv-skeleton--animation' : 'uv-skeleton--static';
			},
			roundClass() {
				return this.round ? 'uv-skeleton--round' : 'uv-skeleton--radius';
			},
			style(item) {
				return item => {
					const style = {};
					return this.$uv.deepMerge(style, this.$uv.addStyle(item.style));
				}
			}
		},
		created() {
			this.init();
			// #ifdef APP-NVUE
			if (this.loading && this.animate) {
				this.$uv.sleep(50).then(res => {
					this.createAnimation(this.opacity);
				})
			}
			// #endif
		},
		methods: {
			/**
			 * 初始化数据
			 */
			init() {
				let elements = [];
				if (!this.$uv.test.array(this.skeleton)) return this.$uv.error('skeleton参数必须为数组形式，参考文档示例：');
				this.skeleton.forEach(el => {
					const elClass = this.getElCounts(el);
					elements = elements.concat(elClass);
				})
				this.elements = [...elements];
			},
			/**
			 * 处理骨架屏参数内容
			 * @param {Object} el 每项数据
			 */
			getElCounts(el) {
				let elements = [];
				let children = [];
				if (this.$uv.test.number(el)) {
					elements.push({
						type: 'gap',
						height: el
					});
					return elements;
				} else {
					const type = el.type ? el.type : 'line';
					const num = el.num ? el.num : 1;
					const style = el.style ? el.style : {};
					const styleIsArray = this.$uv.test.array(style);
					const gap = el.gap ? el.gap : '20rpx';
					const child = el.children ? el.children : [];
					for (let i = 0; i < child.length; i++) {
						children[i] = {
							clas: child[i].type.indexOf('avatar') > -1 || child[i].type.indexOf('custom') > -1 ? '' : 'uv-skeleton__group__sub',
							elements: this.getElCounts(child[i])
						};
					}
					for (let i = 0; i < num; i++) {
						if (gap && i < num && i > 0) {
							elements.push({
								type: 'gap',
								height: gap
							});
						}
						elements.push({
							clas: `uv-skeleton__${type}`,
							type,
							style: styleIsArray ? style[i] : style,
							gap,
							children
						});
					}
					return elements;
				}
			},
			/**
			 * 创建动画
			 */
			createAnimation(opacity = 1) {
				// loading结束之后或未开启动画不执行
				if (!this.loading || !this.animate) return;
				let count = 0;
				const skeletons = this.$refs.skeleton;
				skeletons.forEach(item => {
					animation.transition(item, {
						styles: {
							opacity: opacity,
						},
						duration: this.duration
					}, () => {
						count++;
						if (count >= skeletons.length) {
							setTimeout(() => {
								this.createAnimation(opacity < 1 ? 1 : this.opacity);
							}, 200)
						}
					});
				})
			}
		}
	}
</script>
<style scoped lang="scss">
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@mixin background {
		/* #ifdef APP-NVUE */
		background-color: #e6e6e6;
		/* #endif */
		/* #ifndef APP-NVUE */
		background: linear-gradient(90deg, #F1F2F4 25%, #e6e6e6 37%, #F1F2F4 50%);
		background-size: 400% 100%;
		/* #endif */
	}
	.uv-skeleton__line {
		height: 32rpx;
		// margin-bottom: 30rpx;
	}
	.uv-skeleton__line--sm {
		height: 24rpx;
		margin-bottom: 30rpx;
	}
	.uv-skeleton__line--lg {
		height: 48rpx;
		margin-bottom: 30rpx;
	}
	.uv-skeleton--static {
		@include background;
	}
	.uv-skeleton--radius {
		border-radius: 8rpx;
	}
	.uv-skeleton--round {
		border-radius: 30rpx;
	}
	.uv-skeleton__avatar {
		width: 100rpx;
		height: 100rpx;
		border-radius: 50rpx;
	}
	.uv-skeleton__avatar--sm {
		width: 50rpx;
		height: 50rpx;
		border-radius: 25rpx;
	}
	.uv-skeleton__avatar--lg {
		width: 200rpx;
		height: 200rpx;
		border-radius: 100rpx;
	}
	.uv-skeleton__group {
		@include flex;
		&__sub {
			flex: 1;
		}
	}
	.uv-skeleton--animation {
		@include background;
		/* #ifndef APP-NVUE */
		animation: skeleton 1.8s ease infinite
			/* #endif */
	}
	/* #ifndef APP-NVUE */
	@keyframes skeleton {
		0% {
			background-position: 100% 50%
		}
		100% {
			background-position: 0 50%
		}
	}
	/* #endif */
</style>$YmxoB{
  "id": "uv-skeletons",
  "displayName": "uv-skeletons 骨架屏@I1",
  "description": "全新升级骨架屏，更加灵活，体验更加，强烈推荐使用新版骨架屏。一般用于页面在请求远程数据尚未完成时，在内容加载出来前展示与内容布局结构一致的灰白块，提升用户觉体验	skeletons!!skeleton",
    "骨架屏\texts
,{!Vx	# Skeletons 新版骨架屏skeletons**

骨架屏一般用于页面在请求远程数据尚未完成时，在内容加载出来前展示与内容布局结构一致的灰白块，提升用户视觉体验。

新版骨架屏与老版本使用参数有很大的区别，所以才有新版本，无法替换老版本。

新版骨架屏比老版本骨架屏更加灵活，理论上简单的左右上下布局c构均可以轻松实现，样式自由度较高，只要你会写css，推荐使用新版。

# (	skeletons/dfU	x e100644 changelog.md eAW.K5=zG40000 components  ERҋ 100644 package.json xȵ{kjl100644 readme.md z6'WD*A>x^## 1.0.3（2023-07-25）
1. 将inactiveColor修正为backgroundColor 参数，避免不生效
## 1.0.2（2023-07-13）
1.  修复 uv-slider设置value属性不生效的BUG 
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-slider 滑动选择器
:bҤx$ 40000 uv-slider "`wEQw١xM 100644 props.js b-oq0`su100644 uv-slider.vue *r)e:cR@xexport default {
	props: {
		value: {
			type: [Number, String],
			default: 0
		},
		modelValue: {
			type: [Number, String],
			default: 0
		},
		// 最小可选值
		min: {
			type: [Number, String],
			default: 0
		},
		// 最大可选值
		max: {
			type: [Number, String],
			default: 100
		},
		// 步长，取值必须大于 0，并且可被(max - min)整除
		step: {
			type: [Number, String],
			default: 1
		},
		// 滑块右侧已选择部分的背景色
		activeColor: {
			type: String,
			default: '#2979ff'
		},
		// 滑块左侧未选择部分的背景色
		backgroundColor: {
			type: String,
			default: '#c0c4cc'
		},
		// 滑块的大小，取值范围为 12 - 28
		blockSize: {
			type: [Number, String],
			default: 18
		},
		// 滑块的颜色
		blockColor: {
			type: String,
			default: '#ffffff'
		},
		// 禁用状态
		disabled: {
			type: Boolean,
			default: false
		},
		// 是否显示当前的选择值
		showValue: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.slider
	}
}DPx<template>
	<view
		class="uv-slider"
		:style="[$uv.addStyle(customStyle)]"
	>
		<slider
			:min="min"
			:max="max"
			:step="step"
			:value="sliderValue"
			:activeColor="activeColor"
			:backgroundColor="backgroundColor"
			:blockSize="$uv.getPx(blockSize)"
			:blockColor="blockColor"
			:showValue="showValue"
			:disabled="disabled"
			@changing="changingHandler"
			@change="changeHandler"
		></slider>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js'
	export default {
		name: 'uv-slider',
		mixins: [mpMixin, mixin, props],
		computed: {
			sliderValue(){
				return this.value || this.modelValue;
			}
		},
		methods: {
			// 拖动过程中触发
			changingHandler(e) {
				const { value } = e.detail
				// 更新v-model的值
				this.$emit('input', value)
				this.$emit('update:modelValue',value)
				// 触发事件
				this.$emit('changing', value)
			},
			// 滑动结束时触发
			changeHandler(e) {
				const {
					value
				} = e.detail
				// 更新v-model的值
				this.$emit('input', value)
				this.$emit('update:modelValue',value)
				// 触发事件
				this.$emit('change', value)
			}
		}
	}
</script>

=x B{
  "id": "uv-slider",
  "displayName": "uv-slider 滑动选择器EH3",
  "description": "滑动选择器组件一般用于表单中，手动选择一个区间范围的场景。",
  "keywords": [@	slideN"slider",
    "滑动选择器	{mx r## Slider 滑动
Yslider**

该组件一般用于表单中，手动选择一个区间范围的场景。

# Q(slid,u]u[
(RK	x e100644 changelog.md eЕLD˘伞-40000 components jdIE#d'100644 package.json C<v^-
_lg100644 readme.md axLYT$*q@RHxK 1## 1.0.2（2023-06-05）
1. 兼容渐变背景色istatus-bar组件
_#x( 40000 uv-status-bar OGq:w}Tc~8;xQ 100644 props.js .RP>BM/100644 uv-status-bar.vue |qp:VTp^mRx export default {
    props: {
        bgColor: {
            type: String,
            default: 'transparent'
        }
    }
}
U!bx"<template>
	<view
	    :style="[style]"
	    class="uv-status-bar"
	>
		<slot />
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * StatbusBar 状态栏占位
	 * @description 本组件主要用于状态填充，比如在自定导航栏的时候，它会自动适配一个恰当的状态栏高度。
	 * @tutorial https://www.uvui.cn/components/statusBar.html
	 * @property {String}			bgColor			背景色 (默认 'transparent' )
	 * @property {String | Object}	customStyle		自定义样式 
	 * @example <uv-status-bar></uv-status-bar>
	 */
	export default {
		name: 'uv-status-bar',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
			}
		},
		computed: {
			style() {
				const style = {}
				// 状态栏高度，由于某些安卓和微信开发工具无法识别css的顶部状态栏变量，所以使用js获取的方式
				style.height = this.$uv.addUnit(this.$uv.sys().statusBarHeight, 'px')
				if(this.bgColor){
					if (this.bgColor.indexOf("gradient") > -1) {// 渐变色
						style.backgroundImage = this.bgColor;
					}else{
						style.background = this.bgColor;
					}
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
	}
</script>

<style lang="scss" scoped>
	.uv-status-bar {
		// nvue会默认100%，如果nvue下，显式写100%的话，会导致宽度不为100%而异常
		/* #ifndef APP-NVUE */
		width: 100%;
		/* #endif */
	}
</style>
qzx	J{
  "id": "uv-status-bar",
  "displayName": "uv-status-bar 状态栏占位u+状态栏占位组件主要用于状态填充，比如在自定导航栏的时候，它会自动适配一个恰当的状态栏度-	tatus-barS"tatus-bar",
    "状态栳Bx I## StatbusBar 状态栏占位tatus-bar**

本组件主要用于状态填充，比如在自定导航栏的时候，它会自动适配一个恰当的状态栏	高度。~
.!m	x e100644 changelog.md \@ڤ1bG:`W40000 components Ag-bn0R*-$100644 package.json 8ȟZP*B@&_100644 readme.md /WF?`p99l\(<}x:## 1.0.3（2023-06-29）
1. 增加customStyle参数，方便设置样式
## 1.0.2（2023-06-29）
1. 新增title自定义
2. 完善文档说明
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-steps 步骤条
xK 40000 uv-steps-item j&eT݄ 40000 uv-steps 13  Ф[S1|"F}
xQ 100644 props.js q]|p0G100644 uv-steps-item.vue ϶a*-p~A׬rN7 fx s 标题
		titlncIdescoc标大小<6917
		},
		// 当前步骤是否处于失败状态
		error/2stepsItem
	}
}(<x<template>
	<view 
		class="uv-steps-item" 
		ref="uv-steps-item" 
		:class="[`uv-steps-item--${parentData.direction}`]"
		:style="[$uv.addStyle(customStyle)]"
		>
		<view 
			class="uv-steps-item__line" 
			v-if="index + 1 < childLength"
			:class="[`uv-steps-item__line--${parentData.direction}`]" 
			:style="[lineStyle]">
		</view>
		<view 
			:class="[
				'uv-steps-item__wrapper',
				`uv-steps-item__wrapper--${parentData.direction}`, 
				parentData.dot && `uv-steps-item__wrapper--${parentData.direction}--dot`
			]">
			<slot name="icon">
				<view 
					class="uv-steps-item__wrapper__dot" 
					v-if="parentData.dot" 
					:style="{
						backgroundColor: statusColor
					}">
				</view>
				<view 
					class="uv-steps-item__wrapper__icon" 
					v-else-if="parentData.activeIcon || parentData.inactiveIcon">
					<uv-icon 
						:name="index <= parentData.current ? parentData.activeIcon : parentData.inactiveIcon"
						:size="iconSize"
						:color="index <= parentData.current ? parentData.activeColor : parentData.inactiveColor">
					</uv-icon>
				</view>
				<view 
					v-else 
					:style="{
						backgroundColor: statusClass === 'process' ? parentData.activeColor : 'transparent',
						borderColor: statusColor
					}" 
					class="uv-steps-item__wrapper__circle">
					<text 
						v-if="statusClass === 'process' || statusClass === 'wait'"
						class="uv-steps-item__wrapper__circle__text" 
						:style="{
							color: index == parentData.current ? '#ffffff' : parentData.inactiveColor
						}">{{ index + 1}}</text>
					<uv-icon 
						v-else 
						:color="statusClass === 'error' ? 'error' : parentData.activeColor" 
						size="12"
						:name="statusClass === 'error' ? 'close' : 'checkmark'">
					</uv-icon>
				</view>
			</slot>
		</view>
		<view 
			:class="[
				'uv-steps-item__content',
				`uv-steps-item__content--${parentData.direction}`
			]"
			:style="[contentStyle]"
		>
			<slot name="title">
				<uv-text
					:text="title" 
					:type="parentData.current == index ? 'main' : 'content'" 
					lineHeight="20px"
					:size="parentData.current == index ? 14 : 13"
				></uv-text>
			</slot>
			<slot name="desc">
				<uv-text 
					:text="desc" 
					type="tips" 
					size="12"
				></uv-text>
			</slot>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * StepsItem 步骤条的子组件
	 * @description 本组件需要和uv-steps配合使用
	 * @tutorial https://www.uvui.cn/components/steps.html
	 * @property {String}			title			标题文字
	 * @property {String}			current			描述文本
	 * @property {String | Number}	iconSize		图标大小  (默认 17 )
	 * @property {Boolean}			error			当前步骤是否处于失败状态  (默认 false )
	 * @example <uv-steps current="0"><uv-steps-item title="已出库" desc="10:35" ></uv-steps-item></uv-steps>
	 */
	export default {
		name: 'uv-steps-item',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				index: 0,
				childLength: 0,
				showLine: false,
				size: {
					height: 0,
					width: 0
				},
				parentData: {
					direction: 'row',
					current: 0,
					activeColor: '',
					inactiveColor: '',
					activeIcon: '',
					inactiveIcon: '',
					dot: false
				}
			}
		},
		watch: {
			'parentData'(newValue, oldValue) {}
		},
		created() {
			this.init()
		},
		computed: {
			lineStyle() {
				const style = {}
				if (this.parentData.direction === 'row') {
					style.width = this.size.width + 'px'
					style.left = this.size.width / 2 + 'px'
				} else {
					style.height = this.size.height + 'px'
				}
				style.backgroundColor = this.parent.children?.[this.index + 1]?.error ? '#f56c6c' : this.index < this.parentData.current ? this.parentData.activeColor : this.parentData.inactiveColor
				return style
			},
			statusClass() {
				const {
					index,
					error
				} = this
				const {
					current
				} = this.parentData
				if (current == index) {
					return error === true ? 'error' : 'process'
				} else if (error) {
					return 'error'
				} else if (current > index) {
					return 'finish'
				} else {
					return 'wait'
				}
			},
			statusColor() {
				let color = ''
				switch (this.statusClass) {
					case 'finish':
						color = this.parentData.activeColor
						break
					case 'error':
						color = '#f56c6c'
						break
					case 'process':
						color = this.parentData.dot ? this.parentData.activeColor : 'transparent'
						break
					default:
						color = this.parentData.inactiveColor
						break
				}
				return color
			},
			contentStyle() {
				const style = {}
				if (this.parentData.direction === 'column') {
					style.marginLeft = this.parentData.dot ? '2px' : '6px'
					style.marginTop = this.parentData.dot ? '0px' : '6px'
				} else {
					style.marginTop = this.parentData.dot ? '2px' : '6px'
					style.marginLeft = this.parentData.dot ? '2px' : '6px'
				}
				return style
			}
		},
		mounted() {
			this.parent && this.parent.updateFromChild()
			this.$uv.sleep().then(() => {
				this.getStepsItemRect()
			})
		},
		methods: {
			init() {
				// 初始化数据
				this.updateParentData()
				if (!this.parent) {
					return this.$uv.error('uv-steps-item必须要搭配uv-steps组件使用')
				}
				this.index = this.parent.children.indexOf(this)
				this.childLength = this.parent.children.length
			},
			updateParentData() {
				// 此方法在mixin中
				this.getParentData('uv-steps')
			},
			// 父组件数据发生变化
			updateFromParent() {
				this.init()
			},
			// 获取组件的尺寸，用于设置横线的位置
			getStepsItemRect() {
				// #ifndef APP-NVUE
				this.$uvGetRect('.uv-steps-item').then(size => {
					this.size = size
				})
				// #endif
				// #ifdef APP-NVUE
				dom.getComponentRect(this.$refs['uv-steps-item'], res => {
					const {
						size
					} = res
					this.size = size
				})
				// #endif
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-steps-item {
		flex: 1;
		@include flex;

		&--row {
			flex-direction: column;
			align-items: center;
			position: relative;
		}

		&--column {
			position: relative;
			flex-direction: row;
			justify-content: flex-start;
			padding-bottom: 5px;
		}

		&__wrapper {
			@include flex;
			justify-content: center;
			align-items: center;
			position: relative;
			background-color: #fff;

			&--column {
				width: 20px;
				height: 32px;

				&--dot {
					height: 20px;
					width: 20px;
				}
			}

			&--row {
				width: 32px;
				height: 20px;

				&--dot {
					width: 20px;
					height: 20px;
				}
			}

			&__circle {
				width: 20px;
				height: 20px;
				/* #ifndef APP-NVUE */
				box-sizing: border-box;
				flex-shrink: 0;
				/* #endif */
				border-radius: 100px;
				border-width: 1px;
				border-color: $uv-tips-color;
				border-style: solid;
				@include flex(row);
				align-items: center;
				justify-content: center;
				transition: background-color 0.3s;

				&__text {
					color: $uv-tips-color;
					font-size: 11px;
					@include flex(row);
					align-items: center;
					justify-content: center;
					text-align: center;
					line-height: 11px;
				}
			}

			&__dot {
				width: 10px;
				height: 10px;
				border-radius: 100px;
				background-color: $uv-content-color;
			}
		}

		&__content {
			@include flex;
			flex: 1;

			&--row {
				flex-direction: column;
				align-items: center;
			}

			&--column {
				flex-direction: column;
				margin-left: 6px;
			}
		}

		&__line {
			position: absolute;
			background: $uv-tips-color;

			&--row {
				top: 10px;
				height: 1px;
			}

			&--column {
				width: 1px;
				left: 10px;
			}
		}
	}
</style>
CxL 100644 props.js aANs-L'Ҁy100644 uv-steps.vue H;azGj*8'xwexport default {
	props: {
		// 排列方向
		direction: {
			type: String,
			default: 'row'
		},
		// 设置第几个步骤
		current: {
			type: [String, Number],
			default: 0
		},
		// 激活状态颜色
		activeColor: {
			type: String,
			default: '#3c9cff'
		},
		// 未激活状态颜色
		inactiveColor: {
			type: String,
			default: '#969799'
		},
		// 激活状态的图标
		activeIcon: {
			type: String,
			default: ''
		},
		// 未激活状态图标
		inactiveIcon: {
			type: String,
			default: ''
		},
		// 是否显示点类型
		dot: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.steps
	}
}gxK	<template>
	<view
	  :class="['uv-steps',`uv-steps--${direction}`]"
		:style="[$uv.addStyle(customStyle)]"
	>
		<slot></slot>
	</view>
</template>

<script>
	import { func } from '@/uni_modules/uv-ui-tools/libs/function/test.js'
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Steps 步骤条
	 * @description 该组件一般用于完成一个任务要分几个步骤，标识目前处于第几步的场景。
	 * @tutorial https://www.uvui.cn/components/steps.html
	 * @property {String}			direction		row-横向，column-竖向 (默认 'row' )
	 * @property {String | Number}	current			设置当前处于第几步 (默认 0 )
	 * @property {String}			activeColor		激活状态颜色 (默认 '#3c9cff' )
	 * @property {String}			inactiveColor	未激活状态颜色 (默认 '#969799' )
	 * @property {String}			activeIcon		激活状态的图标
	 * @property {String}			inactiveIcon	未激活状态图标 
	 * @property {Boolean}			dot				是否显示点类型 (默认 false )
	 * @example <uv-steps current="0"><uv-steps-item title="已出库" desc="10:35" ></uv-steps-item></uv-steps>
	 */
	export default {
		name: 'uv-steps',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
			}
		},
		watch: {
			children() {
				this.updateChildData()
			},
			parentData() {
				this.updateChildData()
			}
		},
		computed: {
			// 监听参数的变化，通过watch中，手动去更新子组件的数据，否则子组件不会自动变化
			parentData() {
				return [this.current, this.direction, this.activeColor, this.inactiveColor, this.activeIcon, this.inactiveIcon, this.dot]
			}
		},
		methods: {
			// 更新子组件的数据
			updateChildData() {
				this.children.map(child => {
					// 先判断子组件是否存在对应的方法
					func((child || {}).updateFromParent()) && child.updateFromParent()
				})
			},
			// 接受子组件的通知，去修改其他子组件的数据
			updateFromChild() {
				this.updateChildData()
			}
		},
		created() {
			this.children = []
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-steps {
		@include flex;

		&--column {
			flex-direction: column
		}

		&--row {
			flex-direction: row;
			flex: 1;
		}
	}
</style>
L÷ox :{
  "id": "uv-steps",
  "displayName": "uv-steps 步骤条?`]步骤条组件一般用于完成一个任务要分几个步骤，标识目前处于第几步'steps!!steps",
    "步骤条\icon",
			"uv-textsnQ,st	:x l## Steps 步骤条geps**

该组件一般用于完成一个任务要分几个步骤，标识目前处于第几步的场景3epsZiW	x e100644 changelog.md ypYgus\[40000 components e+^9@k100644 package.json o @|1+xy100644 readme.md 1mpTUs1vdWBxn ## 1.0.4"K3（2023-10-13）
1. unmounted兼容vue3
## 1.0.2（2023-08-27）
1. 优化sticky 吸顶
t*lx$ 40000 uv-sticky 7իX,"Cm_MxM 100644 props.js 1J~@ 100644 uv-sticky.vue LSkڿm^[pQ!ð5xPexport default {
	props: {
		// 吸顶容器到顶部某个距离的时候，进行吸顶，在H5平台，NavigationBar为44px
		offsetTop: {
			type: [String, Number],
			default: 0
		},
		// 自定义导航栏的高度
		customNavHeight: {
			type: [String, Number],
			// #ifdef H5
			// H5端的导航栏属于“自定义”导航栏的范畴，因为它是非原生的，与普通元素一致
			default: 44,
			// #endif
			// #ifndef H5
			default: 0
			// #endif
		},
		// 是否禁用吸顶功能
		disabled: {
			type: Boolean,
			default: false
		},
		// 吸顶区域的背景颜色
		bgColor: {
			type: String,
			default: 'transparent'
		},
		// z-index值
		zIndex: {
			type: [String, Number],
			default: ''
		},
		// 列表中的索引值
		index: {
			type: [String, Number],
			default: ''
		},
		...uni.$uv?.props?.sticky
	}
}IbxR<template>
	<view
		class="uv-sticky"
		:id="elId"
		:style="[style]"
	>
		<view
			:style="[stickyContent]"
			class="uv-sticky__content"
		>
			<slot />
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';;
	/**
	 * sticky 吸顶
	 * @description 该组件与CSS中position: sticky属性实现的效果一致，当组件达到预设的到顶部距离时， 就会固定在指定位置，组件位置大于预设的顶部距离时，会重新按照正常的布局排列。
	 * @tutorial https://www.uvui.cn/components/sticky.html
	 * @property {String ｜ Number}	offsetTop		吸顶时与顶部的距离，单位px（默认 0 ）
	 * @property {String ｜ Number}	customNavHeight	自定义导航栏的高度 （h5 默认44  其他默认 0 ）
	 * @property {Boolean}			disabled		是否开启吸顶功能 （默认 false ）
	 * @property {String}			bgColor			组件背景颜色（默认 '#ffffff' ）
	 * @property {String ｜ Number}	zIndex			吸顶时的z-index值
	 * @property {String ｜ Number}	index			自定义标识，用于区分是哪一个组件
	 * @property {Object}			customStyle		组件的样式，对象形式
	 * @example <uv-sticky offsetTop="200"><view>塞下秋来风景异，衡阳雁去无留意</view></uv-sticky>
	 */
	export default {
		name: 'uv-sticky',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				cssSticky: false, // 是否使用css的sticky实现
				stickyTop: 0, // 吸顶的top值，因为可能受自定义导航栏影响，最终的吸顶值非offsetTop值
				elId: '',
				left: 0, // js模式时，吸顶的内容因为处于postition: fixed模式，为了和原来保持一致的样式，需要记录并重新设置它的left，height，width属性
				width: 'auto',
				height: 'auto',
				fixed: false, // js模式时，是否处于吸顶模式
			}
		},
		computed: {
			style() {
				const style = {}
				if(!this.disabled) {
					if (this.cssSticky) {
						style.position = 'sticky'
						style.zIndex = this.uZindex
						style.top = this.$uv.addUnit(this.stickyTop)
					} else {
						style.height = this.fixed ? this.height + 'px' : 'auto'
					}
				} else {
					// 无需吸顶时，设置会默认的relative(nvue)和非nvue的static静态模式即可
					// #ifdef APP-NVUE
					style.position = 'relative'
					// #endif
					// #ifndef APP-NVUE
					style.position = 'static'
					// #endif
				}
				style.backgroundColor = this.bgColor
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			},
			// 吸顶内容的样式
			stickyContent() {
				const style = {}
				if (!this.cssSticky) {
					style.position = this.fixed ? 'fixed' : 'static'
					style.top = this.stickyTop + 'px'
					style.left = this.left + 'px'
					style.width = this.width == 'auto' ? 'auto' : this.width + 'px'
					style.zIndex = this.uZindex
				}
				return style
			},
			uZindex() {
				return this.zIndex ? this.zIndex : 970
			}
		},
		created() {
			this.elId = this.$uv.guid();
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				this.getStickyTop()
				// 判断使用的模式
				this.checkSupportCssSticky()
				// 如果不支持css sticky，则使用js方案，此方案性能比不上css方案
				if (!this.cssSticky) {
					!this.disabled && this.initObserveContent()
				}
			},
			initObserveContent() {
				// 获取吸顶内容的高度，用于在js吸顶模式时，给父元素一个填充高度，防止"塌陷"
				this.$uvGetRect('#' + this.elId).then((res) => {
					this.height = res.height
					this.left = res.left
					this.width = res.width
					this.$nextTick(() => {
						this.observeContent()
					})
				})
			},
			observeContent() {
				// 先断掉之前的观察
				this.disconnectObserver('contentObserver')
				const contentObserver = uni.createIntersectionObserver({
					// 检测的区间范围
					thresholds: [0.95, 0.98, 1]
				})
				// 到屏幕顶部的高度时触发
				contentObserver.relativeToViewport({
					top: -this.stickyTop
				})
				// 绑定观察的元素
				contentObserver.observe(`#${this.elId}`, res => {
					this.setFixed(res.boundingClientRect.top)
				})
				this.contentObserver = contentObserver
			},
			setFixed(top) {
				// 判断是否出于吸顶条件范围
				const fixed = top <= this.stickyTop
				this.fixed = fixed
			},
			disconnectObserver(observerName) {
				// 断掉观察，释放资源
				const observer = this[observerName]
				observer && observer.disconnect()
			},
			getStickyTop() {
				this.stickyTop = this.$uv.getPx(this.offsetTop) + this.$uv.getPx(this.customNavHeight)
			},
			async checkSupportCssSticky() {
				// #ifdef H5
				// H5，一般都是现代浏览器，是支持css sticky的，这里使用创建元素嗅探的形式判断
				if (this.checkCssStickyForH5()) {
					this.cssSticky = true
				}
				// #endif

				// 如果安卓版本高于8.0，依然认为是支持css sticky的(因为安卓7在某些机型，可能不支持sticky)
				if (this.$uv.os() === 'android' && Number(this.$uv.sys().system) > 8) {
					this.cssSticky = true
				}

				// APP-Vue和微信平台，通过computedStyle判断是否支持css sticky
				// #ifdef APP-VUE || MP-WEIXIN
				this.cssSticky = await this.checkComputedStyle()
				// #endif

				// ios上，从ios6开始，都是支持css sticky的
				if (this.$uv.os() === 'ios') {
					this.cssSticky = true
				}

				// nvue，是支持css sticky的
				// #ifdef APP-NVUE
				this.cssSticky = true
				// #endif
			},
			// 在APP和微信小程序上，通过uni.createSelectorQuery可以判断是否支持css sticky
			checkComputedStyle() {
				// 方法内进行判断，避免在其他平台生成无用代码
				// #ifdef APP-VUE || MP-WEIXIN
				return new Promise(resolve => {
					uni.createSelectorQuery().in(this).select('.uv-sticky').fields({
						computedStyle: ["position"]
					}).exec(e => {
						resolve('sticky' === e[0].position)
					})
				})
				// #endif
			},
			// H5通过创建元素的形式嗅探是否支持css sticky
			// 判断浏览器是否支持sticky属性
			checkCssStickyForH5() {
				// 方法内进行判断，避免在其他平台生成无用代码
				// #ifdef H5
				const vendorList = ['', '-webkit-', '-ms-', '-moz-', '-o-'],
					vendorListLength = vendorList.length,
					stickyElement = document.createElement('div')
				for (let i = 0; i < vendorListLength; i++) {
					stickyElement.style.position = vendorList[i] + 'sticky'
					if (stickyElement.style.position !== '') {
						return true
					}
				}
				return false;
				// #endif
			}
		},
		// #ifdef VUE2
		beforeDestroy() {
			this.disconnectObserver('contentObserver')
		},
		// #endif
		// #ifdef VUE3
		unmounted() {
			this.disconnectObserver('contentObserver')
		}
		// #endif
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-sticky {
		/* #ifdef APP-VUE || MP-WEIXIN */
		// 此处默认写sticky属性，是为了给微信和APP通过uni.createSelectorQuery查询是否支持css sticky使用
		position: sticky;
		/* #endif */
	}
</style>
h&	x e100644 changelog.md _K>ޔI&K40000 components ':ȡF~x#r100644 package.json C>D:QW!100644 readme.md GNe_iEMֶ"z9?x8## 1.0.3（2023-12-20）
1. 优化
## 1.0.2（2023-11-27）
1. 增加customItemStyle属性，方便修改bar样式
2. 文档后续更新
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-subsection 分段器
x( 40000 uv-subsection wQ~w5oJ6~xQ 100644 props.js Uh5Uttp tX)J100644 uv-subsection.vue d3nw^SmY":;x@export default {
	props: {
		// tab的数据
		list: {
			type: Array,
			default: () => []
		},
		// 当前活动的tab的index
		current: {
			type: [String, Number],
			default: 0
		},
		// 激活的颜色
		activeColor: {
			type: String,
			default: '#3c9cff'
		},
		// 未激活的颜色
		inactiveColor: {
			type: String,
			default: '#303133'
		},
		// 模式选择，mode=button为按钮形式，mode=subsection时为分段模式
		mode: {
			type: String,
			default: 'button'
		},
		// 字体大小
		fontSize: {
			type: [String, Number],
			default: 12
		},
		// 激活tab的字体是否加粗
		bold: {
			type: Boolean,
			default: true
		},
		// mode = button时，组件背景颜色
		bgColor: {
			type: String,
			default: '#eeeeef'
		},
		// 从list元素对象中读取的键名
		keyName: {
			type: String,
			default: 'name'
		},
		customItemStyle: {
			type: [String, Object],
			default: ''
		},
		...uni.$uv?.props?.subsection
	}
}'dx$ <template>
	<view 
		class="uv-subsection"
		ref="uv-subsection"
		:class="[`uv-subsection--${mode}`]"
		:style="[$uv.addStyle(customStyle), wrapperStyle]">
		<view 
			class="uv-subsection__bar"
			ref="uv-subsection__bar"
			:style="[barStyle]"
			:class="[
        mode === 'button' && 'uv-subsection--button__bar',
        current === 0 && mode === 'subsection' && 'uv-subsection__bar--first',
        current > 0 && current < list.length - 1 && mode === 'subsection' && 'uv-subsection__bar--center',
        current === list.length - 1 && mode === 'subsection' && 'uv-subsection__bar--last'
      ]"
		></view>
		<view class="uv-subsection__item"
			:class="[
        `uv-subsection__item--${index}`,
        index < list.length - 1 && 'uv-subsection__item--no-border-right',
        index === 0 && 'uv-subsection__item--first',
        index === list.length - 1 && 'uv-subsection__item--last'
      ]"
			:ref="`uv-subsection__item--${index}`"
			:style="[itemStyle(index)]"
			@tap="clickHandler(index)"
			v-for="(item, index) in list"
			:key="index"
		>
			<text 
				class="uv-subsection__item__text"
				:style="[textStyle(index)]">{{ getText(item) }}
			</text>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin("dom");
	const animation = uni.requireNativePlugin("animation");
	// #endif
	import props from "./props.js";
	/**
	 * Subsection 分段器
	 * @description 该分段器一般用于用户从几个选项中选择某一个的场景
	 * @tutorial https://www.uvui.cn/components/subsection.html
	 * @property {Array}			list			tab的数据
	 * @property {String ｜ Number}	current			当前活动的tab的index（默认 0 ）
	 * @property {String}			activeColor		激活时的颜色（默认 '#3c9cff' ）
	 * @property {String}			inactiveColor	未激活时的颜色（默认 '#303133' ）
	 * @property {String}			mode			模式选择，mode=button为按钮形式，mode=subsection时为分段模式（默认 'button' ）
	 * @property {String ｜ Number}	fontSize		字体大小，单位px（默认 12 ）
	 * @property {Boolean}			bold			激活选项的字体是否加粗（默认 true ）
	 * @property {String}			bgColor			组件背景颜色，mode为button时有效（默认 '#eeeeef' ）
	 * @property {Object}			customStyle		定义需要用到的外部样式
	 * @property {String}	        keyName	        从`list`元素对象中读取的键名（默认 'name' ）
	 *
	 * @event {Function} change		分段器选项发生改变时触发  回调 index：选项的index索引值，从0开始
	 * @example <uv-subsection :list="list" :current="curNow" @change="sectionChange"></uv-subsection>
	 */
	export default {
		name: "uv-subsection",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 组件尺寸
				itemRect: {
					width: 0,
					height: 0,
				}
			}
		},
		watch: {
			list: {
				deep: true,
				handler(){
					this.init();
				}
			},
			current: {
				immediate: true,
				handler(n) {
					// #ifdef APP-NVUE
					// 在安卓nvue上，如果通过translateX进行位移，到最后一个时，会导致右侧无法绘制圆角
					// 故用animation模块进行位移
					const ref = this.$refs?.["uv-subsection__bar"]?.ref;
					// 不存在ref的时候(理解为第一次初始化时，需要渲染dom，进行一定延时再获取ref)，这里的100ms是经过测试得出的结果(某些安卓需要延时久一点)，勿随意修改
					this.$uv.sleep(ref ? 0 : 150).then(() => {
						animation.transition(this.$refs["uv-subsection__bar"].ref, {
							styles: {
								transform: `translateX(${ n * this.itemRect.width }px)`,
								transformOrigin: "center center"
							},
							duration: 300,
						});
					});
					// #endif
				}
			}
		},
		computed: {
			wrapperStyle() {
				const style = {};
				// button模式时，设置背景色
				if (this.mode === "button") {
					style.backgroundColor = this.bgColor;
				}
				return style;
			},
			// 滑块的样式
			barStyle() {
				const style = {};
				style.width = `${this.itemRect.width}px`;
				style.height = `${this.itemRect.height}px`;
				// 通过translateX移动滑块，其移动的距离为索引*item的宽度
				// #ifndef APP-NVUE
				style.transform = `translateX(${ this.current * this.itemRect.width }px)`;
				// #endif
				if (this.mode === "subsection") {
					// 在subsection模式下，需要动态设置滑块的圆角，因为移动滑块使用的是translateX，无法通过父元素设置overflow: hidden隐藏滑块的直角
					style.backgroundColor = this.activeColor;
				}
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customItemStyle));
			},
			// 分段器item的样式
			itemStyle(index) {
				return (index) => {
					const style = {};
					if (this.mode === "subsection") {
						// 设置border的样式
						style.borderColor = this.activeColor;
						style.borderWidth = "1px";
						style.borderStyle = "solid";
					}
					return style;
				};
			},
			// 分段器文字颜色
			textStyle(index) {
				return (index) => {
					const style = {};
					style.fontWeight = this.bold && this.current === index ? "bold" : "normal";
					style.fontSize = this.$uv.addUnit(this.fontSize);
					// subsection模式下，激活时默认为白色的文字
					if (this.mode === "subsection") {
						style.color = this.current === index ? "#fff" : this.inactiveColor;
					} else {
						// button模式下，激活时文字颜色默认为activeColor
						style.color = this.current === index ? this.activeColor : this.inactiveColor;
					}
					return style;
				};
			},
		},
		mounted() {
			this.init();
		},
		methods: {
			init() {
				this.$uv.sleep().then(() => this.getRect());
			},
			// 判断展示文本
			getText(item) {
				return typeof item === 'object' ? item[this.keyName] : item
			},
			// 获取组件的尺寸
			getRect() {
				// #ifndef APP-NVUE
				this.$uvGetRect(".uv-subsection__item--0").then((size) => {
					this.itemRect = size;
				});
				// #endif

				// #ifdef APP-NVUE
				const ref = this.$refs["uv-subsection__item--0"][0];
				ref && dom.getComponentRect(ref, (res) => {
					this.itemRect = res.size;
				});
				// #endif
			},
			clickHandler(index) {
				this.$emit("change", index);
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-subsection {
		@include flex;
		position: relative;
		overflow: hidden;
		/* #ifndef APP-NVUE */
		width: 100%;
		box-sizing: border-box;
		/* #endif */
		&--button {
			height: 32px;
			background-color: rgb(238, 238, 239);
			padding: 3px;
			border-radius: 3px;
			align-items: stretch;
			&__bar {
				background-color: #ffffff;
			}
		}
		&--subsection {
			height: 30px;
		}
		&__bar {
			position: absolute;
			/* #ifndef APP-NVUE */
			transition-property: transform, color;
			transition-duration: 0.3s;
			transition-timing-function: ease-in-out;
			/* #endif */
			&--first {
				border-top-left-radius: 3px;
				border-bottom-left-radius: 3px;
				border-top-right-radius: 0px;
				border-bottom-right-radius: 0px;
			}
			&--center {
				border-top-left-radius: 0px;
				border-bottom-left-radius: 0px;
				border-top-right-radius: 0px;
				border-bottom-right-radius: 0px;
			}
			&--last {
				border-top-left-radius: 0px;
				border-bottom-left-radius: 0px;
				border-top-right-radius: 3px;
				border-bottom-right-radius: 3px;
			}
		}
		&__item {
			@include flex;
			flex: 1;
			justify-content: center;
			align-items: center;
			// vue环境下，需要设置相对定位，因为滑块为绝对定位，item需要在滑块的上面
			position: relative;
			&--no-border-right {
				border-right-width: 0 !important;
			}
			&--first {
				border-top-left-radius: 3px;
				border-bottom-left-radius: 3px;
			}
			&--last {
				border-top-right-radius: 3px;
				border-bottom-right-radius: 3px;
			}
			&__text {
				font-size: 12px;
				line-height: 12px;
				@include flex;
				align-items: center;
				transition-property: color;
				transition-duration: 0.3s;
			}
		}
	}
</style>Usx 5D{
  "id": "uv-subsection",
  "displayName": "uv-subsection 分段器?`E该分段器组件一般用于用户从几个选项中选择某一个'
subsection!!subsection",
    "分段器\t	6c!x s## Subsection 分段器Uubsection**

该分段器一般用于用户从几个选项中选择某一个的场景2	ubsectionZM>	x e100644 changelog.md PC׍euw40000 components 4Ro^]?100644 package.json i,XhE%C100644 readme.md 1if>d59fN<Lx ~+## 1.0.4（2023-10-13）
1. 优化
## 1.0.3/x'27）
1. 不支持抖音小程序说明swipe-action 滑动单元格
;|xY 40000 uv-swipe-action-item g*	Iu40000 uv-swipe-action }W\2|աUC#8x100644 index - backup.wxs =bxJṅ8K100644 index.wxs e&5D$ǃ[9>Y100644 nvue - backup.js %d̈&ĿNk+100644 nvue.js nImt(ϮLh"SW100644 props.js [2#'pUw;Fύr100644 uv-swipe-action-item.vue Evd7;3100644 wxs.js I ^(<!?n]x8/**
 * 此为wxs模块，只支持APP-VUE，微信和QQ小程序以及H5平台
 * wxs内部不支持es6语法，变量只能使用var定义，无法使用解构，箭头函数等特性
 */

// 开始触摸
function touchstart(event, ownerInstance) {
	// 触发事件的组件的ComponentDescriptor实例
	var instance = event.instance
	// wxs内的局部变量快照，此快照是属于整个组件的，在touchstart和touchmove事件中都能获取到相同的结果
	var state = instance.getState()
	if (state.disabled) return
	var touches = event.touches
	// 如果进行的是多指触控，不允许进行操作
	if (touches && touches.length > 1) return
	// 标识当前为滑动中状态
	state.moving = true
	// 记录触摸开始点的坐标值
	state.startX = touches[0].pageX
	state.startY = touches[0].pageY
	
	ownerInstance.callMethod('closeOther')
}

// 触摸滑动
function touchmove(event, ownerInstance) {
	// 触发事件的组件的ComponentDescriptor实例
	var instance = event.instance
	// wxs内的局部变量快照
	var state = instance.getState()
	if (state.disabled || !state.moving) return
	var touches = event.touches
	var pageX = touches[0].pageX
	var pageY = touches[0].pageY
	var moveX = pageX - state.startX
	var moveY = pageY - state.startY
	var buttonsWidth = state.buttonsWidth

	// 移动的X轴距离大于Y轴距离，也即终点与起点位置连线，与X轴夹角小于45度时，禁止页面滚动
	if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > state.threshold) {
		event.preventDefault && event.preventDefault()
		event.stopPropagation && event.stopPropagation()
	}
	// 如果移动的X轴距离小于Y轴距离，也即终点位置与起点位置连线，与Y轴夹角小于45度时，认为是页面上下滑动，而不是左右滑动单元格
	if (Math.abs(moveX) < Math.abs(moveY)) return

	// 限制右滑的距离，不允许内容部分往右偏移，右滑会导致X轴偏移值大于0，以此做判断
	// 此处不能直接return，因为滑动过程中会缺失某些关键点坐标，会导致错乱，最好的办法就是
	// 在超出后，设置为0
	if (state.status === 'open') {
		// 在开启状态下，向左滑动，需忽略
		if (moveX < 0) moveX = 0
		// 想要收起菜单，最大能移动的距离为按钮的总宽度
		if (moveX > buttonsWidth) moveX = buttonsWidth
		// 如果是已经打开了的状态，向左滑动时，移动收起菜单
		moveSwipeAction(-buttonsWidth + moveX, instance, ownerInstance)
	} else {
		// 关闭状态下，右滑动需忽略
		if (moveX > 0) moveX = 0
		// 滑动的距离不允许超过所有按钮的总宽度，此时只能是左滑，最终设置按钮的总宽度，同时为负数
		if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth
		// 只要是在滑过程中，就不断移动单元格内容部分，从而使隐藏的菜单显示出来
		moveSwipeAction(moveX, instance, ownerInstance)
	}
}

// 触摸结束
function touchend(event, ownerInstance) {
	// 触发事件的组件的ComponentDescriptor实例
	var instance = event.instance
	// wxs内的局部变量快照
	var state = instance.getState()
	if (!state.moving || state.disabled) return
	var touches = event.changedTouches ? event.changedTouches[0] : {}
	var pageX = touches.pageX
	var pageY = touches.pageY
	var moveX = pageX - state.startX
	if (state.status === 'open') {
		// 在展开的状态下，继续左滑，无需操作
		if (moveX < 0) return
		// 在开启状态下，点击一下内容区域，moveX为0，也即没有进行移动，这时执行收起菜单逻辑
		if (moveX === 0) {
			return closeSwipeAction(instance, ownerInstance)
		}
		// 在开启状态下，滑动距离小于阈值，则默认为不关闭，同时恢复原来的打开状态
		if (Math.abs(moveX) < state.threshold) {
			openSwipeAction(instance, ownerInstance)
		} else {
			// 如果滑动距离大于阈值，则执行收起逻辑
			closeSwipeAction(instance, ownerInstance)
		}
	} else {
		// 在关闭的状态下，右滑，无需操作
		if (moveX > 0) return
		// 理由同上
		if (Math.abs(moveX) < state.threshold) {
			closeSwipeAction(instance, ownerInstance)
		} else {
			openSwipeAction(instance, ownerInstance)
		}
	}
}

// 获取过渡时间
function getDuration(value) {
	if (value.toString().indexOf('s') >= 0) return value
	return value > 30 ? value + 'ms' : value + 's'
}

// 滑动结束时判断滑动的方向
function getMoveDirection(instance, ownerInstance) {
	var state = instance.getState()
}

// 移动滑动选择器内容区域，同时显示出其隐藏的菜单
function moveSwipeAction(moveX, instance, ownerInstance) {
	var state = instance.getState()
	// 获取所有按钮的实例，需要通过它去设置按钮的位移
	var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button')

	// 设置菜单内容部分的偏移
	instance.requestAnimationFrame(function() {
		instance.setStyle({
			// 设置translateX的值
			'transition': 'none',
			transform: 'translateX(' + moveX + 'px)',
			'-webkit-transform': 'translateX(' + moveX + 'px)'
		})
	})
}

// 一次性展开滑动菜单
function openSwipeAction(instance, ownerInstance) {
	var state = instance.getState()
	// 获取所有按钮的实例，需要通过它去设置按钮的位移
	var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button')
	// 处理duration单位问题
	var duration = getDuration(state.duration)
	// 展开过程中，是向左移动，所以X的偏移应该为负值
	var buttonsWidth = -state.buttonsWidth
	instance.requestAnimationFrame(function() {
		// 设置菜单主体内容
		instance.setStyle({
			'transition': 'transform ' + duration,
			'transform': 'translateX(' + buttonsWidth + 'px)',
			'-webkit-transform': 'translateX(' + buttonsWidth + 'px)',
		})
	})
	setStatus('open', instance, ownerInstance)
}

// 标记菜单的当前状态，open-已经打开，close-已经关闭
function setStatus(status, instance, ownerInstance) {
	var state = instance.getState()
	state.status = status
	ownerInstance.callMethod('setState', status)
}

// 一次性收起滑动菜单
function closeSwipeAction(instance, ownerInstance) {
	var state = instance.getState()
	// 获取所有按钮的实例，需要通过它去设置按钮的位移
	var buttons = ownerInstance.selectAllComponents('.uv-swipe-action-item__right__button')
	var len = buttons.length
	// 处理duration单位问题
	var duration = getDuration(state.duration)
	instance.requestAnimationFrame(function() {
		// 设置菜单主体内容
		instance.setStyle({
			'transition': 'transform ' + duration,
			'transform': 'translateX(0px)',
			'-webkit-transform': 'translateX(0px)'
		})
		// 设置各个隐藏的按钮为收起的状态
		for (var i = len - 1; i >= 0; i--) {
			buttons[i].setStyle({
				'transition': 'transform ' + duration,
				'transform': 'translateX(0px)',
				'-webkit-transform': 'translateX(0px)'
			})
		}
	})
	setStatus('close', instance, ownerInstance)
}

// status的状态发生变化
function statusChange(newValue, oldValue, ownerInstance, instance) {
	var state = instance.getState()
	if (state.disabled) return
	// 打开或关闭单元格
	if (newValue === 'close' && state.status === 'open') {
		closeSwipeAction(instance, ownerInstance)
	} else if(newValue === 'open' && state.status === 'close') {
		openSwipeAction(instance, ownerInstance)
	}
}

// 菜单尺寸发生变化
function sizeChange(newValue, oldValue, ownerInstance, instance) {
	// wxs内的局部变量快照
	var state = instance.getState()
	state.disabled = newValue.disabled
	state.duration = newValue.duration
	state.show = newValue.show
	state.threshold = newValue.threshold
	state.buttons = newValue.buttons

	if (state.buttons) {
		var len = state.buttons.length
		var buttonsWidth = 0
		var buttons = newValue.buttons
		for (var i = 0; i < len; i++) {
			buttonsWidth += buttons[i].width
		}
	}
	state.buttonsWidth = buttonsWidth
}

module.exports = {
	touchstart: touchstart,
	touchmove: touchmove,
	touchend: touchend,
	sizeChange: sizeChange,
	statusChange: statusChange
}
N=YUxa?J	
,``"U	菜单的var previewButtonsMoveX = 0
	// 折叠按钮动画+c// 通过比例，得出元素自身该移动的距离
			var translateX = state.buttons[i].width / * moveX
			// 最终移动的距离，是通过自身比例算出的距离，再加上在它之前所有按钮移动的距离>和
			var realTranslateX = translateX + previewButtonsMoveX// 在移动期间，不能使用过渡效果，否则会造成卡顿，本质原因是每次移动一点，就要花一定时去过渡这个过程
	{brealTranslateX + 'px)',
	(realTranslateX + 'px)'
			})
			// 记录本按钮之前的所有按钮的移动距离之和
			previewButtonsMoveX += translateX
		} 9const=var previewButtonsMoveX = 0o|^N"展开v4c// 通过比例，得出元素自身该移动的距离
			var translateX = state.buttons[i].width / * buttonsWidth
			// 最终移动的距离，是通过自身比例算出的距离，再加上在它之前所有按钮移动的E距离之和
			var realTranslateX = translateX + previewButtonsMoveX-// 在移动期间，需要加上动画效果I' + realTranslateX + 'px)',
	(realTranslateX + 'px)'
			})
			// 记录本按钮之前的所有按钮的移动距离之和
			previewButtonsMoveX += translateX?p&Uconst=)q)
}

// show how) {
,	#+Sn 
if (len) {
}
kϪx.// nvue操作dom的库，用于获取dom的尺寸信息
const dom = uni.requireNativePlugin('dom')
// nvue中用于操作元素动画的库，类似于uni.animation，只不过uni.animation不能用于nvue
const animation = uni.requireNativePlugin('animation')
import { sleep } from '@/uni_modules/uv-ui-tools/libs/function/index.js'
export default {
    data() {
        return {
            // 是否滑动中
            moving: false,
            // 状态，open-打开状态，close-关闭状态
            status: 'close',
            // 开始触摸点的X和Y轴坐标
            startX: 0,
            startY: 0,
            // 所有隐藏按钮的尺寸信息数组
            buttons: [],
            // 所有按钮的总宽度
            buttonsWidth: 0,
            // 记录上一次移动的位置值
            moveX: 0,
            // 记录上一次滑动的位置，用于前后两次做对比，如果移动的距离小于某一阈值，则认为前后之间没有移动，为了解决可能存在的通信阻塞问题
            lastX: 0
        }
    },
    computed: {
        // 获取过渡时间
        getDuratin() {
            let duration = String(this.duration)
            // 如果ms为单位，返回ms的数值部分
            if (duration.indexOf('ms') >= 0) return parseInt(duration)
            // 如果s为单位，为了得到ms的数值，需要乘以1000
            if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000
            // 如果值传了数值，且小于30，认为是s单位
            duration = Number(duration)
            return duration < 30 ? duration * 1000 : duration
        }
    },
    watch: {
        show: {
            immediate: true,
            handler(n) {
                
            }
        }
    },
    mounted() {
        sleep(20).then(() => {
            this.queryRect()
        })
    },
    methods: {
        close() {
            this.closeSwipeAction()
        },
        // 触摸单元格
        touchstart(event) {
            if (this.disabled) return
            this.closeOther()
            const { touches } = event
            // 记录触摸开始点的坐标值
            this.startX = touches[0].pageX
            this.startY = touches[0].pageY
        },
        // // 触摸滑动
        touchmove(event) {
            if (this.disabled) return
            const { touches } = event
            const { pageX } = touches[0]
            const { pageY } = touches[0]
            let moveX = pageX - this.startX
            const moveY = pageY - this.startY
            const { buttonsWidth } = this
            const len = this.buttons.length

            // 判断前后两次的移动距离，如果小于一定值，则不进行移动处理
            if (Math.abs(pageX - this.lastX) < 0.3) return
            this.lastX = pageX

            // 移动的X轴距离大于Y轴距离，也即终点与起点位置连线，与X轴夹角小于45度时，禁止页面滚动
            if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > this.threshold) {
                event.stopPropagation()
            }
            // 如果移动的X轴距离小于Y轴距离，也即终点位置与起点位置连线，与Y轴夹角小于45度时，认为是页面上下滑动，而不是左右滑动单元格
            if (Math.abs(moveX) < Math.abs(moveY)) return

            // 限制右滑的距离，不允许内容部分往右偏移，右滑会导致X轴偏移值大于0，以此做判断
            // 此处不能直接return，因为滑动过程中会缺失某些关键点坐标，会导致错乱，最好的办法就是
            // 在超出后，设置为0
            if (this.status === 'open') {
                // 在开启状态下，向左滑动，需忽略
                if (moveX < 0) moveX = 0
                // 想要收起菜单，最大能移动的距离为按钮的总宽度
                if (moveX > buttonsWidth) moveX = buttonsWidth
                // 如果是已经打开了的状态，向左滑动时，移动收起菜单
                this.moveSwipeAction(-buttonsWidth + moveX)
            } else {
                // 关闭状态下，右滑动需忽略
                if (moveX > 0) moveX = 0
                // 滑动的距离不允许超过所有按钮的总宽度，此时只能是左滑，最终设置按钮的总宽度，同时为负数
                if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth
                // 只要是在滑过程中，就不断移动菜单的内容部分，从而使隐藏的菜单显示出来
                this.moveSwipeAction(moveX)
            }
        },
        // 单元格结束触摸
        touchend(event) {
            if (this.disabled) return
            const touches = event.changedTouches ? event.changedTouches[0] : {}
            const { pageX } = touches
            const { pageY } = touches
            const { buttonsWidth } = this
            this.moveX = pageX - this.startX
            if (this.status === 'open') {
                // 在展开的状态下，继续左滑，无需操作
                if (this.moveX < 0) this.moveX = 0
                if (this.moveX > buttonsWidth) this.moveX = buttonsWidth
                // 在开启状态下，点击一下内容区域，moveX为0，也即没有进行移动，这时执行收起菜单逻辑
                if (this.moveX === 0) {
                    return this.closeSwipeAction()
                }
                // 在开启状态下，滑动距离小于阈值，则默认为不关闭，同时恢复原来的打开状态
                if (Math.abs(this.moveX) < this.threshold) {
                    this.openSwipeAction()
                } else {
                    // 如果滑动距离大于阈值，则执行收起逻辑
                    this.closeSwipeAction()
                }
            } else {
                // 在关闭的状态下，右滑，无需操作
                if (this.moveX >= 0) this.moveX = 0
                if (this.moveX <= -buttonsWidth) this.moveX = -buttonsWidth
                // 理由同上
                if (Math.abs(this.moveX) < this.threshold) {
                    this.closeSwipeAction()
                } else {
                    this.openSwipeAction()
                }
            }
        },
        // 移动滑动选择器内容区域，同时显示出其隐藏的菜单
        moveSwipeAction(moveX) {
            if (this.moving) return
            this.moving = true

            let previewButtonsMoveX = 0
            const len = this.buttons.length
            animation.transition(this.$refs['uv-swipe-action-item__content'].ref, {
                styles: {
                    transform: `translateX(${moveX}px)`
                },
                timingFunction: 'linear'
            }, () => {
                this.moving = false
            })
            // 按钮的组的长度
            for (let i = len - 1; i >= 0; i--) {
                const buttonRef = this.$refs[`uv-swipe-action-item__right__button-${i}`][0].ref
                // 通过比例，得出元素自身该移动的距离
                const translateX = this.buttons[i].width / this.buttonsWidth * moveX
                // 最终移动的距离，是通过自身比例算出的距离，再加上在它之前所有按钮移动的距离之和
                const realTranslateX = translateX + previewButtonsMoveX
                animation.transition(buttonRef, {
                    styles: {
                        transform: `translateX(${realTranslateX}px)`
                    },
                    duration: 0,
                    delay: 0,
                    timingFunction: 'linear'
                }, () => {})
                // 记录本按钮之前的所有按钮的移动距离之和
                previewButtonsMoveX += translateX
            }
        },
        // 关闭菜单
        closeSwipeAction() {
            if (this.status === 'close') return
            this.moving = true
            const { buttonsWidth } = this
            animation.transition(this.$refs['uv-swipe-action-item__content'].ref, {
                styles: {
                    transform: 'translateX(0px)'
                },
                duration: this.getDuratin,
                timingFunction: 'ease-in-out'
            }, () => {
                this.status = 'close'
                this.moving = false
                this.closeHandler()
            })
            // 按钮的组的长度
            const len = this.buttons.length
            for (let i = len - 1; i >= 0; i--) {
                const buttonRef = this.$refs[`uv-swipe-action-item__right__button-${i}`][0].ref
                // 如果不满足边界条件，返回
                if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return

                animation.transition(buttonRef, {
                    styles: {
                        transform: 'translateX(0px)'
                    },
                    duration: this.getDuratin,
                    timingFunction: 'ease-in-out'
                }, () => {})
            }
        },
        // 打开菜单
        openSwipeAction() {
            if (this.status === 'open') return
            this.moving = true
            const buttonsWidth = -this.buttonsWidth
            let previewButtonsMoveX = 0
            animation.transition(this.$refs['uv-swipe-action-item__content'].ref, {
                styles: {
                    transform: `translateX(${buttonsWidth}px)`
                },
                duration: this.getDuratin,
                timingFunction: 'ease-in-out'
            }, () => {
                this.status = 'open'
                this.moving = false
                this.openHandler()
            })
            // 按钮的组的长度
            const len = this.buttons.length
            for (let i = len - 1; i >= 0; i--) {
                const buttonRef = this.$refs[`uv-swipe-action-item__right__button-${i}`][0].ref
                // 如果不满足边界条件，返回
                if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return
                // 通过比例，得出元素自身该移动的距离
                const translateX = this.buttons[i].width / this.buttonsWidth * buttonsWidth
                // 最终移动的距离，是通过自身比例算出的距离，再加上在它之前所有按钮移动的距离之和
                const realTranslateX = translateX + previewButtonsMoveX
                animation.transition(buttonRef, {
                    styles: {
                        transform: `translateX(${realTranslateX}px)`
                    },
                    duration: this.getDuratin,
                    timingFunction: 'ease-in-out'
                }, () => {})
                previewButtonsMoveX += translateX
            }
        },
        // 查询按钮节点信息
        queryRect() {
            // 历遍所有按钮数组，通过getRectByDom返回一个promise
            const promiseAll = this.rightOptions.map((item, index) => this.getRectByDom(this.$refs[`uv-swipe-action-item__right__button-${index}`][0]))
            // 通过promise.all方法，让所有按钮的查询结果返回一个数组的形式
            Promise.all(promiseAll).then((sizes) => {
                this.buttons = sizes
                // 计算所有按钮总宽度
                this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0)
            })
        },
        // 通过nvue的dom模块，查询节点信息
        getRectByDom(ref) {
            return new Promise((resolve) => {
                dom.getComponentRect(ref, (res) => {
                    resolve(res.size)
                })
            })
        }
    }
}
c'x// nvue操作dom的库，用于获取dom的尺寸信息
const dom = uni.requireNativePlugin('dom');
const bindingX = uni.requireNativePlugin('bindingx');
const animation = uni.requireNativePlugin('animation');
import { getDuration, getPx } from '@/uni_modules/uv-ui-tools/libs/function/index.js'
export default {
	data() {
		return {
			// 所有按钮的总宽度
			buttonsWidth: 0,
			// 是否正在移动中
			moving: false
		}
	},
	computed: {
		// 获取过渡时间
		getDuratin() {
			let duration = String(this.duration)
			// 如果ms为单位，返回ms的数值部分
			if (duration.indexOf('ms') >= 0) return parseInt(duration)
			// 如果s为单位，为了得到ms的数值，需要乘以1000
			if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000
			// 如果值传了数值，且小于30，认为是s单位
			duration = Number(duration)
			return duration < 30 ? duration * 1000 : duration
		}
	},
	watch: {
		show(n) {
			if(n) {
				this.moveCellByAnimation('open') 
			} else {
				this.moveCellByAnimation('close') 
			}
		}
	},
	mounted() {
		setTimeout(()=>{
			this.initialize()
		},20)
	},
	methods: {
		initialize() {
			this.queryRect() 
		},
		// 关闭单元格，用于打开一个，自动关闭其他单元格的场景
		closeHandler() {
			if(this.status === 'open') {
				// 如果在打开状态下，进行点击的话，直接关闭单元格
				return this.moveCellByAnimation('close') && this.unbindBindingX()
			}
		},
		// 点击单元格
		clickHandler() {
			// 如果在移动中被点击，进行忽略
			if(this.moving) return
			// 尝试关闭其他打开的单元格
			this.parent && this.parent.closeOther(this)
			if(this.status === 'open') {
				// 如果在打开状态下，进行点击的话，直接关闭单元格
				return this.moveCellByAnimation('close') && this.unbindBindingX()
			}
		},
		// 滑动单元格
		onTouchstart(e) {
			// 如果当前正在移动中，或者disabled状态，则返回
			if(this.moving || this.disabled) { 
				return this.unbindBindingX()   
			}
			if(this.status === 'open') {
				// 如果在打开状态下，进行点击的话，直接关闭单元格
				return this.moveCellByAnimation('close') && this.unbindBindingX()
			}
			// 特殊情况下，e可能不为一个对象
			e?.stopPropagation && e.stopPropagation() 
			e?.preventDefault && e.preventDefault()
			this.moving = true
			// 获取元素ref
			const content = this.getContentRef()
			let expression = `min(max(${-this.buttonsWidth}, x), 0)`
			// 尝试关闭其他打开的单元格
			this.parent && this.parent.closeOther(this)
			// 阿里为了KPI而开源的BindingX
			this.panEvent = bindingX.bind({
				anchor: content,
				eventType: 'pan',
				props: [{
					element: content,
					// 绑定width属性，设置其宽度值
					property: 'transform.translateX',
					expression
				}]
			}, (res) => {
				this.moving = false
				if (res.state === 'end' || res.state === 'exit') {
					const deltaX = res.deltaX
					if(deltaX <= -this.buttonsWidth || deltaX >= 0) {
						// 如果触摸滑动的过程中，大于单元格的总宽度，或者大于0，意味着已经动过滑动达到了打开或者关闭的状态
						// 这里直接进行状态的标记
						this.$nextTick(() => {
							this.status = deltaX <= -this.buttonsWidth ? 'open' : 'close'
						})
					} else if(Math.abs(deltaX) > getPx(this.threshold)) {
						// 在移动大于阈值、并且小于总按钮宽度时，进行自动打开或者关闭
						// 移动距离大于0时，意味着需要关闭状态
						if(Math.abs(deltaX) < this.buttonsWidth) {
							this.moveCellByAnimation(deltaX > 0 ? 'close' : 'open')
						}
					} else {
						// 在小于阈值时，进行关闭操作(如果在打开状态下，将不会执行bindingX)
						this.moveCellByAnimation('close')
					}
				}
			})
		},
		// 释放bindingX
		unbindBindingX() {
			// 释放上一次的资源
			if (this?.panEvent?.token != 0) {
				bindingX.unbind({
					token: this.panEvent?.token,
					// pan为手势事件
					eventType: 'pan'
				})
			}
		},
		// 查询按钮节点信息
		queryRect() {
			// 历遍所有按钮数组，通过getRectByDom返回一个promise
			const promiseAll = this.options.map(async(item, index) => {
				return await this.getRectByDom(this.$refs[`uv-swipe-action-item__right__button-${index}`][0])
			})
			// 通过promise.all方法，让所有按钮的查询结果返回一个数组的形式
			Promise.all(promiseAll).then(sizes => {
				this.buttons = sizes
				// 计算所有按钮总宽度
				this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0)
			})
		},
		// 通过nvue的dom模块，查询节点信息
		getRectByDom(ref) {
			return new Promise(resolve => {
				dom.getComponentRect(ref, res => {
					resolve(res.size)
				})
			}) 
		},
		// 移动单元格到左边或者右边尽头
		moveCellByAnimation(status = 'open') {
			if(this.moving) return
			// 标识当前状态
			this.moveing = true
			const content = this.getContentRef()
			const x = status === 'open' ? -this.buttonsWidth : 0 
			animation.transition(content, {
				styles: {
					transform: `translateX(${x}px)`,
				},
				duration: getDuration(this.duration, false),
				timingFunction: 'ease-in-out'
			}, () => {
				this.moving = false
				this.status = status
				this.unbindBindingX()
			})
		},
		// 获取元素ref
		getContentRef() {
			return this.$refs['uv-swipe-action-item__content'].ref
		}
	},
	// #ifdef VUE2
	beforeDestroy() {
		this.unbindBindingX()
	},
	// #endif
	// #ifdef VUE3
	unmounted() {
		this.unbindBindingX()
	}
	// #endif
}

.xexport default {
	props: {
		// 控制打开或者关闭
		show: {
			type: Boolean,
			default: false
		},
		// 标识符，如果是v-for，可用index索引值
		name: {
			type: [String, Number],
			default: ''
		},
		// 是否禁用
		disabled: {
			type: Boolean,
			default: false
		},
		// 是否自动关闭其他swipe按钮组
		autoClose: {
			type: Boolean,
			default: true
		},
		// 滑动距离阈值，只有大于此值，才被认为是要打开菜单
		threshold: {
			type: Number,
			default: 20
		},
		// 右侧按钮内容
		options: {
			type: Array,
			default: () => []
		},
		// 动画过渡时间，单位ms
		duration: {
			type: [String, Number],
			default: 300
		},
		...uni.$uv?.props?.swipeActionItem
	}
}k,x<template>
	<view class="uv-swipe-action-item" ref="uv-swipe-action-item">
		<view class="uv-swipe-action-item__right">
			<slot name="button">
				<view v-for="(item,index) in options" :key="index" class="uv-swipe-action-item__right__button"
					:ref="`uv-swipe-action-item__right__button-${index}`" :style="[{
						alignItems: item.style && item.style.borderRadius ? 'center' : 'stretch'
					}]" @tap="buttonClickHandler(item, index)">
					<view class="uv-swipe-action-item__right__button__wrapper" :style="[{
							backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',
							borderRadius: item.style && item.style.borderRadius ? item.style.borderRadius : '0',
							padding: item.style && item.style.borderRadius ? '0' : '0 15px',
						}, item.style]">
						<uv-icon v-if="item.icon" :name="item.icon"
							:color="item.style && item.style.color ? item.style.color : '#ffffff'"
							:size="item.iconSize ? $uv.addUnit(item.iconSize) : item.style && item.style.fontSize ? $uv.getPx(item.style.fontSize) * 1.2 : 17"
							:customStyle="{
								marginRight: item.text ? '2px' : 0
							}"></uv-icon>
						<text v-if="item.text" class="uv-swipe-action-item__right__button__wrapper__text uv-line-1"
							:style="[{
								color: item.style && item.style.color ? item.style.color : '#ffffff',
								fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px',
								lineHeight: item.style && item.style.fontSize ? item.style.fontSize : '16px',
							}]">{{ item.text }}</text>
					</view>
				</view>
			</slot>
		</view>
		<!-- #ifndef APP-NVUE -->
		<view class="uv-swipe-action-item__content" @touchstart="wxs.touchstart" @touchmove="wxs.touchmove"
			@touchend="wxs.touchend" :status="status" :change:status="wxs.statusChange" :size="size"
			:change:size="wxs.sizeChange">
			<!-- #endif -->
			<!-- #ifdef APP-NVUE -->
			<view class="uv-swipe-action-item__content" ref="uv-swipe-action-item__content" @panstart="onTouchstart"
				@tap="clickHandler">
				<!-- #endif -->
				<slot />
			</view>
		</view>
</template>
<!-- #ifdef APP-VUE || MP-WEIXIN || H5 || MP-QQ -->
<script src="./index.wxs" module="wxs" lang="wxs"></script>
<!-- #endif -->
<script>
	import touch from '@/uni_modules/uv-ui-tools/libs/mixin/touch.js'
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	import nvue from './nvue.js';
	// #endif
	// #ifdef APP-VUE || MP-WEIXIN || H5 || MP-QQ
	import wxs from './wxs.js';
	// #endif
	/**
	 * SwipeActionItem 滑动单元格子组件
	 * @description 该组件一般用于左滑唤出操作菜单的场景，用的最多的是左滑删除操作
	 * @tutorial https://www.uvui.cn/components/swipeAction.html
	 * @property {Boolean}			show			控制打开或者关闭（默认 false ）
	 * @property {String | Number}	index			标识符，如果是v-for，可用index索引
	 * @property {Boolean}			disabled		是否禁用（默认 false ）
	 * @property {Boolean}			autoClose		是否自动关闭其他swipe按钮组（默认 true ）
	 * @property {Number}			threshold		滑动距离阈值，只有大于此值，才被认为是要打开菜单（默认 30 ）
	 * @property {Array}			options			右侧按钮内容
	 * @property {String | Number}	duration		动画过渡时间，单位ms（默认 350 ）
	 * @event {Function(index)}	open	组件打开时触发
	 * @event {Function(index)}	close	组件关闭时触发
	 * @example	<uv-swipe-action><uv-swipe-action-item :options="options1" ></uv-swipe-action-item></uv-swipe-action>
	 */
	export default {
		name: 'uv-swipe-action-item',
		emits: ['click'],
		// #ifndef APP-NVUE
		mixins: [mpMixin, mixin, props, touch],
		// #endif
		// #ifdef APP-NVUE
		mixins: [mpMixin, mixin, props, nvue , touch],
		// #endif
		// #ifdef APP-VUE || MP-WEIXIN || H5 || MP-QQ
		mixins: [mpMixin, mixin, props, touch, wxs],
		// #endif
		data() {
			return {
				// 按钮的尺寸信息
				size: {},
				// 父组件uv-swipe-action的参数
				parentData: {
					autoClose: true,
				},
				// 当前状态，open-打开，close-关闭
				status: 'close',
			}
		},
		watch: {
			// 由于wxs无法直接读取外部的值，需要在外部值变化时，重新执行赋值逻辑
			wxsInit(newValue, oldValue) {
				this.queryRect()
			}
		},
		computed: {
			wxsInit() {
				return [this.disabled, this.autoClose, this.threshold, this.options, this.duration]
			}
		},
		mounted() {
			// #ifdef MP-TOUTIAO
			this.$uv.error('抖音小程序暂不支持wxs，故该组件暂不支持抖音小程序');
			// #endif
			this.init()
		},
		methods: {
			init() {
				// 初始化父组件数据
				this.updateParentData()
				// #ifndef APP-NVUE
				this.$uv.sleep().then(() => {
					this.queryRect()
				})
				// #endif
			},
			updateParentData() {
				// 此方法在mixin中
				this.getParentData('uv-swipe-action')
			},
			// #ifndef APP-NVUE
			// 查询节点
			queryRect() {
				this.$uvGetRect('.uv-swipe-action-item__right__button', true).then(buttons => {
					this.size = {
						buttons,
						show: this.show,
						disabled: this.disabled,
						threshold: this.threshold,
						duration: this.duration
					}
				})
			},
			// #endif
			// 按钮被点击
			buttonClickHandler(item, index) {
				this.$emit('click', {
					index,
					name: this.name
				})
			}
		},
	}
</script>

<style lang="scss" scoped>
	$show-lines: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-swipe-action-item {
		position: relative;
		overflow: hidden;
		/* #ifndef APP-NVUE || MP-WEIXIN */
		touch-action: pan-y;
		/* #endif */

		&__content {
			background-color: #FFFFFF;
			z-index: 10;
		}

		&__right {
			position: absolute;
			top: 0;
			bottom: 0;
			right: 0;
			@include flex;

			&__button {
				@include flex;
				justify-content: center;
				overflow: hidden;
				align-items: center;

				&__wrapper {
					@include flex;
					align-items: center;
					justify-content: center;
					padding: 0 15px;

					&__text {
						@include flex;
						align-items: center;
						color: #FFFFFF;
						font-size: 15px;
						text-align: center;
						justify-content: center;
					}
				}
			}
		}
	}
</style>
x]export default {
    methods: {
        // 关闭时执行
        closeHandler() {
            this.status = 'close'
        },
        setState(status) {
            this.status = status
        },
        closeOther() {
            // 尝试关闭其他打开的单元格
            this.parent && this.parent.closeOther(this)
        }
    }
}
pܣxS 100644 props.js }v_6cnh)100644 uv-swipe-action.vue >OI."	f/ҪvX?
x \export default {
	props: {
		// 是否自动关闭其他swipe按钮组
		autoClose: {
			type: Boolean,
			default: true
		},
		...uni.$uv?.props?.swipeAction
	}
}?xj<template>
	<view class="uv-swipe-action">
		<slot></slot>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * SwipeAction 滑动单元格 
	 * @description 该组件一般用于左滑唤出操作菜单的场景，用的最多的是左滑删除操作
	 * @tutorial https://www.uvui.cn/components/swipeAction.html
	 * @property {Boolean}	autoClose	是否自动关闭其他swipe按钮组
	 * @event {Function(index)}	click	点击组件时触发
	 * @example	<uv-swipe-action><uv-swipe-action-item :rightOptions="options1" ></uv-swipe-action-item></uv-swipe-action>
	 */
	export default {
		name: 'uv-swipe-action',
		mixins: [mpMixin, mixin, props],
		data() {
			return {}
		},
		provide() {
			return {
				swipeAction: this
			}
		},
		computed: {
			// 这里computed的变量，都是子组件uv-swipe-action-item需要用到的，由于头条小程序的兼容性差异，子组件无法实时监听父组件参数的变化
			// 所以需要手动通知子组件，这里返回一个parentData变量，供watch监听，在其中去通知每一个子组件重新从父组件(uv-swipe-action-item)
			// 拉取父组件新的变化后的参数
			parentData() {
				return [this.autoClose]
			}
		},
		watch: {
			// 当父组件需要子组件需要共享的参数发生了变化，手动通知子组件
			parentData() {
				if (this.children.length) {
					this.children.map(child => {
						// 判断子组件(uv-swipe-action-item)如果有updateParentData方法的话，就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
						typeof(child.updateParentData) === 'function' && child.updateParentData()
					})
				}
			},
		},
		created() {
			this.children = []
		},
		methods: {
			closeOther(child) {
				if (this.autoClose) {
					// 历遍所有的单元格，找出非当前操作中的单元格，进行关闭
					this.children.map((item, index) => {
						if (child !== item) {
							item.closeHandler()
						}
					})
				}
			}
		}
	}
</script>
DxN{
  "id": "uv-swipe-action",
  "displayName": "uv-swipe-action 滑动单元格?J4",
  "description": "滑动单元格组件一般用于左滑唤出操作菜单的场景，用的最多的是左滑删除操作swipe-action!!#swipe-action",
    "滑动单元格\icqm .	x e100644 changelog.md 0lcZ940000 components Xfzj48c+100644 package.json a$;k͔O3100644 readme.md Us< zA`x>$xO## 1.0.6（2023-12-20）
1. 优化
## 1.0.5（2023-08-24）
1. 修复标题文字过多未隐藏掉的BUG
## 1.0.4（2023-07-24）
1. 增加 滑动方向是否为纵向  属性vertical
## 1.0.3（2023-06-27）
1. 增加titleStyle属性，方便修改标题样式
2. 标题上去掉是否是图片的判断，避免无后缀的图片不显示
## 1.0.2（2023-06-01）
1. 修复点击触发两次事件的BUG 
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-swiper 轮播图，走马灯
>xR 40000 uv-swiper-indicator aC_P{:'G_a"O}40000 uv-swiper t9,	`a_ŧxW 100644 props.js 0Zp1)5|100644 uv-swiper-indicator.vue &7b=\1N&i^8!7x # 轮播的长度
		lengG-@0
		},
		// 当前处于活动状态的轮播的索引
		currentI+0)/-o	'Ina,o	=// 指示器模式，line-线型，dot-点型
		indicatorMode"owiperIndicator
	}
}f޳x<template>
	<view class="uv-swiper-indicator">
		<view
			class="uv-swiper-indicator__wrapper"
			v-if="indicatorMode === 'line'"
			:class="[`uv-swiper-indicator__wrapper--${indicatorMode}`]"
			:style="{
				width: $uv.addUnit(lineWidth * length),
				backgroundColor: indicatorInactiveColor
			}"
		>
			<view
				class="uv-swiper-indicator__wrapper--line__bar"
				:style="[lineStyle]"
			></view>
		</view>
		<view
			class="uv-swiper-indicator__wrapper"
			v-if="indicatorMode === 'dot'"
		>
			<view
				class="uv-swiper-indicator__wrapper__dot"
				v-for="(item, index) in length"
				:key="index"
				:class="[index === current && 'uv-swiper-indicator__wrapper__dot--active']"
				:style="[dotStyle(index)]"
			>

			</view>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * SwiperIndicator 轮播图指示器
	 * @description 该组件一般用于导航轮播，广告展示等场景,可开箱即用，
	 * @tutorial https://www.uvui.cn/components/swiper.html
	 * @property {String | Number}	length					轮播的长度（默认 0 ）
	 * @property {String | Number}	current					当前处于活动状态的轮播的索引（默认 0 ）
	 * @property {String}			indicatorActiveColor	指示器非激活颜色
	 * @property {String}			indicatorInactiveColor	指示器的激活颜色
	 * @property {String}			indicatorMode			指示器模式（默认 'line' ）
	 * @example	<uv-swiper :list="list4" indicator keyName="url" :autoplay="false"></uv-swiper>
	 */
	export default {
		name: 'uv-swiper-indicator',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				lineWidth: 22
			}
		},
		computed: {
			// 指示器为线型的样式
			lineStyle() {
				let style = {}
				style.width = this.$uv.addUnit(this.lineWidth)
				style.transform = `translateX(${ this.$uv.addUnit(this.current * this.lineWidth) })`
				style.backgroundColor = this.indicatorActiveColor
				return style
			},
			// 指示器为点型的样式
			dotStyle() {
				return index => {
					let style = {}
					style.backgroundColor = index === this.current ? this.indicatorActiveColor : this.indicatorInactiveColor
					return style
				}
			}
		},
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-swiper-indicator {

		&__wrapper {
			@include flex;

			&--line {
				border-radius: 100px;
				height: 4px;

				&__bar {
					width: 22px;
					height: 4px;
					border-radius: 100px;
					background-color: #FFFFFF;
					transition: transform 0.3s;
				}
			}

			&__dot {
				width: 5px;
				height: 5px;
				border-radius: 100px;
				margin: 0 4px;

				&--active {
					width: 12px;
				}
			}

		}
	}
</style>
1HxM 100644 props.js fxvG\|sꏡ客Z5100644 uv-swiper.vue FnZ}<h8W3,"0xnexport default {
	props: {
		// 列表数组，元素可为字符串，如为对象可通过keyName指定目标属性名
		list: {
			type: Array,
			default: () => []
		},
		// 是否显示面板指示器
		indicator: {
			type: Boolean,
			default: false
		},
		// 指示器非激活颜色
		indicatorActiveColor: {
			type: String,
			default: '#fff'
		},
		// 指示器的激活颜色
		indicatorInactiveColor: {
			type: String,
			default: 'rgba(255, 255, 255, 0.35)'
		},
		// 指示器样式，可通过bottom，left，right进行定位
		indicatorStyle: {
			type: [String, Object],
			default: ''
		},
		// 指示器模式，line-线型，dot-点型
		indicatorMode: {
			type: String,
			default: 'line'
		},
		// 是否自动切换
		autoplay: {
			type: Boolean,
			default: true
		},
		// 当前所在滑块的 index
		current: {
			type: [String, Number],
			default: 0
		},
		// 当前所在滑块的 item-id ，不能与 current 被同时指定
		currentItemId: {
			type: String,
			default: ''
		},
		// 滑块自动切换时间间隔
		interval: {
			type: [String, Number],
			default: 3000
		},
		// 滑块切换过程所需时间
		duration: {
			type: [String, Number],
			default: 300
		},
		// 播放到末尾后是否重新回到开头
		circular: {
			type: Boolean,
			default: false
		},
		// 滑动方向是否为纵向
		vertical: {
			type: Boolean,
			default: false
		},
		// 前边距，可用于露出前一项的一小部分，nvue和支付宝不支持
		previousMargin: {
			type: [String, Number],
			default: 0
		},
		// 后边距，可用于露出后一项的一小部分，nvue和支付宝不支持
		nextMargin: {
			type: [String, Number],
			default: 0
		},
		// 当开启时，会根据滑动速度，连续滑动多屏，支付宝不支持
		acceleration: {
			type: Boolean,
			default: false
		},
		// 同时显示的滑块数量，nvue、支付宝小程序不支持
		displayMultipleItems: {
			type: Number,
			default: 1
		},
		// 指定swiper切换缓动动画类型，有效值：default、linear、easeInCubic、easeOutCubic、easeInOutCubic
		// 只对微信小程序有效
		easingFunction: {
			type: String,
			default: 'default'
		},
		// list数组中指定对象的目标属性名
		keyName: {
			type: String,
			default: 'url'
		},
		// 图片的裁剪模式
		imgMode: {
			type: String,
			default: 'aspectFill'
		},
		// 组件高度
		height: {
			type: [String, Number],
			default: 130
		},
		// 背景颜色
		bgColor: {
			type: String,
			default: '#f3f4f6'
		},
		// 组件圆角，数值或带单位的字符串
		radius: {
			type: [String, Number],
			default: 4
		},
		// 是否加载中
		loading: {
			type: Boolean,
			default: false
		},
		// 是否显示标题，要求数组对象中有title属性
		showTitle: {
			type: Boolean,
			default: false
		},
		// 显示的标题样式
		titleStyle: {
			type: [Object, String],
			default: ''
		},
		...uni.$uv?.props?.swiper
	}
}Rkx"<template>
	<view
		class="uv-swiper"
		:style="{
			backgroundColor: bgColor,
			height: $uv.addUnit(height),
			borderRadius: $uv.addUnit(radius)
		}"
	>
		<view
			class="uv-swiper__loading"
			v-if="loading"
		>
			<uv-loading-icon mode="circle"></uv-loading-icon>
		</view>
		<swiper
			v-else
			class="uv-swiper__wrapper"
			:style="{
				height: $uv.addUnit(height),
				flex: 1
			}"
			@change="change"
			:circular="circular"
			:vertical="vertical"
			:interval="interval"
			:duration="duration"
			:autoplay="autoplay"
			:current="current"
			:currentItemId="currentItemId"
			:previousMargin="$uv.addUnit(previousMargin)"
			:nextMargin="$uv.addUnit(nextMargin)"
			:acceleration="acceleration"
			:displayMultipleItems="displayMultipleItems"
			:easingFunction="easingFunction"
		>
			<swiper-item
				class="uv-swiper__wrapper__item"
				v-for="(item, index) in list"
				:key="index"
			>
				<view
					class="uv-swiper__wrapper__item__wrapper"
					:style="[itemStyle(index)]"
				>
					<!-- 在nvue中，image图片的宽度默认为屏幕宽度，需要通过flex:1撑开，另外必须设置高度才能显示图片 -->
					<image
						class="uv-swiper__wrapper__item__wrapper__image"
						v-if="getItemType(item) === 'image'"
						:src="getSource(item)"
						:mode="imgMode"
						@tap="clickHandler(index)"
						:style="{
							height: $uv.addUnit(height),
							borderRadius: $uv.addUnit(radius)
						}"
					></image>
					<video
						class="uv-swiper__wrapper__item__wrapper__video"
						v-if="getItemType(item) === 'video'"
						:id="`video-${index}`"
						:enable-progress-gesture="false"
						:src="getSource(item)"
						:poster="getPoster(item)"
						:title="showTitle && $uv.test.object(item) && item.title ? item.title : ''"
						:style="{
							height: $uv.addUnit(height)
						}"
						controls
						@tap="clickHandler(index)"
					></video>
					<text
						v-if="showTitle && $uv.test.object(item) && item.title"
						class="uv-swiper__wrapper__item__wrapper__title uv-line-1"
						:style="[$uv.addStyle(titleStyle)]"
					>{{ item.title }}</text>
				</view>
			</swiper-item>
		</swiper>
		<view class="uv-swiper__indicator" :style="[$uv.addStyle(indicatorStyle)]">
			<slot name="indicator">
				<uv-swiper-indicator
					v-if="!loading && indicator && !showTitle"
					:indicatorActiveColor="indicatorActiveColor"
					:indicatorInactiveColor="indicatorInactiveColor"
					:length="list.length"
					:current="currentIndex"
					:indicatorMode="indicatorMode"
				></uv-swiper-indicator>
			</slot>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Swiper 轮播图
	 * @description 该组件一般用于导航轮播，广告展示等场景,可开箱即用，
	 * @tutorial https://www.uvui.cn/components/swiper.html
	 * @property {Array}			list					轮播图数据
	 * @property {Boolean}			indicator				是否显示面板指示器（默认 false ）
	 * @property {String}			indicatorActiveColor	指示器非激活颜色（默认 '#FFFFFF' ）
	 * @property {String}			indicatorInactiveColor	指示器的激活颜色（默认 'rgba(255, 255, 255, 0.35)' ）
	 * @property {String | Object}	indicatorStyle			指示器样式，可通过bottom，left，right进行定位
	 * @property {String}			indicatorMode			指示器模式（默认 'line' ）
	 * @property {Boolean}			autoplay				是否自动切换（默认 true ）
	 * @property {String | Number}	current					当前所在滑块的 index（默认 0 ）
	 * @property {String}			currentItemId			当前所在滑块的 item-id ，不能与 current 被同时指定
	 * @property {String | Number}	interval				滑块自动切换时间间隔（ms）（默认 3000 ）
	 * @property {String | Number}	duration				滑块切换过程所需时间（ms）（默认 300 ）
	 * @property {Boolean}			circular				播放到末尾后是否重新回到开头（默认 false ）
	 * @property {String | Number}	previousMargin			前边距，可用于露出前一项的一小部分，nvue和支付宝不支持（默认 0 ）
	 * @property {String | Number}	nextMargin				后边距，可用于露出后一项的一小部分，nvue和支付宝不支持（默认 0 ）
	 * @property {Boolean}			acceleration			当开启时，会根据滑动速度，连续滑动多屏，支付宝不支持（默认 false ）
	 * @property {Number}			displayMultipleItems	同时显示的滑块数量，nvue、支付宝小程序不支持（默认 1 ）
	 * @property {String}			easingFunction			指定swiper切换缓动动画类型， 只对微信小程序有效（默认 'default' ）
	 * @property {String}			keyName					list数组中指定对象的目标属性名（默认 'url' ）
	 * @property {String}			imgMode					图片的裁剪模式（默认 'aspectFill' ）
	 * @property {String | Number}	height					组件高度（默认 130 ）
	 * @property {String}			bgColor					背景颜色（默认 	'#f3f4f6' ）
	 * @property {String | Number}	radius					组件圆角，数值或带单位的字符串（默认 4 ）
	 * @property {Boolean}			loading					是否加载中（默认 false ）
	 * @property {Boolean}			showTitle				是否显示标题，要求数组对象中有title属性（默认 false ）
	 * @event {Function(index)}	click	点击轮播图时触发	index：点击了第几张图片，从0开始
	 * @event {Function(index)}	change	轮播图切换时触发(自动或者手动切换)	index：切换到了第几张图片，从0开始
	 * @example	<uv-swiper :list="list4" keyName="url" :autoplay="false"></uv-swiper>
	 */
	export default {
		name: 'uv-swiper',
		mixins: [mpMixin, mixin, props],
		emits: ['click','change'],
		data() {
			return {
				currentIndex: 0
			}
		},
		watch: {
			current(val, preVal) {
				if(val === preVal) return;
				this.currentIndex = val; // 和上游数据关联上
			}
		},
		computed: {
			itemStyle() {
				return index => {
					const style = {}
					// #ifndef APP-NVUE || MP-TOUTIAO
					// 左右流出空间的写法不支持nvue和头条
					// 只有配置了此二值，才加上对应的圆角，以及缩放
					if (this.nextMargin && this.previousMargin) {
						style.borderRadius = this.$uv.addUnit(this.radius)
						if (index !== this.currentIndex) style.transform = 'scale(0.92)'
					}
					// #endif
					return style
				}
			}
		},
		methods: {
      getItemType(item) {
        if (typeof item === 'string') return this.$uv.test.video(this.getSource(item)) ? 'video' : 'image'
        if (typeof item === 'object' && this.keyName) {
          if (!item.type) return this.$uv.test.video(this.getSource(item)) ? 'video' : 'image'
          if (item.type === 'image') return 'image'
          if (item.type === 'video') return 'video'
          return 'image'
        }
      },
			// 获取目标路径，可能数组中为字符串，对象的形式，额外可指定对象的目标属性名keyName
			getSource(item) {
				if (typeof item === 'string') return item
				if (typeof item === 'object' && this.keyName) return item[this.keyName]
				else this.$uv.error('请按格式传递列表参数')
				return ''
			},
			// 轮播切换事件
			change(e) {
				// 当前的激活索引
				const {
					current
				} = e.detail
				this.pauseVideo(this.currentIndex)
				this.currentIndex = current
				this.$emit('change', e.detail)
			},
			// 切换轮播时，暂停视频播放
			pauseVideo(index) {
				const lastItem = this.getSource(this.list[index])
				if (this.$uv.test.video(lastItem)) {
					// 当视频隐藏时，暂停播放
					const video = uni.createVideoContext(`video-${index}`, this)
					video.pause()
				}
			},
			// 当一个轮播item为视频时，获取它的视频海报
			getPoster(item) {
				return typeof item === 'object' && item.poster ? item.poster : ''
			},
			// 点击某个item
			clickHandler(index) {
				this.$emit('click', index)
			}
		},
	}
</script>

<style lang="scss" scoped>
	$show-lines: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-swiper {
		@include flex;
		justify-content: center;
		align-items: center;
		position: relative;
		overflow: hidden;

		&__wrapper {
			flex: 1;

			&__item {
				flex: 1;

				&__wrapper {
					@include flex;
					position: relative;
					overflow: hidden;
					transition: transform 0.3s;
					flex: 1;

					&__image {
						flex: 1;
					}

					&__video {
						flex: 1;
					}

					&__title {
						position: absolute;
						background-color: rgba(0, 0, 0, 0.3);
						bottom: 0;
						left: 0;
						right: 0;
						font-size: 28rpx;
						height: 60rpx;
						line-height: 60rpx;
						color: #FFFFFF;
						flex: 1;
					}
				}
			}
		}

		&__indicator {
			position: absolute;
			bottom: 10px;
		}
	}
</style>
9ȥ-x {
  "id": "uv-swipswiper 轮播图TH6",
  "description": "该组件为轮播、跑马灯，支持卡片式。一般用于导航轮播，广告展示等场景，开	箱即用.swipS#轮播图",
    "走马灯loading-icon
uȢLx =## Swiper 轮播图 

> **组件名：uv-swiper**

该组件为轮播、跑马灯，支持卡片式。一般用于导航轮播-广告展示等场景，开箱即用。

# (swiper{AYsͪ	x e100644 changelog.md e\
O,{P>r40000 components YLaaG@100644 package.json + ս(ݛgPR;100644 readme.md }Mʁ[uמiu:@x&## 1.0.5（2023-09-21）
1. 优化细节
## 1.0.4（2023-08-23）
1. 取消value传值，只能使用v-model传值，避免异步操作不生效的BUG
## 1.0.3（2023-07-13）
1. 修复  uv-switch设置value属性不生效的BUG
## 1.0.2（2023-06-19）
1. size属性兼容和单位一起使用

## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-switch 开关选择器
Kۤx$ 40000 uv-switch s{E4+%nV|bW_֭xM 100644 props.js s}ڧB%A?100644 uv-switch.vue Ic\LvS;{䟗m!%xU<template>
	<view
	  class="uv-switch"
	  :class="[disabled && 'uv-switch--disabled']"
	  :style="[switchStyle, $uv.addStyle(customStyle)]"
	  @tap="clickHandler"
	>
		<view
		  class="uv-switch__bg"
		  :style="[bgStyle]"
		>
		</view>
		<view
		  class="uv-switch__node"
		  :class="[innerValue && 'uv-switch__node--on']"
		  :style="[nodeStyle]"
		  ref="uv-switch__node"
		>
			<uv-loading-icon
			  :show="loading"
			  mode="circle"
			  timingFunction='linear'
			  :color="innerValue ? activeColor : '#AAABAD'"
			  :size="size * 0.6"
			/>
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * switch 开关选择器
	 * @description 选择开关一般用于只有两个选择，且只能选其一的场景。
	 * @tutorial https://www.uvui.cn/components/switch.html
	 * @property {Boolean}						loading			是否处于加载中（默认 false ）
	 * @property {Boolean}						disabled		是否禁用（默认 false ）
	 * @property {String | Number}				size			开关尺寸，单位px （默认 25 ）
	 * @property {String}						activeColor		打开时的背景色 （默认 '#2979ff' ）
	 * @property {String} 						inactiveColor	关闭时的背景色 （默认 '#ffffff' ）
	 * @property {Boolean | String | Number}	value			通过v-model双向绑定的值 （默认 false ）
	 * @property {Boolean | String | Number}	activeValue		打开选择器时通过change事件发出的值 （默认 true ）
	 * @property {Boolean | String | Number}	inactiveValue	关闭选择器时通过change事件发出的值 （默认 false ）
	 * @property {Boolean}						asyncChange		是否开启异步变更，开启后需要手动控制输入值 （默认 false ）
	 * @property {String | Number}				space			圆点与外边框的距离 （默认 0 ）
	 * @property {Object}						customStyle		定义需要用到的外部样式
	 *
	 * @event {Function} change 在switch打开或关闭时触发
	 * @example <uv-switch v-model="checked" active-color="red" inactive-color="#eee"></uv-switch>
	 */
	export default {
		name: "uv-switch",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				bgColor: '#ffffff',
				innerValue: false
			}
		},
		watch: {
			// #ifdef VUE2
			value: {
				immediate: true,
				handler(newVal) {
					if (newVal !== this.inactiveValue && newVal !== this.activeValue) {
						return this.$uv.error('v-model绑定的值必须为inactiveValue、activeValue二者之一')
					}
					this.innerValue = newVal;
				}
			},
			// #endif
			// #ifndef VUE2
			modelValue: {
				immediate: true,
				handler(newVal) {
					if (newVal !== this.inactiveValue && newVal !== this.activeValue) {
						return this.$uv.error('v-model绑定的值必须为inactiveValue、activeValue二者之一')
					}
					this.innerValue = newVal;
				}
			}
			// #endif
		},
		created() {
			this.innerValue = this.value || this.modelValue;
		},
		computed: {
			isActive() {
				return this.innerValue === this.activeValue;
			},
			switchStyle() {
				let style = {}
				// 这里需要加2，是为了腾出边框的距离，否则圆点node会和外边框紧贴在一起
				style.width = this.$uv.addUnit(this.$uv.getPx(this.size) * 2 + 2)
				style.height = this.$uv.addUnit(this.$uv.getPx(this.size) + 2)
				// 如果自定义了“非激活”演示，name边框颜色设置为透明(跟非激活颜色一致)
				// 这里不能简单的设置为非激活的颜色，否则打开状态时，会有边框，所以需要透明
				if (this.customInactiveColor) {
					style.borderColor = 'rgba(0, 0, 0, 0)'
				}
				style.backgroundColor = this.isActive ? this.activeColor : this.inactiveColor
				return style;
			},
			nodeStyle() {
				let style = {}
				// 如果自定义非激活颜色，将node圆点的尺寸减少两个像素，让其与外边框距离更大一点
				style.width = this.$uv.addUnit(this.$uv.getPx(this.size) - this.space)
				style.height = this.$uv.addUnit(this.$uv.getPx(this.size) - this.space)
				const translateX = this.isActive ? this.$uv.addUnit(this.space) : this.$uv.addUnit(this.$uv.getPx(this.size));
				style.transform = `translateX(-${translateX})`
				return style
			},
			bgStyle() {
				let style = {}
				// 这里配置一个多余的元素在HTML中，是为了让switch切换时，有更良好的背景色扩充体验(见实际效果)
				style.width = this.$uv.addUnit(this.$uv.getPx(this.size) * 2 - this.$uv.getPx(this.size) / 2)
				style.height = this.$uv.addUnit(this.$uv.getPx(this.size))
				style.backgroundColor = this.inactiveColor
				// 打开时，让此元素收缩，否则反之
				style.transform = `scale(${this.isActive ? 0 : 1})`
				return style
			},
			customInactiveColor() {
				// 之所以需要判断是否自定义了“非激活”颜色，是为了让node圆点离外边框更宽一点的距离
				return this.inactiveColor !== '#fff' && this.inactiveColor !== '#ffffff'
			}
		},
		methods: {
			clickHandler() {
				if (!this.disabled && !this.loading) {
					const oldValue = this.isActive ? this.inactiveValue : this.activeValue
					if (!this.asyncChange) {
						this.$emit('input', oldValue)
						this.$emit('update:modelValue', oldValue)
					}
					// 放到下一个生命周期，因为双向绑定的value修改父组件状态需要时间，且是异步的
					this.$nextTick(() => {
						this.$emit('change', oldValue)
					})
				}
			}
		}
	};
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-switch {
		@include flex(row);
		/* #ifndef APP-NVUE */
		box-sizing: border-box;
		/* #endif */
		position: relative;
		background-color: #fff;
		border-width: 1px;
		border-radius: 100px;
		transition: background-color 0.4s;
		border-color: rgba(0, 0, 0, 0.12);
		border-style: solid;
		justify-content: flex-end;
		align-items: center;
		// 由于weex为阿里逗着玩的KPI项目，导致bug奇多，这必须要写这一行，
		// 否则在iOS上，点击页面任意地方，都会触发switch的点击事件
		overflow: hidden;
		&__node {
			@include flex(row);
			align-items: center;
			justify-content: center;
			border-radius: 100px;
			background-color: #fff;
			border-radius: 100px;
			box-shadow: 1px 1px 1px 0 rgba(0, 0, 0, 0.25);
			transition-property: transform;
			transition-duration: 0.4s;
			transition-timing-function: cubic-bezier(0.3, 1.05, 0.4, 1.05);
		}
		&__bg {
			position: absolute;
			border-radius: 100px;
			background-color: #FFFFFF;
			transition-property: transform;
			transition-duration: 0.4s;
			border-top-left-radius: 0;
			border-bottom-left-radius: 0;
			transition-timing-function: ease;
		}
		&--disabled {
			opacity: 0.6;
		}
	}
</style>ʤCx $B{
  "id": "uv-switch",
  "displayName": "uv-switch 开关选择器=^Q选择开关用于在打开和关闭状态之间进行切换，支持异步操作;switcha!switch",
    "开关选择器loading9o]	x e100644 changelog.md %͋#}ܧ40000 components {a [4g6FGV100644 package.json A%{o	0.b100644 readme.md T`/ɔ~?1Ym?xf## 1.0.5（2023-07-17）
1. 优化文档
2. 优化其他
## 1.0.4（2023-06-13）
1. 底部安全距离依赖添加
## 1.0.3（2023-06-09）
1. 增加iconSize参数
## 1.0.2（2023-06-01）
1. 修复点击触发两次事件的BUG 
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-tabbar 底部导航栏 
bΠxM 40000 uv-tabbar-item #H[hv߯A~#40000 uv-tabbar _	k|%U7R5u8nKqxR 100644 props.js y"jҺ2c_j{2x100644 uv-tabbar-item.vue e\Ԩ',WZ7 * xP<template>
	<view
	    class="uv-tabbar-item"
	    :style="[$uv.addStyle(customStyle)]"
	    @tap="clickHandler"
	>
		<view class="uv-tabbar-item__icon">
			<uv-icon
			    v-if="icon"
			    :name="icon"
			    :color="isActive? parentData.activeColor : parentData.inactiveColor"
			    :size="iconSize? iconSize: parentData.iconSize"
			></uv-icon>
			<template v-else>
				<slot
				    v-if="isActive"
				    name="active-icon"
				/>
				<slot
				    v-else
				    name="inactive-icon"
				/>
			</template>
			<uv-badge
				absolute
				:offset="[0, dot ? '34rpx' : badge > 9 ? '14rpx' : '20rpx']"
			    :customStyle="badgeStyle"
			    :isDot="dot"
			    :value="badge || (dot ? 1 : null)"
			    :show="dot || badge > 0"
			></uv-badge>
		</view>
		
		<slot name="text">
			<text
			    class="uv-tabbar-item__text"
			    :style="{
					color: isActive? parentData.activeColor : parentData.inactiveColor
				}"
			>{{ text }}</text>
		</slot>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * TabbarItem 底部导航栏子组件
	 * @description 此组件提供了自定义tabbar的能力。
	 * @tutorial https://www.uvui.cn/components/tabbar.html
	 * @property {String | Number}	name		item标签的名称，作为与uv-tabbar的value参数匹配的标识符
	 * @property {String}			icon		uvui内置图标或者绝对路径的图片
	 * @property {String | Number}	badge		右上角的角标提示信息
	 * @property {Boolean}			dot			是否显示圆点，将会覆盖badge参数（默认 false ）
	 * @property {String}			text		描述文本
	 * @property {Object | String}	badgeStyle	控制徽标的位置，对象或者字符串形式，可以设置top和right属性（默认 'top: 6px;right:2px;' ）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * 
	 * @example <uv-tabbar :value="value2" :placeholder="false" @change="name => value2 = name" :fixed="false" :safeAreaInsetBottom="false"><uv-tabbar-item text="首页" icon="home" dot ></uv-tabbar-item></uv-tabbar>
	 */
	export default {
		name: 'uv-tabbar-item',
		mixins: [mpMixin, mixin, props],
		emits: ['click','change'],
		data() {
			return {
				isActive: false, // 是否处于激活状态
				parentData: {
					value: null,
					activeColor: '',
					inactiveColor: '',
					iconSize: 20
				}
			}
		},
		created() {
			this.init()
		},
		methods: {
			init() {
				// 支付宝小程序不支持provide/inject，所以使用这个方法获取整个父组件，在created定义，避免循环引用
				this.updateParentData()
				if (!this.parent) {
					this.$uv.error('uv-tabbar-item必须搭配uv-tabbar组件使用')
				}
				// 本子组件在uv-tabbar的children数组中的索引
				const index = this.parent.children.indexOf(this)
				// 判断本组件的name(如果没有定义name，就用index索引)是否等于父组件的value参数
				this.isActive = (this.name || index) === this.parentData.value
			},
			updateParentData() {
				// 此方法在mixin中
				this.getParentData('uv-tabbar')
			},
			// 此方法将会被父组件uv-tabbar调用
			updateFromParent() {
				// 重新初始化
				this.init()
			},
			clickHandler() {
				this.$nextTick(() => {
					const index = this.parent.children.indexOf(this)
					const name = this.name || index
					// 点击的item为非激活的item才发出change事件
					if (name !== this.parent.value) {
						this.parent.$emit('change', name)
					}
					this.$emit('click', name)
				})
			}
		},
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-tabbar-item {
		@include flex(column);
		align-items: center;
		justify-content: center;
		flex: 1;
		
		&__icon {
			@include flex;
			position: relative;
			width: 150rpx;
			justify-content: center;
		}

		&__text {
			margin-top: 2px;
			font-size: 12px;
			color: $uv-content-color;
		}
	}

	/* #ifdef MP */
	// 由于小程序都使用shadow DOM形式实现，需要给影子宿主设置flex: 1才能让其撑开
	:host {
		flex: 1
	}
	/* #endif */
</style>
`xM 100644 props.js b
	d*=Eиϫj100644 uv-tabbar.vue iN>&uf}4xl 当前匹配项的name
		valueb, null],
			default: null
		},
		// 是否为iPhoneX留出底部安全距离
		safeAreaInsetBottom"I方g1I元素层级z-index
		zIndex+*9
		},
		// 选中标签的颜色
		active7(51989fa'
		},
		// 未选中标签的颜色
		inactive7(7d7e80'底<fixed定位固定在底'<I图标大小
		i~<...uni.$uv?.props?.tabbar
	}
}ث x<template>
	<view class="uv-tabbar">
		<view
		    class="uv-tabbar__content"
		    ref="uv-tabbar__content"
		    @touchmove.stop.prevent="noop"
		    :class="[border && 'uv-border-top', fixed && 'uv-tabbar--fixed']"
		    :style="[tabbarStyle]"
		>
			<view class="uv-tabbar__content__item-wrapper">
				<slot />
			</view>
			<uv-safe-bottom v-if="safeAreaInsetBottom"></uv-safe-bottom>
		</view>
		<view
		    class="uv-tabbar__placeholder"
			v-if="placeholder"
		    :style="{
				height: placeholderHeight + 'px',
			}"
		></view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * Tabbar 底部导航栏
	 * @description 此组件提供了自定义tabbar的能力。
	 * @tutorial https://www.uvui.cn/components/tabbar.html
	 * @property {String | Number}	value				当前匹配项的name
	 * @property {Boolean}			safeAreaInsetBottom	是否为iPhoneX留出底部安全距离（默认 true ）
	 * @property {Boolean}			border				是否显示上方边框（默认 true ）
	 * @property {String | Number}	zIndex				元素层级z-index（默认 1 ）
	 * @property {String}			activeColor			选中标签的颜色（默认 '#1989fa' ）
	 * @property {String}			inactiveColor		未选中标签的颜色（默认 '#7d7e80' ）
	 * @property {Boolean}			fixed				是否固定在底部（默认 true ）
	 * @property {Boolean}			placeholder			fixed定位固定在底部时，是否生成一个等高元素防止塌陷（默认 true ）
	 * @property {Object}			customStyle			定义需要用到的外部样式
	 * 
	 * @example <uv-tabbar :value="value2" :placeholder="false" @change="name => value2 = name" :fixed="false" :safeAreaInsetBottom="false"><uv-tabbar-item text="首页" icon="home" dot ></uv-tabbar-item></uv-tabbar>
	 */
	export default {
		name: 'uv-tabbar',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				placeholderHeight: 0
			}
		},
		computed: {
			tabbarStyle() {
				const style = {
					zIndex: this.zIndex
				}
				// 合并来自父组件的customStyle样式
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			},
			// 监听多个参数的变化，通过在computed执行对应的操作
			updateChild() {
				return [this.value, this.activeColor, this.inactiveColor]
			},
			updatePlaceholder() {
				return [this.fixed, this.placeholder]
			}
		},
		watch: {
			updateChild() {
				// 如果updateChildren中的元素发生了变化，则执行子元素初始化操作
				this.updateChildren()
			},
			updatePlaceholder() {
				// 如果fixed，placeholder等参数发生变化，重新计算占位元素的高度
				this.setPlaceholderHeight()
			}
		},
		created() {
			this.children = []
		},
		mounted() {
			this.setPlaceholderHeight()
		},
		methods: {
			updateChildren() {
				// 如果存在子元素，则执行子元素的updateFromParent进行更新数据
				this.children.length && this.children.map(child => child.updateFromParent())
			},
			// 设置用于防止塌陷元素的高度
			async setPlaceholderHeight() {
				if (!this.fixed || !this.placeholder) return
				// 延时一定时间
				await this.$uv.sleep(20)
				// #ifndef APP-NVUE
				this.$uvGetRect('.uv-tabbar__content').then(({height = 50}) => {
					// 修复IOS safearea bottom 未填充高度
					this.placeholderHeight = height
				})
				// #endif

				// #ifdef APP-NVUE
				dom.getComponentRect(this.$refs['uv-tabbar__content'], (res) => {
					const {
						size
					} = res
					this.placeholderHeight = size.height
				})
				// #endif
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-border: 1;
	$show-border-top: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-tabbar {
		@include flex(column);
		flex: 1;
		justify-content: center;
		
		&__content {
			@include flex(column);
			background-color: #fff;
			
			&__item-wrapper {
				height: 50px;
				@include flex(row);
			}
		}

		&--fixed {
			position: fixed;
			bottom: 0;
			left: 0;
			right: 0;
		}
	}
</style>
"]i
x {
  "id": "uv-tabtabbar 底部<Q5",
  "description": "底部导航栏组件提供了自定义tabbar的能力，可以满足某些需要鉴权跳转等场景。.tabL$tabbar",
    "底部badge",
			"uv-safe-bottom
`u_ɠaxh## Tabbar 底部导航栏tabbar**

此组件提供了自定义`tabbar`的能力。

一般固定在底部，可以满足某些需要鉴权跳转等场。一旦自定义底部导航栏后，为了达到不闪烁的效果，建议在`tabbar`页面进行组件切换。

# <a hre"tabbarv+pan style="font-size:14px;font-weight:700;"#pan;J	x e100644 changelog.md K%gb&[O140000 components  eEsΊiσ100644 package.json oTr dQؗbv100644 readme.md J\<v ^;g>M2x/## 1.0.9（2023-12-01）
1. 修复current为字符串activeStyle不生效的BUG
2. 优化文档
## 1.0.8（2023-10-13）
1. 优化点击一个选项，change事件重复派发的问题
## 1.0.7（2023-09-14）
1. 优化首次加载时，处理下划线会有左到右的过渡效果
## 1.0.6（2023-09-13）
1. 修复设置lineWidth未带单位产生的误差BUG
## 1.0.5（2023-06-23）
添加uv-icon依赖
## 1.0.4（2023-06-16）
1. 增加customStyle参数
## 1.0.3（2023-06-12）
1. activeStyle设置字体大小，导致下划线位置不对的BUG，增加this.$nextTick机制
## 1.0.2（2023-05-23）
1. 修复nvue中不滚动的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-tabs 标签选项卡
Ѫkx" 40000 uv-tabs <Bϛ^)f
,U)xK 100644 props.js )c\>(ד100644 uv-tabs.vue ϼ;pT#WFmLx1export default {
	props: {
		// 滑块的移动过渡时间，单位ms
		duration: {
			type: Number,
			default: 300
		},
		// tabs标签数组
		list: {
			type: Array,
			default: () => []
		},
		// 滑块颜色
		lineColor: {
			type: String,
			default: '#3c9cff'
		},
		// 菜单选择中时的样式
		activeStyle: {
			type: [String, Object],
			default: () => ({
				color: '#303133'
			})
		},
		// 菜单非选中时的样式
		inactiveStyle: {
			type: [String, Object],
			default: () => ({
				color: '#606266'
			})
		},
		// 滑块长度
		lineWidth: {
			type: [String, Number],
			default: 20
		},
		// 滑块高度
		lineHeight: {
			type: [String, Number],
			default: 3
		},
		// 滑块背景显示大小，当滑块背景设置为图片时使用
		lineBgSize: {
			type: String,
			default: 'cover'
		},
		// 菜单item的样式
		itemStyle: {
			type: [String, Object],
			default: () => ({
				height: '44px'
			})
		},
		// 菜单是否可滚动
		scrollable: {
			type: Boolean,
			default: true
		},
		// 当前选中标签的索引
		current: {
			type: [Number, String],
			default: 0
		},
		// 默认读取的键名
		keyName: {
			type: String,
			default: 'name'
		},
		...uni.$uv?.props?.tabs
	}
}˽x2B<template>
	<view class="uv-tabs" :style="[$uv.addStyle(customStyle)]">
		<view class="uv-tabs__wrapper">
			<slot name="left" />
			<view class="uv-tabs__wrapper__scroll-view-wrapper">
				<scroll-view
					:scroll-x="scrollable"
					:scroll-left="scrollLeft"
					scroll-with-animation
					class="uv-tabs__wrapper__scroll-view"
					:show-scrollbar="false"
					ref="uv-tabs__wrapper__scroll-view"
				>
					<view
						class="uv-tabs__wrapper__nav"
						ref="uv-tabs__wrapper__nav"
						:style="{
							flex: scrollable ? '' : 1
						}"
					>
						<view
							class="uv-tabs__wrapper__nav__item"
							v-for="(item, index) in list"
							:key="index"
							@tap="clickHandler(item, index)"
							:ref="`uv-tabs__wrapper__nav__item-${index}`"
							:style="[{flex: scrollable ? '' : 1},$uv.addStyle(itemStyle)]"
							:class="[`uv-tabs__wrapper__nav__item-${index}`, item.disabled && 'uv-tabs__wrapper__nav__item--disabled']"
						>
							<text
								:class="[item.disabled && 'uv-tabs__wrapper__nav__item__text--disabled']"
								class="uv-tabs__wrapper__nav__item__text"
								:style="[textStyle(index)]"
							>{{ item[keyName] }}</text>
							<uv-badge
								:show="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))"
								:isDot="item.badge && item.badge.isDot || propsBadge.isDot"
								:value="item.badge && item.badge.value || propsBadge.value"
								:max="item.badge && item.badge.max || propsBadge.max"
								:type="item.badge && item.badge.type || propsBadge.type"
								:showZero="item.badge && item.badge.showZero || propsBadge.showZero"
								:bgColor="item.badge && item.badge.bgColor || propsBadge.bgColor"
								:color="item.badge && item.badge.color || propsBadge.color"
								:shape="item.badge && item.badge.shape || propsBadge.shape"
								:numberType="item.badge && item.badge.numberType || propsBadge.numberType"
								:inverted="item.badge && item.badge.inverted || propsBadge.inverted"
								customStyle="margin-left: 4px;"
							></uv-badge>
						</view>
						<!-- #ifdef APP-NVUE -->
						<view
							class="uv-tabs__wrapper__nav__line"
							ref="uv-tabs__wrapper__nav__line"
							:style="[{
								width: $uv.addUnit(lineWidth),
								height: firstTime?0:$uv.addUnit(lineHeight),
								background: lineColor,
								backgroundSize: lineBgSize
							}]"
						>
						<!-- #endif -->
						<!-- #ifndef APP-NVUE -->
						<view
							class="uv-tabs__wrapper__nav__line"
							ref="uv-tabs__wrapper__nav__line"
							:style="[{
									width: $uv.addUnit(lineWidth),
									transform: `translate(${lineOffsetLeft}px)`,
									transitionDuration: `${firstTime ? 0 : duration}ms`,
									height: firstTime?0:$uv.addUnit(lineHeight),
									background: lineColor,
									backgroundSize: lineBgSize,
								}]"
						>
						<!-- #endif -->
						</view>
					</view>
				</scroll-view>
			</view>
			<slot name="right" />
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import uvBadgeProps from '@/uni_modules/uv-badge/components/uv-badge/props.js'
	// #ifdef APP-NVUE
	const animation = uni.requireNativePlugin('animation')
	const dom = uni.requireNativePlugin('dom')
	// #endif
	import props from './props.js';
	/**
	 * Tabs 标签
	 * @description tabs标签组件，在标签多的时候，可以配置为左右滑动，标签少的时候，可以禁止滑动。 该组件的一个特点是配置为滚动模式时，激活的tab会自动移动到组件的中间位置。
	 * @tutorial https://www.uvui.cn/components/tabs.html
	 * @property {Array}	list	标签数组，元素为对象，如[{name: '推荐'}]
	 * @property {String | Number}	duration			滑块移动一次所需的时间，单位秒（默认 200 ）
	 * @property {String | Object} activeStyle	菜单选择中时的样式（默认{ color: '#303133' }）
	 * @property {String | Object} inactiveStyle	菜单非选择中时的样式（默认{ color: '#606266' }）
	 * @property {String | Number} lineWidth	滑块长度（默认 20）
	 * @property {String | Number} lineHeight	滑块高度（默认 3）
	 * @property {String}	lineColor	滑块颜色（默认：'#3c9cff'）
	 * @property {String} lineBgSize	滑块背景显示大小，当滑块背景设置为图片时使用（默认 cover）
	 * @property {String | Number} itemStyle	菜单item的样式（默认 { height: '44px' }）
	 * @property {String}	scrollable	菜单是否可滚动，选项很少的时候设置为false整个tabs自动居中显示（默认：true）
	 * @property {String | Number}	current	当前选中标签的索引（默认 0 ）
	 * @property {String}	keyName	从list元素对象中读取的键名（默认 'name' ）
	 * @property {String | Number}	swierWidth			swiper的宽度（默认 '750rpx' ）
	 * @property {String | Object}	customStyle	 自定义外部样式
	 * 
	 * @event {Function(index)} change 标签改变时触发 index: 点击了第几个tab，索引从0开始
	 * @event {Function(index)} click 点击标签时触发 index: 点击了第几个tab，索引从0开始
	 * @example <uv-tabs :list="list" :is-scroll="false" :current="current" @change="change"></uv-tabs>
	 */
	export default {
		name: 'uv-tabs',
		emits: ['click','change'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				firstTime: true,
				scrollLeft: 0,
				scrollViewWidth: 0,
				lineOffsetLeft: 0,
				tabsRect: {
					left: 0
				},
				innerCurrent: 0,
				moving: false,
			}
		},
		watch: {
			current: {
				immediate: true,
				handler (newValue, oldValue) {
					// 内外部值不相等时，才尝试移动滑块
					if (newValue !== this.innerCurrent) {
						this.innerCurrent = newValue
						this.$nextTick(() => {
							this.resize()
						})
					}
				}
			},
			// list变化时，重新渲染list各项信息
			list() {
				this.$nextTick(() => {
					this.resize()
				})
			}
		},
		computed: {
			textStyle() {
				return index => {
					const style = {}
					// 取当期是否激活的样式
					const customeStyle = index == this.innerCurrent ? this.$uv.addStyle(this.activeStyle) : this.$uv
						.addStyle(
							this.inactiveStyle)
					// 如果当前菜单被禁用，则加上对应颜色，需要在此做处理，是因为nvue下，无法在style样式中通过!import覆盖标签的内联样式
					if (this.list[index].disabled) {
						style.color = '#c8c9cc'
					}
					return this.$uv.deepMerge(customeStyle, style)
				}
			},
			propsBadge() {
				return uvBadgeProps
			}
		},
		async mounted() {
			this.init()
		},
		methods: {
			setLineLeft() {
				const tabItem = this.list[this.innerCurrent];
				if (!tabItem) {
					return;
				}
				// 获取滑块该移动的位置
				let lineOffsetLeft = this.list
					.slice(0, this.innerCurrent)
					.reduce((total, curr) => total + curr.rect.width, 0);
        // 获取下划线的数值px表示法
				let lineWidth = this.$uv.getPx(this.lineWidth);
				// 如果传的值未带单位+设置了全局单位，则带上单位计算，这样才没有误差
				if (this.$uv.test.number(this.lineWidth) && this.$uv.unit) {
					lineWidth = this.$uv.getPx(`${this.lineWidth}${this.$uv.unit}`);
				}
				this.lineOffsetLeft = lineOffsetLeft + (tabItem.rect.width - lineWidth) / 2
				// #ifdef APP-NVUE
				// 第一次移动滑块，无需过渡时间
				this.animation(this.lineOffsetLeft, this.firstTime ? 0 : parseInt(this.duration))
				// #endif

				// 如果是第一次执行此方法，让滑块在初始化时，瞬间滑动到第一个tab item的中间
				// 这里需要一个定时器，因为在非nvue下，是直接通过style绑定过渡时间，需要等其过渡完成后，再设置为false(非第一次移动滑块)
				if (this.firstTime) {
					setTimeout(() => {
						this.firstTime = false
					}, 20);
				}
			},
			// nvue下设置滑块的位置
			animation(x, duration = 0) {
				// #ifdef APP-NVUE
				const ref = this.$refs['uv-tabs__wrapper__nav__line']
				animation.transition(ref, {
					styles: {
						transform: `translateX(${x}px)`
					},
					duration
				})
				// #endif
			},
			// 点击某一个标签
			clickHandler(item, index) {
				// 因为标签可能为disabled状态，所以click是一定会发出的，但是change事件是需要可用的状态才发出
				this.$emit('click', {
					...item,
					index
				})
				// 如果disabled状态，返回
				if (item.disabled) return
				if(this.innerCurrent != index) {
					this.$emit('change', {
						...item,
						index
					})
				}
				this.innerCurrent = index
				// #ifndef APP-NVUE
				this.$nextTick(()=>{
					this.resize()
				})
				// #endif
				// #ifdef APP-NVUE
				this.$nextTick(()=>{
					// nvue模式下再给点延时，确保万无一失
					this.$uv.sleep(30).then(res=>{
						this.resize()
					});
				})
				// #endif
			},
			init() {
				this.$uv.sleep().then(() => {
					this.resize()
				})
			},
			setScrollLeft() {
				// 当前活动tab的布局信息，有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息
				const tabRect = this.list[this.innerCurrent]
				// 累加得到当前item到左边的距离
				const offsetLeft = this.list
					.slice(0, this.innerCurrent)
					.reduce((total, curr) => {
						return total + curr.rect.width
					}, 0)
				// 此处为屏幕宽度
				const windowWidth = this.$uv.sys().windowWidth
				// 将活动的tabs-item移动到屏幕正中间，实际上是对scroll-view的移动
				let scrollLeft = offsetLeft - (this.tabsRect.width - tabRect.rect.width) / 2 - (windowWidth - this.tabsRect
					.right) / 2 + this.tabsRect.left / 2
				// 这里做一个限制，限制scrollLeft的最大值为整个scroll-view宽度减去tabs组件的宽度
				scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width)
				this.scrollLeft = Math.max(0, scrollLeft)
			},
			// 获取所有标签的尺寸
			resize() {
				// 如果不存在list，则不处理
				if(this.list.length === 0) {
					return
				}
				Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => {
					this.tabsRect = tabsRect
					this.scrollViewWidth = 0
					itemRect.map((item, index) => {
						// 计算scroll-view的宽度，这里
						this.scrollViewWidth += item.width
						// 另外计算每一个item的中心点X轴坐标
						this.list[index].rect = item
					})
					// 获取了tabs的尺寸之后，设置滑块的位置
					this.setLineLeft()
					this.setScrollLeft()
				})
			},
			// 获取导航菜单的尺寸
			getTabsRect() {
				return new Promise(resolve => {
					this.queryRect('uv-tabs__wrapper__scroll-view').then(size => resolve(size))
				})
			},
			// 获取所有标签的尺寸
			getAllItemRect() {
				return new Promise(resolve => {
					const promiseAllArr = this.list.map((item, index) => this.queryRect(
						`uv-tabs__wrapper__nav__item-${index}`, true))
					Promise.all(promiseAllArr).then(sizes => resolve(sizes))
				})
			},
			// 获取各个标签的尺寸
			queryRect(el, item) {
				// #ifndef APP-NVUE
				// $uvGetRect为uni-ui自带的节点查询简化方法，详见文档介绍：https://www.uvui.cn/js/getRect.html
				// 组件内部一般用this.$uvGetRect，对外的为getRect，二者功能一致，名称不同
				return new Promise(resolve => {
					this.$uvGetRect(`.${el}`).then(size => {
						resolve(size)
					})
				})
				// #endif

				// #ifdef APP-NVUE
				// nvue下，使用dom模块查询元素高度
				// 返回一个promise，让调用此方法的主体能使用then回调
				return new Promise(resolve => {
					dom.getComponentRect(item ? this.$refs[el][0] : this.$refs[el], res => {
						resolve(res.size)
					})
				})
				// #endif
			},
		},
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-tabs {

		&__wrapper {
			@include flex;
			align-items: center;

			&__scroll-view-wrapper {
				flex: 1;
				/* #ifndef APP-NVUE */
				overflow: auto hidden;
				/* #endif */
			}

			&__scroll-view {
				@include flex;
				flex: 1;
			}

			&__nav {
				@include flex;
				position: relative;

				&__item {
					padding: 0 11px;
					@include flex;
					align-items: center;
					justify-content: center;

					&--disabled {
						/* #ifndef APP-NVUE */
						cursor: not-allowed;
						/* #endif */
					}

					&__text {
						font-size: 15px;
						color: $uv-content-color;

						&--disabled {
							color: $uv-disabled-color !important;
						}
					}
				}

				&__line {
					height: 3px;
					background: $uv-primary;
					width: 30px;
					position: absolute;
					bottom: 2px;
					border-radius: 100px;
					transition-property: transform;
					transition-duration: 300ms;
				}
			}
		}
	}
</style>
S4ʰ~xv{
  "id": "uv-tabstabs 标签选项卡TH9签选项卡组件，是一个tabs标签组件，在标签多的时候，可以配置为左右滑动，标签少的时候，以禁止滑动。 该组件的一个特点是配置为滚动模式时，激活的tab会自动移动到组件的中间位置,	选项卡U!tab",
    "标签#badge",
			"uv-sticky",
			"uv-icon
^Aʯ/x~## Vtabs 垂直选项卡

> **组件名：uv-vtabs**

该组件主要用于分类选择，开箱即用，简单配置参数即使用，左右自动进行联动，不用自己再去做复杂的计算，组件内部已经完成相关计算。联动和m联动两种可选方式，联动-左右均可滚动，不联动-右边区域只会在选中时显示。

# (vtabs{x5## Tabs 标签tabs**

标签选项卡组件，是一个`tabs`标签组件，在标签多的时候，可以配置为左右滑动，标签少时候，可以禁止滑动。 该组件的一个特点是配置为滚动模式时，激活的`tab`会自动移动到组件的中间位置d/tabsdtȜ	x e100644 changelog.md Em8w(DV!y40000 components CZ7>˫100644 package.json j]߭>N=O100644 readme.md ap4/	n%GHAx]## 1.0.3（2023-10-02）
1.  兼容customStyle参数
2.  优化
## 1.0.2（2023-07-31）
1. nvue模式下增加cell-child参数，避免在list中使用出现回收后不显示的BUG
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-tags 标签
ox" 40000 uv-tags ÀtGzXdm<xK 100644 props.js z@IQ<Iћvf100644 uv-tags.vue Oj$
POAbY4:sx=export default {
	props: {
		// 标签类型info、primary、success、warning、error
		type: {
			type: String,
			default: 'primary'
		},
		// 不可用
		disabled: {
			type: [Boolean, String],
			default: false
		},
		// 标签的大小，large，medium，mini
		size: {
			type: String,
			default: 'medium'
		},
		// tag的形状，circle（两边半圆形）, square（方形，带圆角）
		shape: {
			type: String,
			default: 'square'
		},
		// 标签文字
		text: {
			type: [String, Number],
			default: ''
		},
		// 背景颜色，默认为空字符串，即不处理
		bgColor: {
			type: String,
			default: ''
		},
		// 标签字体颜色，默认为空字符串，即不处理
		color: {
			type: String,
			default: ''
		},
		// 标签的边框颜色
		borderColor: {
			type: String,
			default: ''
		},
		// 点击时返回的索引值，用于区分例遍的数组哪个元素被点击了
		name: {
			type: [String, Number],
			default: ''
		},
		// 镂空时是否填充背景色
		plainFill: {
			type: Boolean,
			default: false
		},
		// 是否镂空
		plain: {
			type: Boolean,
			default: false
		},
		// 是否可关闭
		closable: {
			type: Boolean,
			default: false
		},
		// 关闭按钮图标的颜色
		closeColor: {
			type: String,
			default: '#C6C7CB'
		},
		// 关闭按钮图标的位置 right（右边）right-top（右上） 默认right-top
		closePlace: {
			type: String,
			default: 'right-top'
		},
		// 是否显示
		show: {
			type: Boolean,
			default: true
		},
		// 内置图标，或绝对路径的图片
		icon: {
			type: String,
			default: ''
		},
		// 图标颜色
		iconColor: {
			type: String,
			default: ''
		},
		// nvue模式下 是否直接显示，在uv-list等cell下面使用就需要设置
		cellChild: {
			type: Boolean,
			default: false
		},
		...uni.$uv?.props?.tags
	}
}|xc!<template>
	<uv-transition
		mode="fade"
		:show="show"
		:cell-child="cellChild"
	>
		<view class="uv-tags-wrapper">
			<view
				class="uv-tags"
				:class="[`uv-tags--${shape}`, !plain && `uv-tags--${type}`, plain && `uv-tags--${type}--plain`, `uv-tags--${size}`,`uv-tags--${size}--${closePlace}`, plain && plainFill && `uv-tags--${type}--plain--fill`]"
				@tap.stop="clickHandler"
				:style="[{
					marginRight: closable&& closePlace=='right-top' ? '10px' : 0,
					marginTop: closable && closePlace=='right-top' ? '10px' : 0,
				}, style, $uv.addStyle(customStyle)]"
			>
				<slot name="icon">
					<view
						class="uv-tags__icon"
						v-if="icon"
					>
						<image
							v-if="$uv.test.image(icon)"
							:src="icon"
							:style="[imgStyle]"
						></image>
						<uv-icon
							v-else
							:color="elIconColor"
							:name="icon"
							:size="iconSize"
						></uv-icon>
					</view>
				</slot>
				<text
					class="uv-tags__text"
					:style="[textColor]"
					:class="[`uv-tags__text--${type}`, plain && `uv-tags__text--${type}--plain`, `uv-tags__text--${size}`]"
				>{{ text }}</text>
				<view
					class="uv-tags__close"
					:class="[`uv-tags__close--${size}`,`uv-tags__close--${closePlace}`]"
					v-if="closable && closePlace=='right'"
					@tap.stop="closeHandler"
					:style="{backgroundColor: closeColor}"
				>
					<uv-icon
						name="close"
						:size="closeSize"
						color="#ffffff"
					></uv-icon>
				</view>
			</view>
			<view
				class="uv-tags__close"
				:class="[`uv-tags__close--${size}`,`uv-tags__close--${closePlace}`]"
				v-if="closable && closePlace=='right-top'"
				@tap.stop="closeHandler"
				:style="{backgroundColor: closeColor}"
			>
				<uv-icon
					name="close"
					:size="closeSize"
					color="#ffffff"
				></uv-icon>
			</view>
		</view>
	</uv-transition>
</template>

<script>
	import { image } from '@/uni_modules/uv-ui-tools/libs/function/test.js'
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Tag 标签
	 * @description tag组件一般用于标记和选择，我们提供了更加丰富的表现形式，能够较全面的涵盖您的使用场景
	 * @tutorial https://www.uvui.cn/components/tag.html
	 * @property {String}			type		标签类型info、primary、success、warning、error （默认 'primary' ）
	 * @property {Boolean | String}	disabled	不可用（默认 false ）
	 * @property {String}			size		标签的大小，large，medium，mini （默认 'medium' ）
	 * @property {String}			shape		tag的形状，circle（两边半圆形）, square（方形，带圆角）（默认 'square' ）
	 * @property {String | Number}	text		标签的文字内容 
	 * @property {String}			bgColor		背景颜色，默认为空字符串，即不处理
	 * @property {String}			color		标签字体颜色，默认为空字符串，即不处理
	 * @property {String}			borderColor	镂空形式标签的边框颜色
	 * @property {String}			closeColor	关闭按钮图标的颜色（默认 #C6C7CB）
	 * @property {String | Number}	name		点击时返回的索引值，用于区分例遍的数组哪个元素被点击了
	 * @property {Boolean}			plainFill	镂空时是否填充背景色（默认 false ）
	 * @property {Boolean}			plain		是否镂空（默认 false ）
	 * @property {Boolean}			closable	是否可关闭，设置为true，文字右边会出现一个关闭图标（默认 false ）
	 * @property {Boolean}			show		标签显示与否（默认 true ）
	 * @property {String}			icon		内置图标，或绝对路径的图片
	 * @event {Function(index)} click 点击标签时触发 index: 传递的index参数值
	 * @event {Function(index)} close closable为true时，点击标签关闭按钮触发 index: 传递的index参数值	
	 * @example <uv-tags text="标签" type="error" plain plainFill></uv-tags>
	 */
	export default {
		name: 'uv-tags',
		emits: ['click','close'],
		mixins: [mpMixin, mixin, props],
		computed: {
			style() {
				const style = {}
				if (this.bgColor) {
					style.backgroundColor = this.bgColor
				}
				if (this.color) {
					style.color = this.color
				}
				if(this.borderColor) {
					style.borderColor = this.borderColor
				}
				return style
			},
			// nvue下，文本颜色无法继承父元素
			textColor() {
				const style = {}
				if (this.color) {
					style.color = this.color
				}
				return style
			},
			imgStyle() {
				const width = this.size === 'large' ? '17px' : this.size === 'medium' ? '15px' : '13px'
				return {
					width,
					height: width
				}
			},
			// 文本的样式
			closeSize() {
				const size = this.size === 'large' ? 15 : this.size === 'medium' ? 13 : 12
				return size
			},
			// 图标大小
			iconSize() {
				const size = this.size === 'large' ? 21 : this.size === 'medium' ? 19 : 16
				return size
			},
			// 图标颜色
			elIconColor() {
				return this.iconColor ? this.iconColor : this.plain ? this.type : '#ffffff'
			}
		},
		methods: {
			// 点击关闭按钮
			closeHandler() {
				this.$emit('close', this.name)
			},
			// 点击标签
			clickHandler() {
				this.$emit('click', this.name)
			}
		}
	}
</script>

<style lang="scss" scoped >
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-tags-wrapper {
		position: relative;
	}

	.uv-tags {
		@include flex;
		align-items: center;
		border-style: solid;

		&--circle {
			border-radius: 100px;
		}

		&--square {
			border-radius: 3px;
		}

		&__icon {
			margin-right: 4px;
		}

		&__text {
			&--mini {
				font-size: 12px;
				line-height: 12px;
			}

			&--medium {
				font-size: 13px;
				line-height: 13px;
			}

			&--large {
				font-size: 15px;
				line-height: 15px;
			}
		}

		&--mini {
			height: 22px;
			line-height: 22px;
			padding: 0 5px;
			&--right {
				padding-right: 2px;
			}
		}

		&--medium {
			height: 26px;
			line-height: 22px;
			padding: 0 10px;
			&--right {
				padding: 0 4px 0 8px;
			}
		}

		&--large {
			height: 32px;
			line-height: 32px;
			padding: 0 15px;
			&--right {
				padding: 0 4px 0 8px;
			}
		}

		&--primary {
			background-color: $uv-primary;
			border-width: 1px;
			border-color: $uv-primary;
		}

		&--primary--plain {
			border-width: 1px;
			border-color: $uv-primary;
		}

		&--primary--plain--fill {
			background-color: #ecf5ff;
		}

		&__text--primary {
			color: #FFFFFF;
		}

		&__text--primary--plain {
			color: $uv-primary;
		}

		&--error {
			background-color: $uv-error;
			border-width: 1px;
			border-color: $uv-error;
		}

		&--error--plain {
			border-width: 1px;
			border-color: $uv-error;
		}

		&--error--plain--fill {
			background-color: #fef0f0;
		}

		&__text--error {
			color: #FFFFFF;
		}

		&__text--error--plain {
			color: $uv-error;
		}

		&--warning {
			background-color: $uv-warning;
			border-width: 1px;
			border-color: $uv-warning;
		}

		&--warning--plain {
			border-width: 1px;
			border-color: $uv-warning;
		}

		&--warning--plain--fill {
			background-color: #fdf6ec;
		}

		&__text--warning {
			color: #FFFFFF;
		}

		&__text--warning--plain {
			color: $uv-warning;
		}

		&--success {
			background-color: $uv-success;
			border-width: 1px;
			border-color: $uv-success;
		}

		&--success--plain {
			border-width: 1px;
			border-color: $uv-success;
		}

		&--success--plain--fill {
			background-color: #f5fff0;
		}

		&__text--success {
			color: #FFFFFF;
		}

		&__text--success--plain {
			color: $uv-success;
		}

		&--info {
			background-color: $uv-info;
			border-width: 1px;
			border-color: $uv-info;
		}

		&--info--plain {
			border-width: 1px;
			border-color: $uv-info;
		}

		&--info--plain--fill {
			background-color: #f4f4f5;
		}

		&__text--info {
			color: #FFFFFF;
		}

		&__text--info--plain {
			color: $uv-info;
		}

		&__close {
			border-radius: 100px;
			background-color: #C6C7CB;
			@include flex(row);
			align-items: center;
			justify-content: center;
			transform: scale(0.6);
			&--right-top {
				position: absolute;
				z-index: 999;
				top: 10px;
				right: 10px;
				/* #ifndef APP-NVUE */
				transform: scale(0.6) translate(80%,-80%);
				/* #endif */
				/* #ifdef APP-NVUE */
				transform: scale(0.6) translate(50%, -50%);
				/* #endif */
			}
			&--mini {
				width: 18px;
				height: 18px;
			}

			&--medium {
				width: 22px;
				height: 22px;
			}

			&--large {
				width: 25px;
				height: 25px;
			}
		}

	}
</style>
}h/Dx 
5{
  "id": "uv-tags",
  "displayName": "uv-tags 标签?`tag组件一般用于标记和选择，我们提供了更加丰富的表现形式，能够较全面的涵盖您的使用场景tags!!tag",
    "标签\i,
			"uv-icq\
x Q## Tag 标签tags**

tag组件一般用于标记和选择，我们提供了更加丰富的表现形式，能够较全面的涵盖您的使场景1tagZ$ iN	x e100644 changelog.md HR Iૺ40000 components Sʜ3%s&!d#D(100644 package.json IɎbS100644 readme.md VS&<ul8|c|B-x" 40000 uv-text wʐer1yM`؝$2Dxo 100644 props.js 3l-â*$?+I100644 uv-text.vue >ӛo[)Tnu3?100644 value.js Х~a>֠~Cj(0xexport default {
	props: {
		// 主题颜色
		type: {
			type: String,
			default: ''
		},
		// 是否显示
		show: {
			type: Boolean,
			default: true
		},
		// 显示的值
		text: {
			type: [String, Number],
			default: ''
		},
		// 前置图标
		prefixIcon: {
			type: String,
			default: ''
		},
		// 后置图标
		suffixIcon: {
			type: String,
			default: ''
		},
		// 文本处理的匹配模式
		// text-普通文本，price-价格，phone-手机号，name-姓名，date-日期，link-超链接
		mode: {
			type: String,
			default: ''
		},
		// mode=link下，配置的链接
		href: {
			type: String,
			default: ''
		},
		// 格式化规则
		format: {
			type: [String, Function],
			default: ''
		},
		// mode=phone时，点击文本是否拨打电话
		call: {
			type: Boolean,
			default: true
		},
		// 小程序的打开方式
		openType: {
			type: String,
			default: ''
		},
		// 是否粗体，默认normal
		bold: {
			type: Boolean,
			default: false
		},
		// 是否块状
		block: {
			type: Boolean,
			default: false
		},
		// 文本显示的行数，如果设置，超出此行数，将会显示省略号
		lines: {
			type: [String, Number],
			default: ''
		},
		// 文本颜色
		color: {
			type: String,
			default: '#303133'
		},
		// 字体大小
		size: {
			type: [String, Number],
			default: 15
		},
		// 图标的样式
		iconStyle: {
			type: [Object, String],
			default: () => ({
				fontSize: '15px'
			})
		},
		// 文字装饰，下划线，中划线等，可选值 none|underline|line-through
		decoration: {
			type: String,
			default: 'none'
		},
		// 外边距，对象、字符串，数值形式均可
		margin: {
			type: [Object, String, Number],
			default: 0
		},
		// 文本行高
		lineHeight: {
			type: [String, Number],
			default: ''
		},
		// 文本对齐方式，可选值left|center|right
		align: {
			type: String,
			default: 'left'
		},
		// 文字换行，可选值break-word|normal|anywhere
		wordWrap: {
			type: String,
			default: 'normal'
		},
		...uni.$uv?.props?.text
	}
}'Nxo<template>
    <view
      class="uv-text"
      :class="[]"
      v-if="show"
      :style="{
        margin: margin,
				justifyContent: align === 'left' ? 'flex-start' : align === 'center' ? 'center' : 'flex-end'
      }"
      @tap="clickHandler"
    >
      <text
        :class="['uv-text__price', type && `uv-text__value--${type}`]"
        v-if="mode === 'price'"
        :style="[valueStyle]"
        >￥</text
      >
      <view class="uv-text__prefix-icon" v-if="prefixIcon">
        <uv-icon
          :name="prefixIcon"
          :customStyle="$uv.addStyle(iconStyle)"
        ></uv-icon>
      </view>
      <uv-link
        v-if="mode === 'link'"
        :text="value"
        :href="href"
        underLine
      ></uv-link>
      <template v-else-if="openType && isMp">
        <button
          class="uv-reset-button uv-text__value"
          :style="[valueStyle]"
          :openType="openType"
          @getuserinfo="onGetUserInfo"
          @contact="onContact"
          @getphonenumber="onGetPhoneNumber"
          @error="onError"
          @launchapp="onLaunchApp"
          @opensetting="onOpenSetting"
          :lang="lang"
          :session-from="sessionFrom"
          :send-message-title="sendMessageTitle"
          :send-message-path="sendMessagePath"
          :send-message-img="sendMessageImg"
          :show-message-card="showMessageCard"
          :app-parameter="appParameter"
        >
          {{ value }}
        </button>
      </template>
      <text
        v-else
        class="uv-text__value"
        :style="[valueStyle]"
        :class="[
          type && `uv-text__value--${type}`,
          lines && `uv-line-${lines}`
        ]"
        >{{ value }}</text
      >
      <view class="uv-text__suffix-icon" v-if="suffixIcon">
        <uv-icon
          :name="suffixIcon"
          :customStyle="$uv.addStyle(iconStyle)"
        ></uv-icon>
      </view>
    </view>
</template>
<script>
	import value from './value.js'
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import button from '@/uni_modules/uv-ui-tools/libs/mixin/button.js'
	import openType from '@/uni_modules/uv-ui-tools/libs/mixin/openType.js'
	import props from './props.js'
	/**
	 * Text 文本
	 * @description 此组件集成了文本类在项目中的常用功能，包括状态，拨打电话，格式化日期，*替换，超链接...等功能。 您大可不必在使用特殊文本时自己定义，text组件几乎涵盖您能使用的大部分场景。
	 * @tutorial https://www.uvui.cn/components/loading.html
	 * @property {String} 					type		主题颜色
	 * @property {Boolean} 					show		是否显示（默认 true ）
	 * @property {String | Number}			text		显示的值
	 * @property {String}					prefixIcon	前置图标
	 * @property {String} 					suffixIcon	后置图标
	 * @property {String} 					mode		文本处理的匹配模式 text-普通文本，price-价格，phone-手机号，name-姓名，date-日期，link-超链接
	 * @property {String} 					href		mode=link下，配置的链接
	 * @property {String | Function} 		format		格式化规则
	 * @property {Boolean} 					call		mode=phone时，点击文本是否拨打电话（默认 false ）
	 * @property {String} 					openType	小程序的打开方式
	 * @property {Boolean} 					bold		是否粗体，默认normal（默认 false ）
	 * @property {Boolean} 					block		是否块状（默认 false ）
	 * @property {String | Number} 			lines		文本显示的行数，如果设置，超出此行数，将会显示省略号
	 * @property {String} 					color		文本颜色（默认 '#303133' ）
	 * @property {String | Number} 			size		字体大小（默认 15 ）
	 * @property {Object | String} 			iconStyle	图标的样式 （默认 {fontSize: '15px'} ）
	 * @property {String} 					decoration	文字装饰，下划线，中划线等，可选值 none|underline|line-through（默认 'none' ）
	 * @property {Object | String | Number}	margin		外边距，对象、字符串，数值形式均可（默认 0 ）
	 * @property {String | Number} 			lineHeight	文本行高
	 * @property {String} 					align		文本对齐方式，可选值left|center|right（默认 'left' ）
	 * @property {String} 					wordWrap	文字换行，可选值break-word|normal|anywhere（默认 'normal' ）
	 * @event {Function} click  点击触发事件
	 * @example <uv-text text="我用十年青春,赴你最后之约"></uv-text>
	 */
	export default {
		name: 'uv-text',
		emits: ['click'],
		// #ifdef MP
		mixins: [mpMixin, mixin, value, button, openType, props],
		// #endif
		// #ifndef MP
		mixins: [mpMixin, mixin, value, props],
		// #endif
		computed: {
			valueStyle() {
				const style = {
					textDecoration: this.decoration,
					fontWeight: this.bold ? 'bold' : 'normal',
					wordWrap: this.wordWrap,
					fontSize: this.$uv.addUnit(this.size)
				};
				!this.type && (style.color = this.color);
				this.isNvue && this.lines && (style.lines = this.lines);
				if(this.isNvue && this.mode != 'price' && !this.prefixIcon && !this.suffixIcon) {
					 style.flex = 1;
					 style.textAlign = this.align === 'left' ? 'flex-start' : this.align === 'center' ? 'center' : 'right';
				}
				this.lineHeight && (style.lineHeight = this.$uv.addUnit(this.lineHeight));
				!this.isNvue && this.block && (style.display = 'block');
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			},
			isNvue() {
				let nvue = false
				// #ifdef APP-NVUE
				nvue = true
				// #endif
				return nvue
			},
			isMp() {
				let mp = false
				// #ifdef MP
				mp = true
				// #endif
				return mp
			}
		},
		data() {
			return {}
		},
		methods: {
			clickHandler() {
				// 如果为手机号模式，拨打电话
				if (this.call && this.mode === 'phone') {
					uni.makePhoneCall({
						phoneNumber: this.text
					})
				}
				this.$emit('click')
			}
		}
	}
</script>
<style lang="scss" scoped>
	$show-lines: 1;
	$show-reset-button: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-text {
		@include flex(row);
		align-items: center;
		flex-wrap: nowrap;
		flex: 1;
		/* #ifndef APP-NVUE */
		width: 100%;
		/* #endif */
		&__price {
			font-size: 14px;
			color: $uv-content-color;
		}
		&__value {
			font-size: 14px;
			@include flex;
			color: $uv-content-color;
			flex-wrap: wrap;
			// flex: 1;
			text-overflow: ellipsis;
			align-items: center;
			&--primary {
				color: $uv-primary;
			}
			&--warning {
				color: $uv-warning;
			}
			&--success {
				color: $uv-success;
			}
			&--info {
				color: $uv-info;
			}
			&--error {
				color: $uv-error;
			}
			&--main {
				color: $uv-main-color;
			}
			&--content {
				color: $uv-content-color;
			}
			&--tips {
				color: $uv-tips-color;
			}
			&--light {
				color: $uv-light-color;
			}
		}
	}
</style>#xHimport { func, date, url } from '@/uni_modules/uv-ui-tools/libs/function/test.js'
import { error, timeFormat, priceFormat } from '@/uni_modules/uv-ui-tools/libs/function/index.js'
export default {
    computed: {
        // 经处理后需要显示的值
        value() {
            const {
                text,
                mode,
                format,
                href
            } = this
            // 价格类型
            if (mode === 'price') {
                // 如果text不为金额进行提示
                if (!/^\d+(\.\d+)?$/.test(text)) {
                    error('金额模式下，text参数需要为金额格式');
                }
                // 进行格式化，判断用户传入的format参数为正则，或者函数，如果没有传入format，则使用默认的金额格式化处理
                if (func(format)) {
                    // 如果用户传入的是函数，使用函数格式化
                    return format(text)
                }
                // 如果format非正则，非函数，则使用默认的金额格式化方法进行操作
                return priceFormat(text, 2)
            } if (mode === 'date') {
                // 判断是否合法的日期或者时间戳
                !date(text) && error('日期模式下，text参数需要为日期或时间戳格式')
                // 进行格式化，判断用户传入的format参数为正则，或者函数，如果没有传入format，则使用默认的格式化处理
                if (func(format)) {
                    // 如果用户传入的是函数，使用函数格式化
                    return format(text)
                } if (format) {
                    // 如果format非正则，非函数，则使用默认的时间格式化方法进行操作
                    return timeFormat(text, format)
                }
                // 如果没有设置format，则设置为默认的时间格式化形式
                return timeFormat(text, 'yyyy-mm-dd')
            } if (mode === 'phone') {
                // 判断是否合法的手机号
                // !mobile(text) && error('手机号模式下，text参数需要为手机号码格式')
                if (func(format)) {
                    // 如果用户传入的是函数，使用函数格式化
                    return format(text)
                } if (format === 'encrypt') {
                    // 如果format为encrypt，则将手机号进行星号加密处理
                    return `${text.substr(0, 3)}****${text.substr(7)}`
                }
                return text
            } if (mode === 'name') {
                // 判断是否合法的字符粗
                !(typeof (text) === 'string') && error('姓名模式下，text参数需要为字符串格式')
                if (func(format)) {
                    // 如果用户传入的是函数，使用函数格式化
                    return format(text)
                } if (format === 'encrypt') {
                    // 如果format为encrypt，则将姓名进行星号加密处理
                    return this.formatName(text)
                }
                return text
            } if (mode === 'link') {
                // 判断是否合法的字符粗
                !url(href) && error('超链接模式下，href参数需要为URL格式')
                return text
            }
            return text
        }
    },
    methods: {
        // 默认的姓名脱敏规则
        formatName(name) {
            let value = ''
            if (name.length === 2) {
                value = name.substr(0, 1) + '*'
            } else if (name.length > 2) {
                let char = ''
                for (let i = 0, len = name.length - 2; i < len; i++) {
                    char += '*'
                }
                value = name.substr(0, 1) + char + name.substr(-1, 1)
            } else {
                value = name
            }
            return value
        }
    }
}
̀Xx~5{
  "id": "uv-text",
  "displayName": "uv-text 文本=H4",
  "description": "此组件集成了文本类在项目中的常用功能，包括状态，拨打电话，格式化日期，*替换，超链接...等功能。 您大可不必在使用特殊文本时自己定义，text组件涵盖您能使用的大部场景Ouv-texto!text",
    "文本,
			"uv-link
ׅ5x2## Text 文本

> **组件名：uv-text**

此组件集成了文本类在项目中的常用功能，包括状态，拨打电话，格式化日期，*替换，超链接...等功能。 您大可不必在使用特殊文本时自己定义，text组件涵盖能使用的大部分场景/tex!,7	x e100644 changelog.md c	H _'Gm40000 components 2hkx5z.')z100644 package.json }JDG9ey%100644 readme.md jd]e`'?.0Gs:	>x## 1.0.11（2023-12-26）
1. 优化confirmType默认值改成return
## 1.0.10（2023-09-13）
1. 修复设置autoHeight后出现高度异常的BUG
## 1.0.9（2023-08-08）
1. 优化
## 1.0.8（2023-08-07）
1. 修复值为null或undefined时显示错误的bug
## 1.0.7（2023-08-05）
1. v-model设置为数据时的BUG
2. 复制过多内容，计数显示错误的BUG
3. maxlength为-1改成不显示计数
## 1.0.6（2023-07-30）
1. 增加confirm-hold参数，参考官方文档
## 1.0.5（2023-07-25）
1. 增加textStyle属性，自定义文本样式
2. 增加countStyle属性，自定义统计数字的样式
## 1.0.4（2023-07-14）
1. 修复  设置maxlength为-1时不生效的BUG
## 1.0.3（2023-07-13）
1. 修复  uv-textarea设置value属性不生效的BUG 
## 1.0.2（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.1（2023-05-12）
1. 修复vue3中双向绑定问题
## 1.0.0（2023-05-10）
uv-textarea 文本域
tFx& 40000 uv-textarea  HQ\{@w2/9mauxO 100644 props.js ǈ5~0Uh3100644 uv-textarea.vue zD>$<ߡ!6x'export default {
	props: {
		value: {
			type: [String, Number],
			default: ''
		},
		modelValue: {
			type: [String, Number],
			default: ''
		},
		// 输入框为空时占位符
		placeholder: {
			type: [String, Number],
			default: ''
		},
		// 指定placeholder的样式类，注意页面或组件的style中写了scoped时，需要在类名前写/deep/
		placeholderClass: {
			type: String,
			default: 'textarea-placeholder'
		},
		// 指定placeholder的样式
		placeholderStyle: {
			type: [String, Object],
			default: 'color: #c0c4cc'
		},
		// 输入框高度
		height: {
			type: [String, Number],
			default: 70
		},
		// 设置键盘右下角按钮的文字，仅微信小程序，App-vue和H5有效
		confirmType: {
			type: String,
			default: 'return'
		},
		// 是否禁用
		disabled: {
			type: Boolean,
			default: false
		},
		// 是否显示统计字数
		count: {
			type: Boolean,
			default: false
		},
		// 是否自动获取焦点，nvue不支持，H5取决于浏览器的实现
		focus: {
			type: Boolean,
			default: false
		},
		// 是否自动增加高度
		autoHeight: {
			type: Boolean,
			default: false
		},
		// 如果textarea是在一个position:fixed的区域，需要显示指定属性fixed为true
		fixed: {
			type: Boolean,
			default: false
		},
		// 指定光标与键盘的距离
		cursorSpacing: {
			type: Number,
			default: 0
		},
		// 指定focus时的光标位置
		cursor: {
			type: [String, Number],
			default: ''
		},
		// 是否显示键盘上方带有”完成“按钮那一栏，
		showConfirmBar: {
			type: Boolean,
			default: true
		},
		// 光标起始位置，自动聚焦时有效，需与selection-end搭配使用
		selectionStart: {
			type: Number,
			default: -1
		},
		// 光标结束位置，自动聚焦时有效，需与selection-start搭配使用
		selectionEnd: {
			type: Number,
			default: -1
		},
		// 键盘弹起时，是否自动上推页面
		adjustPosition: {
			type: Boolean,
			default: true
		},
		// 是否去掉 iOS 下的默认内边距，只微信小程序有效
		disableDefaultPadding: {
			type: Boolean,
			default: false
		},
		// focus时，点击页面的时候不收起键盘，只微信小程序有效
		holdKeyboard: {
			type: Boolean,
			default: false
		},
		// 最大输入长度，设置为 -1 的时候不限制最大长度
		maxlength: {
			type: [String, Number],
			default: 140
		},
		// 边框类型，surround-四周边框，bottom-底部边框
		border: {
			type: String,
			default: 'surround'
		},
		// 用于处理或者过滤输入框内容的方法
		formatter: {
			type: [Function, null],
			default: null
		},
		// 是否忽略组件内对文本合成系统事件的处理
		ignoreCompositionEvent: {
			type: Boolean,
			default: true
		},
		// 是否忽略组件内对文本合成系统事件的处理
		confirmHold: {
			type: Boolean,
			default: false
		},
		// 文本样式
		textStyle: {
			type: [Object, String],
			default: () => {}
		},
		// 统计数字的样式
		countStyle: {
			type: [Object, String],
			default: () => {}
		},
		...uni.$uv?.props?.textarea
	}
}oJβxB#<template>
	<view class="uv-textarea"
		:class="textareaClass"
		:style="[textareaStyle]">
		<textarea class="uv-textarea__field"
			:value="innerValue"
			:style="[
				{height: autoHeight ? 'auto' :$uv.addUnit(height)},
				$uv.addStyle(textStyle)
			]"
			:placeholder="placeholder"
			:placeholder-style="$uv.addStyle(placeholderStyle, 'string')"
			:placeholder-class="placeholderClass"
			:disabled="disabled"
			:focus="focus"
			:autoHeight="autoHeight"
			:fixed="fixed"
			:cursorSpacing="cursorSpacing"
			:cursor="cursor"
			:showConfirmBar="showConfirmBar"
			:selectionStart="selectionStart"
			:selectionEnd="selectionEnd"
			:adjustPosition="adjustPosition"
			:disableDefaultPadding="disableDefaultPadding"
			:holdKeyboard="holdKeyboard"
			:maxlength="maxlen"
			:confirmType="confirmType"
			:ignoreCompositionEvent="ignoreCompositionEvent"
			:confirm-hold="confirmHold"
			@focus="onFocus"
			@blur="onBlur"
			@linechange="onLinechange"
			@input="onInput"
			@confirm="onConfirm"
			@keyboardheightchange="onKeyboardheightchange"></textarea>
			<text class="uv-textarea__count"
			:style="[{
        'background-color': disabled ? 'transparent' : '#fff',
      },$uv.addStyle(countStyle)]"
			v-if="count && maxlen!=-1">{{ getCount }}/{{ maxlen }}</text>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from "./props.js";
	/**
	 * Textarea 文本域
	 * @description 文本域此组件满足了可能出现的表单信息补充，编辑等实际逻辑的功能，内置了字数校验等
	 * @tutorial https://www.uvui.cn/components/textarea.html
	 *
	 * @property {String | Number} 		value	/ v-model				输入框的内容
	 * @property {String | Number}		placeholder				输入框为空时占位符
	 * @property {String}			    placeholderClass		指定placeholder的样式类，注意页面或组件的style中写了scoped时，需要在类名前写/deep/ （ 默认 'input-placeholder' ）
	 * @property {String | Object}	    placeholderStyle		指定placeholder的样式，字符串/对象形式，如"color: red;"
	 * @property {String | Number}		height					输入框高度（默认 70 ）
	 * @property {String}				confirmType				设置键盘右下角按钮的文字，仅微信小程序，App-vue和H5有效（默认 'done' ）
	 * @property {Boolean}				disabled				是否禁用（默认 false ）
	 * @property {Boolean}				count					是否显示统计字数（默认 false ）
	 * @property {Boolean}				focus					是否自动获取焦点，nvue不支持，H5取决于浏览器的实现（默认 false ）
	 * @property {Boolean | Function}	autoHeight				是否自动增加高度（默认 false ）
	 * @property {Boolean}				fixed					如果textarea是在一个position:fixed的区域，需要显示指定属性fixed为true（默认 false ）
	 * @property {Number}				cursorSpacing			指定光标与键盘的距离（默认 0 ）
	 * @property {String | Number}		cursor					指定focus时的光标位置
	 * @property {Function}			    formatter			    内容式化函数
	 * @property {Boolean}				showConfirmBar			是否显示键盘上方带有”完成“按钮那一栏，（默认 true ）
	 * @property {Number}				selectionStart			光标起始位置，自动聚焦时有效，需与selection-end搭配使用，（默认 -1 ）
	 * @property {Number | Number}		selectionEnd			光标结束位置，自动聚焦时有效，需与selection-start搭配使用（默认 -1 ）
	 * @property {Boolean}				adjustPosition			键盘弹起时，是否自动上推页面（默认 true ）
	 * @property {Boolean | Number}		disableDefaultPadding	是否去掉 iOS 下的默认内边距，只微信小程序有效（默认 false ）
	 * @property {Boolean}				holdKeyboard			focus时，点击页面的时候不收起键盘，只微信小程序有效（默认 false ）
	 * @property {String | Number}		maxlength				最大输入长度，设置为 -1 的时候不限制最大长度（默认 140 ）
	 * @property {String}				border					边框类型，surround-四周边框，none-无边框，bottom-底部边框（默认 'surround' ）
	 * @property {Boolean}				ignoreCompositionEvent	是否忽略组件内对文本合成系统事件的处理
	 * @property {Boolean} confirmHold 点击键盘右下角按钮时是否保持键盘不收起
	 * @property {Object}	textStyle	文本样式
	 * @property {Object}	countStyle	统计数字的样式
	 *
	 * @event {Function(e)} focus					输入框聚焦时触发，event.detail = { value, height }，height 为键盘高度
	 * @event {Function(e)} blur					输入框失去焦点时触发，event.detail = {value, cursor}
	 * @event {Function(e)} linechange				输入框行数变化时调用，event.detail = {height: 0, heightRpx: 0, lineCount: 0}
	 * @event {Function(e)} input					当键盘输入时，触发 input 事件
	 * @event {Function(e)} confirm					点击完成时， 触发 confirm 事件
	 * @event {Function(e)} keyboardheightchange	键盘高度发生变化的时候触发此事件
	 * @example <uv--textarea v-model="value1" placeholder="请输入内容" ></uv--textarea>
	 */
	export default {
		name: "uv-textarea",
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 输入框的值
				innerValue: "",
				// 是否处于获得焦点状态
				focused: false,
				// 过滤处理方法
				innerFormatter: value => value
			}
		},
		created() {
			// #ifndef VUE3
			this.innerValue = this.value;
			// #endif
			// #ifdef VUE3
			this.innerValue = this.modelValue;
			// #endif
		},
		watch: {
			value(newVal) {
				this.innerValue = newVal;
			},
			modelValue(newVal) {
				this.innerValue = newVal;
			}
		},
		computed: {
			// 组件的类名
			textareaClass() {
				let classes = [],
					{ border, disabled } = this;
				border === "surround" && (classes = classes.concat(["uv-border", "uv-textarea--radius"]));
				border === "bottom" && (classes = classes.concat(["uv-border-bottom", "uv-textarea--no-radius", ]));
				disabled && classes.push("uv-textarea--disabled");
				return classes.join(" ");
			},
			// 组件的样式
			textareaStyle() {
				const style = {};
				// #ifdef APP-NVUE
				// 由于textarea在安卓nvue上的差异性，需要额外再调整其内边距
				if (this.$uv.os() === "android") {
					style.paddingTop = "6px";
					style.paddingLeft = "9px";
					style.paddingBottom = "3px";
					style.paddingRight = "6px";
				}
				// #endif
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			},
			maxlen() {
				return this.maxlength < 0 ? this.maxlength < 0 ? -1 : 140 : this.maxlength;
			},
			getCount() {
				try{
					return this.innerValue.length > this.maxlen ? this.maxlen: this.innerValue.length;
				}catch(e){
					return 0;
				}
			}
		},
		methods: {
			// 在微信小程序中，不支持将函数当做props参数，故只能通过ref形式调用
			setFormatter(e) {
				this.innerFormatter = e
			},
			onFocus(e) {
				this.$emit("focus", e);
			},
			onBlur(e) {
				this.$emit("blur", e);
				// 尝试调用uv-form的验证方法
				this.$uv.formValidate(this, "blur");
			},
			onLinechange(e) {
				this.$emit("linechange", e);
			},
			onInput(e) {
				let { value = "" } = e.detail || {};
				// 格式化过滤方法
				const formatter = this.formatter || this.innerFormatter
				const formatValue = formatter(value)
				// 为了避免props的单向数据流特性，需要先将innerValue值设置为当前值，再在$nextTick中重新赋予设置后的值才有效
				this.innerValue = value
				this.$nextTick(() => {
					this.innerValue = formatValue;
					this.valueChange();
				})
			},
			// 内容发生变化，进行处理
			valueChange() {
				const value = this.innerValue;
				this.$nextTick(() => {
					this.$emit("input", value);
					this.$emit("update:modelValue", value);
					this.$emit("change", value);
					// 尝试调用uv-form的验证方法
					this.$uv.formValidate(this, "change");
				});
			},
			onConfirm(e) {
				this.$emit("confirm", e);
			},
			onKeyboardheightchange(e) {
				this.$emit("keyboardheightchange", e);
			},
		},
	};
</script>
<style lang="scss" scoped>
	$show-border: 1;
	$show-border-surround: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-textarea {
		border-radius: 4px;
		background-color: #fff;
		position: relative;
		@include flex;
		flex: 1;
		padding: 9px;
		&--radius {
			border-radius: 4px;
		}
		&--no-radius {
			border-radius: 0;
		}
		&--disabled {
			background-color: #f5f7fa;
		}
		&__field {
			flex: 1;
			font-size: 15px;
			color: $uv-content-color;
			width: 100%;
		}
		&__count {
			position: absolute;
			right: 5px;
			bottom: 2px;
			font-size: 12px;
			color: $uv-tips-color;
			background-color: #ffffff;
			padding: 1px 4px;
		}
	}
</style>YKx@{
  "id": "uv-textarea",
  "displayName": "uv-textarea 文本域EH11",
  "description": "文本域此组件满足了可能出现的表单信息补充，编辑等实际逻辑的功能，内置字数校验等+textareaO!textarea",
    "文本域	*Z%x :## Textarea 文本域textarea**

文本域此组件满足了可能出现的表单信息补充，编辑等实际逻辑的功能，内置了字数校等/textareavmallP#mallv1sު	x e100644 changelog.md xX䝾Ģ;-vŔ40000 components 7sbut\}{!#100644 package.json yNl0-moQ>100644 readme.md ZZ^[hRy΢yTox4>oxn O## 1.0.3（2023-12-06）
1. 增加z-index参数
2. 增加overlay参数
## 1.0.2/ܓtoast 消息提示
k|/x# 40000 uv-toast 	ݬrD;&S,%x( 100644 uv-toast.vue TXhTҕ=m0御x*<template>
	<view class="uv-toast">
		<uv-overlay :show="isShow && tmpConfig.overlay" :custom-style="overlayStyle"></uv-overlay>
		<uv-transition :show="isShow" mode="fade" :custom-style="aniStyle">
			<view
				class="uv-toast__content"
				ref="uvToastContent"
				:style="[contentStyle]"
				:class="['uv-type-' + tmpConfig.type, (tmpConfig.type === 'loading' || tmpConfig.loading) ?  'uv-toast__content--loading' : '']"
			>
				<uv-loading-icon
					v-if="tmpConfig.type === 'loading'"
					mode="circle"
					color="rgb(255, 255, 255)"
					inactiveColor="rgb(120, 120, 120)"
					size="25"
				></uv-loading-icon>
				<uv-icon
					v-else-if="tmpConfig.type !== 'defalut' && iconName"
					:name="iconName"
					size="17"
					:color="tmpConfig.type"
					:customStyle="iconStyle"
				></uv-icon>
				<uv-gap
					v-if="tmpConfig.type === 'loading' || tmpConfig.loading"
					height="12"
					bgColor="transparent"
				></uv-gap>
				<text
					class="uv-toast__content__text"
					:class="['uv-toast__content__text--' + tmpConfig.type]"
					style="max-width: 400rpx;"
				>{{ tmpConfig.message }}</text>
			</view>
		</uv-transition>
	</view>
</template>
<script>
	import { hexToRgb } from '@/uni_modules/uv-ui-tools/libs/function/colorGradient.js'
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * toast 消息提示
	 * @description 此组件表现形式类似uni的uni.showToastAPI，但也有不同的地方。
	 * @tutorial https://www.uvui.cn/components/toast.html
	 * @property {Boolean}	loading		是否加载中 （默认 false ）
	 * @property {String | Number}	zIndex	toast展示时的zIndex值 (默认 10090 )
	 * @property {String | Number}	message		显示的文字内容
	 * @property {String} icon 图标，或者绝对路径的图片
	 * @property {String} type 主题类型 （默认 default）
	 * @property {Boolean} overlay 是否显示透明遮罩，防止点击穿透 （默认 false ）
	 * @property {String} position 位置 （默认 'center' ）
	 * @property {Object} params 跳转的参数 
	 * @property {String | Number}  duration	展示时间，单位ms （默认 2000 ）
	 * @property {Function} complete 执行完后的回调函数 
	 * 
	 * @event {Function} show 显示toast，如需一进入页面就显示toast，请在onReady生命周期调用
	 * @example <uv-toast ref="uvToastRef" />
	 */
	export default {
		name: 'uv-toast',
		mixins: [mpMixin, mixin],
		data() {
			return {
				isShow: false,
				timer: null, // 定时器
				config: {
					message: '', // 显示文本
					type: '', // 主题类型，primary，success，error，warning，black
					duration: 2000, // 显示的时间，毫秒
					icon: true, // 显示的图标
					position: 'center', // toast出现的位置
					complete: null, // 执行完后的回调函数
					overlay: true, // 是否防止触摸穿透
					loading: false ,// 是否加载中状态
					zIndex: 10090 //弹出的层级
				},
				tmpConfig: {}, // 将用户配置和内置配置合并后的临时配置变量
				rect: {},
				opacity: 0
			}
		},
		computed: {
			iconName() {
				// 只有不为none，并且type为error|warning|succes|info时候，才显示图标
				if (!this.tmpConfig.icon || this.tmpConfig.icon == 'none') {
					return '';
				}
				if (['error', 'warning', 'success', 'primary'].includes(this.tmpConfig.type)) {
					return this.$uv.type2icon(this.tmpConfig.type)
				} else {
					return ''
				}
			},
			overlayStyle() {
				const style = {
					justifyContent: 'center',
					alignItems: 'center',
					display: 'flex',
					zIndex: this.tmpConfig.zIndex
				}
				// 将遮罩设置为100%透明度，避免出现灰色背景
				style.backgroundColor = 'rgba(0, 0, 0, 0)'
				return style
			},
			iconStyle() {
				const style = {}
				// 图标需要一个右边距，以跟右边的文字有隔开的距离
				style.marginRight = '4px'
				// #ifdef APP-NVUE
				// iOSAPP下，图标有1px的向下偏移，这里进行修正
				if (this.$uv.os() === 'ios') {
					style.marginTop = '-1px'
				}
				// #endif
				return style
			},
			aniStyle() {
				const style = {
					position: 'fixed',
					zIndex: this.tmpConfig.zIndex
				}
				return style
			},
			// 内容盒子的样式
			contentStyle() {
				const { windowWidth, windowHeight } = this.$uv.sys();
				const style = {
					position: 'fixed',
					top: '50%',
					left: '50%',
					// #ifdef APP-NVUE
					opacity: this.opacity
					// #endif
				};
				let value = 0
				// #ifndef APP-NVUE
				// 根据top和bottom，对Y轴进行窗体高度的百分比偏移
				if (this.tmpConfig.position === 'top') {
					style.top = '25%'
				} else if (this.tmpConfig.position === 'bottom') {
					style.top = '75%'
				} else {
					value = '-50%'
				}
				style.transform = `translate(-50%,${value})`
				// #endif
				// #ifdef APP-NVUE
				const { width = 0, height = 0 } = this.rect ? this.rect : {};
				if (width && height) {
					style.left = `${windowWidth*0.5 - width/2}px`
					if (this.tmpConfig.position === 'top') {
						style.top = `${windowHeight*0.5- height/2 - windowHeight*0.25}px`
					} else if (this.tmpConfig.position === 'bottom') {
						style.top = `${windowHeight*0.5- height/2 + windowHeight*0.25}px`
					} else {
						style.top = `${windowHeight*0.5- height/2}px`
					}
				}
				// #endif
				return style
			}
		},
		created() {
			// 通过主题的形式调用toast，批量生成方法函数
			['primary', 'success', 'error', 'warning', 'default', 'loading'].map(item => {
				this[item] = message => this.show({
					type: item,
					message
				})
			})
		},
		methods: {
			// 显示toast组件，由父组件通过this.$refs.xxx.show(options)形式调用
			show(options) {
				// 不将结果合并到this.config变量，避免多次调用uv-toast，前后的配置造成混乱
				this.tmpConfig = this.$uv.deepMerge(this.config, options)
				// 清除定时器
				this.clearTimer()
				this.isShow = true
				//#ifdef APP-NVUE
				this.$nextTick(() => {
					this.$uv.sleep(100).then(async res => {
						this.rect = await this.queryRect();
						this.$nextTick(() => {
							this.opacity = 1;
						})
					})
				})
				// #endif
				this.timer = setTimeout(() => {
					// 倒计时结束，清除定时器，隐藏toast组件
					this.clearTimer()
					// 判断是否存在callback方法，如果存在就执行
					typeof(this.tmpConfig.complete) === 'function' && this.tmpConfig.complete()
				}, this.tmpConfig.duration)
			},
			// 查询内容高度
			queryRect() {
				return new Promise(resolve => {
					const ref = this.$refs['uvToastContent'];
					dom.getComponentRect(ref, res => {
						resolve(res.size)
					})
				})
			},
			// 隐藏toast组件，由父组件通过this.$refs.xxx.hide()形式调用
			hide() {
				this.clearTimer()
			},
			clearTimer() {
				// #ifdef APP-NVUE
				this.opacity = 0;
				// #endif
				this.isShow = false
				// 清除定时器
				clearTimeout(this.timer)
				this.timer = null
			}
		},
		// #ifdef VUE2
		beforeDestroy() {
			this.clearTimer()
		},
		// #endif
		// #ifdef VUE3
		unmounted() {
			this.clearTimer()
		}
		// #endif
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-toast-color: #fff !default;
	$uv-toast-border-radius: 4px !default;
	$uv-toast-border-background-color: #585858 !default;
	$uv-toast-border-font-size: 14px !default;
	$uv-toast-border-padding: 12px 20px !default;
	$uv-toast-loading-border-padding: 20px 20px !default;
	$uv-toast-content-text-color: #fff !default;
	$uv-toast-content-text-font-size: 15px !default;
	$uv-toast-uv-icon: 10rpx !default;
	$uv-toast-uv-type-primary-color: $uv-primary !default;
	$uv-toast-uv-type-primary-background-color: #ecf5ff !default;
	$uv-toast-uv-type-primary-border-color: rgb(215, 234, 254) !default;
	$uv-toast-uv-type-primary-border-width: 1px !default;
	$uv-toast-uv-type-success-color: $uv-success !default;
	$uv-toast-uv-type-success-background-color: #dbf1e1 !default;
	$uv-toast-uv-type-success-border-color: #BEF5C8 !default;
	$uv-toast-uv-type-success-border-width: 1px !default;
	$uv-toast-uv-type-error-color: $uv-error !default;
	$uv-toast-uv-type-error-background-color: #fef0f0 !default;
	$uv-toast-uv-type-error-border-color: #fde2e2 !default;
	$uv-toast-uv-type-error-border-width: 1px !default;
	$uv-toast-uv-type-warning-color: $uv-warning !default;
	$uv-toast-uv-type-warning-background-color: #fdf6ec !default;
	$uv-toast-uv-type-warning-border-color: #faecd8 !default;
	$uv-toast-uv-type-warning-border-width: 1px !default;
	$uv-toast-uv-type-default-color: #fff !default;
	$uv-toast-uv-type-default-background-color: #585858 !default;
	.uv-toast {
		&__content {
			@include flex;
			padding: $uv-toast-border-padding;
			border-radius: $uv-toast-border-radius;
			background-color: $uv-toast-border-background-color;
			color: $uv-toast-color;
			align-items: center;
			/* #ifndef APP-NVUE */
			max-width: 600rpx;
			/* #endif */
			position: relative;
			&--loading {
				flex-direction: column;
				padding: $uv-toast-loading-border-padding;
			}
			&__text {
				color: $uv-toast-content-text-color;
				font-size: $uv-toast-content-text-font-size;
				line-height: $uv-toast-content-text-font-size;
				&--default {
					color: $uv-toast-content-text-color;
				}
				&--error {
					color: $uv-error;
				}
				&--primary {
					color: $uv-primary;
				}
				&--success {
					color: $uv-success;
				}
				&--warning {
					color: $uv-warning;
				}
			}
		}
	}
	.uv-type-primary {
		color: $uv-toast-uv-type-primary-color;
		background-color: $uv-toast-uv-type-primary-background-color;
		border-color: $uv-toast-uv-type-primary-border-color;
		border-width: $uv-toast-uv-type-primary-border-width;
	}
	.uv-type-success {
		color: $uv-toast-uv-type-success-color;
		background-color: $uv-toast-uv-type-success-background-color;
		border-color: $uv-toast-uv-type-success-border-color;
		border-width: 1px;
	}
	.uv-type-error {
		color: $uv-toast-uv-type-error-color;
		background-color: $uv-toast-uv-type-error-background-color;
		border-color: $uv-toast-uv-type-error-border-color;
		border-width: $uv-toast-uv-type-error-border-width;
	}
	.uv-type-warning {
		color: $uv-toast-uv-type-warning-color;
		background-color: $uv-toast-uv-type-warning-background-color;
		border-color: $uv-toast-uv-type-warning-border-color;
		border-width: 1px;
	}
	.uv-type-default {
		color: $uv-toast-uv-type-default-color;
		background-color: $uv-toast-uv-type-default-background-color;
	}
</style>Qΰ9x =## Toast 消息提示toast**

Toast 组件主要用于消息通知、加载提示、操作结果提示等醒目提示效果，我们为其提供了种丰富的API1toastZ=-s_	x e100644 changelog.md :nWrvCT ?40000 components /o$t9ȧO <*100644 package.json fY/USx&100644 readme.md 6Cڝ;oƛ >x2 ## 1.0.0（2023-08-02）
1. 新增工具条组件
x% 40000 uv-toolbar z0J>&KS>q9xN 100644 props.js 2A%\p:.JX100644 uv-toolbar.vue ?Mly.]h~ܽ'x}export default {
	props: {
		// 是否展示工具条
		show: {
			type: Boolean,
			default: true
		},
		// 是否显示下边框
		showBorder: {
			type: Boolean,
			default: false
		},
		// 取消按钮的文字
		cancelText: {
			type: String,
			default: '取消'
		},
		// 确认按钮的文字
		confirmText: {
			type: String,
			default: '确认'
		},
		// 取消按钮的颜色
		cancelColor: {
			type: String,
			default: '#909193'
		},
		// 确认按钮的颜色
		confirmColor: {
			type: String,
			default: '#3c9cff'
		},
		// 标题文字
		title: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.toolbar
	}
}|놰x0
<template>
	<view
		:class="['uv-toolbar',{'uv-border-bottom':showBorder}]"
		@touchmove.stop.prevent="noop"
		v-if="show"
	>
		<view
			class="uv-toolbar__cancel__wrapper"
			hover-class="uv-hover-class"
		>
			<text
				class="uv-toolbar__wrapper__cancel"
				@tap="cancel"
				:style="{
					color: cancelColor
				}"
			>{{ cancelText }}</text>
		</view>
		<text
			class="uv-toolbar__title uv-line-1"
			v-if="title"
		>{{ title }}</text>
		<view
			class="uv-toolbar__confirm__wrapper"
			hover-class="uv-hover-class"
		>
			<text
				class="uv-toolbar__wrapper__confirm"
				@tap="confirm"
				:style="{
				color: confirmColor
			}"
			>{{ confirmText }}</text>
		</view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * Toolbar 工具条
	 * @description 
	 * @tutorial https://www.uvui.cn/components/toolbar.html
	 * @property {Boolean}	show			是否展示工具条（默认 true ）
	 * @property {Boolean}	showBorder			是否展示工具条下方边框（默认 false ）
	 * @property {String}	cancelText		取消按钮的文字（默认 '取消' ）
	 * @property {String}	confirmText		确认按钮的文字（默认 '确认' ）
	 * @property {String}	cancelColor		取消按钮的颜色（默认 '#909193' ）
	 * @property {String}	confirmColor	确认按钮的颜色（默认 '#3c9cff' ）
	 * @property {String}	title	标题文字
	 * @event {Function} 
	 * @example 
	 */
	export default {
		name: 'uv-toolbar',
		emits: ['confirm', 'cancel'],
		mixins: [mpMixin, mixin, props],
		methods: {
			// 点击取消按钮
			cancel() {
				this.$emit('cancel')
			},
			// 点击确定按钮
			confirm() {
				this.$emit('confirm')
			}
		}
	}
</script>

<style lang="scss" scoped>
	$show-lines: 1;
	$show-hover: 1;
	$show-border: 1;
	$show-border-bottom: 1;
	@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	$uv-tips-color: #909193 !default;
	$uv-main-color: #303133 !default;
	$uv-primary: #3c9cff !default;
	.uv-toolbar {
		height: 42px;
		@include flex;
		justify-content: space-between;
		align-items: center;
		&__wrapper {
			&__cancel {
				color: $uv-tips-color;
				font-size: 15px;
				padding: 0 15px;
			}
		}
		&__title {
			color: $uv-main-color;
			padding: 0 60rpx;
			font-size: 16px;
			flex: 1;
			text-align: center;
		}
		&__wrapper {
			&__confirm {
				color: $uv-primary;
				font-size: 15px;
				padding: 0 15px;
			}
		}
	}
</style>arx({
  "id": "uv-tooltoolbar 工具条",
  "version": "1.0.0",
  "description": "该组价是仅用于uv-ui中一个公共小工具，提供一个^消和确定的样式，可以设置标题，主要用于弹窗顶部的选择确定工具条.toolL$工具条",
    "工具	.Lx2## Toolbar 工具条

> **组件名：uv-toolbar**

该组价是仅用于uv-ui中一个公共小工具，提供一个取消和确定的样式，可以设置标题，主要用于弹窗顶部的选择确定工具条。

### 基本使用

```vue
<uv-toolbar title="标题文字"></uv-toolbar>
```

### Toolbar Props

| 属性名 | 类型 | 默认值 | 说明 |
|:-|:-|:-|:-|
| show | Boolean | true | 是否展示工具条 |
| showBorder | Boolean | false | 是否显示下边框 |
| cancelText | String | '取消' | 取消按钮的文字 |
| confirmText | String | '确定' | 确定按钮的文字 |
| cancelColor | String | '#909193' | 取消按钮的颜色 |
| confirmColor | String | '#3c9cff' | 确认按钮的颜色 |
| title | String | - | 标题文字 |

## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui)

### [更多插件，请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)

![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)

#### 如使用过程中有任何问题反馈，或者您对uv-ui有一些好的建议，欢迎加入uv-ui官方交流群：<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>h	x e100644 changelog.md P	Go o6}$BFt40000 components ) ֚::enSi100644 package.json 	-2bg|c4t.100644 readme.md \(:=j7L5c<<3x M)## 1.0.5（2023-07-02）
修改VUE3模式,tooltipoY5-17）
1. 修复报错的BUG
## 1.0.2（2023-05-17）
1. vue2模式下报错的BUG修复tooltip 长按提示
Rx% 40000 uv-tooltip dbY#B(xN 100644 props.js A0Rw:%wvvzG100644 uv-tooltip.vue nv-p,Ρ|q"1QFxaexport default {
	props: {
		// 需要显示的提示文字
		text: {
			type: [String, Number],
			default: ''
		},
		// 点击复制按钮时，复制的文本，为空则使用text值
		copyText: {
			type: [String, Number],
			default: ''
		},
		// 文本大小
		size: {
			type: [String, Number],
			default: 14
		},
		// 字体颜色
		color: {
			type: String,
			default: '#606266'
		},
		// 弹出提示框时，文本的背景色
		bgColor: {
			type: String,
			default: 'transparent'
		},
		// 弹出提示的方向，top-上方，bottom-下方
		direction: {
			type: String,
			default: 'top'
		},
		// 弹出提示的z-index，nvue无效
		zIndex: {
			type: [String, Number],
			default: 10071
		},
		// 是否显示复制按钮
		showCopy: {
			type: Boolean,
			default: true
		},
		// 扩展的按钮组
		buttons: {
			type: Array,
			default: () => []
		},
		// 是否显示透明遮罩以防止触摸穿透
		overlay: {
			type: Boolean,
			default: true
		},
		// 是否显示复制成功或者失败的toast
		showToast: {
			type: Boolean,
			default: true
		},
		...uni.$uv?.props?.tooltip
	}
}uŨx8)<template>
	<view
		class="uv-tooltip"
		:style="[$uv.addStyle(customStyle)]"
	>
		<uv-overlay
			:show="showTooltip && tooltipTop !== -10000 && overlay && timeout>0"
			customStyle="backgroundColor: rgba(0, 0, 0, 0)"
			@click="overlayClickHandler"
		></uv-overlay>
		<view class="uv-tooltip__wrapper">
			<template v-if="isShow">
				<text
					class="uv-tooltip__wrapper__text"
					:id="textId"
					:ref="textId"
					:userSelect="false"
					:selectable="false"
					@click.stop="longpressHandler"
					:style="{
						color: color,
						backgroundColor: bgColor && showTooltip && tooltipTop !== -10000 ? bgColor : 'transparent'
					}"
				>{{ text }}</text>
			</template>
			<template v-else>
				<text
					class="uv-tooltip__wrapper__text"
					:id="textId"
					:ref="textId"
					:userSelect="false"
					:selectable="false"
					@longpress.stop="longpressHandler"
					:style="{
						color: color,
						backgroundColor: bgColor && showTooltip && tooltipTop !== -10000 ? bgColor : 'transparent'
					}"
				>{{ text }}</text>
			</template>
			<uv-transition
				mode="fade"
				:show="showTooltip"
				:duration="300"
				:customStyle="{
					position: 'absolute', 
					top: $uv.addUnit(tooltipTop),
					zIndex: zIndex,
					...tooltipStyle
				}"
			>
				<view
					class="uv-tooltip__wrapper__popup"
					:id="tooltipId"
					:ref="tooltipId"
				>
					<view
						class="uv-tooltip__wrapper__popup__indicator"
						hover-class="uv-tooltip__wrapper__popup__indicator--hover"
						v-if="showCopy || buttons.length"
						:style="[indicatorStyle, {
							width: $uv.addUnit(indicatorWidth),
							height: $uv.addUnit(indicatorWidth),
						}]"
					>
						<!-- 由于nvue不支持三角形绘制，这里就做一个四方形，再旋转45deg，得到露出的一个三角 -->
					</view>
					<view class="uv-tooltip__wrapper__popup__list">
						<view
							v-if="showCopy"
							class="uv-tooltip__wrapper__popup__list__btn"
							hover-class="uv-tooltip__wrapper__popup__list__btn--hover"
							@tap="setClipboardData"
						>
							<text
								class="uv-tooltip__wrapper__popup__list__btn__text"
							>复制</text>
						</view>
						<uv-line
							direction="column"
							color="#8d8e90"
							v-if="showCopy && buttons.length > 0"
							length="18"
						></uv-line>
						<block v-for="(item , index) in buttons" :key="index">
							<view
								class="uv-tooltip__wrapper__popup__list__btn"
								hover-class="uv-tooltip__wrapper__popup__list__btn--hover"
							>
								<text
									class="uv-tooltip__wrapper__popup__list__btn__text"
									@tap="btnClickHandler(index)"
								>{{ item }}</text>
							</view>
							<uv-line
								direction="column"
								color="#8d8e90"
								v-if="index < buttons.length - 1"
								length="18"
							></uv-line>
						</block>
					</view>
				</view>
			</uv-transition>
		</view>
	</view>
</template>

<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	// #ifdef APP-NVUE 
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * Tooltip 
	 * @description 
	 * @tutorial https://www.uvui.cn/components/tooltip.html
	 * @property {String | Number}	text		需要显示的提示文字
	 * @property {String | Number}	copyText	点击复制按钮时，复制的文本，为空则使用text值
	 * @property {String | Number}	size		文本大小（默认 14 ）
	 * @property {String}			color		字体颜色（默认 '#606266' ）
	 * @property {String}			bgColor		弹出提示框时，文本的背景色（默认 'transparent' ）
	 * @property {String}			direction	弹出提示的方向，top-上方，bottom-下方（默认 'top' ）
	 * @property {String | Number}	zIndex		弹出提示的z-index，nvue无效（默认 10071 ）
	 * @property {Boolean}			showCopy	是否显示复制按钮（默认 true ）
	 * @property {Array}			buttons		扩展的按钮组
	 * @property {Boolean}			overlay		是否显示透明遮罩以防止触摸穿透（默认 true ）
	 * @property {Object}			customStyle	定义需要用到的外部样式
	 * 
	 * @event {Function} 
	 * @example 
	 */
	export default {
		name: 'uv-tooltip',
		emits: ['click'],
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				// 是否展示气泡
				showTooltip: true,
				// 生成唯一id，防止一个页面多个组件，造成干扰
				textId: '',
				tooltipId: '',
				// 初始时甚至为很大的值，让其移到屏幕外面，为了计算元素的尺寸
				tooltipTop: -10000,
				// 气泡的位置信息
				tooltipInfo: {
					width: 0,
					left: 0
				},
				// 文本的位置信息
				textInfo: {
					width: 0,
					left: 0
				},
				// 三角形指示器的样式
				indicatorStyle: {},
				// 气泡在可能超出屏幕边沿范围时，重新定位后，距离屏幕边沿的距离
				screenGap: 12,
				// 三角形指示器的宽高，由于对元素进行了角度旋转，精确计算指示器位置时，需要用到其尺寸信息
				indicatorWidth: 14,
				timeout: 0
			}
		},
		watch: {
			propsChange() {
				this.getElRect()
			},
			showTooltip(newVal){
				if(!newVal) this.timeout = 0;
			}
		},
		computed: {
			isShow(){
				const isPC = this.$uv.sys()?.model == 'PC';
				if(isPC) {
					return true;
				}
				// #ifdef MP-WEIXIN || H5
				return false;
				// #endif
				return true;
			},
			// 特别处理H5的复制，因为H5浏览器是自带系统复制功能的，在H5环境
			// 当一些依赖参数变化时，需要重新计算气泡和指示器的位置信息
			propsChange() {
				return [this.text, this.buttons]
			},
			// 计算气泡和指示器的位置信息
			tooltipStyle() {
				const style = {};
				if (this.tooltipInfo.width / 2 > this.textInfo.left + this.textInfo.width / 2 - this.screenGap) {
					this.indicatorStyle = {}
					style.left = `-${this.$uv.addUnit(this.textInfo.left - this.screenGap)}`
					this.indicatorStyle.left = this.$uv.addUnit(this.textInfo.width / 2 - this.$uv.getPx(style.left) - this.indicatorWidth /
						2)
				} else if (this.tooltipInfo.width / 2 > this.$uv.sys().windowWidth - this.textInfo.right + this.textInfo.width / 2 -
					this.screenGap) {
					this.indicatorStyle = {}
					style.right = `-${this.$uv.addUnit(this.$uv.sys().windowWidth - this.textInfo.right - this.screenGap)}`
					this.indicatorStyle.right = this.$uv.addUnit(this.textInfo.width / 2 - this.$uv.getPx(style.right) - this
						.indicatorWidth / 2)
				} else {
					const left = Math.abs(this.textInfo.width / 2 - this.tooltipInfo.width / 2)
					style.left = this.textInfo.width > this.tooltipInfo.width ? this.$uv.addUnit(left) : -this.$uv.addUnit(left)
					this.indicatorStyle = {}
				}
				if (this.direction === 'top') {
					style.marginTop = `-${10 + this.tooltipInfo.height}px`
					this.indicatorStyle.bottom = '-4px'
				} else {
					style.marginTop = `${this.tooltipInfo.height-10}px`
					this.indicatorStyle.top = '-4px'
				}
				return style
			}
		},
		created() {
			this.textId = this.$uv.guid();
			this.tooltipId = this.$uv.guid();
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				this.getElRect()
			},
			// 长按触发事件
			async longpressHandler(e) {
				this.tooltipTop = 0
				this.showTooltip = true
				setTimeout(()=>{
					this.timeout = 1;
				},300)
			},
			// 点击透明遮罩
			overlayClickHandler() {
				this.showTooltip = false
			},
			// 点击弹出按钮
			btnClickHandler(index) {
				this.showTooltip = false
				// 如果需要展示复制按钮，此处index需要加1，因为复制按钮在第一个位置
				this.$emit('click', this.showCopy ? index + 1 : index)
			},
			// 查询内容高度
			queryRect(ref) {
				// #ifndef APP-NVUE
				// 组件内部一般用this.$uvGetRect，对外的为getRect，二者功能一致，名称不同
				return new Promise(resolve => {
					this.$uvGetRect(`#${ref}`).then(size => {
						resolve(size)
					})
				})
				// #endif

				// #ifdef APP-NVUE
				// nvue下，使用dom模块查询元素高度
				// 返回一个promise，让调用此方法的主体能使用then回调
				return new Promise(resolve => {
					dom.getComponentRect(this.$refs[ref], res => {
						resolve(res.size)
					})
				})
				// #endif
			},
			// 元素尺寸
			getElRect() {
				// 调用之前，先将指示器调整到屏幕外，方便获取尺寸
				this.showTooltip = true
				this.tooltipTop = -10000
				this.$uv.sleep(500).then(() => {
					this.queryRect(this.tooltipId).then(size => {
						this.tooltipInfo = size
						// 获取气泡尺寸之后，将其隐藏，为了让下次切换气泡显示与隐藏时，有淡入淡出的效果
						this.showTooltip = false
					})
					this.queryRect(this.textId).then(size => {
						this.textInfo = size
					})
				})
			},
			// 复制文本到粘贴板
			setClipboardData() {
				// 关闭组件
				this.showTooltip = false
				this.$emit('click', 0)
				uni.setClipboardData({
					// 优先使用copyText字段，如果没有，则默认使用text字段当做复制的内容
					data: this.copyText || this.text,
					success: () => {
						this.showToast && this.$uv.toast('复制成功')
					},
					fail: () => {
						this.showToast && this.$uv.toast('复制失败')
					},
					complete: () => {
						this.showTooltip = false
					}
				})
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';

	.uv-tooltip {
		position: relative;
		@include flex;

		&__wrapper {
			@include flex;
			justify-content: center;
			/* #ifndef APP-NVUE */
			white-space: nowrap;
			/* #endif */

			&__text {
				font-size: 14px;
			}

			&__popup {
				@include flex;
				justify-content: center;

				&__list {
					background-color: #060607;
					position: relative;
					flex: 1;
					border-radius: 5px;
					padding: 0px 0;
					@include flex(row);
					align-items: center;
					overflow: hidden;

					&__btn {
						padding: 11px 13px;

						&--hover {
							background-color: #58595B;
						}

						&__text {
							line-height: 12px;
							font-size: 13px;
							color: #FFFFFF;
						}
					}
				}

				&__indicator {
					position: absolute;
					background-color: #060607;
					width: 14px;
					height: 14px;
					bottom: -4px;
					transform: rotate(45deg);
					border-radius: 2px;
					z-index: -1;

					&--hover {
						background-color: #58595B;
					}
				}
			}
		}
	}
</style>
4.x {
  "id": "uv-tooltip",
  "displayName": "uv-tooltip 长按提示",
  "version": "1.0.5",
  "description": "Tooltip组件主要0用于长按操作，类似微信的长按气泡tooltip!!tooltip",
    "长按VX,
			"uv-linesnQ,Bm+ϼx }## Tooltip 长按提示Ntooltip**

Tooltip组件主要用于长按操作，类似微信的长按气泡1tooltiZGx	x e100644 changelog.md Y䖈cH B_کIOR40000 components BC/Rx100644 package.json ^aVD`54d_J100644 readme.md W١QtO	"=޿8xp## 1.0.8（2023-10-18）
1. 修复在APP上不能正常显示的BUG
## 1.0.7（2023-10-12）
1. 修复部分情况，修改某属性自动关闭的BUG
## 1.0.6（2023-07-24）
1. 优化  nvue模式下增加cellChild参数，是否在list中cell节点下，nvue中cell下建议设置成true
## 1.0.5（2023-07-02）
修改VUE3模式下可能存在的BUG
## 1.0.4（2023-07-02）
uv-transition  动画组件，代码重构优化，性能更加友好，增加自定义动画功能。详情参考文档：https://www.uvui.cn/components/transition.html
## 1.0.3（2023-06-12）
1. 恢复this.$nextTick的使用，经过测试百度等平台无问题
## 1.0.2（2023-05-23）
1. 百度小程序等平台不支持this.$nextick，修改成延时
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
1. 新增动画组件
gx( 40000 uv-transition 4	x yM)@;px 100644 createAnimation.js ADVpGSZqE?100644 props.js :ԭˣz6	Ċ;:100644 uv-transition.vue ϗ?b%t?6`1x.// const defaultOption = {
// 	duration: 300,
// 	timingFunction: 'linear',
// 	delay: 0,
// 	transformOrigin: '50% 50% 0'
// }
// #ifdef APP-NVUE
const nvueAnimation = uni.requireNativePlugin('animation')
// #endif
class MPAnimation {
	constructor(options, _this) {
		this.options = options
		// 在iOS10+QQ小程序平台下，传给原生的对象一定是个普通对象而不是Proxy对象，否则会报parameter should be Object instead of ProxyObject的错误
		this.animation = uni.createAnimation({
			...options
		})
		this.currentStepAnimates = {}
		this.next = 0
		this.$ = _this

	}

	_nvuePushAnimates(type, args) {
		let aniObj = this.currentStepAnimates[this.next]
		let styles = {}
		if (!aniObj) {
			styles = {
				styles: {},
				config: {}
			}
		} else {
			styles = aniObj
		}
		if (animateTypes1.includes(type)) {
			if (!styles.styles.transform) {
				styles.styles.transform = ''
			}
			let unit = ''
			if(type === 'rotate'){
				unit = 'deg'
			}
			styles.styles.transform += `${type}(${args+unit}) `
		} else {
			styles.styles[type] = `${args}`
		}
		this.currentStepAnimates[this.next] = styles
	}
	_animateRun(styles = {}, config = {}) {
		let ref = this.$.$refs['ani'].ref
		if (!ref) return
		return new Promise((resolve, reject) => {
			nvueAnimation.transition(ref, {
				styles,
				...config
			}, res => {
				resolve()
			})
		})
	}

	_nvueNextAnimate(animates, step = 0, fn) {
		let obj = animates[step]
		if (obj) {
			let {
				styles,
				config
			} = obj
			this._animateRun(styles, config).then(() => {
				step += 1
				this._nvueNextAnimate(animates, step, fn)
			})
		} else {
			this.currentStepAnimates = {}
			typeof fn === 'function' && fn()
			this.isEnd = true
		}
	}

	step(config = {}) {
		// #ifndef APP-NVUE
		this.animation.step(config)
		// #endif
		// #ifdef APP-NVUE
		this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
		this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
		this.next++
		// #endif
		return this
	}

	run(fn) {
		// #ifndef APP-NVUE
		this.$.animationData = this.animation.export()
		this.$.timer = setTimeout(() => {
			typeof fn === 'function' && fn()
		}, this.$.durationTime)
		// #endif
		// #ifdef APP-NVUE
		this.isEnd = false
		let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref
		if(!ref) return
		this._nvueNextAnimate(this.currentStepAnimates, 0, fn)
		this.next = 0
		// #endif
	}
}


const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
	'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
	'translateZ'
]
const animateTypes2 = ['opacity', 'backgroundColor']
const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom']
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
	MPAnimation.prototype[type] = function(...args) {
		// #ifndef APP-NVUE
		this.animation[type](...args)
		// #endif
		// #ifdef APP-NVUE
		this._nvuePushAnimates(type, args)
		// #endif
		return this
	}
})

export function createAnimation(option, _this) {
	if(!_this) return
	clearTimeout(_this.timer)
	return new MPAnimation(option, _this)
}
5x	export default {
	props: {
		// 是否展示组件
		show: {
			type: Boolean,
			default: false
		},
		// 使用的动画模式
		mode: {
			type: [Array, String, null],
			default() {
				return 'fade'
			}
		},
		// 动画的执行时间，单位ms
		duration: {
			type: [String, Number],
			default: 300
		},
		// 使用的动画过渡函数
		timingFunction: {
			type: String,
			default: 'ease-out'
		},
		customClass: {
			type: String,
			default: ''
		},
		...uni.$uv?.props?.transition
	}
}Ѳx=<template>
  <!-- #ifndef APP-NVUE -->
  <view 
		v-if="isShow" 
		ref="ani" 
		:animation="animationData" 
		:class="customClass" 
		:style="transformStyles" 
		@click="onClick">
		<slot></slot>
	</view>
  <!-- #endif -->
  <!-- #ifdef APP-NVUE -->
  <view 
		v-if="isShow" 
		ref="ani" 
		:animation="animationData" 
		:class="customClass" 
		:style="transformStyles" 
		@click="onClick">
		<slot></slot>
	</view>
  <!-- #endif -->
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import { createAnimation } from './createAnimation'
	/**
	* transition  动画组件
	* @description
	* @tutorial
	* @property {Boolean}	show	控制组件显示或关闭 （默认 false ）
	* @property {Array | String	}	mode	内置过渡动画类型 （默认 'fade' ）
	* @value fade 渐隐渐出过渡
	* @value slide-top 由上至下过渡
	* @value slide-bottom 由下至上过渡
	* @value slide-left 由左至右过渡
	* @value slide-right 由右至左过渡
	* @value zoom-in 由小到大过渡
	* @value zoom-out 由大到小过渡
	* @property {String | Number}	duration	动画的执行时间，单位ms （默认 300 ）
	* @property {String} timingFunction	使用的动画过渡函数 （默认 'ease-out' ）
	* @property {Object} customStyle	自定义样式
	* @property {String} customClass	自定义类名
	* @event {Function} click 点击组件触发	
	* @event {Function} change	过渡动画结束时触发	
	* @example 
	*/
	export default {
		name: 'uv-transition',
		mixins: [mpMixin,mixin],
		emits:['click','change'],
		props: {
			// 是否展示组件
			show: {
				type: Boolean,
				default: false
			},
			// 使用的动画模式
			mode: {
				type: [Array, String, null],
				default() {
					return 'fade'
				}
			},
			// 动画的执行时间，单位ms
			duration: {
				type: [String, Number],
				default: 300
			},
			// 使用的动画过渡函数
			timingFunction: {
				type: String,
				default: 'ease-out'
			},
			customClass: {
				type: String,
				default: ''
			},
			// nvue模式下 是否直接显示，在uv-list等cell下面使用就需要设置
			cellChild: {
				type: Boolean,
				default: false
			}
		},
		data(){
			return {
				isShow: false,
				transform: '',
				opacity: 1,
				animationData: {},
				durationTime: 300,
				config: {}
			}
		},
		watch: {
			show: {
				handler(newVal) {
					if (newVal) {
						this.open();
					} else {
						// 避免上来就执行 close,导致动画错乱
						if (this.isShow) {
							this.close();
						}
					}
				},
				immediate: true
			}
		},
		computed: {
			// 初始化动画条件
			transformStyles() {
				const style = {
					transform: this.transform,
					opacity: this.opacity,
					...this.$uv.addStyle(this.customStyle),
					'transition-duration': `${this.duration / 1000}s`
				};
				return this.$uv.addStyle(style,'string');
			}
		},
		created() {
			// 动画默认配置
			this.config = {
				duration: this.duration,
				timingFunction: this.timingFunction,
				transformOrigin: '50% 50%',
				delay: 0
			};
			this.durationTime = this.duration;
		},
		methods: {
			/**
			 *  ref 触发 初始化动画
			 */
			init(obj = {}) {
				if (obj.duration) {
					this.durationTime = obj.duration;
				}
				this.animation = createAnimation(Object.assign(this.config, obj),this);
			},
			/**
			 * 点击组件触发回调
			 */
			onClick() {
				this.$emit('click', {
					detail: this.isShow
				})
			},
			/**
			 * ref 触发 动画分组
			 * @param {Object} obj
			 */
			step(obj, config = {}) {
				if (!this.animation) return;
				for (let i in obj) {
					try {
						if(typeof obj[i] === 'object'){
							this.animation[i](...obj[i]);
						}else{
							this.animation[i](obj[i]);
						}
					} catch (e) {
						console.error(`方法 ${i} 不存在`);
					}
				}
				this.animation.step(config);
				return this;
			},
			/**
			 *  ref 触发 执行动画
			 */
			run(fn) {
				if (!this.animation) return;
				this.animation.run(fn);
			},
			// 开始过度动画
			open() {
				clearTimeout(this.timer);
				this.transform = '';
				this.isShow = true;
				let { opacity, transform } = this.styleInit(false);
				if (typeof opacity !== 'undefined') {
					this.opacity = opacity;
				}
				this.transform = transform;
				// 确保动态样式已经生效后，执行动画，如果不加 nextTick ，会导致 wx 动画执行异常
				this.$nextTick(() => {
					// TODO 定时器保证动画完全执行，目前有些问题，后面会取消定时器
					this.timer = setTimeout(() => {
						this.animation = createAnimation(this.config, this);
						this.tranfromInit(false).step();
						// #ifdef APP-NVUE
						if(this.cellChild) {
							this.opacity = 1;
						} else{
							this.animation.run();
						}
						// #endif
						// #ifndef APP-NVUE
						this.animation.run();
						// #endif
						// #ifdef VUE3
						// #ifdef H5
						this.opacity = 1;
						// #endif
						// #endif
						this.$emit('change', {
							detail: this.isShow
						})
						// #ifdef H5
						// #ifdef VUE3
						this.transform = '';
						// #endif
						// #endif
					}, 20);
				})
			},
			// 关闭过渡动画
			close(type) {
				if (!this.animation) return;
				this.tranfromInit(true)
					.step()
					.run(() => {
						this.isShow = false;
						this.animationData = null;
						this.animation = null;
						let { opacity, transform } = this.styleInit(false);
						this.opacity = opacity || 1;
						this.transform = transform;
						this.$emit('change', {
							detail: this.isShow
						});
					})
			},
			// 处理动画开始前的默认样式
			styleInit(type) {
				let styles = {
					transform: ''
				};
				let buildStyle = (type, mode) => {
					if (mode === 'fade') {
						styles.opacity = this.animationType(type)[mode];
					} else {
						styles.transform += this.animationType(type)[mode] + ' ';
					}
				}
				if (typeof this.mode === 'string') {
					buildStyle(type, this.mode);
				} else {
					this.mode.forEach(mode => {
						buildStyle(type, mode)
					})
				}
				return styles
			},
			// 处理内置组合动画
			tranfromInit(type) {
				let buildTranfrom = (type, mode) => {
					let aniNum = null;
					if (mode === 'fade') {
						aniNum = type ? 0 : 1;
					} else {
						aniNum = type ? '-100%' : '0';
						if (mode === 'zoom-in') {
							aniNum = type ? 0.8 : 1
						}
						if (mode === 'zoom-out') {
							aniNum = type ? 1.2 : 1
						}
						if (mode === 'slide-right') {
							aniNum = type ? '100%' : '0'
						}
						if (mode === 'slide-bottom') {
							aniNum = type ? '100%' : '0'
						}
					}
					this.animation[this.animationMode()[mode]](aniNum)
				}
				if (typeof this.mode === 'string') {
					buildTranfrom(type, this.mode)
				} else {
					this.mode.forEach(mode => {
						buildTranfrom(type, mode)
					})
				}
				return this.animation;
			},
			animationType(type) {
				return {
					fade: type ? 1 : 0,
					'slide-top': `translateY(${type ? '0' : '-100%'})`,
					'slide-right': `translateX(${type ? '0' : '100%'})`,
					'slide-bottom': `translateY(${type ? '0' : '100%'})`,
					'slide-left': `translateX(${type ? '0' : '-100%'})`,
					'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`,
					'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})`
				}
			},
			// 内置动画类型与实际动画对应字典
			animationMode() {
				return {
					fade: 'opacity',
					'slide-top': 'translateY',
					'slide-right': 'translateX',
					'slide-bottom': 'translateY',
					'slide-left': 'translateX',
					'zoom-in': 'scale',
					'zoom-out': 'scale'
				}
			},
			// 驼峰转中横线
			toLine(name) {
				return name.replace(/([A-Z])/g, '-$1').toLowerCase()
			}
		}
	}
</script>
q4x 4A{
  "id": "uv-transition",
  "displayName": "uv-transition 动画EHK8",
  "description": "transition 该组件用于组件的动画过渡效果+
transitionO!transition",
    "动画	KVϦCx t## Transition 动画Ptransition**

该组件用于组件的动画过渡效果，支持自定义动画>transitiu][[
Jx)100644 changelog.md sXSU:#{,_ 40000 components ؆(T	'`.2100644 index.js qh!&A
100644 index.scss ڗr4hԿZw40000 libs VƬYUWqK_q>e100644 package.json -aB8ۈxb))d100644 readme.md y^t2tzlH100644 theme.scss Ϫ/^G^q,}:_%wx;## 1.1.25（2024-01-20）
1.1.20版本更新
## 1.1.24（2023-12-21）
1. luch-request更新
## 1.1.23（2023-12-12）
1. 1.1.19版本
## 1.1.22（2023-11-28）
1. 优化
## 1.1.21（2023-11-10）
1. 1.1.17版本
## 1.1.20（2023-10-30）
1. 1.1.16版本
## 1.1.19（2023-10-13）
1. 兼容vue3
## 1.1.18（2023-10-12）
1. 1.1.15版本
## 1.1.17（2023-09-27）
1. 1.1.14版本发布
## 1.1.16（2023-09-15）
1. 1.1.13版本发布
## 1.1.15（2023-09-15）
1. 更新button.js相关按钮支持open-type="agreePrivacyAuthorization"
## 1.1.14（2023-09-14）
1. 优化dayjs
## 1.1.13（2023-09-13）
1. 优化，$uv中增加unit参数，方便组件中使用
## 1.1.12（2023-09-10）
1. 升级版本
## 1.1.11（2023-09-04）
1. 1.1.11版本
## 1.1.10（2023-08-31）
1. 修复customStyle和customClass存在冲突的问题
## 1.1.9（2023-08-27）
1. 版本升级
2. 优化
## 1.1.8（2023-08-24）
1. 版本升级
## 1.1.7（2023-08-22）
1. 版本升级
## 1.1.6（2023-08-18）
uvui版本：1.1.6
## 1.0.15（2023-08-14）
1. 更新uvui版本号
## 1.0.13（2023-08-06）
1. 优化
## 1.0.12（2023-08-06）
1. 修改版本号
## 1.0.11（2023-08-06）
1. 路由增加events参数
2. 路由拦截修复
## 1.0.10（2023-08-01）
1. 优化
## 1.0.9（2023-06-28）
优化openType.js
## 1.0.8（2023-06-15）
1. 修改支付宝报错的BUG
## 1.0.7（2023-06-07）
1. 解决微信小程序使用uvui提示 Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors
2. 解决上述提示，需要在uni.scss配置$uvui-nvue-style: false; 然后在APP.vue下面引入uvui内置的基础样式:@import '@/uni_modules/uv-ui-tools/index.scss';
## 1.0.6（2023-06-04）
1.  uv-ui-tools 优化工具组件，兼容更多功能
2.  小程序分享功能优化等
## 1.0.5（2023-06-02）
1. 修改扩展使用mixin中方法的问题
## 1.0.4（2023-05-23）
1. 兼容百度小程序修改bem函数
## 1.0.3（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.2（2023-05-10）
1. 增加Http请求封装
2. 优化
## 1.0.1（2023-05-04）
1. 修改名称及备注
## 1.0.0（2023-05-04）
1. uv-ui工具集首次发布
cYx& 40000 uv-ui-tools c%tFWx+ 100644 uv-ui-tools.vue ^O-yT"`x; <template>
</template>
<script>
</script>
<style>
</style>
d꿎x// 全局挂载引入http相关请求拦截插件
import Request from './libs/luch-request'

// 引入全局mixin
import mixin from './libs/mixin/mixin.js'
// 小程序特有的mixin
import mpMixin from './libs/mixin/mpMixin.js'
// #ifdef MP
import mpShare from './libs/mixin/mpShare.js'
// #endif

// 路由封装
import route from './libs/util/route.js'
// 公共工具函数
import * as index from './libs/function/index.js'
// 防抖方法
import debounce from './libs/function/debounce.js'
// 节流方法
import throttle from './libs/function/throttle.js'
// 规则检验
import * as test from './libs/function/test.js'

// 颜色渐变相关,colorGradient-颜色渐变,hexToRgb-十六进制颜色转rgb颜色,rgbToHex-rgb转十六进制
import * as colorGradient from './libs/function/colorGradient.js'

// 配置信息
import config from './libs/config/config.js'
// 平台
import platform from './libs/function/platform'

const $uv = {
	route,
	config,
	test,
	date: index.timeFormat, // 另名date
	...index,
	colorGradient: colorGradient.colorGradient,
	hexToRgb: colorGradient.hexToRgb,
	rgbToHex: colorGradient.rgbToHex,
	colorToRgba: colorGradient.colorToRgba,
	http: new Request(),
	debounce,
	throttle,
	platform,
	mixin,
	mpMixin
}
uni.$uv = $uv;
const install = (Vue,options={}) => {
		// #ifndef APP-NVUE
		const cloneMixin = index.deepClone(mixin);
		delete cloneMixin?.props?.customClass;
		delete cloneMixin?.props?.customStyle;
		Vue.mixin(cloneMixin);
		// #ifdef MP
		if(options.mpShare){
			Vue.mixin(mpShare);
		}
		// #endif
		// #endif
		// #ifdef VUE2
		// 时间格式化，同时两个名称，date和timeFormat
		Vue.filter('timeFormat', (timestamp, format) => uni.$uv.timeFormat(timestamp, format));
		Vue.filter('date', (timestamp, format) => uni.$uv.timeFormat(timestamp, format));
		// 将多久以前的方法，注入到全局过滤器
		Vue.filter('timeFrom', (timestamp, format) => uni.$uv.timeFrom(timestamp, format));
		// 同时挂载到uni和Vue.prototype中
		// #ifndef APP-NVUE
		// 只有vue，挂载到Vue.prototype才有意义，因为nvue中全局Vue.prototype和Vue.mixin是无效的
		Vue.prototype.$uv = $uv;
		// #endif
		// #endif
		// #ifdef VUE3
		Vue.config.globalProperties.$uv = $uv;
		// #endif
}
export default {
	install
}ۏP	x m// 引入公共基础类
@import "./libs/css/common.scss";

// 非nvue的样式
/* #ifndef APP-NVUE */
@import "./libs/css/vue.scss";
/* #endif */9x 740000 config kٖ_JGj>~՞40000 css Je[Il0O40000 function ؠ33CuWD40000 luch-request g8];zo]40000 mixin <XQRͯ|V籼40000 util ,cEE5;p WnUx% 100644 config.js @[<;_i㞴v%ط@x// 此版本发布于2024-01-20
const version = '1.1.20'

// 开发环境才提示，生产环境不会提示
if (process.env.NODE_ENV === 'development') {
	console.log(`\n %c uvui V${version} https://www.uvui.cn/ \n\n`, 'color: #ffffff; background: #3c9cff; padding:5px 0; border-radius: 5px;');
}

export default {
    v: version,
    version,
    // 主题名称
    type: [
        'primary',
        'success',
        'info',
        'error',
        'warning'
    ],
    // 颜色部分，本来可以通过scss的:export导出供js使用，但是奈何nvue不支持
    color: {
        'uv-primary': '#2979ff',
        'uv-warning': '#ff9900',
        'uv-success': '#19be6b',
        'uv-error': '#fa3534',
        'uv-info': '#909399',
        'uv-main-color': '#303133',
        'uv-content-color': '#606266',
        'uv-tips-color': '#909399',
        'uv-light-color': '#c0c4cc'
    },
	// 默认单位，可以通过配置为rpx，那么在用于传入组件大小参数为数值时，就默认为rpx
	unit: 'px'
}
Ix :100644 color.scss et47Pη=\^J100644 common.scss z`o1e_BL100644 components.scss ׆;hwd<f( 100644 variable.scss c<D~Ў/l)=100644 vue.scss +uY6nUP:xQ$uv-main-color: #303133 !default;
$uv-content-color: #606266 !default;
$uv-tips-color: #909193 !default;
$uv-light-color: #c0c4cc !default;
$uv-border-color: #dadbde !default;
$uv-bg-color: #f3f4f6 !default;
$uv-disabled-color: #c8c9cc !default;

$uv-primary: #3c9cff !default;
$uv-primary-dark: #398ade !default;
$uv-primary-disabled: #9acafc !default;
$uv-primary-light: #ecf5ff !default;

$uv-warning: #f9ae3d !default;
$uv-warning-dark: #f1a532 !default;
$uv-warning-disabled: #f9d39b !default;
$uv-warning-light: #fdf6ec !default;

$uv-success: #5ac725 !default;
$uv-success-dark: #53c21d !default;
$uv-success-disabled: #a9e08f !default;
$uv-success-light: #f5fff0;

$uv-error: #f56c6c !default;
$uv-error-dark: #e45656 !default;
$uv-error-disabled: #f7b2b2 !default;
$uv-error-light: #fef0f0 !default;

$uv-info: #909399 !default;
$uv-info-dark: #767a82 !default;
$uv-info-disabled: #c4c6c9 !default;
$uv-info-light: #f4f4f5 !default;
c/x 
// 超出行数，自动显示行尾省略号，最多5行
// 来自uvui的温馨提示：当您在控制台看到此报错，说明需要在App.vue的style标签加上【lang="scss"】
@for $i from 1 through 5 {
	.uv-line-#{$i} {
		/* #ifdef APP-NVUE */
		// nvue下，可以直接使用lines属性，这是weex特有样式
		lines: $i;
		text-overflow: ellipsis;
		overflow: hidden;
		flex: 1;
		/* #endif */

		/* #ifndef APP-NVUE */
		// vue下，单行和多行显示省略号需要单独处理
		@if $i == '1' {
			overflow: hidden;
			white-space: nowrap;
			text-overflow: ellipsis;
		} @else {
			display: -webkit-box!important;
			overflow: hidden;
			text-overflow: ellipsis;
			word-break: break-all;
			-webkit-line-clamp: $i;
			-webkit-box-orient: vertical!important;
		}
		/* #endif */
	}
}
$uv-bordercolor: #dadbde;
@if variable-exists(uv-border-color) {
	$uv-bordercolor: $uv-border-color;
}

// 此处加上!important并非随意乱用，而是因为目前*.nvue页面编译到H5时，
// App.vue的样式会被uni-app的view元素的自带border属性覆盖，导致无效
// 综上，这是uni-app的缺陷导致我们为了多端兼容，而必须要加上!important
// 移动端兼容性较好，直接使用0.5px去实现细边框，不使用伪元素形式实现
.uv-border {
	border-width: 0.5px!important;
	border-color: $uv-bordercolor!important;
    border-style: solid;
}

.uv-border-top {
	border-top-width: 0.5px!important;
	border-color: $uv-bordercolor!important;
    border-top-style: solid;
}

.uv-border-left {
	border-left-width: 0.5px!important;
	border-color: $uv-bordercolor!important;
    border-left-style: solid;
}

.uv-border-right {
	border-right-width: 0.5px!important;
	border-color: $uv-bordercolor!important;
    border-right-style: solid;
}

.uv-border-bottom {
	border-bottom-width: 0.5px!important;
	border-color: $uv-bordercolor!important;
    border-bottom-style: solid;
}

.uv-border-top-bottom {
	border-top-width: 0.5px!important;
	border-bottom-width: 0.5px!important;
	border-color: $uv-bordercolor!important;
    border-top-style: solid;
    border-bottom-style: solid;
}

// 去除button的所有默认样式，让其表现跟普通的view、text元素一样
.uv-reset-button {
	padding: 0;
	background-color: transparent;
	/* #ifndef APP-PLUS */
	font-size: inherit;
	line-height: inherit;
	color: inherit;
	/* #endif */
	/* #ifdef APP-NVUE */
	border-width: 0;
	/* #endif */
}

/* #ifndef APP-NVUE */
.uv-reset-button::after {
   border: none;
}
/* #endif */

.uv-hover-class {
	opacity: 0.7;
}

3E&xl@mixin flex($direction: row) {
	/* #ifndef APP-NVUE */
	display: flex;
	/* #endif */
	flex-direction: $direction;
}

/* #ifndef APP-NVUE */
// 由于uvui是基于nvue环境进行开发的，此环境中普通元素默认为flex-direction: column;
// 所以在非nvue中，需要对元素进行重置为flex-direction: column; 否则可能会表现异常
$uvui-nvue-style: true !default;
@if $uvui-nvue-style == true {
	view, scroll-view, swiper-item {
		display: flex;
		flex-direction: column;
		flex-shrink: 0;
		flex-grow: 0;
		flex-basis: auto;
		align-items: stretch;
		align-content: flex-start;
	}
}
/* #endif */
EGxqBshow-lines) {
		.uv-line-#{$i} {
		P	H
	lines: $i!flex: 1;
			/* #endif */

	@	@if $i == '1' {
	~(	text-overflow: ellipsis;
			} @else {
	[&	text-overflow: ellipsis;
	+	}
			/* #endif */
		}
	}
}@+show-border) {
	$uv-bordercolor: #dadbde;
	A(h$	}
	^	X	E`	c	A)show-border-surround) {
		.uv-border {
		!	1* 			border-style: solid;
		}
	}
	A(show-border-top) {
		.uv-border-top {
		%	1*					}
	}
	A*show-border-left) {
		.uv-border-left {
		&	1*			_		}
	}
	A,show-border-right) {
		.uv-border-right {
		'	1*&			border-right-style: solid;
		}
	}
	Ashow-border-bottom) {
			(	1*				j		}
	}
	A6show-border-top-bottom) {
		.uv-border-top-bottom {
		%	(	1*						j		}
	}
}@show-reset-button) {
	VW#	.uv-reset-button {
		padding: 0;
	!O	font-size: inherit;
		line-height: inherit;
		color: inherit;
		/* #endif */
	P	%	border-width: 0;
		/* #endif */
	}

	#		 border: none;
	}
	/* #endif */
}@6show-hover) {
	.uv-hover-class {
		opacity: 0.7;
	}
}
Y@?5x_// 历遍生成4个方向的底部安全区
@each $d in top, right, bottom, left {
	.uv-safe-area-inset-#{$d} {
		padding-#{$d}: 0;
		padding-#{$d}: constant(safe-area-inset-#{$d});  
		padding-#{$d}: env(safe-area-inset-#{$d});  
	}
}

//提升H5端uni.toast()的层级，避免被uvui的modal等遮盖
/* #ifdef H5 */
uni-toast {
    z-index: 10090;
}
uni-toast .uni-toast {
   z-index: 10090;
}
/* #endif */

// 隐藏scroll-view的滚动条
::-webkit-scrollbar {
    display: none;  
    width: 0 !important;  
    height: 0 !important;  
    -webkit-appearance: none;  
    background: transparent;  
}

$uvui-nvue-style: true !default;
@if $uvui-nvue-style == false {
	view, scroll-view, swiper-item {
		display: flex;
		flex-direction: column;
		flex-shrink: 0;
		flex-grow: 0;
		flex-basis: auto;
		align-items: stretch;
		align-content: flex-start;
	}
}
4x100644 colorGradient.js U 8ZtsJ100644 debounce.js 9V4?/%5 ua100644 digit.js &
꿹b+K%QoQ100644 index.js ^
z?Qwң100644 platform.js ֹ&I~ӇMBâ100644 test.js |ts.X	iVi100644 throttle.js /3atp 
^Žd.)lx7/**
 * 求两个颜色之间的渐变值
 * @param {string} startColor 开始的颜色
 * @param {string} endColor 结束的颜色
 * @param {number} step 颜色等分的份额
 * */
function colorGradient(startColor = 'rgb(0, 0, 0)', endColor = 'rgb(255, 255, 255)', step = 10) {
    const startRGB = hexToRgb(startColor, false) // 转换为rgb数组模式
    const startR = startRGB[0]
    const startG = startRGB[1]
    const startB = startRGB[2]

    const endRGB = hexToRgb(endColor, false)
    const endR = endRGB[0]
    const endG = endRGB[1]
    const endB = endRGB[2]

    const sR = (endR - startR) / step // 总差值
    const sG = (endG - startG) / step
    const sB = (endB - startB) / step
    const colorArr = []
    for (let i = 0; i < step; i++) {
        // 计算每一步的hex值
        let hex = rgbToHex(`rgb(${Math.round((sR * i + startR))},${Math.round((sG * i + startG))},${Math.round((sB
			* i + startB))})`)
        // 确保第一个颜色值为startColor的值
        if (i === 0) hex = rgbToHex(startColor)
        // 确保最后一个颜色值为endColor的值
        if (i === step - 1) hex = rgbToHex(endColor)
        colorArr.push(hex)
    }
    return colorArr
}

// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
function hexToRgb(sColor, str = true) {
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
    sColor = String(sColor).toLowerCase()
    if (sColor && reg.test(sColor)) {
        if (sColor.length === 4) {
            let sColorNew = '#'
            for (let i = 1; i < 4; i += 1) {
                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
            }
            sColor = sColorNew
        }
        // 处理六位的颜色值
        const sColorChange = []
        for (let i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
        }
        if (!str) {
            return sColorChange
        }
        return `rgb(${sColorChange[0]},${sColorChange[1]},${sColorChange[2]})`
    } if (/^(rgb|RGB)/.test(sColor)) {
        const arr = sColor.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
        return arr.map((val) => Number(val))
    }
    return sColor
}

// 将rgb表示方式转换为hex表示方式
function rgbToHex(rgb) {
    const _this = rgb
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
    if (/^(rgb|RGB)/.test(_this)) {
        const aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
        let strHex = '#'
        for (let i = 0; i < aColor.length; i++) {
            let hex = Number(aColor[i]).toString(16)
            hex = String(hex).length == 1 ? `${0}${hex}` : hex // 保证每个rgb的值为2位
            if (hex === '0') {
                hex += hex
            }
            strHex += hex
        }
        if (strHex.length !== 7) {
            strHex = _this
        }
        return strHex
    } if (reg.test(_this)) {
        const aNum = _this.replace(/#/, '').split('')
        if (aNum.length === 6) {
            return _this
        } if (aNum.length === 3) {
            let numHex = '#'
            for (let i = 0; i < aNum.length; i += 1) {
                numHex += (aNum[i] + aNum[i])
            }
            return numHex
        }
    } else {
        return _this
    }
}

/**
* JS颜色十六进制转换为rgb或rgba,返回的格式为 rgba（255，255，255，0.5）字符串
* sHex为传入的十六进制的色值
* alpha为rgba的透明度
*/
function colorToRgba(color, alpha) {
    color = rgbToHex(color)
    // 十六进制颜色值的正则表达式
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
    /* 16进制颜色转为RGB格式 */
    let sColor = String(color).toLowerCase()
    if (sColor && reg.test(sColor)) {
        if (sColor.length === 4) {
            let sColorNew = '#'
            for (let i = 1; i < 4; i += 1) {
                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
            }
            sColor = sColorNew
        }
        // 处理六位的颜色值
        const sColorChange = []
        for (let i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
        }
        // return sColorChange.join(',')
        return `rgba(${sColorChange.join(',')},${alpha})`
    }

    return sColor
}

export {
    colorGradient,
    hexToRgb,
    rgbToHex,
    colorToRgba
}
l{:xSlet timeout = null

/**
 * 防抖原理：一定时间内，只有最后一次操作，再过wait毫秒后才执行函数
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function debounce(func, wait = 500, immediate = false) {
    // 清除定时器
    if (timeout !== null) clearTimeout(timeout)
    // 立即执行，此类情况一般用不到
    if (immediate) {
        const callNow = !timeout
        timeout = setTimeout(() => {
            timeout = null
        }, wait)
        if (callNow) typeof func === 'function' && func()
    } else {
        // 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
        timeout = setTimeout(() => {
            typeof func === 'function' && func()
        }, wait)
    }
}

export default debounce
Օ#xlet _boundaryCheckingState = true; // 是否进行越界检查的全局开关

/**
 * 把错误的数据转正
 * @private
 * @example strip(0.09999999999999998)=0.1
 */
function strip(num, precision = 15) {
  return +parseFloat(Number(num).toPrecision(precision));
}

/**
 * Return digits length of a number
 * @private
 * @param {*number} num Input number
 */
function digitLength(num) {
  // Get digit length of e
  const eSplit = num.toString().split(/[eE]/);
  const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
  return len > 0 ? len : 0;
}

/**
 * 把小数转成整数,如果是小数则放大成整数
 * @private
 * @param {*number} num 输入数
 */
function float2Fixed(num) {
  if (num.toString().indexOf('e') === -1) {
    return Number(num.toString().replace('.', ''));
  }
  const dLen = digitLength(num);
  return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
}

/**
 * 检测数字是否越界，如果越界给出提示
 * @private
 * @param {*number} num 输入数
 */
function checkBoundary(num) {
  if (_boundaryCheckingState) {
    if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
      console.warn(`${num} 超出了精度限制，结果可能不正确`);
    }
  }
}

/**
 * 把递归操作扁平迭代化
 * @param {number[]} arr 要操作的数字数组
 * @param {function} operation 迭代操作
 * @private
 */
function iteratorOperation(arr, operation) {
  const [num1, num2, ...others] = arr;
  let res = operation(num1, num2);

  others.forEach((num) => {
    res = operation(res, num);
  });

  return res;
}

/**
 * 高精度乘法
 * @export
 */
export function times(...nums) {
  if (nums.length > 2) {
    return iteratorOperation(nums, times);
  }

  const [num1, num2] = nums;
  const num1Changed = float2Fixed(num1);
  const num2Changed = float2Fixed(num2);
  const baseNum = digitLength(num1) + digitLength(num2);
  const leftValue = num1Changed * num2Changed;

  checkBoundary(leftValue);

  return leftValue / Math.pow(10, baseNum);
}

/**
 * 高精度加法
 * @export
 */
export function plus(...nums) {
  if (nums.length > 2) {
    return iteratorOperation(nums, plus);
  }

  const [num1, num2] = nums;
  // 取最大的小数位
  const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  // 把小数都转为整数然后再计算
  return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
}

/**
 * 高精度减法
 * @export
 */
export function minus(...nums) {
  if (nums.length > 2) {
    return iteratorOperation(nums, minus);
  }

  const [num1, num2] = nums;
  const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
}

/**
 * 高精度除法
 * @export
 */
export function divide(...nums) {
  if (nums.length > 2) {
    return iteratorOperation(nums, divide);
  }

  const [num1, num2] = nums;
  const num1Changed = float2Fixed(num1);
  const num2Changed = float2Fixed(num2);
  checkBoundary(num1Changed);
  checkBoundary(num2Changed);
  // 重要，这里必须用strip进行修正
  return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
}

/**
 * 四舍五入
 * @export
 */
export function round(num, ratio) {
  const base = Math.pow(10, ratio);
  let result = divide(Math.round(Math.abs(times(num, base))), base);
  if (num < 0 && result !== 0) {
    result = times(result, -1);
  }
  // 位数不足则补0
  return result;
}

/**
 * 是否进行边界检查，默认开启
 * @param flag 标记开关，true 为开启，false 为关闭，默认为 true
 * @export
 */
export function enableBoundaryChecking(flag = true) {
  _boundaryCheckingState = flag;
}


export default {
  times,
  plus,
  minus,
  divide,
  round,
  enableBoundaryChecking,
};

͙
xWVimport { number, empty } from './test.js'
import { round } from './digit.js'
/**
 * @description 如果value小于min，取min；如果value大于max，取max
 * @param {number} min
 * @param {number} max
 * @param {number} value
 */
function range(min = 0, max = 0, value = 0) {
	return Math.max(min, Math.min(max, Number(value)))
}

/**
 * @description 用于获取用户传递值的px值  如果用户传递了"xxpx"或者"xxrpx"，取出其数值部分，如果是"xxxrpx"还需要用过uni.upx2px进行转换
 * @param {number|string} value 用户传递值的px值
 * @param {boolean} unit
 * @returns {number|string}
 */
function getPx(value, unit = false) {
	if (number(value)) {
		return unit ? `${value}px` : Number(value)
	}
	// 如果带有rpx，先取出其数值部分，再转为px值
	if (/(rpx|upx)$/.test(value)) {
		return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)))
	}
	return unit ? `${parseInt(value)}px` : parseInt(value)
}

/**
 * @description 进行延时，以达到可以简写代码的目的 比如: await uni.$uv.sleep(20)将会阻塞20ms
 * @param {number} value 堵塞时间 单位ms 毫秒
 * @returns {Promise} 返回promise
 */
function sleep(value = 30) {
	return new Promise((resolve) => {
		setTimeout(() => {
			resolve()
		}, value)
	})
}
/**
 * @description 运行期判断平台
 * @returns {string} 返回所在平台(小写)
 * @link 运行期判断平台 https://uniapp.dcloud.io/frame?id=判断平台
 */
function os() {
	return uni.getSystemInfoSync().platform.toLowerCase()
}
/**
 * @description 获取系统信息同步接口
 * @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync
 */
function sys() {
	return uni.getSystemInfoSync()
}

/**
 * @description 取一个区间数
 * @param {Number} min 最小值
 * @param {Number} max 最大值
 */
function random(min, max) {
	if (min >= 0 && max > 0 && max >= min) {
		const gab = max - min + 1
		return Math.floor(Math.random() * gab + min)
	}
	return 0
}

/**
 * @param {Number} len uuid的长度
 * @param {Boolean} firstU 将返回的首字母置为"u"
 * @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
 */
function guid(len = 32, firstU = true, radix = null) {
	const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
	const uuid = []
	radix = radix || chars.length

	if (len) {
		// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
		for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
	} else {
		let r
		// rfc4122标准要求返回的uuid中,某些位为固定的字符
		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
		uuid[14] = '4'

		for (let i = 0; i < 36; i++) {
			if (!uuid[i]) {
				r = 0 | Math.random() * 16
				uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
			}
		}
	}
	// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
	if (firstU) {
		uuid.shift()
		return `u${uuid.join('')}`
	}
	return uuid.join('')
}

/**
* @description 获取父组件的参数，因为支付宝小程序不支持provide/inject的写法
   this.$parent在非H5中，可以准确获取到父组件，但是在H5中，需要多次this.$parent.$parent.xxx
   这里默认值等于undefined有它的含义，因为最顶层元素(组件)的$parent就是undefined，意味着不传name
   值(默认为undefined)，就是查找最顶层的$parent
*  @param {string|undefined} name 父组件的参数名
*/
function $parent(name = undefined) {
	let parent = this.$parent
	// 通过while历遍，这里主要是为了H5需要多层解析的问题
	while (parent) {
		// 父组件
		if (parent.$options && parent.$options.name !== name) {
			// 如果组件的name不相等，继续上一级寻找
			parent = parent.$parent
		} else {
			return parent
		}
	}
	return false
}

/**
 * @description 样式转换
 * 对象转字符串，或者字符串转对象
 * @param {object | string} customStyle 需要转换的目标
 * @param {String} target 转换的目的，object-转为对象，string-转为字符串
 * @returns {object|string}
 */
function addStyle(customStyle, target = 'object') {
	// 字符串转字符串，对象转对象情形，直接返回
	if (empty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target === 'string' &&
		typeof(customStyle) === 'string') {
		return customStyle
	}
	// 字符串转对象
	if (target === 'object') {
		// 去除字符串样式中的两端空格(中间的空格不能去掉，比如padding: 20px 0如果去掉了就错了)，空格是无用的
		customStyle = trim(customStyle)
		// 根据";"将字符串转为数组形式
		const styleArray = customStyle.split(';')
		const style = {}
		// 历遍数组，拼接成对象
		for (let i = 0; i < styleArray.length; i++) {
			// 'font-size:20px;color:red;'，如此最后字符串有";"的话，会导致styleArray最后一个元素为空字符串，这里需要过滤
			if (styleArray[i]) {
				const item = styleArray[i].split(':')
				style[trim(item[0])] = trim(item[1])
			}
		}
		return style
	}
	// 这里为对象转字符串形式
	let string = ''
	for (const i in customStyle) {
		// 驼峰转为中划线的形式，否则css内联样式，无法识别驼峰样式属性名
		const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
		string += `${key}:${customStyle[i]};`
	}
	// 去除两端空格
	return trim(string)
}

/**
 * @description 添加单位，如果有rpx，upx，%，px等单位结尾或者值为auto，直接返回，否则加上px单位结尾
 * @param {string|number} value 需要添加单位的值
 * @param {string} unit 添加的单位名 比如px
 */
function addUnit(value = 'auto', unit = uni?.$uv?.config?.unit ? uni?.$uv?.config?.unit : 'px') {
	value = String(value)
	// 用uvui内置验证规则中的number判断是否为数值
	return number(value) ? `${value}${unit}` : value
}

/**
 * @description 深度克隆
 * @param {object} obj 需要深度克隆的对象
 * @param cache 缓存
 * @returns {*} 克隆后的对象或者原值（不是对象）
 */
function deepClone(obj, cache = new WeakMap()) {
	if (obj === null || typeof obj !== 'object') return obj;
	if (cache.has(obj)) return cache.get(obj);
	let clone;
	if (obj instanceof Date) {
		clone = new Date(obj.getTime());
	} else if (obj instanceof RegExp) {
		clone = new RegExp(obj);
	} else if (obj instanceof Map) {
		clone = new Map(Array.from(obj, ([key, value]) => [key, deepClone(value, cache)]));
	} else if (obj instanceof Set) {
		clone = new Set(Array.from(obj, value => deepClone(value, cache)));
	} else if (Array.isArray(obj)) {
		clone = obj.map(value => deepClone(value, cache));
	} else if (Object.prototype.toString.call(obj) === '[object Object]') {
		clone = Object.create(Object.getPrototypeOf(obj));
		cache.set(obj, clone);
		for (const [key, value] of Object.entries(obj)) {
			clone[key] = deepClone(value, cache);
		}
	} else {
		clone = Object.assign({}, obj);
	}
	cache.set(obj, clone);
	return clone;
}

/**
 * @description JS对象深度合并
 * @param {object} target 需要拷贝的对象
 * @param {object} source 拷贝的来源对象
 * @returns {object|boolean} 深度合并后的对象或者false（入参有不是对象）
 */
function deepMerge(target = {}, source = {}) {
	target = deepClone(target)
	if (typeof target !== 'object' || target === null || typeof source !== 'object' || source === null) return target;
	const merged = Array.isArray(target) ? target.slice() : Object.assign({}, target);
	for (const prop in source) {
		if (!source.hasOwnProperty(prop)) continue;
		const sourceValue = source[prop];
		const targetValue = merged[prop];
		if (sourceValue instanceof Date) {
			merged[prop] = new Date(sourceValue);
		} else if (sourceValue instanceof RegExp) {
			merged[prop] = new RegExp(sourceValue);
		} else if (sourceValue instanceof Map) {
			merged[prop] = new Map(sourceValue);
		} else if (sourceValue instanceof Set) {
			merged[prop] = new Set(sourceValue);
		} else if (typeof sourceValue === 'object' && sourceValue !== null) {
			merged[prop] = deepMerge(targetValue, sourceValue);
		} else {
			merged[prop] = sourceValue;
		}
	}
	return merged;
}

/**
 * @description error提示
 * @param {*} err 错误内容
 */
function error(err) {
	// 开发环境才提示，生产环境不会提示
	if (process.env.NODE_ENV === 'development') {
		console.error(`uvui提示：${err}`)
	}
}

/**
 * @description 打乱数组
 * @param {array} array 需要打乱的数组
 * @returns {array} 打乱后的数组
 */
function randomArray(array = []) {
	// 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0
	return array.sort(() => Math.random() - 0.5)
}

// padStart 的 polyfill，因为某些机型或情况，还无法支持es7的padStart，比如电脑版的微信小程序
// 所以这里做一个兼容polyfill的兼容处理
if (!String.prototype.padStart) {
	// 为了方便表示这里 fillString 用了ES6 的默认参数，不影响理解
	String.prototype.padStart = function(maxLength, fillString = ' ') {
		if (Object.prototype.toString.call(fillString) !== '[object String]') {
			throw new TypeError(
				'fillString must be String'
			)
		}
		const str = this
		// 返回 String(str) 这里是为了使返回的值是字符串字面量，在控制台中更符合直觉
		if (str.length >= maxLength) return String(str)

		const fillLength = maxLength - str.length
		let times = Math.ceil(fillLength / fillString.length)
		while (times >>= 1) {
			fillString += fillString
			if (times === 1) {
				fillString += fillString
			}
		}
		return fillString.slice(0, fillLength) + str
	}
}

/**
 * @description 格式化时间
 * @param {String|Number} dateTime 需要格式化的时间戳
 * @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
 * @returns {string} 返回格式化后的字符串
 */
function timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
	let date
	// 若传入时间为假值，则取当前时间
	if (!dateTime) {
		date = new Date()
	}
	// 若为unix秒时间戳，则转为毫秒时间戳（逻辑有点奇怪，但不敢改，以保证历史兼容）
	else if (/^\d{10}$/.test(dateTime?.toString().trim())) {
		date = new Date(dateTime * 1000)
	}
	// 若用户传入字符串格式时间戳，new Date无法解析，需做兼容
	else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
		date = new Date(Number(dateTime))
	}
	// 处理平台性差异，在Safari/Webkit中，new Date仅支持/作为分割符的字符串时间
	// 处理 '2022-07-10 01:02:03'，跳过 '2022-07-10T01:02:03'
	else if (typeof dateTime === 'string' && dateTime.includes('-') && !dateTime.includes('T')) {
		date = new Date(dateTime.replace(/-/g, '/'))
	}
	// 其他都认为符合 RFC 2822 规范
	else {
		date = new Date(dateTime)
	}

	const timeSource = {
		'y': date.getFullYear().toString(), // 年
		'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
		'd': date.getDate().toString().padStart(2, '0'), // 日
		'h': date.getHours().toString().padStart(2, '0'), // 时
		'M': date.getMinutes().toString().padStart(2, '0'), // 分
		's': date.getSeconds().toString().padStart(2, '0') // 秒
		// 有其他格式化字符需求可以继续添加，必须转化成字符串
	}

	for (const key in timeSource) {
		const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
		if (ret) {
			// 年可能只需展示两位
			const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
			formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
		}
	}

	return formatStr
}

/**
 * @description 时间戳转为多久之前
 * @param {String|Number} timestamp 时间戳
 * @param {String|Boolean} format
 * 格式化规则如果为时间格式字符串，超出一定时间范围，返回固定的时间格式；
 * 如果为布尔值false，无论什么时间，都返回多久以前的格式
 * @returns {string} 转化后的内容
 */
function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
	if (timestamp == null) timestamp = Number(new Date())
	timestamp = parseInt(timestamp)
	// 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
	if (timestamp.toString().length == 10) timestamp *= 1000
	let timer = (new Date()).getTime() - timestamp
	timer = parseInt(timer / 1000)
	// 如果小于5分钟,则返回"刚刚",其他以此类推
	let tips = ''
	switch (true) {
		case timer < 300:
			tips = '刚刚'
			break
		case timer >= 300 && timer < 3600:
			tips = `${parseInt(timer / 60)}分钟前`
			break
		case timer >= 3600 && timer < 86400:
			tips = `${parseInt(timer / 3600)}小时前`
			break
		case timer >= 86400 && timer < 2592000:
			tips = `${parseInt(timer / 86400)}天前`
			break
		default:
			// 如果format为false，则无论什么时间戳，都显示xx之前
			if (format === false) {
				if (timer >= 2592000 && timer < 365 * 86400) {
					tips = `${parseInt(timer / (86400 * 30))}个月前`
				} else {
					tips = `${parseInt(timer / (86400 * 365))}年前`
				}
			} else {
				tips = timeFormat(timestamp, format)
			}
	}
	return tips
}

/**
 * @description 去除空格
 * @param String str 需要去除空格的字符串
 * @param String pos both(左右)|left|right|all 默认both
 */
function trim(str, pos = 'both') {
	str = String(str)
	if (pos == 'both') {
		return str.replace(/^\s+|\s+$/g, '')
	}
	if (pos == 'left') {
		return str.replace(/^\s*/, '')
	}
	if (pos == 'right') {
		return str.replace(/(\s*$)/g, '')
	}
	if (pos == 'all') {
		return str.replace(/\s+/g, '')
	}
	return str
}

/**
 * @description 对象转url参数
 * @param {object} data,对象
 * @param {Boolean} isPrefix,是否自动加上"?"
 * @param {string} arrayFormat 规则 indices|brackets|repeat|comma
 */
function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
	const prefix = isPrefix ? '?' : ''
	const _result = []
	if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'
	for (const key in data) {
		const value = data[key]
		// 去掉为空的参数
		if (['', undefined, null].indexOf(value) >= 0) {
			continue
		}
		// 如果值为数组，另行处理
		if (value.constructor === Array) {
			// e.g. {ids: [1, 2, 3]}
			switch (arrayFormat) {
				case 'indices':
					// 结果: ids[0]=1&ids[1]=2&ids[2]=3
					for (let i = 0; i < value.length; i++) {
						_result.push(`${key}[${i}]=${value[i]}`)
					}
					break
				case 'brackets':
					// 结果: ids[]=1&ids[]=2&ids[]=3
					value.forEach((_value) => {
						_result.push(`${key}[]=${_value}`)
					})
					break
				case 'repeat':
					// 结果: ids=1&ids=2&ids=3
					value.forEach((_value) => {
						_result.push(`${key}=${_value}`)
					})
					break
				case 'comma':
					// 结果: ids=1,2,3
					let commaStr = ''
					value.forEach((_value) => {
						commaStr += (commaStr ? ',' : '') + _value
					})
					_result.push(`${key}=${commaStr}`)
					break
				default:
					value.forEach((_value) => {
						_result.push(`${key}[]=${_value}`)
					})
			}
		} else {
			_result.push(`${key}=${value}`)
		}
	}
	return _result.length ? prefix + _result.join('&') : ''
}

/**
 * 显示消息提示框
 * @param {String} title 提示的内容，长度与 icon 取值有关。
 * @param {Number} duration 提示的延迟时间，单位毫秒，默认：2000
 */
function toast(title, duration = 2000) {
	uni.showToast({
		title: String(title),
		icon: 'none',
		duration
	})
}

/**
 * @description 根据主题type值,获取对应的图标
 * @param {String} type 主题名称,primary|info|error|warning|success
 * @param {boolean} fill 是否使用fill填充实体的图标
 */
function type2icon(type = 'success', fill = false) {
	// 如果非预置值,默认为success
	if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success'
	let iconName = ''
	// 目前(2019-12-12),info和primary使用同一个图标
	switch (type) {
		case 'primary':
			iconName = 'info-circle'
			break
		case 'info':
			iconName = 'info-circle'
			break
		case 'error':
			iconName = 'close-circle'
			break
		case 'warning':
			iconName = 'error-circle'
			break
		case 'success':
			iconName = 'checkmark-circle'
			break
		default:
			iconName = 'checkmark-circle'
	}
	// 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的
	if (fill) iconName += '-fill'
	return iconName
}

/**
 * @description 数字格式化
 * @param {number|string} number 要格式化的数字
 * @param {number} decimals 保留几位小数
 * @param {string} decimalPoint 小数点符号
 * @param {string} thousandsSeparator 千分位符号
 * @returns {string} 格式化后的数字
 */
function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') {
	number = (`${number}`).replace(/[^0-9+-Ee.]/g, '')
	const n = !isFinite(+number) ? 0 : +number
	const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
	const sep = (typeof thousandsSeparator === 'undefined') ? ',' : thousandsSeparator
	const dec = (typeof decimalPoint === 'undefined') ? '.' : decimalPoint
	let s = ''

	s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.')
	const re = /(-?\d+)(\d{3})/
	while (re.test(s[0])) {
		s[0] = s[0].replace(re, `$1${sep}$2`)
	}

	if ((s[1] || '').length < prec) {
		s[1] = s[1] || ''
		s[1] += new Array(prec - s[1].length + 1).join('0')
	}
	return s.join(dec)
}

/**
 * @description 获取duration值
 * 如果带有ms或者s直接返回，如果大于一定值，认为是ms单位，小于一定值，认为是s单位
 * 比如以30位阈值，那么300大于30，可以理解为用户想要的是300ms，而不是想花300s去执行一个动画
 * @param {String|number} value 比如: "1s"|"100ms"|1|100
 * @param {boolean} unit  提示: 如果是false 默认返回number
 * @return {string|number}
 */
function getDuration(value, unit = true) {
	const valueNum = parseInt(value)
	if (unit) {
		if (/s$/.test(value)) return value
		return value > 30 ? `${value}ms` : `${value}s`
	}
	if (/ms$/.test(value)) return valueNum
	if (/s$/.test(value)) return valueNum > 30 ? valueNum : valueNum * 1000
	return valueNum
}

/**
 * @description 日期的月或日补零操作
 * @param {String} value 需要补零的值
 */
function padZero(value) {
	return `00${value}`.slice(-2)
}

/**
 * @description 在uv-form的子组件内容发生变化，或者失去焦点时，尝试通知uv-form执行校验方法
 * @param {*} instance
 * @param {*} event
 */
function formValidate(instance, event) {
	const formItem = $parent.call(instance, 'uv-form-item')
	const form = $parent.call(instance, 'uv-form')
	// 如果发生变化的input或者textarea等，其父组件中有uv-form-item或者uv-form等，就执行form的validate方法
	// 同时将form-item的pros传递给form，让其进行精确对象验证
	if (formItem && form) {
		form.validateField(formItem.prop, () => {}, event)
	}
}

/**
 * @description 获取某个对象下的属性，用于通过类似'a.b.c'的形式去获取一个对象的的属性的形式
 * @param {object} obj 对象
 * @param {string} key 需要获取的属性字段
 * @returns {*}
 */
function getProperty(obj, key) {
	if (!obj) {
		return
	}
	if (typeof key !== 'string' || key === '') {
		return ''
	}
	if (key.indexOf('.') !== -1) {
		const keys = key.split('.')
		let firstObj = obj[keys[0]] || {}

		for (let i = 1; i < keys.length; i++) {
			if (firstObj) {
				firstObj = firstObj[keys[i]]
			}
		}
		return firstObj
	}
	return obj[key]
}

/**
 * @description 设置对象的属性值，如果'a.b.c'的形式进行设置
 * @param {object} obj 对象
 * @param {string} key 需要设置的属性
 * @param {string} value 设置的值
 */
function setProperty(obj, key, value) {
	if (!obj) {
		return
	}
	// 递归赋值
	const inFn = function(_obj, keys, v) {
		// 最后一个属性key
		if (keys.length === 1) {
			_obj[keys[0]] = v
			return
		}
		// 0~length-1个key
		while (keys.length > 1) {
			const k = keys[0]
			if (!_obj[k] || (typeof _obj[k] !== 'object')) {
				_obj[k] = {}
			}
			const key = keys.shift()
			// 自调用判断是否存在属性，不存在则自动创建对象
			inFn(_obj[k], keys, v)
		}
	}

	if (typeof key !== 'string' || key === '') {

	} else if (key.indexOf('.') !== -1) { // 支持多层级赋值操作
		const keys = key.split('.')
		inFn(obj, keys, value)
	} else {
		obj[key] = value
	}
}

/**
 * @description 获取当前页面路径
 */
function page() {
	const pages = getCurrentPages();
	const route = pages[pages.length - 1]?.route;
	// 某些特殊情况下(比如页面进行redirectTo时的一些时机)，pages可能为空数组
	return `/${route ? route : ''}`
}

/**
 * @description 获取当前路由栈实例数组
 */
function pages() {
	const pages = getCurrentPages()
	return pages
}

/**
 * 获取页面历史栈指定层实例
 * @param back {number} [0] - 0或者负数，表示获取历史栈的哪一层，0表示获取当前页面实例，-1 表示获取上一个页面实例。默认0。
 */
function getHistoryPage(back = 0) {
	const pages = getCurrentPages()
	const len = pages.length
	return pages[len - 1 + back]
}



/**
 * @description 修改uvui内置属性值
 * @param {object} props 修改内置props属性
 * @param {object} config 修改内置config属性
 * @param {object} color 修改内置color属性
 * @param {object} zIndex 修改内置zIndex属性
 */
function setConfig({
	props = {},
	config = {},
	color = {},
	zIndex = {}
}) {
	const {
		deepMerge,
	} = uni.$uv
	uni.$uv.config = deepMerge(uni.$uv.config, config)
	uni.$uv.props = deepMerge(uni.$uv.props, props)
	uni.$uv.color = deepMerge(uni.$uv.color, color)
	uni.$uv.zIndex = deepMerge(uni.$uv.zIndex, zIndex)
}

export {
	range,
	getPx,
	sleep,
	os,
	sys,
	random,
	guid,
	$parent,
	addStyle,
	addUnit,
	deepClone,
	deepMerge,
	error,
	randomArray,
	timeFormat,
	timeFrom,
	trim,
	queryParams,
	toast,
	type2icon,
	priceFormat,
	getDuration,
	padZero,
	formValidate,
	getProperty,
	setProperty,
	page,
	pages,
	getHistoryPage,
	setConfig
}Ο_oCx3/**
 * 注意：
 * 此部分内容，在vue-cli模式下，需要在vue.config.js加入如下内容才有效：
 * module.exports = {
 *     transpileDependencies: ['uview-v2']
 * }
 */

let platform = 'none'

// #ifdef VUE3
platform = 'vue3'
// #endif

// #ifdef VUE2
platform = 'vue2'
// #endif

// #ifdef APP-PLUS
platform = 'plus'
// #endif

// #ifdef APP-NVUE
platform = 'nvue'
// #endif

// #ifdef H5
platform = 'h5'
// #endif

// #ifdef MP-WEIXIN
platform = 'weixin'
// #endif

// #ifdef MP-ALIPAY
platform = 'alipay'
// #endif

// #ifdef MP-BAIDU
platform = 'baidu'
// #endif

// #ifdef MP-TOUTIAO
platform = 'toutiao'
// #endif

// #ifdef MP-QQ
platform = 'qq'
// #endif

// #ifdef MP-KUAISHOU
platform = 'kuaishou'
// #endif

// #ifdef MP-360
platform = '360'
// #endif

// #ifdef MP
platform = 'mp'
// #endif

// #ifdef QUICKAPP-WEBVIEW
platform = 'quickapp-webview'
// #endif

// #ifdef QUICKAPP-WEBVIEW-HUAWEI
platform = 'quickapp-webview-huawei'
// #endif

// #ifdef QUICKAPP-WEBVIEW-UNION
platform = 'quckapp-webview-union'
// #endif

export default platform
^x/**
 * 验证电子邮箱格式
 */
function email(value) {
    return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value)
}

/**
 * 验证手机格式
 */
function mobile(value) {
    return /^1([3589]\d|4[5-9]|6[1-2,4-7]|7[0-8])\d{8}$/.test(value)
}

/**
 * 验证URL格式
 */
function url(value) {
    return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/
        .test(value)
}

/**
 * 验证日期格式
 */
function date(value) {
    if (!value) return false
    // 判断是否数值或者字符串数值(意味着为时间戳)，转为数值，否则new Date无法识别字符串时间戳
    if (number(value)) value = +value
    return !/Invalid|NaN/.test(new Date(value).toString())
}

/**
 * 验证ISO类型的日期格式
 */
function dateISO(value) {
    return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
}

/**
 * 验证十进制数字
 */
function number(value) {
    return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
}

/**
 * 验证字符串
 */
function string(value) {
    return typeof value === 'string'
}

/**
 * 验证整数
 */
function digits(value) {
    return /^\d+$/.test(value)
}

/**
 * 验证身份证号码
 */
function idCard(value) {
    return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
        value
    )
}

/**
 * 是否车牌号
 */
function carNo(value) {
    // 新能源车牌
    const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/
    // 旧车牌
    const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/
    if (value.length === 7) {
        return creg.test(value)
    } if (value.length === 8) {
        return xreg.test(value)
    }
    return false
}

/**
 * 金额,只允许2位小数
 */
function amount(value) {
    // 金额，只允许保留两位小数
    return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value)
}

/**
 * 中文
 */
function chinese(value) {
    const reg = /^[\u4e00-\u9fa5]+$/gi
    return reg.test(value)
}

/**
 * 只能输入字母
 */
function letter(value) {
    return /^[a-zA-Z]*$/.test(value)
}

/**
 * 只能是字母或者数字
 */
function enOrNum(value) {
    // 英文或者数字
    const reg = /^[0-9a-zA-Z]*$/g
    return reg.test(value)
}

/**
 * 验证是否包含某个值
 */
function contains(value, param) {
    return value.indexOf(param) >= 0
}

/**
 * 验证一个值范围[min, max]
 */
function range(value, param) {
    return value >= param[0] && value <= param[1]
}

/**
 * 验证一个长度范围[min, max]
 */
function rangeLength(value, param) {
    return value.length >= param[0] && value.length <= param[1]
}

/**
 * 是否固定电话
 */
function landline(value) {
    const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/
    return reg.test(value)
}

/**
 * 判断是否为空
 */
function empty(value) {
    switch (typeof value) {
    case 'undefined':
        return true
    case 'string':
        if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
        break
    case 'boolean':
        if (!value) return true
        break
    case 'number':
        if (value === 0 || isNaN(value)) return true
        break
    case 'object':
        if (value === null || value.length === 0) return true
        for (const i in value) {
            return false
        }
        return true
    }
    return false
}

/**
 * 是否json字符串
 */
function jsonString(value) {
    if (typeof value === 'string') {
        try {
            const obj = JSON.parse(value)
            if (typeof obj === 'object' && obj) {
                return true
            }
            return false
        } catch (e) {
            return false
        }
    }
    return false
}

/**
 * 是否数组
 */
function array(value) {
    if (typeof Array.isArray === 'function') {
        return Array.isArray(value)
    }
    return Object.prototype.toString.call(value) === '[object Array]'
}

/**
 * 是否对象
 */
function object(value) {
    return Object.prototype.toString.call(value) === '[object Object]'
}

/**
 * 是否短信验证码
 */
function code(value, len = 6) {
    return new RegExp(`^\\d{${len}}$`).test(value)
}

/**
 * 是否函数方法
 * @param {Object} value
 */
function func(value) {
    return typeof value === 'function'
}

/**
 * 是否promise对象
 * @param {Object} value
 */
function promise(value) {
    return object(value) && func(value.then) && func(value.catch)
}

/** 是否图片格式
 * @param {Object} value
 */
function image(value) {
    const newValue = value.split('?')[0]
    const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i
    return IMAGE_REGEXP.test(newValue)
}

/**
 * 是否视频格式
 * @param {Object} value
 */
function video(value) {
    const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i
    return VIDEO_REGEXP.test(value)
}

/**
 * 是否为正则对象
 * @param {Object}
 * @return {Boolean}
 */
function regExp(o) {
    return o && Object.prototype.toString.call(o) === '[object RegExp]'
}

export {
    email,
    mobile,
    url,
    date,
    dateISO,
    number,
    digits,
    idCard,
    carNo,
    amount,
    chinese,
    letter,
    enOrNum,
    contains,
    range,
    rangeLength,
    empty,
    jsonString,
    landline,
    object,
    array,
    code,
    func,
    promise,
    video,
    image,
    regExp,
    string
}
s^4>6xglet timer; let
    flag
/**
 * 节流原理：在一定时间内，只能触发一次
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function throttle(func, wait = 500, immediate = true) {
    if (immediate) {
        if (!flag) {
            flag = true
            // 如果是立即执行，则在wait毫秒内开始时执行
            typeof func === 'function' && func()
            timer = setTimeout(() => {
                flag = false
            }, wait)
        }
    } else if (!flag) {
        flag = true
        // 如果是非立即执行，则在wait毫秒内的结束处执行
        timer = setTimeout(() => {
            flag = false
            typeof func === 'function' && func()
        }, wait)
    }
}
export default throttle
aL}x 40000 adapters K߁l-.;H40000 core J7Ѷǉ2540000 helpers YC@FꋹG100644 index.d.ts bv2nm`Tl\f^=100644 index.js 4baK5<ATP100644 utils.js [RZ1-kg"8#40000 utils 'Rޯ)1dn}
C`̤x$ 100644 index.js 1	đH趦ix,import buildURL from '../helpers/buildURL'
import buildFullPath from '../core/buildFullPath'
import settle from '../core/settle'
import {isUndefined} from "../utils"

/**
 * 返回可选值存在的配置
 * @param {Array} keys - 可选值数组
 * @param {Object} config2 - 配置
 * @return {{}} - 存在的配置项
 */
const mergeKeys = (keys, config2) => {
  let config = {}
  keys.forEach(prop => {
    if (!isUndefined(config2[prop])) {
      config[prop] = config2[prop]
    }
  })
  return config
}
export default (config) => {
  return new Promise((resolve, reject) => {
    let fullPath = buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer)
    const _config = {
      url: fullPath,
      header: config.header,
      complete: (response) => {
        config.fullPath = fullPath
        response.config = config
        response.rawData = response.data
        try {
          let jsonParseHandle = false
          const forcedJSONParsingType = typeof config.forcedJSONParsing
          if (forcedJSONParsingType === 'boolean') {
            jsonParseHandle = config.forcedJSONParsing
          } else if (forcedJSONParsingType === 'object') {
            const includesMethod = config.forcedJSONParsing.include || []
            jsonParseHandle = includesMethod.includes(config.method)
          }

          // 对可能字符串不是json 的情况容错
          if (jsonParseHandle && typeof response.data === 'string') {
            response.data = JSON.parse(response.data)
          }
          // eslint-disable-next-line no-empty
        } catch (e) {
        }
        settle(resolve, reject, response)
      }
    }
    let requestTask
    if (config.method === 'UPLOAD') {
      delete _config.header['content-type']
      delete _config.header['Content-Type']
      let otherConfig = {
        // #ifdef MP-ALIPAY
        fileType: config.fileType,
        // #endif
        filePath: config.filePath,
        name: config.name
      }
      const optionalKeys = [
        // #ifdef APP-PLUS || H5
        'files',
        // #endif
        // #ifdef H5
        'file',
        // #endif
        // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
        'timeout',
        // #endif
        'formData'
      ]
      requestTask = uni.uploadFile({..._config, ...otherConfig, ...mergeKeys(optionalKeys, config)})
    } else if (config.method === 'DOWNLOAD') {
      const optionalKeys = [
        // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
        'timeout',
        // #endif
        // #ifdef MP
        'filePath',
        // #endif
      ]
      requestTask = uni.downloadFile({..._config, ...mergeKeys(optionalKeys, config)})
    } else {
      const optionalKeys = [
        'data',
        'method',
        // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
        'timeout',
        // #endif
        'dataType',
        // #ifndef MP-ALIPAY
        'responseType',
        // #endif
        // #ifdef APP-PLUS
        'sslVerify',
        // #endif
        // #ifdef H5
        'withCredentials',
        // #endif
        // #ifdef APP-PLUS
        'firstIpv4',
        // #endif
        // #ifdef MP-WEIXIN
        'enableHttp2',
        'enableQuic',
        // #endif
        // #ifdef MP-TOUTIAO || MP-WEIXIN
        'enableCache',
        // #endif
        // #ifdef MP-WEIXIN
        'enableHttpDNS',
        'httpDNSServiceId',
        'enableChunked',
        'forceCellularNetwork',
        // #endif
        // #ifdef MP-ALIPAY
        'enableCookie',
        // #endif
        // #ifdef MP-BAIDU
        'cloudCache',
        'defer'
        // #endif
      ]
      requestTask = uni.request({..._config, ...mergeKeys(optionalKeys, config)})
    }
    if (config.getTask) {
      config.getTask(requestTask, config)
    }
  })
}
9+wx'100644 InterceptorManager.js >'L*8p100644 Request.js ȚޝTY 4b]S100644 buildFullPath.js /FtP!i	,
ߟ100644 defaults.js t` oKL[w^Z100644 dispatchRequest.js \Jp{'J`J<100644 mergeConfig.js '=6V3 O+100644 settle.js e;}i/+Qm4tIxi'use strict'


function InterceptorManager() {
  this.handlers = []
}

/**
 * Add a new interceptor to the stack
 *
 * @param {Function} fulfilled The function to handle `then` for a `Promise`
 * @param {Function} rejected The function to handle `reject` for a `Promise`
 *
 * @return {Number} An ID used to remove interceptor later
 */
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  })
  return this.handlers.length - 1
}

/**
 * Remove an interceptor from the stack
 *
 * @param {Number} id The ID that was returned by `use`
 */
InterceptorManager.prototype.eject = function eject(id) {
  if (this.handlers[id]) {
    this.handlers[id] = null
  }
}

/**
 * Iterate over all the registered interceptors
 *
 * This method is particularly useful for skipping over any
 * interceptors that may have become `null` calling `eject`.
 *
 * @param {Function} fn The function to call for each interceptor
 */
InterceptorManager.prototype.forEach = function forEach(fn) {
  this.handlers.forEach(h => {
    if (h !== null) {
      fn(h)
    }
  })
}

export default InterceptorManager
4*x/**
 * @Class Request
 * @description luch-request http请求插件
 * @Author lu-ch
 * @Email webwork.s@qq.com
 * 文档: https://www.quanzhan.co/luch-request/
 * github: https://github.com/lei-mu/luch-request
 * DCloud: http://ext.dcloud.net.cn/plugin?id=392
 */


import dispatchRequest from './dispatchRequest'
import InterceptorManager from './InterceptorManager'
import mergeConfig from './mergeConfig'
import defaults from './defaults'
import { isPlainObject } from '../utils'
import clone from '../utils/clone'

export default class Request {
  /**
   * @param {Object} arg - 全局配置
   * @param {String} arg.baseURL - 全局根路径
   * @param {Object} arg.header - 全局header
   * @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式
   * @param {String} arg.dataType = [json] - 全局默认的dataType
   * @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。支付宝小程序不支持
   * @param {Object} arg.custom - 全局默认的自定义参数
   * @param {Number} arg.timeout - 全局默认的超时时间，单位 ms。默认60000。H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序（2.10.0）、支付宝小程序
   * @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持（HBuilderX 2.3.3+）
   * @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证（cookies）。默认false。仅H5支持（HBuilderX 2.6.15+）
   * @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+)
   * @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300
   */
  constructor(arg = {}) {
    if (!isPlainObject(arg)) {
      arg = {}
      console.warn('设置全局参数必须接收一个Object')
    }
    this.config = clone({...defaults, ...arg})
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    }
  }

  /**
   * @Function
   * @param {Request~setConfigCallback} f - 设置全局默认配置
   */
  setConfig(f) {
    this.config = f(this.config)
  }

  middleware(config) {
    config = mergeConfig(this.config, config)
    let chain = [dispatchRequest, undefined]
    let promise = Promise.resolve(config)

    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
      chain.unshift(interceptor.fulfilled, interceptor.rejected)
    })

    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
      chain.push(interceptor.fulfilled, interceptor.rejected)
    })

    while (chain.length) {
      promise = promise.then(chain.shift(), chain.shift())
    }

    return promise
  }

  /**
   * @Function
   * @param {Object} config - 请求配置项
   * @prop {String} options.url - 请求路径
   * @prop {Object} options.data - 请求参数
   * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型
   * @prop {Object} [options.dataType = config.dataType] - 如果设为 json，会尝试对返回的数据做一次 JSON.parse
   * @prop {Object} [options.header = config.header] - 请求header
   * @prop {Object} [options.method = config.method] - 请求方法
   * @returns {Promise<unknown>}
   */
  request(config = {}) {
    return this.middleware(config)
  }

  get(url, options = {}) {
    return this.middleware({
      url,
      method: 'GET',
      ...options
    })
  }

  post(url, data, options = {}) {
    return this.middleware({
      url,
      data,
      method: 'POST',
      ...options
    })
  }

  // #ifndef MP-ALIPAY || MP-KUAISHOU || MP-JD
  put(url, data, options = {}) {
    return this.middleware({
      url,
      data,
      method: 'PUT',
      ...options
    })
  }

  // #endif

  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
  delete(url, data, options = {}) {
    return this.middleware({
      url,
      data,
      method: 'DELETE',
      ...options
    })
  }

  // #endif

  // #ifdef H5 || MP-WEIXIN
  connect(url, data, options = {}) {
    return this.middleware({
      url,
      data,
      method: 'CONNECT',
      ...options
    })
  }

  // #endif

  // #ifdef  H5 || MP-WEIXIN || MP-BAIDU
  head(url, data, options = {}) {
    return this.middleware({
      url,
      data,
      method: 'HEAD',
      ...options
    })
  }

  // #endif

  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
  options(url, data, options = {}) {
    return this.middleware({
      url,
      data,
      method: 'OPTIONS',
      ...options
    })
  }

  // #endif

  // #ifdef H5 || MP-WEIXIN
  trace(url, data, options = {}) {
    return this.middleware({
      url,
      data,
      method: 'TRACE',
      ...options
    })
  }

  // #endif

  upload(url, config = {}) {
    config.url = url
    config.method = 'UPLOAD'
    return this.middleware(config)
  }

  download(url, config = {}) {
    config.url = url
    config.method = 'DOWNLOAD'
    return this.middleware(config)
  }

  get version () {
    return '3.1.0'
  }
}


/**
 * setConfig回调
 * @return {Object} - 返回操作后的config
 * @callback Request~setConfigCallback
 * @param {Object} config - 全局默认config
 */
'*xV'use strict'

import isAbsoluteURL from '../helpers/isAbsoluteURL'
import combineURLs from '../helpers/combineURLs'

/**
 * Creates a new URL by combining the baseURL with the requestedURL,
 * only when the requestedURL is not already an absolute URL.
 * If the requestURL is absolute, this function returns the requestedURL untouched.
 *
 * @param {string} baseURL The base URL
 * @param {string} requestedURL Absolute or relative URL to combine
 * @returns {string} The combined full path
 */
export default function buildFullPath(baseURL, requestedURL) {
  if (baseURL && !isAbsoluteURL(requestedURL)) {
    return combineURLs(baseURL, requestedURL)
  }
  return requestedURL
}
P(xr/**
 * 默认的全局配置
 */


export default {
  baseURL: '',
  header: {},
  method: 'GET',
  dataType: 'json',
  paramsSerializer: null,
  // #ifndef MP-ALIPAY
  responseType: 'text',
  // #endif
  custom: {},
  // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
  timeout: 60000,
  // #endif
  // #ifdef APP-PLUS
  sslVerify: true,
  // #endif
  // #ifdef H5
  withCredentials: false,
  // #endif
  // #ifdef APP-PLUS
  firstIpv4: false,
  // #endif
  validateStatus: function validateStatus(status) {
    return status >= 200 && status < 300
  },
  // 是否尝试将响应数据json化
  forcedJSONParsing: true
}
C}xb import adapter from '../adapters/index'


export default (config) => {
  return adapter(config)
}
!*x9import {deepMerge, isUndefined} from '../utils'

/**
 * 合并局部配置优先的配置，如果局部有该配置项则用局部，如果全局有该配置项则用全局
 * @param {Array} keys - 配置项
 * @param {Object} globalsConfig - 当前的全局配置
 * @param {Object} config2 - 局部配置
 * @return {{}}
 */
const mergeKeys = (keys, globalsConfig, config2) => {
  let config = {}
  keys.forEach(prop => {
    if (!isUndefined(config2[prop])) {
      config[prop] = config2[prop]
    } else if (!isUndefined(globalsConfig[prop])) {
      config[prop] = globalsConfig[prop]
    }
  })
  return config
}
/**
 *
 * @param globalsConfig - 当前实例的全局配置
 * @param config2 - 当前的局部配置
 * @return - 合并后的配置
 */
export default (globalsConfig, config2 = {}) => {
  const method = config2.method || globalsConfig.method || 'GET'
  let config = {
    baseURL: config2.baseURL || globalsConfig.baseURL || '',
    method: method,
    url: config2.url || '',
    params: config2.params || {},
    custom: {...(globalsConfig.custom || {}), ...(config2.custom || {})},
    header: deepMerge(globalsConfig.header || {}, config2.header || {})
  }
  const defaultToConfig2Keys = ['getTask', 'validateStatus', 'paramsSerializer', 'forcedJSONParsing']
  config = {...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2)}

  // eslint-disable-next-line no-empty
  if (method === 'DOWNLOAD') {
    const downloadKeys = [
      // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
      'timeout',
      // #endif
      // #ifdef MP
      'filePath',
      // #endif
    ]
    config = {...config, ...mergeKeys(downloadKeys, globalsConfig, config2)}
  } else if (method === 'UPLOAD') {
    delete config.header['content-type']
    delete config.header['Content-Type']
    const uploadKeys = [
      // #ifdef APP-PLUS || H5
      'files',
      // #endif
      // #ifdef MP-ALIPAY
      'fileType',
      // #endif
      // #ifdef H5
      'file',
      // #endif
      'filePath',
      'name',
      // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
      'timeout',
      // #endif
      'formData',
    ]
    uploadKeys.forEach(prop => {
      if (!isUndefined(config2[prop])) {
        config[prop] = config2[prop]
      }
    })
    // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
    if (isUndefined(config.timeout) && !isUndefined(globalsConfig.timeout)) {
      config['timeout'] = globalsConfig['timeout']
    }
    // #endif
  } else {
    const defaultsKeys = [
      'data',
      // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
      'timeout',
      // #endif
      'dataType',
      // #ifndef MP-ALIPAY
      'responseType',
      // #endif
      // #ifdef APP-PLUS
      'sslVerify',
      // #endif
      // #ifdef H5
      'withCredentials',
      // #endif
      // #ifdef APP-PLUS
      'firstIpv4',
      // #endif
      // #ifdef MP-WEIXIN
      'enableHttp2',
      'enableQuic',
      // #endif
      // #ifdef MP-TOUTIAO || MP-WEIXIN
      'enableCache',
      // #endif
      // #ifdef MP-WEIXIN
      'enableHttpDNS',
      'httpDNSServiceId',
      'enableChunked',
      'forceCellularNetwork',
      // #endif
      // #ifdef MP-ALIPAY
      'enableCookie',
      // #endif
      // #ifdef MP-BAIDU
      'cloudCache',
      'defer'
      // #endif

    ]
    config = {...config, ...mergeKeys(defaultsKeys, globalsConfig, config2)}
  }

  return config
}
G[! x/**
 * Resolve or reject a Promise based on response status.
 *
 * @param {Function} resolve A function that resolves the promise.
 * @param {Function} reject A function that rejects the promise.
 * @param {object} response The response.
 */
export default function settle(resolve, reject, response) {
  const validateStatus = response.config.validateStatus
  const status = response.statusCode
  if (status && (!validateStatus || validateStatus(status))) {
    resolve(response)
  } else {
    reject(response)
  }
}
$㴒x} 100644 buildURL.js +Q%&Ms2'100644 combineURLs.js {~}j
f100644 isAbsoluteURL.js *Q}mJV%k&%e1$dxN'use strict'

import * as utils from './../utils'

function encode(val) {
  return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, '+').replace(/%5B/gi, '[').replace(/%5D/gi, ']')
}

/**
 * Build a URL by appending params to the end
 *
 * @param {string} url The base of the url (e.g., http://www.google.com)
 * @param {object} [params] The params to be appended
 * @returns {string} The formatted url
 */
export default function buildURL(url, params, paramsSerializer) {
  /*eslint no-param-reassign:0*/
  if (!params) {
    return url
  }

  var serializedParams
  if (paramsSerializer) {
    serializedParams = paramsSerializer(params)
  } else if (utils.isURLSearchParams(params)) {
    serializedParams = params.toString()
  } else {
    var parts = []

    utils.forEach(params, function serialize(val, key) {
      if (val === null || typeof val === 'undefined') {
        return
      }

      if (utils.isArray(val)) {
        key = key + '[]'
      } else {
        val = [val]
      }

      utils.forEach(val, function parseValue(v) {
        if (utils.isDate(v)) {
          v = v.toISOString()
        } else if (utils.isObject(v)) {
          v = JSON.stringify(v)
        }
        parts.push(encode(key) + '=' + encode(v))
      })
    })

    serializedParams = parts.join('&')
  }

  if (serializedParams) {
    var hashmarkIndex = url.indexOf('#')
    if (hashmarkIndex !== -1) {
      url = url.slice(0, hashmarkIndex)
    }

    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
  }

  return url
}
xw'use strict'

/**
 * Creates a new URL by combining the specified URLs
 *
 * @param {string} baseURL The base URL
 * @param {string} relativeURL The relative URL
 * @returns {string} The combined URL
 */
export default function combineURLs(baseURL, relativeURL) {
  return relativeURL
    ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
    : baseURL
}
wG"x,'use strict'

/**
 * Determines whether the specified URL is absolute
 *
 * @param {string} url The URL to test
 * @returns {boolean} True if the specified URL is absolute, otherwise false
 */
export default function isAbsoluteURL(url) {
  // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
  // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
  // by any combination of letters, digits, plus, period, or hyphen.
  return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
}
̹xexport type HttpTask = UniApp.RequestTask | UniApp.UploadTask | UniApp.DownloadTask;

export type HttpRequestTask = UniApp.RequestTask;

export type HttpUploadTask = UniApp.UploadTask;

export type HttpDownloadTask = UniApp.DownloadTask;

export type HttpMethod =
    "GET"
    | "POST"
    | "PUT"
    | "DELETE"
    | "CONNECT"
    | "HEAD"
    | "OPTIONS"
    | "TRACE"
    | "UPLOAD"
    | "DOWNLOAD";

export type HttpRequestHeader = Record<string, string>;

export type HttpParams = Record<string, any>;

export type HttpData = Record<string, any>;

export type HttpResponseType = 'arraybuffer' | 'text';

export type HttpCustom = Record<string, any>;

export type HttpFileType = 'image' | 'video' | 'audio';

export type HttpFormData = Record<string, any>;

export type HttpResponseHeader = Record<string, string> & {
    "set-cookie"?: string[]
};

export interface HttpRequestConfig<T = HttpTask> {
    /** @desc 请求服务器接口地址 */
    url?: string;
    /** @desc 请求方式，默认为 GET */
    method?: HttpMethod;
    /** @desc 请求基地址 */
    baseURL?: string;
    /** @desc 请求头信息，不能设置 Referer，App、H5 端会自动带上 cookie，且 H5 端不可手动修改 */
    header?: HttpRequestHeader;
    /** @desc 请求查询参数，自动拼接为查询字符串 */
    params?: HttpParams;
    /** @desc 请求体参数 */
    data?: HttpData;
    /** @desc 超时时间，单位 ms，默认为 60000，仅 H5 (HBuilderX 2.9.9+)、APP (HBuilderX 2.9.9+)、微信小程序 (2.10.0)、支付宝小程序支持 */
    timeout?: number;
    /** @desc 跨域请求时是否携带凭证 (cookies)，默认为 false，仅 H5 (HBuilderX 2.6.15+) 支持 */
    withCredentials?: boolean;
    /** @desc 设置响应的数据类型，支付宝小程序不支持 */
    responseType?: HttpResponseType;
    /** @desc 全局自定义验证器 */
    validateStatus?: ((statusCode: number) => boolean) | null;


    /** params 参数自定义处理 */
    paramsSerializer?: (params: AnyObject) => string | void;

    /** @desc 默认为 json，如果设为 json，会尝试对返回的数据做一次 JSON.parse */
    dataType?: string;
    /** @desc DNS 解析时是否优先使用 ipv4，默认为 false，仅 App-Android (HBuilderX 2.8.0+) 支持 */
    firstIpv4?: boolean;
    /** @desc 是否验证 SSL 证书，默认为 true，仅 App-Android (HBuilderX 2.3.3+) 支持 */
    sslVerify?: boolean;

    /** @desc 开启 http2;微信小程序 */
    enableHttp2?: boolean;

    /** @desc 开启 quic；微信小程序 */
    enableQuic?: boolean;
    /** @desc 开启 cache;微信小程序、字节跳动小程序 2.31.0+ */
    enableCache?: boolean;
    /** @desc 开启 httpDNS;微信小程序 */
    enableHttpDNS?: boolean;
    /** @desc httpDNS 服务商；微信小程序 */
    httpDNSServiceId?: string;
    /** @desc 开启 transfer-encoding chunked;微信小程序 */
    enableChunked?: boolean;
    /** @desc wifi下使用移动网络发送请求;微信小程序 */
    forceCellularNetwork?: boolean;
    /** @desc 开启后可在headers中编辑cookie;支付宝小程序 10.2.33+ */
    enableCookie?: boolean;
    /** @desc 是否开启云加速;百度小程序 3.310.11+ */
    cloudCache?: boolean | object;
    /** @desc 控制当前请求是否延时至首屏内容渲染后发送；百度小程序 3.310.11+ */
    defer?: boolean;

    /** @desc 自定义参数 */
    custom?: HttpCustom;

    /** @desc 返回当前请求的 task 和 options，不要在这里修改 options */
    getTask?: (task: T, options: HttpRequestConfig<T>) => void;

    /** @desc 需要上传的文件列表，使用 files 时，filePath 和 name 不生效，仅支持 App、H5 (2.6.15+) */
    files?: { name?: string; file?: File; uri: string; }[];
    /** @desc 文件类型，仅支付宝小程序支持且为必填项 */
    fileType?: HttpFileType;
    /** @desc 要上传的文件对象，仅 H5 (2.6.15+) 支持 */
    file?: File;
    /** @desc 要上传文件资源的路径，使用 files 时，filePath 和 name 不生效 */
    filePath?: string;
    /** @desc 文件对应的 key，开发者在服务器端通过这个 key 可以获取到文件二进制内容，使用 files 时，filePath 和 name 不生效 */
    name?: string;
    /** @desc 请求中其他额外的 form data */
    formData?: HttpFormData;
}

export interface HttpResponse<T = any, D = HttpTask> {
    data: T;
    statusCode: number;
    header: HttpResponseHeader;
    config: HttpRequestConfig<D>;
    cookies: string[];
    errMsg: string;
    rawData: any;
}

export interface HttpUploadResponse<T = any, D = HttpTask> {
    data: T;
    statusCode: number;
    config: HttpRequestConfig<D>;
    errMsg: string;
    rawData: any;
}

export interface HttpDownloadResponse extends HttpResponse {
    tempFilePath: string;
    apFilePath?: string;
    filePath?: string;
    fileContent?: string;
}

export interface HttpError<T = any, D = HttpTask> {
    data?: T;
    statusCode?: number;
    header?: HttpResponseHeader;
    config: HttpRequestConfig<D>;
    cookies?: string[];
    errMsg: string;
}

export interface HttpPromise<T = any> extends Promise<HttpResponse<T>> {
}

export interface HttpInterceptorManager<V, E = V> {
    use(onFulfilled?: (value: V) => V | Promise<V>, onRejected?: (error: E) => T | Promise<E>): void;

    eject(id: number): void;
}

export abstract class HttpRequestAbstract {
    constructor(config?: HttpRequestConfig);

    interceptors: {
        request: HttpInterceptorManager<HttpRequestConfig>;
        response: HttpInterceptorManager<HttpResponse, HttpError>;
    }

    request<T = any, R = HttpResponse<T>, D = HttpRequestTask>(config: HttpRequestConfig<D>): Promise<R>;

    get<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, config?: HttpRequestConfig<D>): Promise<R>;

    delete<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;

    head<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;

    options<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;

    post<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;

    put<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;

    config: HttpRequestConfig;

    setConfig<D = HttpTask>(onSend: (config: HttpRequestConfig<D>) => HttpRequestConfig<D>): void;

    connect<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;

    trace<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;

    upload<T = any, R = HttpUploadResponse<T>, D = HttpUploadTask>(url: string, config?: HttpRequestConfig<D>): Promise<R>;

    download<T = any, R = HttpDownloadResponse<T>, D = HttpDownloadTask>(url: string, config?: HttpRequestConfig<D>): Promise<R>;

    middleware<T = any, R = HttpResponse<T>, D = HttpTask>(config: HttpRequestConfig<D>): Promise<R>;
}

declare class HttpRequest extends HttpRequestAbstract {
}

export default HttpRequest;
TKżx< import Request from './core/Request'
export default Request
ɿx 'use strict'

// utils is a library of generic helper functions non-specific to axios

var toString = Object.prototype.toString

/**
 * Determine if a value is an Array
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Array, otherwise false
 */
export function isArray (val) {
  return toString.call(val) === '[object Array]'
}


/**
 * Determine if a value is an Object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Object, otherwise false
 */
export function isObject (val) {
  return val !== null && typeof val === 'object'
}

/**
 * Determine if a value is a Date
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Date, otherwise false
 */
export function isDate (val) {
  return toString.call(val) === '[object Date]'
}

/**
 * Determine if a value is a URLSearchParams object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a URLSearchParams object, otherwise false
 */
export function isURLSearchParams (val) {
  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams
}


/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */
export function forEach (obj, fn) {
  // Don't bother if no value provided
  if (obj === null || typeof obj === 'undefined') {
    return
  }

  // Force an array if not already something iterable
  if (typeof obj !== 'object') {
    /*eslint no-param-reassign:0*/
    obj = [obj]
  }

  if (isArray(obj)) {
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj)
    }
  } else {
    // Iterate over object keys
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj)
      }
    }
  }
}

/**
 * 是否为boolean 值
 * @param val
 * @returns {boolean}
 */
export function isBoolean(val) {
  return typeof val === 'boolean'
}

/**
 * 是否为真正的对象{} new Object
 * @param {any} obj - 检测的对象
 * @returns {boolean}
 */
export function isPlainObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]'
}



/**
 * Function equal to merge with the difference being that no reference
 * to original objects is kept.
 *
 * @see merge
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
export function deepMerge(/* obj1, obj2, obj3, ... */) {
  let result = {}
  function assignValue(val, key) {
    if (typeof result[key] === 'object' && typeof val === 'object') {
      result[key] = deepMerge(result[key], val)
    } else if (typeof val === 'object') {
      result[key] = deepMerge({}, val)
    } else {
      result[key] = val
    }
  }
  for (let i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue)
  }
  return result
}

export function isUndefined (val) {
  return typeof val === 'undefined'
}
^Ilx$ 100644 clone.js /pMQ1r~*xejx/* eslint-disable */
var clone = (function() {
  'use strict';

  function _instanceof(obj, type) {
    return type != null && obj instanceof type;
  }

  var nativeMap;
  try {
    nativeMap = Map;
  } catch(_) {
    // maybe a reference error because no `Map`. Give it a dummy value that no
    // value will ever be an instanceof.
    nativeMap = function() {};
  }

  var nativeSet;
  try {
    nativeSet = Set;
  } catch(_) {
    nativeSet = function() {};
  }

  var nativePromise;
  try {
    nativePromise = Promise;
  } catch(_) {
    nativePromise = function() {};
  }

  /**
   * Clones (copies) an Object using deep copying.
   *
   * This function supports circular references by default, but if you are certain
   * there are no circular references in your object, you can save some CPU time
   * by calling clone(obj, false).
   *
   * Caution: if `circular` is false and `parent` contains circular references,
   * your program may enter an infinite loop and crash.
   *
   * @param `parent` - the object to be cloned
   * @param `circular` - set to true if the object to be cloned may contain
   *    circular references. (optional - true by default)
   * @param `depth` - set to a number if the object is only to be cloned to
   *    a particular depth. (optional - defaults to Infinity)
   * @param `prototype` - sets the prototype to be used when cloning an object.
   *    (optional - defaults to parent prototype).
   * @param `includeNonEnumerable` - set to true if the non-enumerable properties
   *    should be cloned as well. Non-enumerable properties on the prototype
   *    chain will be ignored. (optional - false by default)
   */
  function clone(parent, circular, depth, prototype, includeNonEnumerable) {
    if (typeof circular === 'object') {
      depth = circular.depth;
      prototype = circular.prototype;
      includeNonEnumerable = circular.includeNonEnumerable;
      circular = circular.circular;
    }
    // maintain two arrays for circular references, where corresponding parents
    // and children have the same index
    var allParents = [];
    var allChildren = [];

    var useBuffer = typeof Buffer != 'undefined';

    if (typeof circular == 'undefined')
      circular = true;

    if (typeof depth == 'undefined')
      depth = Infinity;

    // recurse this function so we don't reset allParents and allChildren
    function _clone(parent, depth) {
      // cloning null always returns null
      if (parent === null)
        return null;

      if (depth === 0)
        return parent;

      var child;
      var proto;
      if (typeof parent != 'object') {
        return parent;
      }

      if (_instanceof(parent, nativeMap)) {
        child = new nativeMap();
      } else if (_instanceof(parent, nativeSet)) {
        child = new nativeSet();
      } else if (_instanceof(parent, nativePromise)) {
        child = new nativePromise(function (resolve, reject) {
          parent.then(function(value) {
            resolve(_clone(value, depth - 1));
          }, function(err) {
            reject(_clone(err, depth - 1));
          });
        });
      } else if (clone.__isArray(parent)) {
        child = [];
      } else if (clone.__isRegExp(parent)) {
        child = new RegExp(parent.source, __getRegExpFlags(parent));
        if (parent.lastIndex) child.lastIndex = parent.lastIndex;
      } else if (clone.__isDate(parent)) {
        child = new Date(parent.getTime());
      } else if (useBuffer && Buffer.isBuffer(parent)) {
        if (Buffer.from) {
          // Node.js >= 5.10.0
          child = Buffer.from(parent);
        } else {
          // Older Node.js versions
          child = new Buffer(parent.length);
          parent.copy(child);
        }
        return child;
      } else if (_instanceof(parent, Error)) {
        child = Object.create(parent);
      } else {
        if (typeof prototype == 'undefined') {
          proto = Object.getPrototypeOf(parent);
          child = Object.create(proto);
        }
        else {
          child = Object.create(prototype);
          proto = prototype;
        }
      }

      if (circular) {
        var index = allParents.indexOf(parent);

        if (index != -1) {
          return allChildren[index];
        }
        allParents.push(parent);
        allChildren.push(child);
      }

      if (_instanceof(parent, nativeMap)) {
        parent.forEach(function(value, key) {
          var keyChild = _clone(key, depth - 1);
          var valueChild = _clone(value, depth - 1);
          child.set(keyChild, valueChild);
        });
      }
      if (_instanceof(parent, nativeSet)) {
        parent.forEach(function(value) {
          var entryChild = _clone(value, depth - 1);
          child.add(entryChild);
        });
      }

      for (var i in parent) {
        var attrs = Object.getOwnPropertyDescriptor(parent, i);
        if (attrs) {
          child[i] = _clone(parent[i], depth - 1);
        }

        try {
          var objProperty = Object.getOwnPropertyDescriptor(parent, i);
          if (objProperty.set === 'undefined') {
            // no setter defined. Skip cloning this property
            continue;
          }
          child[i] = _clone(parent[i], depth - 1);
        } catch(e){
          if (e instanceof TypeError) {
            // when in strict mode, TypeError will be thrown if child[i] property only has a getter
            // we can't do anything about this, other than inform the user that this property cannot be set.
            continue
          } else if (e instanceof ReferenceError) {
            //this may happen in non strict mode
            continue
          }
        }

      }

      if (Object.getOwnPropertySymbols) {
        var symbols = Object.getOwnPropertySymbols(parent);
        for (var i = 0; i < symbols.length; i++) {
          // Don't need to worry about cloning a symbol because it is a primitive,
          // like a number or string.
          var symbol = symbols[i];
          var descriptor = Object.getOwnPropertyDescriptor(parent, symbol);
          if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
            continue;
          }
          child[symbol] = _clone(parent[symbol], depth - 1);
          Object.defineProperty(child, symbol, descriptor);
        }
      }

      if (includeNonEnumerable) {
        var allPropertyNames = Object.getOwnPropertyNames(parent);
        for (var i = 0; i < allPropertyNames.length; i++) {
          var propertyName = allPropertyNames[i];
          var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);
          if (descriptor && descriptor.enumerable) {
            continue;
          }
          child[propertyName] = _clone(parent[propertyName], depth - 1);
          Object.defineProperty(child, propertyName, descriptor);
        }
      }

      return child;
    }

    return _clone(parent, depth);
  }

  /**
   * Simple flat clone using prototype, accepts only objects, usefull for property
   * override on FLAT configuration object (no nested props).
   *
   * USE WITH CAUTION! This may not behave as you wish if you do not know how this
   * works.
   */
  clone.clonePrototype = function clonePrototype(parent) {
    if (parent === null)
      return null;

    var c = function () {};
    c.prototype = parent;
    return new c();
  };

// private utility functions

  function __objToStr(o) {
    return Object.prototype.toString.call(o);
  }
  clone.__objToStr = __objToStr;

  function __isDate(o) {
    return typeof o === 'object' && __objToStr(o) === '[object Date]';
  }
  clone.__isDate = __isDate;

  function __isArray(o) {
    return typeof o === 'object' && __objToStr(o) === '[object Array]';
  }
  clone.__isArray = __isArray;

  function __isRegExp(o) {
    return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
  }
  clone.__isRegExp = __isRegExp;

  function __getRegExpFlags(re) {
    var flags = '';
    if (re.global) flags += 'g';
    if (re.ignoreCase) flags += 'i';
    if (re.multiline) flags += 'm';
    return flags;
  }
  clone.__getRegExpFlags = __getRegExpFlags;

  return clone;
})();

export default clone
x 100644 button.js *jIXNmf%100644 mixin.js Ӱ;>za:m866 100644 mpMixin.js <jvت 100644 mpShare.js iZꇑZ2p:V100644 openType.js s
oRUp*100644 touch.js ؎Uie IŔg[x/export default {
    props: {
        lang: String,
        sessionFrom: String,
        sendMessageTitle: String,
        sendMessagePath: String,
        sendMessageImg: String,
        showMessageCard: Boolean,
        appParameter: String,
        formType: String,
        openType: String
    }
}
EYxGimport * as index from '../function/index.js';
import * as test from '../function/test.js';
import route from '../util/route.js';
import debounce from '../function/debounce.js';
import throttle from '../function/throttle.js';
export default {
	// 定义每个组件都可能需要用到的外部样式以及类名
	props: {
		// 每个组件都有的父组件传递的样式，可以为字符串或者对象形式
		customStyle: {
			type: [Object, String],
			default: () => ({})
		},
		customClass: {
			type: String,
			default: ''
		},
		// 跳转的页面路径
		url: {
			type: String,
			default: ''
		},
		// 页面跳转的类型
		linkType: {
			type: String,
			default: 'navigateTo'
		}
	},
	data() {
		return {}
	},
	onLoad() {
		// getRect挂载到$uv上，因为这方法需要使用in(this)，所以无法把它独立成一个单独的文件导出
		this.$uv.getRect = this.$uvGetRect
	},
	created() {
		// 组件当中，只有created声明周期，为了能在组件使用，故也在created中将方法挂载到$uv
		this.$uv.getRect = this.$uvGetRect
	},
	computed: {
		$uv() {
			return {
				...index,
				test,
				route,
				debounce,
				throttle,
				unit: uni?.$uv?.config?.unit
			}
		},
		/**
		 * 生成bem规则类名
		 * 由于微信小程序，H5，nvue之间绑定class的差异，无法通过:class="[bem()]"的形式进行同用
		 * 故采用如下折中做法，最后返回的是数组（一般平台）或字符串（支付宝和字节跳动平台），类似['a', 'b', 'c']或'a b c'的形式
		 * @param {String} name 组件名称
		 * @param {Array} fixed 一直会存在的类名
		 * @param {Array} change 会根据变量值为true或者false而出现或者隐藏的类名
		 * @returns {Array|string}
		 */
		bem() {
			return function(name, fixed, change) {
				// 类名前缀
				const prefix = `uv-${name}--`
				const classes = {}
				if (fixed) {
					fixed.map((item) => {
						// 这里的类名，会一直存在
						classes[prefix + this[item]] = true
					})
				}
				if (change) {
					change.map((item) => {
						// 这里的类名，会根据this[item]的值为true或者false，而进行添加或者移除某一个类
						this[item] ? (classes[prefix + item] = this[item]) : (delete classes[prefix + item])
					})
				}
				return Object.keys(classes)
					// 支付宝，头条小程序无法动态绑定一个数组类名，否则解析出来的结果会带有","，而导致失效
					// #ifdef MP-ALIPAY || MP-TOUTIAO || MP-LARK || MP-BAIDU
					.join(' ')
				// #endif
			}
		}
	},
	methods: {
		// 跳转某一个页面
		openPage(urlKey = 'url') {
			const url = this[urlKey]
			if (url) {
				// 执行类似uni.navigateTo的方法
				uni[this.linkType]({
					url
				})
			}
		},
		// 查询节点信息
		// 目前此方法在支付宝小程序中无法获取组件跟接点的尺寸，为支付宝的bug(2020-07-21)
		// 解决办法为在组件根部再套一个没有任何作用的view元素
		$uvGetRect(selector, all) {
			return new Promise((resolve) => {
				uni.createSelectorQuery()
					.in(this)[all ? 'selectAll' : 'select'](selector)
					.boundingClientRect((rect) => {
						if (all && Array.isArray(rect) && rect.length) {
							resolve(rect)
						}
						if (!all && rect) {
							resolve(rect)
						}
					})
					.exec()
			})
		},
		getParentData(parentName = '') {
			// 避免在created中去定义parent变量
			if (!this.parent) this.parent = {}
			// 这里的本质原理是，通过获取父组件实例(也即类似uv-radio的父组件uv-radio-group的this)
			// 将父组件this中对应的参数，赋值给本组件(uv-radio的this)的parentData对象中对应的属性
			// 之所以需要这么做，是因为所有端中，头条小程序不支持通过this.parent.xxx去监听父组件参数的变化
			// 此处并不会自动更新子组件的数据，而是依赖父组件uv-radio-group去监听data的变化，手动调用更新子组件的方法去重新获取
			this.parent = this.$uv.$parent.call(this, parentName)
			if (this.parent.children) {
				// 如果父组件的children不存在本组件的实例，才将本实例添加到父组件的children中
				this.parent.children.indexOf(this) === -1 && this.parent.children.push(this)
			}
			if (this.parent && this.parentData) {
				// 历遍parentData中的属性，将parent中的同名属性赋值给parentData
				Object.keys(this.parentData).map((key) => {
					this.parentData[key] = this.parent[key]
				})
			}
		},
		// 阻止事件冒泡
		preventEvent(e) {
			e && typeof(e.stopPropagation) === 'function' && e.stopPropagation()
		},
		// 空操作
		noop(e) {
			this.preventEvent(e)
		}
	},
	onReachBottom() {
		uni.$emit('uvOnReachBottom')
	},
	beforeDestroy() {
		// 判断当前页面是否存在parent和chldren，一般在checkbox和checkbox-group父子联动的场景会有此情况
		// 组件销毁时，移除子组件在父组件children数组中的实例，释放资源，避免数据混乱
		if (this.parent && test.array(this.parent.children)) {
			// 组件销毁时，移除父组件中的children数组中对应的实例
			const childrenList = this.parent.children
			childrenList.map((child, index) => {
				// 如果相等，则移除
				if (child === this) {
					childrenList.splice(index, 1)
				}
			})
		}
	},
	// 兼容vue3
	unmounted() {
		if (this.parent && test.array(this.parent.children)) {
			// 组件销毁时，移除父组件中的children数组中对应的实例
			const childrenList = this.parent.children
			childrenList.map((child, index) => {
				// 如果相等，则移除
				if (child === this) {
					childrenList.splice(index, 1)
				}
			})
		}
	}
}nx export default {
    // #ifdef MP-WEIXIN
    // 将自定义节点设置成虚拟的（去掉自定义组件包裹层），更加接近Vue组件的表现，能更好的使用flex属性
    options: {
        virtualHost: true
    }
    // #endif
} }x6export default {
	onLoad() {
	    // 设置默认的转发参数
	    uni.$uv.mpShare = {
	        title: '', // 默认为小程序名称
	        path: '', // 默认为当前页面路径
	        imageUrl: '' // 默认为当前页面的截图
	    }
	},
	onShareAppMessage() {
	    return uni.$uv.mpShare
	}
}<{BZxZexport default {
    props: {
        openType: String
    },
		emits: ['getphonenumber','getuserinfo','error','opensetting','launchapp','contact','chooseavatar','addgroupapp','chooseaddress','subscribe','login','im'],
    methods: {
        onGetPhoneNumber(event) {
            this.$emit('getphonenumber', event.detail)
        },
        onGetUserInfo(event) {
            this.$emit('getuserinfo', event.detail)
        },
        onError(event) {
            this.$emit('error', event.detail)
        },
        onOpenSetting(event) {
            this.$emit('opensetting', event.detail)
        },
        onLaunchApp(event) {
            this.$emit('launchapp', event.detail)
        },
        onContact(event) {
            this.$emit('contact', event.detail)
        },
        onChooseavatar(event) {
            this.$emit('chooseavatar', event.detail)
        },
        onAgreeprivacyauthorization(event) {
            this.$emit('agreeprivacyauthorization', event.detail)
        },
        onAddgroupapp(event) {
            this.$emit('addgroupapp', event.detail)
        },
        onChooseaddress(event) {
            this.$emit('chooseaddress', event.detail)
        },
        onSubscribe(event) {
            this.$emit('subscribe', event.detail)
        },
        onLogin(event) {
            this.$emit('login', event.detail)
        },
        onIm(event) {
            this.$emit('im', event.detail)
        }
    }
}
~ֹgxyconst MIN_DISTANCE = 10

function getDirection(x, y) {
    if (x > y && x > MIN_DISTANCE) {
        return 'horizontal'
    }
    if (y > x && y > MIN_DISTANCE) {
        return 'vertical'
    }
    return ''
}

export default {
    methods: {
        getTouchPoint(e) {
            if (!e) {
                return {
                    x: 0,
                    y: 0
                }
            } if (e.touches && e.touches[0]) {
                return {
                    x: e.touches[0].pageX,
                    y: e.touches[0].pageY
                }
            } if (e.changedTouches && e.changedTouches[0]) {
                return {
                    x: e.changedTouches[0].pageX,
                    y: e.changedTouches[0].pageY
                }
            }
            return {
                x: e.clientX || 0,
                y: e.clientY || 0
            }
        },
        resetTouchStatus() {
            this.direction = ''
            this.deltaX = 0
            this.deltaY = 0
            this.offsetX = 0
            this.offsetY = 0
        },
        touchStart(event) {
            this.resetTouchStatus()
            const touch = this.getTouchPoint(event)
            this.startX = touch.x
            this.startY = touch.y
        },
        touchMove(event) {
            const touch = this.getTouchPoint(event)
            this.deltaX = touch.x - this.startX
            this.deltaY = touch.y - this.startY
            this.offsetX = Math.abs(this.deltaX)
            this.offsetY = Math.abs(this.deltaY)
            this.direction =				this.direction || getDirection(this.offsetX, this.offsetY)
        }
    }
}
xH 100644 dayjs.js J)}n~DdaR100644 route.js ՃFS}	yx+var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};

var require_dayjs_min = __commonJS({
  "uvuidayjs"(exports, module) {
    !function(t, e) {
      "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
    }(exports, function() {
      "use strict";
      var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", f = "month", h = "quarter", c = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), ordinal: function(t2) {
        var e2 = ["th", "st", "nd", "rd"], n2 = t2 % 100;
        return "[" + t2 + (e2[(n2 - 20) % 10] || e2[n2] || e2[0]) + "]";
      } }, m = function(t2, e2, n2) {
        var r2 = String(t2);
        return !r2 || r2.length >= e2 ? t2 : "" + Array(e2 + 1 - r2.length).join(n2) + t2;
      }, v = { s: m, z: function(t2) {
        var e2 = -t2.utcOffset(), n2 = Math.abs(e2), r2 = Math.floor(n2 / 60), i2 = n2 % 60;
        return (e2 <= 0 ? "+" : "-") + m(r2, 2, "0") + ":" + m(i2, 2, "0");
      }, m: function t2(e2, n2) {
        if (e2.date() < n2.date())
          return -t2(n2, e2);
        var r2 = 12 * (n2.year() - e2.year()) + (n2.month() - e2.month()), i2 = e2.clone().add(r2, f), s2 = n2 - i2 < 0, u2 = e2.clone().add(r2 + (s2 ? -1 : 1), f);
        return +(-(r2 + (n2 - i2) / (s2 ? i2 - u2 : u2 - i2)) || 0);
      }, a: function(t2) {
        return t2 < 0 ? Math.ceil(t2) || 0 : Math.floor(t2);
      }, p: function(t2) {
        return { M: f, y: c, w: o, d: a, D: d, h: u, m: s, s: i, ms: r, Q: h }[t2] || String(t2 || "").toLowerCase().replace(/s$/, "");
      }, u: function(t2) {
        return void 0 === t2;
      } }, g = "en", D = {};
      D[g] = M;
      var p = function(t2) {
        return t2 instanceof _;
      }, S = function t2(e2, n2, r2) {
        var i2;
        if (!e2)
          return g;
        if ("string" == typeof e2) {
          var s2 = e2.toLowerCase();
          D[s2] && (i2 = s2), n2 && (D[s2] = n2, i2 = s2);
          var u2 = e2.split("-");
          if (!i2 && u2.length > 1)
            return t2(u2[0]);
        } else {
          var a2 = e2.name;
          D[a2] = e2, i2 = a2;
        }
        return !r2 && i2 && (g = i2), i2 || !r2 && g;
      }, w = function(t2, e2) {
        if (p(t2))
          return t2.clone();
        var n2 = "object" == typeof e2 ? e2 : {};
        return n2.date = t2, n2.args = arguments, new _(n2);
      }, O = v;
      O.l = S, O.i = p, O.w = function(t2, e2) {
        return w(t2, { locale: e2.$L, utc: e2.$u, x: e2.$x, $offset: e2.$offset });
      };
      var _ = function() {
        function M2(t2) {
          this.$L = S(t2.locale, null, true), this.parse(t2);
        }
        var m2 = M2.prototype;
        return m2.parse = function(t2) {
          this.$d = function(t3) {
            var e2 = t3.date, n2 = t3.utc;
            if (null === e2)
              return new Date(NaN);
            if (O.u(e2))
              return new Date();
            if (e2 instanceof Date)
              return new Date(e2);
            if ("string" == typeof e2 && !/Z$/i.test(e2)) {
              var r2 = e2.match($);
              if (r2) {
                var i2 = r2[2] - 1 || 0, s2 = (r2[7] || "0").substring(0, 3);
                return n2 ? new Date(Date.UTC(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2)) : new Date(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2);
              }
            }
            return new Date(e2);
          }(t2), this.$x = t2.x || {}, this.init();
        }, m2.init = function() {
          var t2 = this.$d;
          this.$y = t2.getFullYear(), this.$M = t2.getMonth(), this.$D = t2.getDate(), this.$W = t2.getDay(), this.$H = t2.getHours(), this.$m = t2.getMinutes(), this.$s = t2.getSeconds(), this.$ms = t2.getMilliseconds();
        }, m2.$utils = function() {
          return O;
        }, m2.isValid = function() {
          return !(this.$d.toString() === l);
        }, m2.isSame = function(t2, e2) {
          var n2 = w(t2);
          return this.startOf(e2) <= n2 && n2 <= this.endOf(e2);
        }, m2.isAfter = function(t2, e2) {
          return w(t2) < this.startOf(e2);
        }, m2.isBefore = function(t2, e2) {
          return this.endOf(e2) < w(t2);
        }, m2.$g = function(t2, e2, n2) {
          return O.u(t2) ? this[e2] : this.set(n2, t2);
        }, m2.unix = function() {
          return Math.floor(this.valueOf() / 1e3);
        }, m2.valueOf = function() {
          return this.$d.getTime();
        }, m2.startOf = function(t2, e2) {
          var n2 = this, r2 = !!O.u(e2) || e2, h2 = O.p(t2), l2 = function(t3, e3) {
            var i2 = O.w(n2.$u ? Date.UTC(n2.$y, e3, t3) : new Date(n2.$y, e3, t3), n2);
            return r2 ? i2 : i2.endOf(a);
          }, $2 = function(t3, e3) {
            return O.w(n2.toDate()[t3].apply(n2.toDate("s"), (r2 ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e3)), n2);
          }, y2 = this.$W, M3 = this.$M, m3 = this.$D, v2 = "set" + (this.$u ? "UTC" : "");
          switch (h2) {
            case c:
              return r2 ? l2(1, 0) : l2(31, 11);
            case f:
              return r2 ? l2(1, M3) : l2(0, M3 + 1);
            case o:
              var g2 = this.$locale().weekStart || 0, D2 = (y2 < g2 ? y2 + 7 : y2) - g2;
              return l2(r2 ? m3 - D2 : m3 + (6 - D2), M3);
            case a:
            case d:
              return $2(v2 + "Hours", 0);
            case u:
              return $2(v2 + "Minutes", 1);
            case s:
              return $2(v2 + "Seconds", 2);
            case i:
              return $2(v2 + "Milliseconds", 3);
            default:
              return this.clone();
          }
        }, m2.endOf = function(t2) {
          return this.startOf(t2, false);
        }, m2.$set = function(t2, e2) {
          var n2, o2 = O.p(t2), h2 = "set" + (this.$u ? "UTC" : ""), l2 = (n2 = {}, n2[a] = h2 + "Date", n2[d] = h2 + "Date", n2[f] = h2 + "Month", n2[c] = h2 + "FullYear", n2[u] = h2 + "Hours", n2[s] = h2 + "Minutes", n2[i] = h2 + "Seconds", n2[r] = h2 + "Milliseconds", n2)[o2], $2 = o2 === a ? this.$D + (e2 - this.$W) : e2;
          if (o2 === f || o2 === c) {
            var y2 = this.clone().set(d, 1);
            y2.$d[l2]($2), y2.init(), this.$d = y2.set(d, Math.min(this.$D, y2.daysInMonth())).$d;
          } else
            l2 && this.$d[l2]($2);
          return this.init(), this;
        }, m2.set = function(t2, e2) {
          return this.clone().$set(t2, e2);
        }, m2.get = function(t2) {
          return this[O.p(t2)]();
        }, m2.add = function(r2, h2) {
          var d2, l2 = this;
          r2 = Number(r2);
          var $2 = O.p(h2), y2 = function(t2) {
            var e2 = w(l2);
            return O.w(e2.date(e2.date() + Math.round(t2 * r2)), l2);
          };
          if ($2 === f)
            return this.set(f, this.$M + r2);
          if ($2 === c)
            return this.set(c, this.$y + r2);
          if ($2 === a)
            return y2(1);
          if ($2 === o)
            return y2(7);
          var M3 = (d2 = {}, d2[s] = e, d2[u] = n, d2[i] = t, d2)[$2] || 1, m3 = this.$d.getTime() + r2 * M3;
          return O.w(m3, this);
        }, m2.subtract = function(t2, e2) {
          return this.add(-1 * t2, e2);
        }, m2.format = function(t2) {
          var e2 = this, n2 = this.$locale();
          if (!this.isValid())
            return n2.invalidDate || l;
          var r2 = t2 || "YYYY-MM-DDTHH:mm:ssZ", i2 = O.z(this), s2 = this.$H, u2 = this.$m, a2 = this.$M, o2 = n2.weekdays, f2 = n2.months, h2 = function(t3, n3, i3, s3) {
            return t3 && (t3[n3] || t3(e2, r2)) || i3[n3].slice(0, s3);
          }, c2 = function(t3) {
            return O.s(s2 % 12 || 12, t3, "0");
          }, d2 = n2.meridiem || function(t3, e3, n3) {
            var r3 = t3 < 12 ? "AM" : "PM";
            return n3 ? r3.toLowerCase() : r3;
          }, $2 = { YY: String(this.$y).slice(-2), YYYY: this.$y, M: a2 + 1, MM: O.s(a2 + 1, 2, "0"), MMM: h2(n2.monthsShort, a2, f2, 3), MMMM: h2(f2, a2), D: this.$D, DD: O.s(this.$D, 2, "0"), d: String(this.$W), dd: h2(n2.weekdaysMin, this.$W, o2, 2), ddd: h2(n2.weekdaysShort, this.$W, o2, 3), dddd: o2[this.$W], H: String(s2), HH: O.s(s2, 2, "0"), h: c2(1), hh: c2(2), a: d2(s2, u2, true), A: d2(s2, u2, false), m: String(u2), mm: O.s(u2, 2, "0"), s: String(this.$s), ss: O.s(this.$s, 2, "0"), SSS: O.s(this.$ms, 3, "0"), Z: i2 };
          return r2.replace(y, function(t3, e3) {
            return e3 || $2[t3] || i2.replace(":", "");
          });
        }, m2.utcOffset = function() {
          return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
        }, m2.diff = function(r2, d2, l2) {
          var $2, y2 = O.p(d2), M3 = w(r2), m3 = (M3.utcOffset() - this.utcOffset()) * e, v2 = this - M3, g2 = O.m(this, M3);
          return g2 = ($2 = {}, $2[c] = g2 / 12, $2[f] = g2, $2[h] = g2 / 3, $2[o] = (v2 - m3) / 6048e5, $2[a] = (v2 - m3) / 864e5, $2[u] = v2 / n, $2[s] = v2 / e, $2[i] = v2 / t, $2)[y2] || v2, l2 ? g2 : O.a(g2);
        }, m2.daysInMonth = function() {
          return this.endOf(f).$D;
        }, m2.$locale = function() {
          return D[this.$L];
        }, m2.locale = function(t2, e2) {
          if (!t2)
            return this.$L;
          var n2 = this.clone(), r2 = S(t2, e2, true);
          return r2 && (n2.$L = r2), n2;
        }, m2.clone = function() {
          return O.w(this.$d, this);
        }, m2.toDate = function() {
          return new Date(this.valueOf());
        }, m2.toJSON = function() {
          return this.isValid() ? this.toISOString() : null;
        }, m2.toISOString = function() {
          return this.$d.toISOString();
        }, m2.toString = function() {
          return this.$d.toUTCString();
        }, M2;
      }(), T = _.prototype;
      return w.prototype = T, [["$ms", r], ["$s", i], ["$m", s], ["$H", u], ["$W", a], ["$M", f], ["$y", c], ["$D", d]].forEach(function(t2) {
        T[t2[1]] = function(e2) {
          return this.$g(e2, t2[0], t2[1]);
        };
      }), w.extend = function(t2, e2) {
        return t2.$i || (t2(e2, _, w), t2.$i = true), w;
      }, w.locale = S, w.isDayjs = p, w.unix = function(t2) {
        return w(1e3 * t2);
      }, w.en = D[g], w.Ls = D, w.p = {}, w;
    });
  }
});
export default require_dayjs_min();
_:xu/**
 * 路由跳转方法，该方法相对于直接使用uni.xxx的好处是使用更加简单快捷
 * 并且带有路由拦截功能
 */
import { queryParams, deepMerge, page } from '@/uni_modules/uv-ui-tools/libs/function/index.js'
class Router {
	constructor() {
		// 原始属性定义
		this.config = {
			type: 'navigateTo',
			url: '',
			delta: 1, // navigateBack页面后退时,回退的层数
			params: {}, // 传递的参数
			animationType: 'pop-in', // 窗口动画,只在APP有效
			animationDuration: 300, // 窗口动画持续时间,单位毫秒,只在APP有效
			intercept: false ,// 是否需要拦截
			events: {} // 页面间通信接口，用于监听被打开页面发送到当前页面的数据。hbuilderx 2.8.9+ 开始支持。
		}
		// 因为route方法是需要对外赋值给另外的对象使用，同时route内部有使用this，会导致route失去上下文
		// 这里在构造函数中进行this绑定
		this.route = this.route.bind(this)
	}

	// 判断url前面是否有"/"，如果没有则加上，否则无法跳转
	addRootPath(url) {
		return url[0] === '/' ? url : `/${url}`
	}

	// 整合路由参数
	mixinParam(url, params) {
		url = url && this.addRootPath(url)

		// 使用正则匹配，主要依据是判断是否有"/","?","="等，如“/page/index/index?name=mary"
		// 如果有url中有get参数，转换后无需带上"?"
		let query = ''
		if (/.*\/.*\?.*=.*/.test(url)) {
			// object对象转为get类型的参数
			query = queryParams(params, false)
			// 因为已有get参数,所以后面拼接的参数需要带上"&"隔开
			return url += `&${query}`
		}
		// 直接拼接参数，因为此处url中没有后面的query参数，也就没有"?/&"之类的符号
		query = queryParams(params)
		return url += query
	}

	// 对外的方法名称
	async route(options = {}, params = {}) {
		// 合并用户的配置和内部的默认配置
		let mergeConfig = {}

		if (typeof options === 'string') {
			// 如果options为字符串，则为route(url, params)的形式
			mergeConfig.url = this.mixinParam(options, params)
			mergeConfig.type = 'navigateTo'
		} else {
			mergeConfig = deepMerge(this.config, options)
			// 否则正常使用mergeConfig中的url和params进行拼接
			mergeConfig.url = this.mixinParam(options.url, options.params)
		}
		// 如果本次跳转的路径和本页面路径一致，不执行跳转，防止用户快速点击跳转按钮，造成多次跳转同一个页面的问题
		if (mergeConfig.url === page()) return

		if (params.intercept) {
			mergeConfig.intercept = params.intercept
		}
		// params参数也带给拦截器
		mergeConfig.params = params
		// 合并内外部参数
		mergeConfig = deepMerge(this.config, mergeConfig)
		// 判断用户是否定义了拦截器
		if (typeof mergeConfig.intercept === 'function') {
			// 定一个promise，根据用户执行resolve(true)或者resolve(false)来决定是否进行路由跳转
			const isNext = await new Promise((resolve, reject) => {
				mergeConfig.intercept(mergeConfig, resolve)
			})
			// 如果isNext为true，则执行路由跳转
			isNext && this.openPage(mergeConfig)
		} else {
			this.openPage(mergeConfig)
		}
	}

	// 执行路由跳转
	openPage(config) {
		// 解构参数
		const {
			url,
			type,
			delta,
			animationType,
			animationDuration,
			events
		} = config
		if (config.type == 'navigateTo' || config.type == 'to') {
			uni.navigateTo({
				url,
				animationType,
				animationDuration,
				events
			})
		}
		if (config.type == 'redirectTo' || config.type == 'redirect') {
			uni.redirectTo({
				url
			})
		}
		if (config.type == 'switchTab' || config.type == 'tab') {
			uni.switchTab({
				url
			})
		}
		if (config.type == 'reLaunch' || config.type == 'launch') {
			uni.reLaunch({
				url
			})
		}
		if (config.type == 'navigateBack' || config.type == 'back') {
			uni.navigateBack({
				delta
			})
		}
	}
}

export default (new Router()).routeMxvj{
  "id": "uv-ui-tools",
  "displayName": "uv-ui-tools 工具集 全面兼容vue3+2、app、h5、小程序|1.25",
  "description": "uv-ui-tools，集成工具库，强大的Http请求封装，清晰的文档说明，开箱即用。方便使用，可以全局使用o2uv-ui-tools,uv-ui组件库,工具集,uvui,uView2.x
飞书N
Tp"联盟": "y{KIxi// 此文件为uvUI的主题变量，这些变量目前只能通过uni.scss引入才有效，另外由于
// uni.scss中引入的样式会同时混入到全局样式文件和单独每一个页面的样式中，造成微信程序包太大，
// 故uni.scss只建议放scss变量名相关样式，其他的样式可以通过main.js或者App.vue引入

$uv-main-color: #303133;
$uv-content-color: #606266;
$uv-tips-color: #909193;
$uv-light-color: #c0c4cc;
$uv-border-color: #dadbde;
$uv-bg-color: #f3f4f6;
$uv-disabled-color: #c8c9cc;

$uv-primary: #3c9cff;
$uv-primary-dark: #398ade;
$uv-primary-disabled: #9acafc;
$uv-primary-light: #ecf5ff;

$uv-warning: #f9ae3d;
$uv-warning-dark: #f1a532;
$uv-warning-disabled: #f9d39b;
$uv-warning-light: #fdf6ec;

$uv-success: #5ac725;
$uv-success-dark: #53c21d;
$uv-success-disabled: #a9e08f;
$uv-success-light: #f5fff0;

$uv-error: #f56c6c;
$uv-error-dark: #e45656;
$uv-error-disabled: #f7b2b2;
$uv-error-light: #fef0f0;

$uv-info: #909399;
$uv-info-dark: #767a82;
$uv-info-disabled: #c4c6c9;
$uv-info-light: #f4f4f5;

@mixin flex($direction: row) {
	/* #ifndef APP-NVUE */
	display: flex;
	/* #endif */
	flex-direction: $direction;
}Ȫ	x e100644 changelog.md \wY 40000 components Q+5ofyZ.^*100644 package.json ^-Ls1f4100644 readme.md uRZ$OB1?
:Yx  40000 uv-ui ZZT+ڑl@@Yx% 100644 uv-ui.vue #	S4(cfDx <template>
	<view>占位组件，请勿使用；如需下载示例项目，请使用【下载插件并导入HBuilderX】或【使用 HBuilderX 导入示例项目】或【下载示例项目ZIP】</view>
</template>
<script>
</script>
<style>
</style>
Ჽx-{
	"id": "uv-ui",
	"displayName": "uv-ui 破釜沉舟之兼容vue3+2、app、h5、小程序等多端，灵活导入，利剑出击",
	"version": "1.1.20",
	"description": "uv-ui 是基于uni-app、部分组件基于uView2.x、全端兼容、支持独立导入、内容丰富的UI框架。破釜沉舟之兼容vue3+2、app、h5、小程序等多端，利剑出击，开箱即用。",
	"keywords": [
        "uv-ui",
        "uvui",
        "UI组件库",
        "ui框架",
        "ui库"
    ],
	"repository": "https://github.com/climblee/uv-ui",
	"engines": {
		"HBuilderX": "^3.1.0"
	},
	"dcloudext": {
		"type": "component-vue",
		"sale": {
			"regular": {
				"price": "0.00"
			},
			"sourcecode": {
				"price": "0.00"
			}
		},
		"contact": {
			"qq": ""
		},
		"declaration": {
			"ads": "无",
			"data": "无",
			"permissions": "无"
		},
		"npmurl": "https://www.npmjs.com/package/@climblee/uv-ui"
	},
	"uni_modules": {
		"dependencies": [
			"uv-skeletons",
			"uv-album",
			"uv-drop-down",
			"uv-calendars",
			"uv-scroll-list",
			"uv-vtabs",
			"uv-pick-color",
			"uv-qrcode",
			"uv-ui-tools",
			"uv-action-sheet",
			"uv-alert",
			"uv-avatar",
			"uv-back-top",
			"uv-badge",
			"uv-button",
			"uv-calendar",
			"uv-cell",
			"uv-checkbox",
			"uv-code",
			"uv-code-input",
			"uv-collapse",
			"uv-count-down",
			"uv-count-to",
			"uv-datetime-picker",
			"uv-divider",
			"uv-empty",
			"uv-form",
			"uv-gap",
			"uv-grid",
			"uv-icon",
			"uv-image",
			"uv-index-list",
			"uv-input",
			"uv-keyboard",
			"uv-line",
			"uv-line-progress",
			"uv-link",
			"uv-list",
			"uv-loading-icon",
			"uv-loading-page",
			"uv-load-more",
			"uv-modal",
			"uv-navbar",
			"uv-no-network",
			"uv-notice-bar",
			"uv-notify",
			"uv-number-box",
			"uv-overlay",
			"uv-parse",
			"uv-picker",
			"uv-popup",
			"uv-radio",
			"uv-rate",
			"uv-read-more",
			"uv-row",
			"uv-safe-bottom",
			"uv-search",
			"uv-skeleton",
			"uv-slider",
			"uv-status-bar",
			"uv-steps",
			"uv-sticky",
			"uv-subsection",
			"uv-swipe-action",
			"uv-swiper",
			"uv-switch",
			"uv-tabbar",
			"uv-tabs",
			"uv-tags",
			"uv-text",
			"uv-textarea",
			"uv-toast",
			"uv-tooltip",
			"uv-transition",
			"uv-upload",
			"uv-waterfall"
		],
		"encrypt": [],
		"platforms": {
			"cloud": {
				"tcb": "y",
				"aliyun": "y"
			},
			"client": {
				"Vue": {
					"vue2": "y",
					"vue3": "y"
				},
				"App": {
					"app-vue": "y",
					"app-nvue": "y"
				},
				"H5-mobile": {
					"Safari": "y",
					"Android Browser": "y",
					"微信浏览器(Android)": "y",
					"QQ浏览器(Android)": "y"
				},
				"H5-pc": {
					"Chrome": "y",
					"IE": "y",
					"Edge": "y",
					"Firefox": "y",
					"Safari": "y"
				},
				"小程序": {
					"微信": "y",
					"阿里": "y",
					"百度": "y",
					"字节跳动": "y",
					"QQ": "y",
					"钉钉": "u",
					"快手": "u",
					"飞书": "u",
					"京东": "u"
				},
				"快应用": {
					"华为": "u",
					"联盟": "u"
				}
			}
		}
	}
}x|-<p align="center">
    <span>&nbsp;&nbsp;&nbsp;&nbsp;</span><img alt="logo" src="https://www.uvui.cn/common/logo.png" width="120" height="120">
</p>
<h3 align="center">uv-ui</h3>
<h3 align="center">兼容vue3+2多平台快速开发的UI框架</h3>

[![star](https://gitee.com/climblee/uv-ui/badge/star.svg?theme=gvp)](https://gitee.com/climblee/uv-ui)
[![star](https://gitee.com/climblee/uv-ui/badge/fork.svg?theme=gvp)](https://gitee.com/climblee/uv-ui)
[![star](https://img.shields.io/github/stars/climblee/uv-ui?style=flat-square&logo=GitHub)](https://github.com/climblee/uv-ui)
[![issues](https://img.shields.io/github/issues/climblee/uv-ui?style=flat-square&logo=GitHub)](https://github.com/climblee/uv-ui/issues)
[![Website](https://img.shields.io/badge/uvui-up-blue?style=flat-square)](https://www.uvui.cn)
[![version](https://img.shields.io/badge/version-1.1.16-brightgreen.svg)](https://www.uvui.cn/components/changelog.html)
[![license](https://img.shields.io/github/license/climblee/uv-ui?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)

## 温馨提示：如需下载uv-ui示例项目，请不要使用【下载插件ZIP】按钮。

### uvui官方群1：<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=aaoyDvfV7nSee9vzWfzyZM1vKlu3xrNZ&authKey=pdU6HDpyzGUoc1QvQvCmzCbwzsoHgBbToF%2F0ChP4lNjPIPgWHGRE4I99XYGiTcNI&noverify=0&group_code=549833913" target="_blank">549833913</a>
### uvui官方群2：<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=2QbEeKBn6ysCyQ09V4mgst1W8onxFybQ&authKey=aMTGL5zCYwsinG%2FeH0qMlAqXAdyKr5AjXVf2oMnsmj7NCg%2F2HraMU%2FNFxELLIPvp&noverify=0&group_code=206060892" target="_blank">206060892</a>

## uvui特点

1. **uv-ui的前世今生**，`uv-ui` 是基于 `uview2.x` 版本改造而来。重命名也是为了避开发布冲突和很多组件 `u-`在  `nvue` 中不能使用的情况，所以这才诞生了`uv-ui`。感谢 `uview-ui` 作者的开源奉献，再次为开源点赞。 同时 `uv-ui` 也是无条件开源。

2. **全端兼容**，`uv-ui`支持vue3、vue2、app-vue、app-nvue、h5、小程序等。`uv-ui`的组件都是多端自适应的，底层会抹平很多小程序平台的差异或bug。

3. **扩展配置**，`uv-ui`内置的方法默认不再挂载到`uni`对象之上，也就意味着默认情况下不能在项目中直接使用`uni.$uv.xxx`使用内置方法。但是可以通过扩展可以解决，通过如下方式进行配置即可，使用方式请参考[扩展配置](https://www.uvui.cn/components/setting.html)。其中包括[ JS工具库](https://www.uvui.cn/components/setting.html#%E6%89%A9%E5%B1%95%E9%85%8D%E7%BD%AE-js%E5%B7%A5%E5%85%B7%E5%BA%93)、[ 自定义主题](https://www.uvui.cn/components/setting.html#%E6%89%A9%E5%B1%95%E9%85%8D%E7%BD%AE-%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%BB%E9%A2%98)、[ 基础样式](https://www.uvui.cn/components/setting.html#%E6%89%A9%E5%B1%95%E9%85%8D%E7%BD%AE-%E5%9F%BA%E7%A1%80%E6%A0%B7%E5%BC%8F)、[ setconfig](https://www.uvui.cn/components/setting.html#%E6%89%A9%E5%B1%95%E9%85%8D%E7%BD%AE-setconfig)等。

## 预览

通过微信（APP下载不支持微信扫码）或浏览器扫码查看演示效果。

<img src="https://mp-31ed6237-7b7b-4597-8448-a53d6d6031cf.cdn.bspapp.com/uvui/download-wx.png" width="200" />&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://mp-31ed6237-7b7b-4597-8448-a53d6d6031cf.cdn.bspapp.com/uvui/download-app.png" width="200" />&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://mp-31ed6237-7b7b-4597-8448-a53d6d6031cf.cdn.bspapp.com/uvui/download-h5.png" width="200" />

## 链接

- [官方文档](https://www.uvui.cn)
- [演示地址](https://h5.uvui.cn)
- [更新日志](https://www.uvui.cn/components/changelog.html)
- [关于我们](https://www.uvui.cn/cooperation/about.html)
- <a href="#list">组件列表</a>

## 交流反馈

欢迎加入我们的QQ群交流反馈：[点此跳转](https://www.uvui.cn/components/addQQGroup.html)

## 快速开始

方式一：`uv-ui` 强烈建议通过 `下载插件并导入HbuilderX` 导入组件。

方式二：下载完整 [uv-ui项目](https://ext.dcloud.net.cn/plugin?id=12287) 将 `uni_modules` 复制到自己的项目。

方式三：通过 `npm i @climblee/uv-ui` 下载，此方法需要配置 easycom，配置详情可查看[安装](https://www.uvui.cn/components/install.html)。

请通过[快速上手](https://www.uvui.cn/components/quickstart.html)了解更详细的内容。

**注意：导入插件后，建议`HBuilderX`重新运行项目，可能新导入的插件不能实时更新而导致不能运行。**

## 使用方法

组件导入 `uni_modules` 后，直接在项目中使用，无需通过import引入组件。

```html
<template>
    <uv-icon name="baidu" size="30" color="#909399"></uv-icon>
</template>
```

## 扩展功能

`uv-ui` 内置了强大的工具函数、请求封装等，可以根据自身需求进行扩展配置，详情请查看[扩展配置](https://www.uvui.cn/components/setting.html)。

**注意：只有[扩展配置](https://www.uvui.cn/components/setting.html)后才能在自己的项目页面中使用组件库内置方法和变量等**。

<div id="list"></div>

## 组件列表

下表为 `uv-ui` 的扩展组件清单，点击每个组件**点击下载&安装**即可在详情页面导入组件到项目下，导入后建议重新运行即可直接使用，组件无需import和注册。

| 组件名 | 组件说明 |
| --- | --- |
| uv-skeletons | [新版骨架屏（推荐）](https://www.uvui.cn/components/skeletons.html) |
| uv-calendars | [新版日历（推荐）](https://www.uvui.cn/components/calendars.html) |
| uv-drop-down | [下拉筛选](https://www.uvui.cn/components/dropDown.html) |
| uv-scroll-list | [横向滚动列表](https://www.uvui.cn/components/scrollList.html) |
| uv-vtabs | [垂直选项卡](https://www.uvui.cn/components/vtabs.html) |
| uv-pick-color | [颜色选择器](https://www.uvui.cn/components/pickColor.html) |
| uv-qrcode | [二维码](https://www.uvui.cn/components/qrcode.html) |
| uv-waterfall | [瀑布流](https://www.uvui.cn/components/waterfall.html) |
| uv-row | [Layout 布局](https://www.uvui.cn/components/layout.html) |
| uv-icon | [图标](https://www.uvui.cn/components/icon.html) |
| uv-button | [按钮](https://www.uvui.cn/components/button.html) |
| uv-text | [文本](https://www.uvui.cn/components/text.html) |
| uv-link | [超链接](https://www.uvui.cn/components/link.html) |
| uv-image | [图片](https://www.uvui.cn/components/image.html) |
| uv-transition | [动画](https://www.uvui.cn/components/transition.html) |
| uv-form | [表单](https://www.uvui.cn/components/form.html) |
| uv-input | [增强输入框](https://www.uvui.cn/components/input.html) |
| uv-textarea | [增强文本域](https://www.uvui.cn/components/textarea.html) |
| uv-checkbox | [复选框](https://www.uvui.cn/components/checkbox.html) |
| uv-radio | [单选框](https://www.uvui.cn/components/radio.html) |
| uv-switch | [开关选择器](https://www.uvui.cn/components/switch.html) |
| uv-calendar | [日历](https://www.uvui.cn/components/calendar.html) |
| uv-picker | [选择器](https://www.uvui.cn/components/picker.html) |
| uv-datetime-picker | [时间选择器](https://www.uvui.cn/components/datetimePicker.html) |
| uv-code | [验证码倒计时](https://www.uvui.cn/components/code.html) |
| uv-keyboard | [键盘](https://www.uvui.cn/components/keyboard.html) |
| uv-rate | [评分](https://www.uvui.cn/components/rate.html) |
| uv-search | [多功能搜索框](https://www.uvui.cn/components/search.html) |
| uv-number-box | [步进器](https://www.uvui.cn/components/numberBox.html) |
| uv-upload | [上传](https://www.uvui.cn/components/upload.html) |
| uv-slider | [滑动选择器](https://www.uvui.cn/components/slider.html) |
| uv-list | [列表](https://www.uvui.cn/components/list.html) |
| uv-index-list | [索引列表](https://www.uvui.cn/components/indexList.html) |
| uv-tags | [标签](https://www.uvui.cn/components/tag.html) |
| uv-line-progress | [线形进度条](https://www.uvui.cn/components/lineProgress.html) |
| uv-badge | [徽标数](https://www.uvui.cn/components/badge.html) |
| uv-count-down | [倒计时](https://www.uvui.cn/components/countDown.html) |
| uv-count-to | [数字滚动](https://www.uvui.cn/components/countTo.html) |
| uv-avatar | [头像](https://www.uvui.cn/components/avatar.html) |
| uv-skeleton | [骨架屏](https://www.uvui.cn/components/skeleton.html) |
| uv-loading-icon | [加载动画](https://www.uvui.cn/components/loadingIcon.html) |
| uv-loading-page | [加载页](https://www.uvui.cn/components/loadingPage.html) |
| uv-load-more | [加载更多](https://www.uvui.cn/components/loadMore.html) |
| uv-empty | [内容为空](https://www.uvui.cn/components/empty.html) |
| uv-tooltip | [长按提示](https://www.uvui.cn/components/tooltip.html) |
| uv-alert | [警告提示](https://www.uvui.cn/components/alert.html) |
| uv-toast | [消息提示](https://www.uvui.cn/components/toast.html) |
| uv-notice-bar | [滚动通知](https://www.uvui.cn/components/noticeBar.html) |
| uv-notify | [消息提示](https://www.uvui.cn/components/notify.html) |
| uv-no-network | [无网络提示](https://www.uvui.cn/components/noNetwork.html) |
| uv-popup | [弹出层](https://www.uvui.cn/components/popup.html) |
| uv-modal | [模态框](https://www.uvui.cn/components/modal.html) |
| uv-cell | [单元格](https://www.uvui.cn/components/cell.html) |
| uv-swipe-action | [滑动单元格](https://www.uvui.cn/components/swipeAction.html) |
| uv-swiper | [轮播图](https://www.uvui.cn/components/swiper.html) |
| uv-collapse | [折叠面板](https://www.uvui.cn/components/collapse.html) |
| uv-grid | [宫格布局](https://www.uvui.cn/components/grid.html) |
| uv-album | [相册](https://www.uvui.cn/components/album.html) |
| uv-tabbar | [底部导航栏](https://www.uvui.cn/components/tabbar.html) |
| uv-back-top | [返回顶部](https://www.uvui.cn/components/backTop.html) |
| uv-navbar | [自定义导航栏](https://www.uvui.cn/components/navbar.html) |
| uv-action-sheet | [底部操作菜单](https://www.uvui.cn/components/actionSheet.html) |
| uv-tabs | [标签选项卡](https://www.uvui.cn/components/tabs.html) |
| uv-steps | [步骤条](https://www.uvui.cn/components/steps.html) |
| uv-subsection | [分段器](https://www.uvui.cn/components/subsection.html) |
| uv-sticky | [吸顶](https://www.uvui.cn/components/sticky.html) |
| uv-parse | [富文本解析器](https://www.uvui.cn/components/parse.html) |
| uv-overlay | [遮罩层](https://www.uvui.cn/components/overlay.html) |
| uv-code-input | [验证码输入](https://www.uvui.cn/components/codeInput.html) |
| uv-read-more | [展开阅读更多](https://www.uvui.cn/components/readMore.html) |
| uv-line | [线条](https://www.uvui.cn/components/line.html) |
| uv-gap | [间隔槽](https://www.uvui.cn/components/gap.html) |
| uv-divider | [分割线](https://www.uvui.cn/components/divider.html) |

## 版权信息
uv-ui遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议，意味着您无需支付任何费用，也无需授权，即可将uv-ui应用到您的产品中。

## 作者想说
- 开源真的不易，不图大家的钱财，所以希望大家多多鼓励支持，希望不要恶意评论，有问题加群快速解决。
- 遇到BUG，是一件很正常的事情，是程序肯定就有BUG，所以希望大家能以理解的心态去提出BUG，然后作者才有动力去努力修复。
- 最后觉得好用的小伙伴，不要吝啬你的双手，给个好评就是给我们最大的鼓励。

# 恶评者手下留情，有事加QQ群解决：5498339135	x e100644 changelog.md y;lgAY'Ɩ!40000 components ? D1"dJ100644 package.json 3"qyp(100644 readme.md J~ks_=ZNWBǵ%xU## 1.0.6（2023-12-20）
1. 修复动态设置deletable为false不生效的BUG
## 1.0.5（2023-08-31）
1. 添加uv-popup依赖
## 1.0.4（2023-08-18）
1. 修复图片预览位置错误的BUG
2. 修复视频预览不生效的BUG
3. 修复改变上传视频宽高不生效的BUG
## 1.0.3（2023-07-03）
去除插槽判断，避免某些平台不显示的BUG
## 1.0.2（2023-05-24）
1. 优化fileList，watch中增加deep属性
## 1.0.1（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.0（2023-05-10）
uv-upload 上传
:xO 40000 uv-preview-video }<Pzd:r-40000 uv-upload _ZI" t=tmf5x0 100644 uv-preview-video.vue 2|hSqND_M/3@1x<template>
	<uv-popup ref="popup" @change="change">
		<view class="video-view" v-if="show">
			<video class="video" :src="getSec" :autoplay="autoplay"></video>
		</view>
	</uv-popup>
</template>
<script>
	export default {
		props: {
			src: {
				type: String,
				default: ''
			},
			autoplay: {
				type: Boolean,
				default: true
			}
		},
		data() {
			return {
				videoSrc: '',
				show: false
			}
		},
		computed: {
			getSec() {
				return this.src || this.videoSrc;
			}
		},
		methods: {
			open(url) {
				this.videoSrc = url;
				this.$refs.popup.open();
			},
			close() {
				this.$refs.popup.close();
			},
			change(e) {
				this.show = e.show;
			}
		}
	}
</script>
<style scoped lang="scss">
	.video-view {
		width: 750rpx;
		.video {
			width: 750rpx;
		}
	}
</style>A:	x j100644 mixin.js /
WډH100644 props.js *{hDܘtۉIL+wQJ100644 utils.js `$IC)K48l100644 uv-upload.vue !;jØY=4xDimport { error } from '@/uni_modules/uv-ui-tools/libs/function/index.js'
export default {
    watch: {
        // 监听accept的变化，判断是否符合个平台要求
        // 只有微信小程序才支持选择媒体，文件类型，所以这里做一个判断提示
        accept: {
            immediate: true,
            handler(val) {
                // #ifndef MP-WEIXIN
                if (val === 'all' || val === 'media') {
                    error('只有微信小程序才支持把accept配置为all、media之一')
                }
                // #endif
                // #ifndef H5 || MP-WEIXIN
                if (val === 'file') {
                    error('只有微信小程序和H5(HX2.9.9)才支持把accept配置为file')
                }
                // #endif
            }
        }
    }
}
~Z7Ƿxexport default {
	props: {
		// 接受的文件类型, 可选值为all media image file video
		accept: {
			type: String,
			default: 'image'
		},
		// 	图片或视频拾取模式，当accept为image类型时设置capture可选额外camera可以直接调起摄像头
		capture: {
			type: [String, Array],
			default: () => ['album', 'camera']
		},
		// 当accept为video时生效，是否压缩视频，默认为true
		compressed: {
			type: Boolean,
			default: true
		},
		// 当accept为video时生效，可选值为back或front
		camera: {
			type: String,
			default: 'back'
		},
		// 当accept为video时生效，拍摄视频最长拍摄时间，单位秒
		maxDuration: {
			type: Number,
			default: 60
		},
		// 上传区域的图标，只能内置图标
		uploadIcon: {
			type: String,
			default: 'camera-fill'
		},
		// 上传区域的图标的颜色，默认
		uploadIconColor: {
			type: String,
			default: '#D3D4D6'
		},
		// 是否开启文件读取前事件
		useBeforeRead: {
			type: Boolean,
			default: false
		},
		// 读取后的处理函数
		afterRead: {
			type: Function,
			default: null
		},
		// 读取前的处理函数
		beforeRead: {
			type: Function,
			default: null
		},
		// 是否开启图片预览功能
		previewFullImage: {
			type: Boolean,
			default: true
		},
		// 是否开启视频预览功能
		previewFullVideo: {
			type: Boolean,
			default: true
		},
		// 最大上传数量
		maxCount: {
			type: [String, Number],
			default: 52
		},
		// 是否禁用
		disabled: {
			type: Boolean,
			default: false
		},
		// 预览上传的图片时的裁剪模式，和image组件mode属性一致
		imageMode: {
			type: String,
			default: 'aspectFill'
		},
		// 标识符，可以在回调函数的第二项参数中获取
		name: {
			type: String,
			default: ''
		},
		// 所选的图片的尺寸, 可选值为original compressed
		sizeType: {
			type: Array,
			default: () => ['original', 'compressed']
		},
		// 是否开启图片多选，部分安卓机型不支持
		multiple: {
			type: Boolean,
			default: false
		},
		// 是否展示删除按钮
		deletable: {
			type: Boolean,
			default: true
		},
		// 文件大小限制，单位为byte
		maxSize: {
			type: [String, Number],
			default: Number.MAX_VALUE
		},
		// 显示已上传的文件列表
		fileList: {
			type: Array,
			default: () => []
		},
		// 上传区域的提示文字
		uploadText: {
			type: String,
			default: ''
		},
		// 内部预览图片区域和选择图片按钮的区域宽度
		width: {
			type: [String, Number],
			default: 80
		},
		// 内部预览图片区域和选择图片按钮的区域高度
		height: {
			type: [String, Number],
			default: 80
		},
		// 是否在上传完成后展示预览图
		previewImage: {
			type: Boolean,
			default: true
		},
		...uni.$uv?.props?.upload
	}
}aſx@function pickExclude(obj, keys) {
	// 某些情况下，type可能会为
    if (!['[object Object]', '[object File]'].includes(Object.prototype.toString.call(obj))) {
        return {}
    }
    return Object.keys(obj).reduce((prev, key) => {
        if (!keys.includes(key)) {
            prev[key] = obj[key]
        }
        return prev
    }, {})
}

function formatImage(res) {
    return res.tempFiles.map((item) => ({
        ...pickExclude(item, ['path']),
        type: 'image',
        url: item.path,
        thumb: item.path,
		size: item.size,
		// #ifdef H5
		name: item.name
		// #endif
    }))
}

function formatVideo(res) {
    return [
        {
            ...pickExclude(res, ['tempFilePath', 'thumbTempFilePath', 'errMsg']),
            type: 'video',
            url: res.tempFilePath,
            thumb: res.thumbTempFilePath,
			size: res.size,
			// #ifdef H5
			name: res.name
			// #endif
        }
    ]
}

function formatMedia(res) {
    return res.tempFiles.map((item) => ({
        ...pickExclude(item, ['fileType', 'thumbTempFilePath', 'tempFilePath']),
        type: res.type,
        url: item.tempFilePath,
        thumb: res.type === 'video' ? item.thumbTempFilePath : item.tempFilePath,
		size: item.size
    }))
}

function formatFile(res) {
    return res.tempFiles.map((item) => ({ 
		...pickExclude(item, ['path']), 
		url: item.path, 
		size:item.size,
		// #ifdef H5
		name: item.name,
		type: item.type
		// #endif 
	}))
}
export function chooseFile({
    accept,
    multiple,
    capture,
    compressed,
    maxDuration,
    sizeType,
    camera,
    maxCount
}) {
    return new Promise((resolve, reject) => {
        switch (accept) {
        case 'image':
            uni.chooseImage({
                count: multiple ? Math.min(maxCount, 9) : 1,
                sourceType: capture,
                sizeType,
                success: (res) => resolve(formatImage(res)),
                fail: reject
            })
            break
            // #ifdef MP-WEIXIN
            // 只有微信小程序才支持chooseMedia接口
        case 'media':
            wx.chooseMedia({
                count: multiple ? Math.min(maxCount, 9) : 1,
                sourceType: capture,
                maxDuration,
                sizeType,
                camera,
                success: (res) => resolve(formatMedia(res)),
                fail: reject
            })
            break
            // #endif
        case 'video':
            uni.chooseVideo({
                sourceType: capture,
                compressed,
                maxDuration,
                camera,
                success: (res) => resolve(formatVideo(res)),
                fail: reject
            })
            break
            // #ifdef MP-WEIXIN || H5
            // 只有微信小程序才支持chooseMessageFile接口
        case 'file':
            // #ifdef MP-WEIXIN
            wx.chooseMessageFile({
                count: multiple ? maxCount : 1,
                type: accept,
                success: (res) => resolve(formatFile(res)),
                fail: reject
            })
            // #endif
            // #ifdef H5
            // 需要hx2.9.9以上才支持uni.chooseFile
            uni.chooseFile({
                count: multiple ? maxCount : 1,
                type: accept,
                success: (res) => resolve(formatFile(res)),
                fail: reject
            })
            // #endif
            break
				// #endif
		default: 
			// 此为保底选项，在accept不为上面任意一项的时候选取全部文件
			// #ifdef MP-WEIXIN
			wx.chooseMessageFile({
			    count: multiple ? maxCount : 1,
			    type: 'all',
			    success: (res) => resolve(formatFile(res)),
			    fail: reject
			})
			// #endif
			// #ifdef H5
			// 需要hx2.9.9以上才支持uni.chooseFile
			uni.chooseFile({
				count: multiple ? maxCount : 1,
				type: 'all',
				success: (res) => resolve(formatFile(res)),
				fail: reject
			})
			// #endif
        }
    })
}
xG}<template>
	<view class="uv-upload" :style="[$uv.addStyle(customStyle)]">
		<view class="uv-upload__wrap">
			<template v-if="previewImage">
				<view class="uv-upload__wrap__preview" v-for="(item, index) in lists" :key="index">
					<image 
						v-if="item.isImage || (item.type && item.type === 'image')" 
						:src="item.thumb || item.url" :mode="imageMode" 
						class="uv-upload__wrap__preview__image" 
						@tap="onPreviewImage(item,index)" 
						:style="[{
							width: $uv.addUnit(width),
							height: $uv.addUnit(height)
						}]" 
						/>
					<view 
						v-else 
						class="uv-upload__wrap__preview__other" 
						@tap="onPreviewVideo(item,index)" 
						:style="[{
							width: $uv.addUnit(width),
							height: $uv.addUnit(height)
						}]"
						>
						<uv-icon color="#80CBF9" size="26" :name="item.isVideo || (item.type && item.type === 'video') ? 'movie' : 'folder'"></uv-icon>
						<text class="uv-upload__wrap__preview__other__text">{{item.isVideo || (item.type && item.type === 'video') ? '视频' : '文件'}}</text>
					</view>
					<view class="uv-upload__status" v-if="item.status === 'uploading' || item.status === 'failed'">
						<view class="uv-upload__status__icon">
							<uv-icon v-if="item.status === 'failed'" name="close-circle" color="#ffffff" size="25" />
							<uv-loading-icon size="22" mode="circle" v-else />
						</view>
						<text v-if="item.message" class="uv-upload__status__message">{{ item.message }}</text>
					</view>
					<view class="uv-upload__deletable" v-if="item.status !== 'uploading' && (deletable || item.deletable)" @tap.stop="deleteItem(index)">
						<view class="uv-upload__deletable__icon">
							<uv-icon name="close" color="#ffffff" size="10"></uv-icon>
						</view>
					</view>
					<view class="uv-upload__success" v-if="item.status === 'success'">
						<!-- #ifdef APP-NVUE -->
						<image :src="successIcon" class="uv-upload__success__icon"></image>
						<!-- #endif -->
						<!-- #ifndef APP-NVUE -->
						<view class="uv-upload__success__icon">
							<uv-icon name="checkmark" color="#ffffff" size="12"></uv-icon>
						</view>
						<!-- #endif -->
					</view>
				</view>
			</template>
			<template v-if="isInCount">
				<view @tap="chooseFile">
					<slot>
						<view class="uv-upload__button" :hover-class="!disabled ? 'uv-upload__button--hover' : ''" hover-stay-time="150" @tap.stop="chooseFile" :class="[disabled && 'uv-upload__button--disabled']" :style="[{
								width: $uv.addUnit(width),
								height: $uv.addUnit(height)
							}]">
							<uv-icon :name="uploadIcon" size="26" :color="uploadIconColor"></uv-icon>
							<text v-if="uploadText" class="uv-upload__button__text">{{ uploadText }}</text>
						</view>
					</slot>
				</view>
			</template>
		</view>
		<uv-preview-video ref="previewVideo"></uv-preview-video>
	</view>
</template>

<script>
	import { func, image, video, array, promise } from '@/uni_modules/uv-ui-tools/libs/function/test.js';
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import { chooseFile } from './utils';
	import mixin_accept from './mixin.js';
	import props from './props.js';
	/**
	 * upload 上传
	 * @description 该组件用于上传图片场景
	 * @tutorial https://www.uvui.cn/components/upload.html
	 * @property {String}			accept				接受的文件类型, 可选值为all media image file video （默认 'image' ）
	 * @property {String | Array}	capture				图片或视频拾取模式，当accept为image类型时设置capture可选额外camera可以直接调起摄像头（默认 ['album', 'camera'] ）
	 * @property {Boolean}			compressed			当accept为video时生效，是否压缩视频，默认为true（默认 true ）
	 * @property {String}			camera				当accept为video时生效，可选值为back或front（默认 'back' ）
	 * @property {Number}			maxDuration			当accept为video时生效，拍摄视频最长拍摄时间，单位秒（默认 60 ）
	 * @property {String}			uploadIcon			上传区域的图标，只能内置图标（默认 'camera-fill' ）
	 * @property {String}			uploadIconColor		上传区域的图标的字体颜色，只能内置图标（默认 #D3D4D6 ）
	 * @property {Boolean}			useBeforeRead		是否开启文件读取前事件（默认 false ）
	 * @property {Boolean}			previewFullImage	是否开启图片预览功能（默认 true ）
	 * @property {Boolean}			previewFullVideo	是否开启视频预览功能（默认 true ）
	 * @property {String | Number}	maxCount			最大上传数量（默认 52 ）
	 * @property {Boolean}			disabled			是否启用（默认 false ）
	 * @property {String}			imageMode			预览上传的图片时的裁剪模式，和image组件mode属性一致（默认 'aspectFill' ）
	 * @property {String}			name				标识符，可以在回调函数的第二项参数中获取
	 * @property {Array}			sizeType			所选的图片的尺寸, 可选值为original compressed（默认 ['original', 'compressed'] ）
	 * @property {Boolean}			multiple			是否开启图片多选，部分安卓机型不支持 （默认 false ）
	 * @property {Boolean}			deletable			是否展示删除按钮（默认 true ）
	 * @property {String | Number}	maxSize				文件大小限制，单位为byte （默认 Number.MAX_VALUE ）
	 * @property {Array}			fileList			显示已上传的文件列表
	 * @property {String}			uploadText			上传区域的提示文字
	 * @property {String | Number}	width				内部预览图片区域和选择图片按钮的区域宽度（默认 80 ）
	 * @property {String | Number}	height				内部预览图片区域和选择图片按钮的区域高度（默认 80 ）
	 * @property {Object}			customStyle			组件的样式，对象形式
	 * @event {Function} afterRead		读取后的处理函数
	 * @event {Function} beforeRead		读取前的处理函数
	 * @event {Function} oversize		文件超出大小限制
	 * @event {Function} clickPreview	点击预览时触发
	 * @event {Function} delete 		删除图片
	 * @example <uv-upload :action="action" :fileList="fileList" ></uv-upload>
	 */
	export default {
		name: "uv-upload",
		// #ifdef VUE3
		emits: ['error', 'beforeRead', 'oversize', 'afterRead', 'delete', 'clickPreview'],
		// #endif
		mixins: [mpMixin, mixin, mixin_accept, props],
		data() {
			return {
				// #ifdef APP-NVUE
				successIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAKKADAAQAAAABAAAAKAAAAAB65masAAACP0lEQVRYCc3YXygsURwH8K/dpcWyG3LF5u/6/+dKVylSypuUl6uUPMifKMWL8oKEB1EUT1KeUPdR3uTNUsSLxb2udG/cbvInNuvf2rVnazZ/ZndmZ87snjM1Z+Z3zpzfp9+Z5mEAhlvjRtZgCKs+gnPAOcAkkMOR4jEHfItjDvgRxxSQD8cM0BuOCaAvXNCBQrigAsXgggYUiwsK0B9cwIH+4gIKlIILGFAqLiBAOTjFgXJxigJp4BQD0sIpAqSJow6kjSNAFTnRaHJwLenD6Mud52VQAcrBfTd2oyq+HtGaGGWAcnAVcXWoM3bCZrdi+ncPfaAcXE5UKVpdW/vitGPqqAtn98d0gXJwX7Qp6MmegUYVhvmTIezdmHlxJCjpHRTCFerLkRRu4k0aqdajN3sWOo0BK//msHa+xDuPC/oNFMKRhTtM4xjIX0SCNpXL4+7VIaHuyiWEp2L7ahWLf8fejfPdqPmC3mJicORZUp1CQzm+GiphvljGk+PBvWRbxii+xVTj5M6CiZ/tsDufvaXyxEUDxeLIyvu3m0iOyEFWVAkydcVYdyFrE9tQk9iMq6f/GNlvwt3LjQfh60LUrw9/cFyyMJUW/XkLSNMV4Mi6C5ML+ui4x5ClAX9sB9w0wV6wglJwJCv5fOxcr6EstgbGiEw4XcfUry4cWrcEUW8n+ARKxXEJHhw2WG43UKSvwI/TSZgvl7kh0b3XLZaLEy0QmMgLZAVH7J+ALOE+AVnDvQOyiPMAWcW5gSzjCPAV+78S5WE0GrQAAAAASUVORK5CYII=',
				// #endif
				lists: [],
				isInCount: true,
			}
		},
		watch: {
			// 监听文件列表的变化，重新整理内部数据
			fileList: {
				deep: true,
				immediate: true,
				handler() {
					this.formatFileList()
				}
			},
			deletable(newVal) {
				if(!newVal) {
					this.lists.map(item=>{
						item.deletable = this.deletable;
					})
				}
			}
		},
		methods: {
			formatFileList() {
				const {
					fileList = [], maxCount
				} = this;
				const lists = fileList.map((item) =>
					Object.assign(Object.assign({}, item), {
						// 如果item.url为本地选择的blob文件的话，无法判断其为video还是image，此处优先通过accept做判断处理
						isImage: this.accept === 'image' || image(item.url || item.thumb),
						isVideo: this.accept === 'video' || video(item.url || item.thumb),
						deletable: typeof(item.deletable) === 'boolean' ? item.deletable : this.deletable,
					})
				);
				this.lists = lists
				this.isInCount = lists.length < maxCount
			},
			chooseFile() {
				this.timer && clearTimeout(this.timer);
				this.timer = setTimeout(() => {
					const {
						maxCount,
						multiple,
						lists,
						disabled
					} = this;
					if (disabled) return;
					// 如果用户传入的是字符串，需要格式化成数组
					let capture;
					try {
						capture = array(this.capture) ? this.capture : this.capture.split(',');
					} catch (e) {
						capture = [];
					}
					chooseFile(
							Object.assign({
								accept: this.accept,
								multiple: this.multiple,
								capture: capture,
								compressed: this.compressed,
								maxDuration: this.maxDuration,
								sizeType: this.sizeType,
								camera: this.camera,
							}, {
								maxCount: maxCount - lists.length,
							})
						)
						.then((res) => {
							this.onBeforeRead(multiple ? res : res[0]);
						})
						.catch((error) => {
							this.$emit('error', error);
						});
				}, 100)
			},
			// 文件读取之前
			onBeforeRead(file) {
				const {
					beforeRead,
					useBeforeRead,
				} = this;
				let res = true
				// beforeRead是否为一个方法
				if (func(beforeRead)) {
					// 如果用户定义了此方法，则去执行此方法，并传入读取的文件回调
					res = beforeRead(file, this.getDetail());
				}
				if (useBeforeRead) {
					res = new Promise((resolve, reject) => {
						this.$emit(
							'beforeRead',
							Object.assign(Object.assign({
								file
							}, this.getDetail()), {
								callback: (ok) => {
									ok ? resolve() : reject();
								},
							})
						);
					});
				}
				if (!res) {
					return;
				}
				if (promise(res)) {
					res.then((data) => this.onAfterRead(data || file));
				} else {
					this.onAfterRead(file);
				}
			},
			getDetail(index) {
				return {
					name: this.name,
					index: index == null ? this.fileList.length : index,
				};
			},
			onAfterRead(file) {
				const {
					maxSize,
					afterRead
				} = this;
				const oversize = Array.isArray(file) ?
					file.some((item) => item.size > maxSize) :
					file.size > maxSize;
				if (oversize) {
					this.$emit('oversize', Object.assign({
						file
					}, this.getDetail()));
					return;
				}
				if (typeof afterRead === 'function') {
					afterRead(file, this.getDetail());
				}
				this.$emit('afterRead', Object.assign({
					file
				}, this.getDetail()));
			},
			deleteItem(index) {
				this.$emit(
					'delete',
					Object.assign(Object.assign({}, this.getDetail(index)), {
						file: this.fileList[index],
					})
				);
			},
			// 预览图片
			onPreviewImage(item, index) {
				const lists = this.$uv.deepClone(this.lists);
				lists.map((i,j)=>{
					if(j == index) {
						i.current = true;
					}
				});
				const filters = lists.filter(i=>i.isImage);
				const findIndex = filters.findIndex(i=>i.current);
				this.onClickPreview(item, index);
				if (!item.isImage || !this.previewFullImage) return
				uni.previewImage({
					// 先filter找出为图片的item，再返回filter结果中的图片url
					urls: this.lists.filter((item) => this.accept === 'image' || image(item.url || item.thumb)).map((item) => item.url || item.thumb),
					current: findIndex,
					fail() {
						this.$uv.toast('预览图片失败')
					},
				});
			},
			onPreviewVideo(item, index) {
				this.onClickPreview(item, index);
				if (!this.previewFullVideo || !item.isVideo) return;
				this.$refs.previewVideo.open(item.url);
			},
			onClickPreview(item, index) {
				this.$emit(
					'clickPreview',
					Object.assign(Object.assign({}, item), this.getDetail(index))
				);
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	$uv-upload-preview-border-radius: 2px !default;
	$uv-upload-preview-margin: 0 8px 8px 0 !default;
	$uv-upload-image-width: 80px !default;
	$uv-upload-image-height: $uv-upload-image-width;
	$uv-upload-other-bgColor: rgb(242, 242, 242) !default;
	$uv-upload-other-flex: 1 !default;
	$uv-upload-text-font-size: 11px !default;
	$uv-upload-text-color: $uv-tips-color !default;
	$uv-upload-text-margin-top: 2px !default;
	$uv-upload-deletable-right: 0 !default;
	$uv-upload-deletable-top: 0 !default;
	$uv-upload-deletable-bgColor: rgb(55, 55, 55) !default;
	$uv-upload-deletable-height: 14px !default;
	$uv-upload-deletable-width: $uv-upload-deletable-height;
	$uv-upload-deletable-boder-bottom-left-radius: 100px !default;
	$uv-upload-deletable-zIndex: 3 !default;
	$uv-upload-success-bottom: 0 !default;
	$uv-upload-success-right: 0 !default;
	$uv-upload-success-border-style: solid !default;
	$uv-upload-success-border-top-color: transparent !default;
	$uv-upload-success-border-left-color: transparent !default;
	$uv-upload-success-border-bottom-color: $uv-success !default;
	$uv-upload-success-border-right-color: $uv-upload-success-border-bottom-color;
	$uv-upload-success-border-width: 9px !default;
	$uv-upload-icon-top: 0px !default;
	$uv-upload-icon-right: 0px !default;
	$uv-upload-icon-h5-top: 1px !default;
	$uv-upload-icon-h5-right: 0 !default;
	$uv-upload-icon-width: 16px !default;
	$uv-upload-icon-height: $uv-upload-icon-width;
	$uv-upload-success-icon-bottom: -10px !default;
	$uv-upload-success-icon-right: -10px !default;
	$uv-upload-status-right: 0 !default;
	$uv-upload-status-left: 0 !default;
	$uv-upload-status-bottom: 0 !default;
	$uv-upload-status-top: 0 !default;
	$uv-upload-status-bgColor: rgba(0, 0, 0, 0.5) !default;
	$uv-upload-status-icon-Zindex: 1 !default;
	$uv-upload-message-font-size: 12px !default;
	$uv-upload-message-color: #FFFFFF !default;
	$uv-upload-message-margin-top: 5px !default;
	$uv-upload-button-width: 80px !default;
	$uv-upload-button-height: $uv-upload-button-width;
	$uv-upload-button-bgColor: rgb(244, 245, 247) !default;
	$uv-upload-button-border-radius: 2px !default;
	$uv-upload-botton-margin: 0 8px 8px 0 !default;
	$uv-upload-text-font-size: 11px !default;
	$uv-upload-text-color: $uv-tips-color !default;
	$uv-upload-text-margin-top: 2px !default;
	$uv-upload-hover-bgColor: rgb(230, 231, 233) !default;
	$uv-upload-disabled-opacity: .5 !default;
	.uv-upload {
		@include flex(column);
		flex: 1;
		&__wrap {
			@include flex;
			flex-wrap: wrap;
			flex: 1;
			&__preview {
				border-radius: $uv-upload-preview-border-radius;
				margin: $uv-upload-preview-margin;
				position: relative;
				overflow: hidden;
				@include flex;
				&__image {
					width: $uv-upload-image-width;
					height: $uv-upload-image-height;
				}
				&__other {
					width: $uv-upload-image-width;
					height: $uv-upload-image-height;
					background-color: $uv-upload-other-bgColor;
					flex: $uv-upload-other-flex;
					@include flex(column);
					justify-content: center;
					align-items: center;
					&__text {
						font-size: $uv-upload-text-font-size;
						color: $uv-upload-text-color;
						margin-top: $uv-upload-text-margin-top;
					}
				}
			}
		}
		&__deletable {
			position: absolute;
			top: $uv-upload-deletable-top;
			right: $uv-upload-deletable-right;
			background-color: $uv-upload-deletable-bgColor;
			height: $uv-upload-deletable-height;
			width: $uv-upload-deletable-width;
			@include flex;
			border-bottom-left-radius: $uv-upload-deletable-boder-bottom-left-radius;
			align-items: center;
			justify-content: center;
			z-index: $uv-upload-deletable-zIndex;
			&__icon {
				position: absolute;
				transform: scale(0.7);
				top: $uv-upload-icon-top;
				right: $uv-upload-icon-right;
				/* #ifdef H5 */
				top: $uv-upload-icon-h5-top;
				right: $uv-upload-icon-h5-right;
				/* #endif */
			}
		}
		&__success {
			position: absolute;
			bottom: $uv-upload-success-bottom;
			right: $uv-upload-success-right;
			@include flex;
			// 由于weex(nvue)为阿里巴巴的KPI(部门业绩考核)的laji产物，不支持css绘制三角形
			// 所以在nvue下使用图片，非nvue下使用css实现
			/* #ifndef APP-NVUE */
			border-style: $uv-upload-success-border-style;
			border-top-color: $uv-upload-success-border-top-color;
			border-left-color: $uv-upload-success-border-left-color;
			border-bottom-color: $uv-upload-success-border-bottom-color;
			border-right-color: $uv-upload-success-border-right-color;
			border-width: $uv-upload-success-border-width;
			align-items: center;
			justify-content: center;
			/* #endif */
			&__icon {
				/* #ifndef APP-NVUE */
				position: absolute;
				transform: scale(0.7);
				bottom: $uv-upload-success-icon-bottom;
				right: $uv-upload-success-icon-right;
				/* #endif */
				/* #ifdef APP-NVUE */
				width: $uv-upload-icon-width;
				height: $uv-upload-icon-height;
				/* #endif */
			}
		}
		&__status {
			position: absolute;
			top: $uv-upload-status-top;
			bottom: $uv-upload-status-bottom;
			left: $uv-upload-status-left;
			right: $uv-upload-status-right;
			background-color: $uv-upload-status-bgColor;
			@include flex(column);
			align-items: center;
			justify-content: center;
			&__icon {
				position: relative;
				z-index: $uv-upload-status-icon-Zindex;
			}
			&__message {
				font-size: $uv-upload-message-font-size;
				color: $uv-upload-message-color;
				margin-top: $uv-upload-message-margin-top;
			}
		}
		&__button {
			@include flex(column);
			align-items: center;
			justify-content: center;
			width: $uv-upload-button-width;
			height: $uv-upload-button-height;
			background-color: $uv-upload-button-bgColor;
			border-radius: $uv-upload-button-border-radius;
			margin: $uv-upload-botton-margin;
			/* #ifndef APP-NVUE */
			box-sizing: border-box;
			/* #endif */
			&__text {
				font-size: $uv-upload-text-font-size;
				color: $uv-upload-text-color;
				margin-top: $uv-upload-text-margin-top;
			}
			&--hover {
				background-color: $uv-upload-hover-bgColor;
			}
			&--disabled {
				opacity: $uv-upload-disabled-opacity;
			}
		}
	}
</style> x 69{
  "id": "uv-upload",
  "displayName": "uv-upload 上传EJ6*该组件用于上传图片等文件场景*uploadQ!upload",
    "上传)icon",
			"uv-loading-icon",
			"uv-popup
kR֮kxU ## Upload 上传.upload**

该组件用于上传图片等文件7uploadץ A-*	x e100644 changelog.md MsVޱ%+Yw40000 components bn9̈\k_O($x100644 package.json H~Ps.dmV{100644 readme.md +o5	1<~.&r?W'xy## 1.0.8（2023-12-20）
1. 优化
## 1.0.7（2023-12-20）
1. 优化
## 1.0.6（2023-12-12）
1. 修复设置current，快速点击菜单，导致死循环的BUG
## 1.0.5（2023-06-27）
修复：非联动，内容过多的情况，滚动一段距离，再切换未滚动到顶部的BUG
## 1.0.4（2023-06-13）
1. 增加scrolltolower回调函数
2. 优化
## 1.0.3（2023-06-13）
1. 优化
## 1.0.2（2023-06-13）
1. 增加hdHeight参数，避免顶部有内容计算联动不准确的BUG
2. 优化滑动触发频率，避免跳动
## 1.0.1（2023-06-04）
1. 文档说明
## 1.0.0（2023-06-04）
1. 新增垂直选项卡组件
|DxK 40000 uv-vtabs-item X=tGO쟓40000 uv-vtabs 7r:*1+F}A _x- 100644 uv-vtabs-item.vue (mã; f恿En`x<template>
		<view 
			class="uv-vtabs-item"
			:id="`content_${index}`"
			ref="uv-vtabs-item"
		>
			<slot />
		</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom');
	// #endif
	export default {
		name: 'uv-vtabs-item',
		mixins: [mpMixin, mixin],
		props: {
			index: {
				type: [Number,String],
				default: 0
			}
		},
		data(){
			return {
				// 记录item的离顶部的距离
				top: 0,
				// 记录item的高度
				height: 0
				// 是否为联动
			}
		},
		mounted() {
			this.init();
		},
		methods: {
			async init(){
				this.getParentData('uv-vtabs');
				if (!this.parent) {
					return this.$uv.error('uv-vtabs必须要搭配uv-vtabs-item组件使用')
				}
				if(!this.parent.chain) return;
				await this.$uv.sleep();
				this.getItemRect().then(size=>{
					// 由于对象的引用特性，此处会同时生效到父组件的children数组的本实例的top属性中，供父组件判断读取
					this.top = size.top;
					this.height = size.height;
				});
			},
			getItemRect(){
				return new Promise(resolve => {
					// #ifndef APP-NVUE
					this.$uvGetRect('.uv-vtabs-item').then(size => {
						resolve(size)
					})
					// #endif
					// #ifdef APP-NVUE
					const ref = this.$refs['uv-vtabs-item']
					dom.getComponentRect(ref, res => {
						resolve(res.size)
					})
					// #endif
				})
			}
		}
	}
</script>
}xL 100644 props.js MΏU
Ȏ0K2100644 uv-vtabs.vue #2s8FUﮭq]3bx"export default {
	props: {
		// 列表数据
		list: {
			type: Array,
			default: ()=>[]
		},
		// 从list元素对象中读取的键名，默认name
		keyName: {
			type: String,
			default: 'name'
		},
		// 当前选中项
		current: {
			type: [Number, String],
			default: 0
		},
		// 头部内容的高度
		hdHeight: {
			type: [Number, String],
			default: 0
		},
		// 是否联动，默认开启联动
		chain: {
			type: Boolean,
			default: true
		},
		// 整个列表的高度，默认auto屏幕高度
		height: {
			type: [Number, String],
			default: 'auto'
		},
		// 左边列表的宽度，默认200rpx
		barWidth: {
			type: [Number, String],
			default: '180rpx'
		},
		// 左边列表是否允许滚动
		barScrollable: {
			type: Boolean,
			default: true
		},
		// 背景颜色 默认主题颜色 $bg-color
		barBgColor: {
			type: String,
			default: ''
		},
		// 左边列表的自定义样式
		barStyle: {
			type: [Object, String],
			default: ''
		},
		// 左边列表项的自定义样式
		barItemStyle: {
			type: [Object, String],
			default: ''
		},
		// 左边选择项激活时的自定义样式
		barItemActiveStyle: {
			type: [Object, String],
			default: ''
		},
		// 左边选择项激活时的左边线条自定义样式
		barItemActiveLineStyle: {
			type: [Object, String],
			default: ''
		},
		// 菜单项中的徽标自定义样式，比如定位位置
		barItemBadgeStyle: {
			type: [Object, String],
			default: ''
		},
		// 右边区域自定义样式
		contentStyle: {
			type: [Object, String],
			default: ''
		}
	}
}t.Jx&8<template>
	<view
		class="uv-vtabs"
		:style="[vtabsStyle]"
	>
		<scroll-view
			class="uv-vtabs__bar"
			ref="uv-vtabs__bar"
			:style="[getBarStyle]"
			:scroll-y="barScrollable" 
			:scroll-x="scrollX"
			:show-scrollbar="false"
			:scroll-with-animation="true"
			:scroll-top="barScrollTop"
			:scroll-into-view="barScrollToView"
		>
			<view
				:class="[
					'uv-vtabs__bar-item',
					`uv-vtabs__bar-item--${index}`,
					index == activeIndex && 'uv-vtabs__bar-item-active'
				]"
				:ref="`uv-vtabs__bar-item--${index}`"
				v-for="(item,index) in list"
				:key="index"
				:id="`bar_${index}`"
				:style="[itemStyle(index)]"
				@tap.stop="clickHandler(index)"
			>
				<view 
					class="uv-vtabs__bar-item--line"
					v-if="index == activeIndex"
					:style="[$uv.addStyle(barItemActiveLineStyle)]"
				></view>
				<text 
					:class="[
						'uv-vtabs__bar-item--value',
						index == activeIndex && 'uv-vtabs__bar-item-active--value'
					]"
					:style="[itemStyle(index),textStyle(index)]"
				>{{item[keyName]}}</text>
				<view 
					class="uv-vtabs__bar-item--badge"
					:style="[$uv.addStyle(barItemBadgeStyle)]"
					v-if="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))"
				>
					<uv-badge
						:show="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))"
						:isDot="item.badge && item.badge.isDot || propsBadge.isDot"
						:value="item.badge && item.badge.value || propsBadge.value"
						:max="item.badge && item.badge.max || propsBadge.max"
						:type="item.badge && item.badge.type || propsBadge.type"
						:showZero="item.badge && item.badge.showZero || propsBadge.showZero"
						:bgColor="item.badge && item.badge.bgColor || propsBadge.bgColor"
						:color="item.badge && item.badge.color || propsBadge.color"
						:shape="item.badge && item.badge.shape || propsBadge.shape"
						:numberType="item.badge && item.badge.numberType || propsBadge.numberType"
						:inverted="item.badge && item.badge.inverted || propsBadge.inverted"
					></uv-badge>
				</view>
			</view>
		</scroll-view>
		<scroll-view
			class="uv-vtabs__content"
			:style="[getContentStyle,$uv.addStyle(contentStyle)]"
			:scroll-y="true" 
			:scroll-x="scrollX"
			:show-scrollbar="false"
			:scroll-top="contentScrollTop"
			:scroll-into-view="contentScrollTo"
			:scroll-with-animation="true"
			@scroll="scrollHandler"
			@scrolltolower="scrolltolower"
			v-if="chain"
		>
			<slot />
		</scroll-view>
		<scroll-view 
			v-else
			class="uv-vtabs__content"
			:style="[getContentStyle,$uv.addStyle(contentStyle)]"
			:scroll-y="true" 
			:scroll-x="scrollX"
			:show-scrollbar="false"
			:scroll-top="contentScrollTop2"
			@scrolltolower="scrolltolower"
		>
			<slot />
		</scroll-view>
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import debounce from '@/uni_modules/uv-ui-tools/libs/function/debounce.js'
	import throttle from '@/uni_modules/uv-ui-tools/libs/function/throttle.js'
	import uvBadgeProps from '@/uni_modules/uv-badge/components/uv-badge/props.js'
	import props from './props.js';
	// #ifdef APP-NVUE
	const dom = uni.requireNativePlugin('dom')
	// #endif
	/**
	 * 垂直选项卡
	 * @description 该组件兼容所有端，提供了分类展示和联动等功能
	 * @tutorial https://www.uvui.cn/components/vtabs.html
	 * @property {Array}	list  选项数组，元素为对象，如[{name:'uv-ui'}]（默认 [] ）
	 * @property {String}  keyName  从list元素对象中读取的键名（默认 name ）
	 * @property {Number}  current  当前选中项，从0开始（默认 0 ）
	 * @property {Number | String}  hdHeight  头部内容的高度，头部有内容必传，否则会有联动误差（默认 0 ）
	 * @property {Boolean}  chain  是否开启联动，开启后右边区域可以滑动查看内容（默认 true ）
	 * @property {Number|String}  height  整个列表的高度，默认auto或空则为屏幕高度（默认 auto屏幕高度 ）
	 * @property {Number|String}  barWidth  左边选项区域的宽度（默认 180rpx ）
	 * @property {Boolean}  barScrollable  左边选项区域是否允许滚动 （默认 true ）
	 * @property {String}  barBgColor  左边选项区域的背景颜色（默认$uv-bg-color）
	 * @property {Object}  barStyle  左边选项区域的自定义样式 （默认{}）
	 * @property {Object}  barItemStyle  左边选项区域每个选项的自定义样式 （默认{}）
	 * @property {Object}  barItemActiveStyle  左边选项区域选中选项的自定义样式 （默认{}）
	 * @property {Object}  barItemActiveLineStyle  左边选项区域选中选项竖线条的自定义样式 （默认{}）
	 * @property {Object}  barItemBadgeStyle  左边选项区域选中选项徽标的自定义样式，主要用于设置位置 （默认{}）
	 * @property {Object}  contentStyle  右边区域自定义样式 （默认{}）
	 * @example <uv-vtabs :list="list"><uv-vtabs-item>...</uv-vtabs-item></uv-vtabs>
	 */
	export default {
		name: 'uv-vtabs',
		mixins: [mpMixin, mixin, props],
		created() {
			this.children = []
		},
		mounted() {
			this.$nextTick(()=>{
				this.init(this.current);
			})
		},
		data() {
			return {
				activeIndex: 0,
				// 微信小程序下，scroll-view的scroll-into-view属性无法对slot中的内容的id生效，只能通过设置scrollTop的形式去移动滚动条
				contentScrollTop: 0,
				contentScrollTop2: 0,//针对非联动
				contentScrollTo: '',
				scrolling: false,
				barScrolling: false,
				touching: false,
				hasHeight: 0,
				scrollViewHeight: 0,
				barScrollTop: 0,
				barScrollToView: '',
				timer2: 0
			}
		},
		computed: {
			scrollX(){
				// #ifdef APP-NVUE
				return true;
				// #endif
				return false;
			},
			vtabsStyle() {
				const style = {};
				style.height = this.getHeight();
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
			},
			getBarStyle() {
				const style = {};
				style.width = this.$uv.getPx(this.barWidth, true);
				style.background = this.barBgColor;
				style.height = this.getHeight();
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.barStyle));
			},
			itemStyle(){
				return index =>{
					const style = {};
					let barItemInitStyle = this.barItemStyle;
					// 避免在nvue模式下，切换时候上一个选中颜色不变
					if(this.barItemStyle && !this.barItemStyle?.background) {
						barItemInitStyle.background = 'transparent';
					}
					// 是否激活的样式
					const customeStyle = index === this.activeIndex ? this.$uv.addStyle(this.barItemActiveStyle) : this.$uv.addStyle(barItemInitStyle);
					if (this.list[index].disabled) {
						style.color = '#c8c9cc'
					}
					return this.$uv.deepMerge(style, customeStyle);
				} 
			},
			// nvue设置字体样式必须要text标签上进行
			textStyle(){
				return index=>{
					const style = {};
					style.width = this.$uv.getPx(this.barWidth, true);
					return style;
				}
			},
			getContentStyle() {
				const style = {};
				style.height = this.getHeight();
				return style;
			},
			propsBadge() {
				return uvBadgeProps
			}
		},
		watch: {
			current(newVal){
				if(!this.touching) 
					this.$nextTick(()=>{
						this.init(newVal?newVal:0);
					})
			},
			list(newVal) {
				if (newVal.length) {
					this.$uv.sleep(30).then(res => {
						this.resize();
					})
				}
			},
			activeIndex(newVal){
				if(!this.chain) {// 解决：非联动，内容过多的情况，滚动一段距离，再切换未滚动到顶部的BUG
					this.contentScrollTop2 = 0 - Math.random() * 4 - 4;
				}
				this.$emit('change',newVal);
			}
		},
		methods: {
			init(index){
				let num = 0;
				clearInterval(this.timer2);
				this.timer2 = setInterval(async ()=>{
					num++;
					if(num>50) clearInterval(this.timer2);
					if(this.children.length) {
						clearInterval(this.timer2);
						await this.$uv.sleep(300);
						this.clickHandler(index);
					}
				},100)
			},
			// 内容滚动到底部触发
			scrolltolower(){
				this.$emit('scrolltolower',this.activeIndex);
			},
			async resize() {
				// 如果list数组长度为0就不处理 || 选中目标未变则不处理
				if (this.list.length == 0 || !this.barScrollable) return;
				// 避免滑太快，修复位置
				Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => {
					this.tabsRect = tabsRect;
					this.scrollViewHeight = 0
					itemRect.map((item, index) => {
						this.scrollViewHeight += item.height;
						this.list[index].rect = item;
					})
					this.setBarScrollTop();
				})
			},
			// 设置左边菜单滚动条的位置，目标：将当前的选项移到中间位置
			setBarScrollTop() {
				const tabRect = this.list[this.activeIndex];
				const offsetTop = this.list
					.slice(0, this.activeIndex)
					.reduce((total, item) => {
						return total + item.rect.height;
					}, 0);
				const scrollViewHeight = this.$uv.getPx(this.getHeight());
				let barScrollTop = tabRect.rect.height / 2 + offsetTop - scrollViewHeight / 2;
				// 先给一点随机值，避免出现不能滚动的BUG
				barScrollTop = Math.min(barScrollTop, this.scrollViewHeight - this.tabsRect.height);
				this.barScrollTop = Math.max(0, barScrollTop);
				// 已经不能滚动的时候，就使用scroll-into-view的方式进行定位，避免失效
				if(barScrollTop>=(this.scrollViewHeight - this.tabsRect.height)) {
					this.timer && clearTimeout(this.timer);
					this.timer = setTimeout(()=>{
						this.barScrollToView = `bar_${this.activeIndex}`;
					},400)
				}
			},
			// 左边菜单点击
			async clickHandler(currentIndex) {
				if (currentIndex == this.activeIndex) return;
				this.touching = true;
				this.activeIndex = currentIndex;
				if(this.chain) {
					// 给一点随机值，避免出现不能滚动的BUG。微信端必须用此方法
					this.contentScrollTop = this.children[currentIndex].top - this.$uv.getPx(this.hdHeight) - Math.random() * 4 - 4;
					// #ifndef MP-WEIXIN
					this.contentScrollTo = `content_${currentIndex}`;
					// #endif
				}
				this.timer && clearTimeout(this.timer);
				throttle(()=>{
					this.resize();
				},300,false)
				debounce(() => {
					this.touching = false;
				}, 900)
			},
			// 内容滚动
			scrollHandler(e) {
				if (this.touching || this.scrolling) return;
				// 每过一定时间取样一次，减少资源损耗以及可能带来的卡顿
				this.scrolling = true;
				this.$uv.sleep(80).then(() => {
					this.scrolling = false;
				})
				const scrollTop = e.detail.scrollTop;
				let children = this.children;
				const len = children.length;
				let top = 0;
				let activeIndex = 0;
				children = this.children.map((item, index) => {
					if (item.height > 0) this.hasHeight = item.height;
					item.height = item.height > 0 ? item.height : this.hasHeight;
					const child = {
						height: item.height,
						top
					}
					// 进行累加，给下一个item提供计算依据
					top += item.height;
					return child;
				})
				for (let i = 0; i < len; i++) {
					const item = children[i];
					const nextItem = children[i + 1];
					// 如果滚动条高度小于第一个item的top值，此时无需设置任意字母为高亮
					if (scrollTop <= children[0].top) {
						activeIndex = 0;
						break
					} else if (!nextItem) {
						// 当不存在下一个item时，意味着历遍到了最后一个
						activeIndex = len - 1;
						break
					} else if (scrollTop > item.top && scrollTop < nextItem.top) {
						activeIndex = i;
						break
					}
				}
				this.activeIndex = activeIndex;
				// 当前选中项索引必然来源于前后两个索引，满足才执行，避免闪烁的bug
					this.timer4 && clearTimeout(this.timer4);
				this.timer4 = setTimeout(()=>{
					this.resize();
				},100)
			},
			// 设置高度
			getHeight() {
				let height = 0;
				const isEmpty = this.$uv.test.empty(this.height);
				if (isEmpty || this.height=='auto') height = this.$uv.addUnit(this.$uv.sys().windowHeight);
				else height = this.$uv.getPx(this.height, true);
				return height;
			},
			// 获取导航菜单的尺寸
			getTabsRect() {
				return new Promise(resolve => {
					this.queryRect('uv-vtabs__bar').then(size => resolve(size))
				})
			},
			// 获取所有标签的尺寸
			getAllItemRect() {
				return new Promise(resolve => {
					const promiseAllArr = this.list.map((item, index) => this.queryRect(
						`uv-vtabs__bar-item--${index}`, true))
					Promise.all(promiseAllArr).then(sizes => resolve(sizes))
				})
			},
			// 获取各个标签的尺寸
			queryRect(el, item) {
				// #ifndef APP-NVUE
				// $uvGetRect为uv-ui自带的节点查询简化方法，详见文档介绍：https://www.uvui.cn/js/getRect.html
				// 组件内部一般用this.$uvGetRect，对外的为getRect，二者功能一致，名称不同
				return new Promise(resolve => {
					this.$uvGetRect(`.${el}`).then(size => {
						resolve(size)
					})
				})
				// #endif
				// #ifdef APP-NVUE
				// nvue下，使用dom模块查询元素高度
				// 返回一个promise，让调用此方法的主体能使用then回调
				return new Promise(resolve => {
					dom.getComponentRect(item ? this.$refs[el][0] : this.$refs[el], res => {
						resolve(res.size)
					})
				})
				// #endif
			}
		}
	}
</script>
<style scoped lang="scss">
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
	.uv-vtabs {
		@include flex;
		&__bar {
			background: $uv-bg-color;
			&-item {
				position: relative;
				@include flex;
				align-items: center;
				justify-content: center;
				padding: 35rpx 12rpx 35rpx 20rpx;
				&--value {
					/* #ifdef APP-NVUE */
					padding: 0 12rpx;
					/* #endif */
					font-size: 14px;
					color: $uv-content-color;
				}
				&-active {
					background: #fff;
					&--value {
						color: $uv-primary;
					}
				}
				&--line {
					position: absolute;
					width: 2px;
					left: 0;
					top: 0;
					bottom: 0;
					z-index: 1;
					background-color: $uv-primary;
				}
				&--badge {
					position: absolute;
					top: 4px;
					right: 10px;
					z-index: 1;
				}
			}
		}
		&__content {
			flex: 1;
			background: #fff;
		}
	}
</style>A[Qxd{
  "id": "uv-vvtabs 垂直5Q8",
  "description": "uv-vtabs 垂直分类组件主要用于分类选择，简单配置即可使用，左右自动进行联动，不用自己再去做复杂的计算，组件内部已经完成相关计算。支持联动和不联动，商品分类，灵#配置，多端兼容开箱即用uv-vtabs!#垂直分类",
    "垂直选项卡"engines": {1	_	x e100644 changelog.md  L
YS40000 components xÎx}G5Br\100644 package.json +Υ`uAH,Z{100644 readme.md CY8M^h(	 `)O:2x.## 1.0.8（2023-08-17）
1. 修复只有一条数据切换时可能存在位置错误的BUG
## 1.0.7（2023-07-22）
1. 避免快速切换报错的BUG
## 1.0.6（2023-07-17）
1. 优化文档
2. 优化其他
## 1.0.5（2023-07-14）
1. 优化changeList未处理数据时，正确返回对应列的数据，避免误导
## 1.0.4（2023-05-27）
1. 修复在百度小程序中可能存在的BUG
2. 去掉原有的slot方式
## 1.0.3（2023-05-23）
1. 修复在百度/头条小程序显示异常等BUG
2. 增加changeList回调函数处理数据
3. 更新示例
## 1.0.2（2023-05-16）
1. 优化组件依赖，修改后无需全局引入，组件导入即可使用
2. 优化部分功能
## 1.0.1（2023-05-12）
1. 增加clear回调函数
2. 增加remove回调函数
## 1.0.0（2023-05-10）
uv-waterfall 瀑布流
(x' 40000 uv-waterfall lĽeJ=D62xP 100644 props.js ތ $_<V100644 uv-waterfall.vue ϳWZs|U
C˰S#ZVxaexport default {
	props: {
		// 瀑布流数据
		// #ifdef VUE2
		value: {
			type: Array,
			default: () => []
		},
		// #endif
		// #ifdef VUE3
		modelValue: {
			type: Array,
			default: () => []
		},
		// #endif
		// 数据的id值，根据id值对数据执行删除操作
		// 如数据为：{id: 1, name: 'uv-ui'}，那么该值设置为id
		idKey: {
			type: String,
			default: 'id'
		},
		// 每次插入数据的事件间隔，间隔越长能保证两列高度相近，但是用户体验不好，单位ms
		addTime: {
			type: Number,
			default: 200
		},
		// 瀑布流的列数，默认2，最高为5
		columnCount: {
			type: [Number, String],
			default: 2
		},
		// 列与列的间隙，默认20
		columnGap: {
			type: [Number, String],
			default: 20
		},
		// 左边和列表的间隙
		leftGap: {
			type: [Number, String],
			default: 0
		},
		// 右边和列表的间隙
		rightGap: {
			type: [Number, String],
			default: 0
		},
		// 是否显示滚动条，仅nvue生效
		showScrollbar: {
			type: [Boolean],
			default: false
		},
		// 列宽，nvue生效
		columnWidth: {
			type: [Number, String],
			default: 'auto'
		},
		// 瀑布流的宽度，nvue生效
		width: {
			type: [Number, String],
			default: ''
		},
		// 瀑布流的高度，nvue生效
		height: {
			type: [Number, String],
			default: ''
		},
		...uni.$uv?.props?.waterfall
	}
}2x" <template>
	<view class="uv-waterfall">
		<!-- #ifndef APP-NVUE -->
		<view class="uv-waterfall__gap_left" :style="[gapLeftStyle]"></view>
		<template v-if="columnNum>=1">
			<view id="uv-waterfall-1" class="uv-waterfall__column">
				<slot name="list1"></slot>
			</view>
		</template>
		<template v-if="columnNum>=2">
			<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]"></view>
			<view id="uv-waterfall-2" class="uv-waterfall__column">
				<slot name="list2"></slot>
			</view>
		</template>
		<template v-if="columnNum>=3">
			<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]"></view>
			<view id="uv-waterfall-3" class="uv-waterfall__column">
				<slot name="list3"></slot>
			</view>
		</template>
		<template v-if="columnNum>=4">
			<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]">
			</view>
			<view id="uv-waterfall-4" class="uv-waterfall__column">
				<slot name="list4"></slot>
			</view>
		</template>
		<template v-if="columnNum>=5">
			<view class="uv-waterfall__gap_center" :style="[gapCenterStyle]">
			</view>
			<view id="uv-waterfall-5" class="uv-waterfall__column">
				<slot name="list5"></slot>
			</view>
		</template>
		<view class="uv-waterfall__gap_right" :style="[gapRightStyle]">
		</view>
		<!-- #endif -->
		<!-- #ifdef APP-NVUE -->
		<view class="waterfall-warapper">
			<waterfall :column-count="columnNum" :show-scrollbar="false" column-width="auto" :column-gap="columnGap" :left-gap="leftGap" :right-gap="rightGap" :always-scrollable-vertical="true" :style="[nvueWaterfallStyle]"
				@loadmore="scrolltolower">
				<slot></slot>
			</waterfall>
		</view>
		<!-- #endif -->
	</view>
</template>
<script>
	import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
	import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
	import props from './props.js';
	/**
	 * 瀑布流
	 * @description 该组件兼容所有端，nvue参考https://uniapp.dcloud.net.cn/component/waterfall.html
	 * @tutorial https://www.uvui.cn/components/list.html
	 * @property {Array}	value/modelValue	瀑布流数组数据，非nvue生效 （默认 [] ）
	 * @property {String}	idKey	  数据的id值，根据id值对数据执行删除操作，如数据为：{id: 1, name: 'uv-ui'}，那么该值设置为id，非nvue有效 （默认 '' ）
	 * @property {String ｜ Number}	addTime		每次插入数据的事件间隔，间隔越长能保证两列高度相近，但是用户体验不好，单位ms，非nvue生效（默认 200 ）
	 * @property {String ｜ Number}	columnCount		瀑布流的列数（默认 2 ）
	 * @property {String ｜ Number}			columnGap		列与列的间隙（默认 0 ）
	 * @property {String ｜ Number}			leftGap		左边和列表的间隙（默认 0 ）
	 * @property {String ｜ Number}			rightGap	右边和列表的间隙（默认 0 ）
	 * @property {Boolean}	showScrollbar		控制是否出现滚动条，仅nvue有效 （默认 false ）
	 * @property {String ｜ Number}		columnWidth		描述瀑布流每一列的列宽，nvue生效 （默认 auto）
	 * @property {String ｜ Number}	  width	  瀑布流的宽度，nvue生效 （默认 屏幕宽 ）
	 * @property {String ｜ Number}		height	 瀑布流的高度，nvue生效 （默认 屏幕高 ）
	 * @property {Object}	customStyle		定义需要用到的外部样式
	 *
	 * @example <uv-waterfall v-model="list"></uv-waterfall>
	 */
	export default {
		name: 'uv-waterfall',
		mixins: [mpMixin, mixin, props],
		data() {
			return {
				list1: [],
				list2: [],
				list3: [],
				list4: [],
				list5: [],
				// 临时列表
				tempList: []
			}
		},
		computed: {
			// 破坏value变量引用，否则数据会保持不变
			copyValue() {
				// #ifdef VUE2
				return this.$uv.deepClone(this.value)
				// #endif
				// #ifdef VUE3
				return this.$uv.deepClone(this.modelValue)
				// #endif
			},
			columnNum() {
				return this.columnCount <= 0 ? 0 : this.columnCount >= 5 ? 5 : this.columnCount;
			},
			gapLeftStyle() {
				const style = {}
				style.width = this.$uv.addUnit(this.leftGap)
				return style;
			},
			gapRightStyle() {
				const style = {}
				style.width = this.$uv.addUnit(this.rightGap)
				return style;
			},
			gapCenterStyle() {
				const style = {}
				style.width = this.$uv.addUnit(this.columnGap)
				return style;
			},
			nvueWaterfallStyle() {
				const style = {};
				if (this.width != 0) style.width = this.$uv.addUnit(this.width)
				if (this.height != 0) style.height = this.$uv.addUnit(this.height)
				// 如果没有定义列表高度，则默认使用屏幕高度
				if (!style.width) style.width = this.$uv.addUnit(this.$uv.sys().windowWidth, 'px')
				if (!style.height) style.height = this.$uv.addUnit(this.$uv.sys().windowHeight, 'px')
				return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
			}
		},
		watch: {
			copyValue(nVal, oVal) {
				// #ifndef APP-NVUE
				if (nVal.length != 0) {
					// 取出数组发生变化的部分
					let startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0
					// 拼接原有数据
					this.tempList = this.tempList.concat(this.$uv.deepClone(nVal.slice(startIndex)))
					this.splitData()
				}
				// #endif
			}
		},
		mounted() {
			// #ifndef APP-NVUE
			this.tempList = this.$uv.deepClone(this.copyValue)
			this.splitData()
			// #endif
		},
		methods: {
			// 滚动到底部触发事件
			scrolltolower(e) {
				this.$uv.sleep(30).then(() => {
					this.$emit('scrolltolower')
				})
			},
			// 拆分数据
			async splitData() {
				let rectArr = [];
				let emitList = {};
				if (!this.tempList.length) return
				for (let i = 1; i <= this.columnNum; i++) {
					const rect = await this.$uvGetRect(`#uv-waterfall-${i}`);
					rectArr.push({ ...rect, name: i });
				}
				let item = this.tempList[0]
				// 因为经过上面两个await节点查询和定时器，数组有可能会变成空[]，导致item的值为undefined
				// 解决多次快速滚动会导致数据乱的问题
				if (!item) return
				const minCol = this.getMin(rectArr);
				// 列宽可能使用的到
				item.width = minCol.width;
				this[`list${minCol.name}`].push(item);
				emitList.name = `list${minCol.name}`;
				emitList.value = item;
				this.$emit('changeList', emitList);
				// 移除临时数组中已处理的数据
				this.tempList.splice(0, 1)
				// 如果还有数据则继续执行
				if (this.tempList.length) {
					let _timeout = this.addTime;
					// 部分平台在延时较短的情况会出现BUG
					// #ifdef MP-BAIDU
					_timeout = _timeout < 200 ? 200 : _timeout;
					// #endif
					await this.$uv.sleep(_timeout);
					this.splitData()
				} else {
					this.$emit('finish')
				}
			},
			getMin(arr) {
				let result = null;
				const filter = arr.filter(item => item.height == 0);
				if (!filter.length) {
					const min = Math.min.apply(Math, arr.map(item => {
						return item.height;
					}))
					const [item] = arr.filter(item => item.height == min);
					result = item;
				} else {
					let newArr = [];
					arr.map((item, index) => {
						newArr.push({ len: this[`list${index+1}`].length, item: item });
					});
					const minLen = Math.min.apply(Math, newArr.map(item => {
						return item.len;
					}))
					try {
						const { item } = newArr.find(item => item.len == minLen && item.item.height == 0);
						result = item;
					} catch (e) {
						const { item } = newArr.find(item => item.item.height == 0);
						result = item;
					}
				}
				return result;
			},
			// 清空数据列表
			async clear() {
				// 清除数据
				for (let i = 0; i < this.columnCount; i++) {
					this[`list${i+1}`] = [];
				}
				// #ifdef VUE2
				this.$emit('input', [])
				// #endif
				// #ifdef VUE3
				this.$emit('update:modelValue', [])
				// #endif
				this.tempList = []
				await this.$uv.sleep(300);
				this.$emit('clear');
			},
			// 清除指定的某一条数据，根据id来实现
			remove(id) {
				let index = -1
				// 删除组件数据
				for (let i = 1; i <= this.columnCount; i++) {
					index = this[`list${i}`].findIndex(item => item[this.idKey] == id)
					if (index != -1) {
						this[`list${i}`].splice(index, 1)
					}
				}
				// 同时删除父组件对应的数据
				// #ifdef VUE2
				index = this.value.findIndex(item => item[this.idKey] == id)
				if (index != -1) this.$emit('input', this.value.splice(index, 1))
				// #endif
				// #ifdef VUE3
				index = this.modelValue.findIndex(item => item[this.idKey] == id)
				if (index != -1) this.$emit('update:modelValue', this.modelValue.splice(index, 1))
				// #endif
				this.$emit('remove', id);
			}
		}
	}
</script>
<style lang="scss" scoped>
	@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
	.uv-waterfall {
		@include flex(row);
		align-items: flex-start;
		&__column {
			@include flex(column);
			flex: 1;
			// #ifndef APP-NVUE
			height: auto;
			// #endif
		}
	}
</style>$#
Ð\xcB{
  "id": "uv-waterfall",
  "displayName": "uv-waterfall 瀑布流EH8",
  "description": "该组件主要用于瀑布流式布局显示，视觉表现为参差不齐的多栏布局，随着页面滚动条向下滚动，这种布局还会不断加载数据块并附加至当前尾部，同时集成nvue的原生瀑布流。.	waterfallO!waterfall",
    "瀑布流mage",
			"uv-loading-icon
Px## Waterfall 瀑布流

> **组件名：uv-waterfall**

该组件主要用于瀑布流式布局显示，视觉表现为参差不齐的多栏布局，随着页面滚动条向下滚动，这种布局还会不断加载数据块并附加至当前尾部，同时集成`nvue`的原生瀑布流用于`app-nvue`。常用于一些电商商品展示等，如某宝首页、x红书等。

研究uniapp瀑布流多年，**该方式是目前小程序端最佳方案**，灵活配置，简单易用，开箱即用。

该插件请根据文档耐心查看，`vue`的写法稍微麻烦点，但是效果是很好的，比之前上线的两个版本的瀑布流适用，更有扩展性，我自己的上线项目也是用的此插件。

# <a href="https://www.uvui.cn/components/waterfall.html" target="_blank">查看文档</a>

## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui)

### [更多插件，请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)

![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)

#### 如使用过程中有任何问题反馈，或者您对uv-ui有一些好的建议，欢迎加入uv-ui官方交流群：<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>
-Ůx340031QHNLH*fPwZ[G0*C̼
祓L+)J-,M-.ZR0K!?kWo]Y ''طIxh/**
 * 缓存管理类
 */
class Cache {
  // 写入
  set(key, value = "", expire = 0) {
    let ttl = expire > 0 ? Date.now() + expire * 1000 : 0;
    return uni.setStorageSync(key, {
      value,
      ttl,
    });
  }

  // 读取
  get(key, defalut = null) {
    const data = uni.getStorageSync(key);
    if (data && typeof data === "object") {
      // 没有有效期
      if (data.ttl === 0) {
        return data.value;
      }
      return Date.now() > data.ttl ? defalut : data.value;
    }
    return defalut;
  }

  // 删除
  delete(key) {
    return uni.removeStorageSync(key);
  }

  // 清空
  clear() {
    return uni.clearStorageSync();
  }
}

const cacheInstance = new Cache();
export default cacheInstance;

/**
 * 缓存操作(获取、删除、设置)
 * @param name string
 * @param value any
 * @param expire int 有效时间，秒
 */
export function cache(name = null, value = "", expire = 0) {
  if (name === null) {
    return cacheInstance;
  }

  if (value === "") {
    return cacheInstance.get(name);
  } else if (value === null) {
    return cacheInstance.delete(name);
  } else {
    return cacheInstance.set(name, value, expire);
  }
}
Hxp/**
 * 检查新版本更新
 */
export function checkForUpdate() {
  const updateManager = uni.getUpdateManager();
  // 监听向微信后台请求检查更新结果事件。微信在小程序冷启动时自动检查更新，不需由开发者主动触发。
  updateManager.onCheckForUpdate(function (res) {
    //是否有新版本
    console.log(res.hasUpdate ? "有小程序新版本" : "无小程序新版本");
  });
  //监听小程序有版本更新事件。客户端主动触发下载（无需开发者触发），下载成功后回调
  updateManager.onUpdateReady(function () {
    uni.showModal({
      title: "更新提示",
      content: "新版本已经准备好，是否重启应用？",
      success(res) {
        if (res.confirm) {
          // 强制小程序重启并使用新版本。在小程序新版本下载完成后（即收到 onUpdateReady 回调）调用
          updateManager.applyUpdate();
        }
      },
    });
  });
  // 监听小程序更新失败事件。小程序有新版本，客户端主动触发下载（无需开发者触发），下载失败（可能是网络原因等）后回调
  updateManager.onUpdateFailed(function () {
    uni.showToast({
      title: "小程序更新失败，请刷新后重试",
    });
  });
}

/**
 * 导航栏高度(针对小程序)
 * @returns {String}
 */
export function navigationBarHeight() {
  const { bottom } = uni.getMenuButtonBoundingClientRect();
  return `${bottom + 8}px`;
}

/**
 * 解析url查询参数
 * @param {String} url
 * @returns {Object}
 */
export function parseURLSearchParams(url = "") {
  const queryParams = {};
  if (url.includes("?")) {
    const keyValueArr = url.split("?")[1].split("&");
    keyValueArr.forEach((item) => {
      const [key, value] = item.split("=").map(decodeURIComponent);
      if (queryParams.hasOwnProperty(key)) {
        if (Array.isArray(queryParams[key])) {
          queryParams[key].push(value);
        } else {
          queryParams[key] = [queryParams[key], value];
        }
      } else {
        queryParams[key] = value;
      }
    });
  }
  return queryParams;
}

/**
 * 授权申请
 * 注意: 需要授权 scope.userLocation、scope.userLocationBackground、scope.userFuzzyLocation 时必须在 permission 中配置地理位置用途说明
 * @param {String} scope
 * @returns {Promise}
 * @see https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/authorize.html
 */
export function applyAuthorize(scope) {
  const scopeMap = {
    "scope.userLocation": "精确地理位置",
    "scope.userFuzzyLocation": "模糊地理位置",
    "scope.userLocationBackground": "后台定位",
    "scope.record": "麦克风",
    "scope.camera": "摄像头",
    "scope.bluetooth": "蓝牙",
    "scope.writePhotosAlbum": "添加到相册",
    "scope.addPhoneContact": "添加到通讯录",
    "scope.addPhoneCalendar": "添加到日历",
    "scope.werun": "微信运动步数",
    // "scope.address": "通讯地址",
    // "scope.invoiceTitle": "发票抬头",
    // "scope.invoice": "获取发票",
    // "scope.userInfo": "用户信息",
  };
  if (Object.keys(scopeMap).includes(scope) === false) {
    throw new Error("scope 参数非法");
  }

  return new Promise((resolve, reject) => {
    // 获取用户授权设置
    uni.getSetting({
      success: (res) => {
        // console.log("授权状态", res);
        if (res.authSetting[scope] !== true) {
          // 发起授权请求
          uni.authorize({
            scope: scope,
            success: () => {
              resolve("用户同意授权");
            },
            fail: () => {
              reject("用户拒绝授权");
              uni.showModal({
                title: "权限申请",
                content: `请在设置界面中开启[${scopeMap[scope]}]权限，否则可能无法正常提供服务`,
                success: function (res) {
                  if (res.confirm) {
                    // 打开设置界面(用户发生点击行为后，才可以跳转打开设置页)
                    uni.openSetting({
                      withSubscriptions: true,
                    });
                  }
                },
              });
            },
          });
        } else {
          // 已同意授权的
          resolve("用户已授权");
        }
      },
    });
  });
}

/**
 * 消息订阅
 * @param {Array} tmplIds
 * @returns {Promise}
 */
export function subscribeMessage(tmplIds = []) {
  return new Promise((resolve, reject) => {
    uni.requestSubscribeMessage({
      tmplIds: tmplIds,
      success: (res) => {
        const acceptTmplIds = tmplIds.filter((tmplId) => {
          return res[tmplId] === "accept";
        });
        resolve(acceptTmplIds);
      },
      fail: (err) => {
        if (err.errCode === 20004) {
          uni.showModal({
            title: "通知管理设置",
            content: '请在"通知管理"中打开"接收通知"，否则可能无法正常提供服务',
            success: function (res) {
              if (res.confirm) {
                uni.openSetting({
                  withSubscriptions: true,
                });
              }
            },
          });
        }
        reject(err);
      },
    });
  });
}

/**
 * 对象属性按字典排序
 * @param {Object} obj
 * @returns {Object}
 */
export function ksort(obj = {}) {
  const keys = Object.keys(obj).sort();
  const newObj = {};
  keys.forEach((key) => {
    newObj[key] = obj[key];
  });
  return newObj;
}

/**
 * 查询节点信息
 * 注意：使用 uni.createSelectorQuery() 需要在生命周期 mounted 后进行调用
 * @param {String} selector
 * @param {Boolean} all
 * @returns {Promise}
 * @see https://developers.weixin.qq.com/miniprogram/dev/api/wxml/NodesRef.boundingClientRect.html
 */
export function getRect(selector, all = false) {
  return new Promise((resolve) => {
    uni
      .createSelectorQuery()
      [all ? "selectAll" : "select"](selector)
      .boundingClientRect((rect) => {
        if (all && Array.isArray(rect) && rect.length) {
          resolve(rect);
        }
        if (!all && rect) {
          resolve(rect);
        }
      })
      .exec();
  });
}

/**
 * 比较版本号
 * @param {String} v1
 * @param {String} v2
 * @returns {Number} 1大于 0等于 -1小于
 * @see https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html
 */
export function compareVersion(v1, v2) {
  const parts1 = v1.split(".").map(Number);
  const parts2 = v2.split(".").map(Number);

  const len = Math.max(parts1.length, parts2.length);

  for (let i = 0; i < len; i++) {
    const num1 = parts1[i] || 0;
    const num2 = parts2[i] || 0;

    if (num1 !== num2) {
      return num1 > num2 ? 1 : -1;
    }
  }

  return 0;
}
n;>xiWYs8$-Ėn6eRҤ*SUAspBl*Jc#Ҷ,ɫ$sRU/!.&B-w{w7nXjyO=tT+/G1COUW*TTUͬNEpa(uJOYJܷyJBUO)F_2T[i^TNtCM`?lc)[УbV RxɄ+#eqS jm"F_^4:Q^V]ۏٕxb,k;'B丩ԋ/ +c*JˉJb822=%EsNN
Ovujvn:^|TbT 
7*uClVALW@ :dӤ/%!a3	"zT;p+ppMMU4]mg[>Q
^zO<5v/fśىb28שYJ(,)Zt3u1FOj,Ā48FBg8@T;t,g-rkSyy3jg6x}Ȟ]Svy[޻wu3?Si ˹'_2N-Nn2[]gyDL[xtK98]-/!XVR2븮n?BP_f2ab,o@Xa4'C<EQZ
N1ll]4uۛۙ{xmTfAomRR6LGeKK*<Ј_vOhC&RX.wSz/9ǯP"cX~.]pr$-ٸ٭=7'FAC{	Yܹi<2&>{'uE%bI~Ɓ0<䆤 ->׭Yϧ[-狳 s6d6V毭fw[eR!bOsN>&?ݥ)}~	yarڞ=|Ӓ&ojS8i({:[L3\B$^cwٓkw;Rjb,:,x3
gCDUd7j*/f^17
H,#~IULb+)WҡBY.VqCBI:ijj? 2;x0݃&{kzh`5t5H/JtT9 8pL5L _[vIY7&x>ٽe[VIR@\E(jOnzA{AJVN )9|QS#znu~e]MMtp Ew2!DXI(\@
羿 71]kZ2IGIrʕY-1vE{z%ۖ}cT6r\)+6[Q:3&[Kv)#?y7 uJkhh G=MYLR;2CW^ៃ|9ΧB2.G+}竻P,EiBzeoɐ n_C_OI V!\9B+Y:k@3@;`W!xqgTFIBٸUuBW5#
Ȇ)C슛bIKUPS$kėT/gO}jŕ *J2>9>	Z8J⑚Bܪև?D]>s4RFw𪒨VW՘u0jȗd+j1]jMH%Ӊ*] S? QC$: 0c>
_^UVqLmtp]
NSAJ 2.*K52fkE+NѷTbDRՂ	rЍ`gv IY)~G%NindGfAzfyc$@灀KL<CJ˯vzp"eLN<kej8$ԏ#;`t'6b2Kd"QO!W$x{<<[ /Cx<]׳˕LD#Eyۣ#'xenط`v8O7 ~rÓѭB
Ra6cod%PԱC_aruH:H}!:{,=|r9<׆ج?r8; !v騌d#7d `t0B&qvUo^!cTs t
"8
E'+4"@!xIY.D}hx-	֦:?GSk_1	:pE	n Ld|^*/9}	LnRw\ %r#Nٔ=7@涹5pF;БCO)l
$:c[˅mu|UYP򲀻$;y Mo/V+Bg% <v/{}3=L#<f"H,s^yl}YTH:|*s٢~MU""$Ia:V7O!8ܥbm!bT5ƝzޭB$v!\d*IR	Q"k-hvxG	*|Ah-$6TPyԏ`blZлFA 1E&cZ3,E|97p\TztS8[jiQ%~+fJް=7-MޗCc{vAAA{u)Ԕ(D&!RTCe#pE#$FHP-xBaS0s'BU)5헅qf`eVȤL'g-%Sf5p~7s`
f2S^7x]ōh3x]v_k}s\/J^@烨TV	5hBr>c*P>يN"vl*wM~jp9-tyć}«"!nKK{ѧF:wzqӅ4[f9ξn- r}$-8nc$7׊%؊ymE$l5qRH"{wN1MmM-__]^ݴ&A^L#oau55کxh0c	BZQWG1Z6_^F*XJ2,Nd'<Wyol0جYQa)9쾮<EnSj~UyxD%ANXPq@y?zلY`QO~@EJȀ$qm2ATY8}W[3:Ah O5IW|hK\ Ub2ȩX^=8xRn0}^*ORxMT+hhzfm9N۩ʇGAM6$Kb{|=R\JZJ@y:T+`iuJ:=cJt2_3MV
Ωޑͣha#~/"F7ym!)B%l{ 
H.YM	 IRio:0ӂсJN Rfin r)ϡ-zAﶱqvKn,vvh>V@H6IGYrR8[]ݠ:?Ir5$u$|aT.:E׺LX8>pk4]t;ʗ;Ƴ}U@#mh8o\Ae46>'t!cxwi|1bxJ`l%9{9;J[ۻayhqmFw;*?C&d
0E1}ӫ	*z7
ix`a:~Vq~^QAL%%V9i%)EyzEyyiz:\
pPXZbU;n0&Q;y#{5W5 0Yx[ʹs?sh/bdroN_`I P(HLO-fpoǬrWn	H35X쉞>k׼9QdwO/߻XM?fOf E2@x.Tjd'VGvnyT4$^m/|Kot yx <40000 404 WȽ߯ DYQ{A40000 consumption 3NzU^240000 index %\(,khP)M40000 login 4\D C40000 mine "(+շg{co=<40000 order D?zoz{7f;yOx+ 100644 consumption.vue WsbpM$h@;Nx 87boffsetTop="J
m
Fx% 100644 login.vue iv/Rrs/đi%p-lPx8E	用户名N20" 
2G
d, ]#
		  打开小程序并登录
		</a
	̓-填写9m/ =	// 这里此提示会被this.start()方法中的提示覆盖8$验证码已发送",
	qa	});
				// 通知验证码组件内部开始倒计时
				codeRef.value.start();
			}, 2000);%ub:
		if1
			XcxLogin()VA1u9e8X-&-if(!res.user.phone) {
						uni.showToast({
	-8
							icon: "success",
						});
						uni.$uv.route({^#=Q
							url: redirect,
						});
					} else {
						popup.value.open()
					}
	a%w!t+#(// RPC.post('/api/sms/send', {
			//   <$&M//   type: 'bind'
			// }).then(() => {
			//   uni.hideLoading()
			//   %//     !,//     icon: 'success'
			//   })
			//   F%//  //   uni.hideLoading()
			//   %//     %'M//     icon: 'none'
			//   })
			// })

			// 模拟发送验证码
			m/ 8验证码已发送8(F%;
			}, 1500);%G+K,$0
				js_code: loginRes.code
			}).then(res => {
\"`8
8n-	/
				if(!res.user.phone) {
					uni.showToast({-6
						icon: "success",
					});
					uni.$uv.route({
`!=I
						url: redirect,
					});
				} else {
					popup.value.open()
				}`%
				uni.showToast({

					icon: "error",
				});=/9,.bind-phone', {
			//   <$&//   cod@$7
h//   wechatCode: wechatLoginCode // 微信登录返回的code
			// })

			// 模拟绑定过程
			m/C88T
				// 设置登录状态_8 "wechat_access_token");
				// ult.userInfo)

.9!;

				// 跳转到首页
				m/-4=#@?9$,
					});
				}, 1000);
			}, 202:\', {
				usernam=m
;'=P=#@?_?v@)Au6-x$ 100644 mine.vue +C?aàE>i+d}nx <<1V6x% 100644 order.vue xc"Ϊk6ːhA&~_xQɊCoffsetTop="bc-	<!-- 
\O	)i	(  L    data: orderNo,
	    success: () => {
	      uni.showToast({
	        /        icon: 'success'
	      })
	    }
	  Y3 / HP			
			o.+ success: false n0Y			0}	D5>6Z6v6  
71  <7'		
	})
	
	onReachBottom(() => {
	  8M    return;
	  i8   <7
ing";
	  8  8U	!:L	m:	:^[;	rQFx;xQ RS2Kt2sR~
Y?l[jQ<Q}. x, 100644 edit-profile.vue uxF{Vzw`x~伫x2C<template>
  <view class="container">
    <!-- 个人信息设置 -->
    <view class="profile-section">
      <!-- 头像 -->
<!--      <view class="profile-item" @click="changeAvatar">
        <view class="item-label">头像</view>
        <view class="item-content">
          <image
            class="avatar"
            :src="userInfo.avatar"
            mode="aspectFill"
          ></image>
          <uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
        </view>
      </view> -->

      <!-- 用户名 -->
      <view class="profile-item" @click="editUsername">
        <view class="item-label">用户名</view>
        <view class="item-content">
          <text class="item-value">{{ userStore.userInfo.username }}</text>
          <uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
        </view>
      </view>

      <!-- 邮箱 -->
      <view class="profile-item" @click="editEmail">
        <view class="item-label">邮箱</view>
        <view class="item-content">
          <text class="item-value">{{ userStore.userInfo.email }}</text>
          <uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
        </view>
      </view>
	  
	<!-- 电话 -->
	<view class="profile-item">
	   <view class="item-label">手机号</view>
	   <view class="item-content">
	     <text class="item-value">{{ userStore.userInfo.phone }}</text>
	   </view>
	 </view>
    </view>
	

    <!-- 应用设置 -->
    <view class="app-section">
      <!-- 缓存 -->
      <!-- 			<view class="profile-item" @click="clearCache">
				<view class="item-label">缓存</view>
				<view class="item-content">
					<text class="item-value">{{ cacheSize }}</text>
					<uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
				</view>
			</view> -->

      <!-- 用户协议 -->
      <view class="profile-item" @click="viewUserAgreement">
        <view class="item-label">用户协议</view>
        <view class="item-content">
          <uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
        </view>
      </view>

      <!-- 关于我们 -->
      <view class="profile-item" @click="viewAbout">
        <view class="item-label">关于我们</view>
        <view class="item-content">
          <uv-icon name="arrow-right" size="16" color="#ccc"></uv-icon>
        </view>
      </view>
    </view>

    <!-- 退出登录按钮 -->
    <view class="logout-section">
      <uv-button
        type="primary"
        size="large"
        @click="logout"
        :loading="logoutLoading"
      >
        退出登录
      </uv-button>
    </view>

    <!-- 编辑弹窗 -->
    <uv-popup ref="editPopup" mode="center" @close="closeEditModal" :round="10">
      <view class="edit-modal">
        <view class="modal-title">
          编辑{{
            editType === "username"
              ? "用户名"
              : editType === "phone"
              ? "电话"
              : editType === "email"
              ? "邮箱"
              : ""
          }}
        </view>
        <uv-input
          v-model="editValue"
          :placeholder="getPlaceholder()"
          :type="
            editType === 'phone'
              ? 'number'
              : editType === 'email'
              ? 'email'
              : 'text'
          "
          border="bottom"
          clearable
        ></uv-input>
        <view class="modal-actions">
          <uv-button type="default" @click="closeEditModal">取消</uv-button>
          <uv-button type="primary" @click="saveEdit">保存</uv-button>
        </view>
      </view>
    </uv-popup>

    <!-- 头像选择弹窗 -->
    <uv-popup
      ref="avatarSheet"
      mode="bottom"
      @close="closeAvatarSheet"
      :round="10"
    >
      <view class="avatar-sheet">
        <view class="sheet-header">
          <view class="sheet-title">选择头像</view>
        </view>
        <view class="sheet-actions">
          <view class="action-item" @click="selectAvatarSource('camera')">
            <uv-icon name="camera-fill" size="24" color="#4285f4"></uv-icon>
            <text class="action-text">拍照</text>
          </view>
          <view class="action-item" @click="selectAvatarSource('album')">
            <uv-icon name="photo-fill" size="24" color="#4285f4"></uv-icon>
            <text class="action-text">从相册选择</text>
          </view>
        </view>
        <view class="sheet-cancel">
          <uv-button type="default" size="large" @click="closeAvatarSheet">
            取消
          </uv-button>
        </view>
      </view>
    </uv-popup>
  </view>
</template>

<script setup>
import { ref, onMounted } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { useAuthStore, useUserStore } from "@/store";
import RPC from "@/utils/request";

const authStore = useAuthStore();
const userStore = useUserStore();

// 响应式数据
const userInfo = ref({
  avatar: "/static/imgs/avatar.png",
  username: "张三",
  phone: "15825556676",
  email: "235382903@qq.com",
});

const cacheSize = ref("36MB");
const logoutLoading = ref(false);
const editType = ref("");
const editValue = ref("");
const editPopup = ref(null);
const avatarSheet = ref(null);

// 更换头像
const changeAvatar = () => {
  console.log("点击更换头像");
  avatarSheet.value.open();
};

// 关闭头像选择弹窗
const closeAvatarSheet = () => {
  avatarSheet.value.close();
};

// 选择头像来源
const selectAvatarSource = (source) => {
  console.log("选择头像方式:", source);
  avatarSheet.value.close();

  uni.chooseImage({
    count: 1,
    sizeType: ["compressed"],
    sourceType: source === "camera" ? ["camera"] : ["album"],
    success: (res) => {
      const tempFilePath = res.tempFilePaths[0];
      console.log("选择图片成功:", tempFilePath);

      // 这里应该上传图片到服务器
      // uploadAvatar(tempFilePath)

      // 临时更新头像显示
      userInfo.value.avatar = tempFilePath;

      uni.showToast({
        title: "头像更新成功",
        icon: "success",
      });
    },
    fail: (err) => {
      console.error("选择图片失败:", err);
      uni.showToast({
        title: "选择图片失败",
        icon: "none",
      });
    },
  });
};

// 编辑用户名
const editUsername = () => {
  editType.value = "username";
  editValue.value = userStore.userInfo.username;
  editPopup.value.open();
};

// 编辑电话
const editPhone = () => {
  editType.value = "phone";
  editValue.value = userStore.userInfo.phone;
  editPopup.value.open();
};

// 编辑邮箱
const editEmail = () => {
  editType.value = "email";
  editValue.value = userStore.userInfo.email;
  editPopup.value.open();
};

// 获取输入框占位符
const getPlaceholder = () => {
  switch (editType.value) {
    case "username":
      return "请输入用户名";
    case "phone":
      return "请输入手机号";
    case "email":
      return "请输入邮箱地址";
    default:
      return "请输入";
  }
};

// 关闭编辑弹窗
const closeEditModal = () => {
  editPopup.value.close();
  editType.value = "";
  editValue.value = "";
};

// 保存编辑
const saveEdit = async () => {
  if (!editValue.value.trim()) {
    uni.showToast({
      title: "请输入内容",
      icon: "none",
    });
    return;
  }
  if(editType.value === 'username') {
	  RPC.post('/user/update',{id:userStore.userInfo.id,username:editValue.value}).then(() => {
		  uni.showToast({
		    title: "保存成功",
		    icon: "success",
		  });
		  userStore.setUserInfo({...userStore.userInfo,username:editValue.value})
		  closeEditModal()
	  })
  }
  if(editType.value === 'email') {
	  RPC.post('/user/update',{id:userStore.userInfo.id,email:editValue.value}).then(() => {
		  uni.showToast({
		    title: "保存成功",
		    icon: "success",
		  });
		  userStore.setUserInfo({...userStore.userInfo,email:editValue.value})
		  closeEditModal()
	  })
  }

  // try {
  //   // 调用更新用户信息API
  //   // await RPC.post('/api/user/update', {
  //   //   [editType.value]: editValue.value
  //   // })

  //   // 更新本地数据
  //   userInfo.value[editType.value] = editValue.value;

  //   uni.showToast({
  //     title: "保存成功",
  //     icon: "success",
  //   });

  //   closeEditModal();
  // } catch (error) {
  //   console.error("保存失败:", error);
  //   uni.showToast({
  //     title: "保存失败，请重试",
  //     icon: "none",
  //   });
  // }
};

// 清除缓存
const clearCache = () => {
  uni.showModal({
    title: "清除缓存",
    content: "确定要清除应用缓存吗？",
    success: (res) => {
      if (res.confirm) {
        uni.showLoading({
          title: "清除中...",
        });

        // 模拟清除缓存
        setTimeout(() => {
          uni.hideLoading();
          cacheSize.value = "0MB";
          uni.showToast({
            title: "缓存清除成功",
            icon: "success",
          });
        }, 1500);
      }
    },
  });
};

// 查看用户协议
const viewUserAgreement = () => {
  uni.navigateTo({
    url: "/pagesA/user-agreement/user-agreement",
  });
};

// 查看关于我们
const viewAbout = () => {
  //   uni.navigateTo({
  //     url: "/pagesA/about/about",
  //   });
};

// 退出登录
const logout = () => {
  uni.showModal({
    title: "退出登录",
    content: "确定要退出登录吗？",
    success: (res) => {
      if (res.confirm) {
        logoutLoading.value = true;

        // 模拟退出登录
        setTimeout(() => {
          authStore.signOut();
          logoutLoading.value = false;

          // 清除用户信息和token
          // authStore.logout()

          uni.showToast({
            title: "已退出登录",
            icon: "success",
          });

          // 跳转到登录页
          uni.reLaunch({
            url: "/pages/login/login",
          });
        }, 1000);
      }
    },
  });
};

// 加载用户信息
const loadUserInfo = async () => {
  try {
    // 调用获取用户信息API
    // const result = await RPC.get('/api/user/info')
    // userInfo.value = result.data
  } catch (error) {
    console.error("加载用户信息失败:", error);
  }
};

// 计算缓存大小
const calculateCacheSize = () => {
  // 实际项目中应该计算真实的缓存大小
  // const size = await getCacheSize()
  // cacheSize.value = formatSize(size)
};

onMounted(() => {
  loadUserInfo();
  calculateCacheSize();
});

onShow(() => {
  // 页面显示时刷新用户信息
  loadUserInfo();
});
</script>

<style lang="scss" scoped>
.container {
  font-size: 14px;
  min-height: 100vh;
  background-color: #f8f8f8;
  padding: 16px;
}

.profile-section,
.app-section {
  background: white;
  border-radius: 12px;
  margin-bottom: 16px;
  overflow: hidden;

  .profile-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px;
    border-bottom: 1px solid #f0f0f0;

    &:last-child {
      border-bottom: none;
    }

    .item-label {
      font-size: 16px;
      color: #333;
      font-weight: 500;
    }

    .item-content {
      display: flex;
      align-items: center;
      gap: 8px;

      .avatar {
        width: 40px;
        height: 40px;
        border-radius: 50%;
      }

      .item-value {
        font-size: 14px;
        color: #666;
      }
    }
  }
}

.logout-section {
  margin-top: 32px;
}

.edit-modal {
  width: 300px;
  padding: 24px;

  .modal-title {
    font-size: 18px;
    font-weight: bold;
    color: #333;
    text-align: center;
    margin-bottom: 20px;
  }

  .modal-actions {
    display: flex;
    gap: 12px;
    margin-top: 20px;

    .uv-button {
      flex: 1;
    }
  }
}

.avatar-sheet {
  padding: 20px;

  .sheet-header {
    text-align: center;
    margin-bottom: 20px;

    .sheet-title {
      font-size: 18px;
      font-weight: bold;
      color: #333;
    }
  }

  .sheet-actions {
    display: flex;
    justify-content: space-around;
    margin-bottom: 20px;

    .action-item {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      padding: 20px;
      border-radius: 8px;
      background: #f8f9fa;
      min-width: 100px;
      transition: all 0.3s;

      &:active {
        background: #e9ecef;
        transform: scale(0.95);
      }

      .action-text {
        font-size: 14px;
        color: #333;
      }
    }
  }

  .sheet-cancel {
    margin-top: 10px;
  }
}
</style>p(>x˛%"|WI1RNة 7x;4i|7d899S3-RSMSLRM-,LR7 P}ux! 		/ܗ;Pe[Cbj?x <40000 404 WȽ߯ DYQ{A40000 consumption 3NzU^240000 index &{+sOy4S40000 login 4\D C40000 mine uB{%H r40000 order D?zoz{7f;RT׫xK 100644 index.vue `I]ZʟtV100644 index1.vue U$YVxIhCNs	x MK# Nx$ 100644 mine.vue H)klٍD LOgspx! 		/Xf8pfI+w9CbE+x 03(&p,D«x+ 100644 consumption.vue 
_Q̓&,_5ԂXdN:xy 86boffsetTop="p7=jm
		if(tab === '生成')1#'生成'
		}
		if(tab === '会员')1'会员'MXs,0>xB 		/5=ql%WV;0[Z)40000 pagesA F|.vBWA] dA
@x Jӥ@6kf&wdox% 100644 order.vue 'zxnEcy'Box)a%&+
			<div class="tabBox">Q63Q6EQ{

			</div>j % % % A % %>;0L	02	L	HL	/	
						
57ړ
	f
	K$p
	    data: orderNo,
	      uni.showToast({&0
	        icon: 'success'
	      })
	    }
	  })*a?
		active.value = tab
		page.value = 1
		if(tab === '全部') {
		} else {tab
		}) 2)支付',
			content: '确定继续支付BQK
				}
			}
		})
	}
	
	const page = ref(1)
	const typeParams = ref('')04'X41
		uni.showLoading();4'4#
			page:page.value,5 
			size:20
		}).then(res => {B5.q55+5nomore";
			} else {5'
			}
		}).catch(() => {/6%0
		}).finally(() => {
			uni.hideLoading();
		})6"
	66N
	    return;#7!
5ing";j7
	  getList();7@#
		list.value = []
		page.value = 17
58
	
	.tabBox {
		height: 50px;91
		display: flex;
	
		.tabItem {
			height: 100%;Q9
			display: flex;
;:
			justify-content: center;
			flex: 1;
	
			&.selected {99&	
			}
		}:	p[3ix6 =";W
fssWQ6dvA?^𾑬ʦ3)xV 100644 generate-record.vue ntwFf*`100644 new_file.js ,R!]('9(x"x!<template>
  <view class="container">
    <!-- 生成记录列表 -->
    <view class="record-list">
      <uv-swipe-action>
        <uv-swipe-action-item
          @click="delItem(record)"
          :options="options"
          v-for="record in list"
          :key="record.id"
        >
          <view class="record-item">
            <!-- 记录信息 -->
            <view class="record-info">
              <view class="record-title">{{ record.file_name }}</view>
              <view class="record-time">
                生成时间:
                {{
                  record.CreatedAt
                    ? dayjs(record.CreatedAt).format("YYYY-MM-DD")
                    : ""
                }}
              </view>
            </view>

            <!-- 状态标签 -->
            <view
              class="status-tag"
              :class="{
                completed: record.status == 4,
                failed: record.status == 5,
              }"
            >
              <span v-if="record.status == 4">已完成</span>
              <span v-else-if="record.status == 5">生成失败</span>
              <span v-else>生成中</span>
            </view>

            <!-- 操作按钮 -->
            <view class="record-actions">
              <uv-button
                v-if="record.status === 4"
                type="primary"
                size="small"
                @click="downloadRecord(record)"
              >
                <uv-icon
                  name="download"
                  size="14"
                  color="white"
                  style="margin-right: 4px"
                ></uv-icon>
                下载
              </uv-button>
              <uv-button v-else type="info" size="small" disabled>
                <uv-icon
                  name="download"
                  size="14"
                  color="#aaa"
                  style="margin-right: 4px"
                ></uv-icon>
                下载
              </uv-button>
            </view>
          </view>
        </uv-swipe-action-item>
      </uv-swipe-action>
    </view>

    <!-- 空状态 -->
    <view v-if="list.length === 0 && loadingStatus !== 'loading'" class="empty-state">
      <uv-icon name="file-text" size="60" color="#ccc"></uv-icon>
      <text class="empty-text">暂无生成记录</text>
    </view>

    <!-- 加载更多 -->
    <uv-load-more :status="loadingStatus" @loadmore="loadmore" />
  </view>
</template>

<script setup>
import { ref, onMounted } from "vue";
import RPC from "@/utils/request";
import dayjs from "dayjs";
import { onShow, onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";

const options = ref([
  {
    text: "删除",
    style: {
      backgroundColor: "#f56c6c",
    },
  },
]);
const delItem = (item) => {
  console.log(item);
  deleteRecord(item);
};
// 响应式数据
const loading = ref(false);
const loadingStatus = ref("loadmore");
const page = ref(1);
const list = ref([]);
const count = ref(0);

// 下载记录
const downloadRecord = (record) => {
  uni.showLoading({
    title: "准备下载...",
  });

  // #ifdef H5
  // H5端直接使用浏览器下载
  const link = document.createElement("a");
  link.href = record.result_url;
  link.download = record.file_name || "download";
  link.target = "_blank";
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);

  uni.hideLoading();
  uni.showToast({
    title: "开始下载",
    icon: "success",
  });
  // #endif
  // #ifdef MP-WEIXIN
  // 小程序和App端使用uni.downloadFile
  uni.downloadFile({
    url: 'https://ksdt-1255846884.cos.ap-shanghai.myqcloud.com/lift-result/2025/09/24/d6180add4cd94875a1854a4febce8966.pdf',
    success: (res) => {
      console.log(res);
      if (res.statusCode === 200) {
        uni.openDocument({
		  filePath: res.tempFilePath,
		  showMenu: true,
          success: () => {
            uni.hideLoading();
            uni.showToast({
              title: "下载成功",
              icon: "success",
            });
          },
          fail: () => {
            uni.hideLoading();
            uni.showToast({
              title: "保存失败",
              icon: "none",
            });
          },
        });
      } else {
        uni.hideLoading();
        uni.showToast({
          title: "下载失败",
          icon: "none",
        });
      }
    },
    fail: () => {
      uni.hideLoading();
      uni.showToast({
        title: "下载失败",
        icon: "none",
      });
    },
  });
  // #endif
};

// 删除记录
const deleteRecord = (record) => {
  uni.showModal({
    title: "确认删除",
    content: "确定要删除这条生成记录吗？删除后无法恢复。",
    success: (res) => {
      if (res.confirm) {
        // 从列表中移除记录
        const index = records.value.findIndex((item) => item.id === record.id);
        if (index !== -1) {
          records.value.splice(index, 1);
        }

        uni.showToast({
          title: "删除成功",
          icon: "success",
        });

        // 实际项目中调用删除API
        // try {
        //   await RPC.post('/api/generate-record/delete', { id: record.id })
        // } catch (error) {
        //   console.error('删除失败:', error)
        // }
      }
    },
  });
};

// 加载生成记录
const loadRecords = async () => {
  loadingStatus.value = "loading";
  RPC.post("/planned_list", { page: page.value, page_size: 20 })
    .then((res) => {
      list.value = [...list.value, ...res.list];
      count.value = res.total;
      if (list.value.length >= count.value) {
        loadingStatus.value = "nomore";
      } else {
        loadingStatus.value = "loadmore";
      }
    })
    .catch(() => {
      loadingStatus.value = "loadmore";
    });
};

// 刷新数据
onPullDownRefresh(() => {
  list.value = [];
  page.value = 1;
  loadingStatus.value = "loading";
  RPC.post("/planned_list", { page: page.value, page_size: 20 })
    .then((res) => {
      list.value = [...list.value, ...res.list];
      count.value = res.total;
      if (list.value.length >= count.value) {
        loadingStatus.value = "nomore";
      } else {
        loadingStatus.value = "loadmore";
      }
    })
    .catch(() => {
      loadingStatus.value = "loadmore";
    })
    .finally(() => {
      uni.stopPullDownRefresh();
    });
});

onReachBottom(() => {
  loadmore();
});

const loadmore = () => {
  if (list.value.length >= count.value || loadingStatus.value === "loading")
    return;
  console.log("上拉加载:");
  loadingStatus.value = "loading";
  page.value = ++page.value;
  loadRecords();
};

onShow(() => {
  // 页面显示时刷新数据
  list.value = [];
  page.value = 1;
  loadRecords();
});
</script>

<style lang="scss" scoped>
.container {
  font-size: 14px;
  min-height: 100vh;
  background-color: #f8f8f8;
  padding: 16px;
}

.record-list {
  .record-item {
    background: white;
    border-radius: 12px;
    padding: 16px;
    margin-bottom: 12px;
    display: flex;
    align-items: center;
    gap: 12px;

    .record-info {
      flex: 1;

      .record-title {
        font-size: 16px;
        color: #333;
        font-weight: 500;
        margin-bottom: 6px;
      }

      .record-time {
        font-size: 13px;
        color: #999;
      }
    }

    .status-tag {
      padding: 4px 8px;
      border-radius: 4px;
      font-size: 12px;
      font-weight: 500;
      background: #fff7e6;
      color: #fa8c16;

      &.completed {
        background: #e8f5e8;
        color: #52c41a;
      }

      &.failed {
        background: #fff1f0;
        color: #ff4d4f;
      }

      &.processing {
        background: #fff7e6;
        color: #fa8c16;
      }
    }

    .record-actions {
      display: flex;
      align-items: center;
      flex-shrink: 0;
    }
  }
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 20px;

  .empty-text {
    color: #999;
    font-size: 14px;
    margin-top: 16px;
  }
}

.load-more {
  padding: 20px;
  text-align: center;
}
</style>K,xw BB	v-els	record.result_url("%uni.showLoading();
 '.finally(() => {
		uni.hideLoading();
		}()x]订单列表的

"id":             it.ID,                         // 订单ID
            "order_no":       it.OrderNo,                    // 订单号（M=会员订单，R=充值订单）
            "user_id":        it.UserID,                     // 用户ID
            "user_name":      userNameMap[it.UserID],        // 用户名
            "plan_id":        it.PlanID,                     // 套餐ID（充值订单为0）
            "plan_name":      planName,                      // 套餐名称（充值订单固定为“钱包充值”）
            "order_type":     it.OrderType,                  // 订单类型：会员购买/钱包充值（中文）
            "amount_cents":   it.AmountCents.ToInt64(),      // 订单金额（分）
            "amount":         it.AmountCents.String(),       // 订单金额（元，字符串，保留两位小数）
            "pay_channel":    it.PayChannel,                 // 支付渠道：wallet|wxpay|alipay|other
            "status":         it.Status,                     // 订单状态：created|paid|canceled|refunded
            "pay_time":       it.PayTime,                    // 支付时间（Unix 时间戳，秒）
            "transaction_id": it.TransactionID,              // 第三方交易号/平台流水号
            "remark":         it.Remark,                     // 备注
            "created_at":     it.CreatedAt,                  // 创建时间（Unix 时间戳，秒）
            "updated_at":     it.UpdatedAt,                  // 更新时间（Unix 时间戳，秒）


消费列表

"id":                   it.ID,                                         // 流水ID
   "user_id":              it.UserID,                                      // 用户ID
   "user_name":            userName,                                       // 用户名
   "type":                 it.Type,                                        // 交易类型：recharge(充值)|purchase(消费)
   "amount_cents":         it.AmountCents.ToInt64(),                       // 金额（分）
   "amount":               it.AmountCents.String(),                        // 金额（元，字符串，保留两位小数）
   "related_order_id":     it.RelatedOrderID,                              // 关联的订单ID（可为空）
   "order_no":             it.OrderNo,                                     // 关联订单号（M* 会员订单 / R* 充值订单）
   "pay_channel":          it.PayChannel,                                  // 支付渠道：wallet|wxpay|alipay|other
   "status":               it.Status,                                      // 交易状态：success|failed|pending
   "remark":               it.Remark,                                      // 备注
   "balance_before_cents": it.BalanceBeforeCents.ToInt64(),                // 变动前余额（分）
   "balance_after_cents":  it.BalanceAfterCents.ToInt64(),                 // 变动后余额（分）
   "finished_at":          it.FinishedAt,                                  // 完成时间（Unix 时间戳，秒）
   "external_txn_id":      it.ExternalTxnID,                               // 外部交易号（第三方平台返回）
   "currency":             it.Currency,                                    // 币种（默认 CNY）
   "created_at":           it.CreatedAt,                                   // 创建时间（Unix 时间戳，秒）
  })Wx( 100644 recharge.vue ν̾OkhGɱ) ZU2Ix s		zy#7{#R^100644 pages.json &,Q7ԫ40000 pages qIǗ̞M540000 pagesA Nc'΍NpobxW4000h=*<x, {
  "name": "lift<卡叔电梯m#WA[lsx Q x <40000 404 WȽ߯ DYQ{A40000 consumption ?_PٯcsJ|340000 index &{+sOy4S40000 login Fa*0O==Ycs+V40000 mine 濠ITʊ640000 order Ι]64WB5]4$٥Ox+ 100644 consumption.vue >$5"J
莎E>ٮ5^x"j<template>
  <view class="container">
    <!-- 顶部筛选标签 -->
    <view class="filter-tabs">
      <view
        class="tab-item"
        :class="{ active: activeTab === 'all' }"
        @click="switchTab('all')"
      >
        全部
      </view>
      <view
        class="tab-item"
        :class="{ active: activeTab === 'generate' }"
        @click="switchTab('generate')"
      >
        生成
      </view>
      <view
        class="tab-item"
        :class="{ active: activeTab === 'member' }"
        @click="switchTab('member')"
      >
        会员
      </view>
      <view
        class="tab-item"
        :class="{ active: activeTab === 'other' }"
        @click="switchTab('other')"
      >
        其他
      </view>
    </view>

    <!-- 消费记录列表 -->
    <view class="consumption-list">
      <view
        class="consumption-item"
        v-for="item in filteredConsumptions"
        :key="item.id"
      >
        <!-- 消费项目和金额 -->
        <view class="item-header">
          <view class="item-title">{{ item.title }}</view>
          <view
            class="item-amount"
            :class="{
              positive: item.amount > 0,
              negative: item.amount < 0,
            }"
          >
            {{ item.amount > 0 ? "+" : "-" }}¥{{
              Math.abs(item.amount).toFixed(2)
            }}
          </view>
        </view>

        <!-- 消费详情 -->
        <view class="item-details">
          <view class="detail-row">
            <text class="detail-label">消费编号:</text>
            <text class="detail-value">{{ item.consumptionNumber }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">消费时间:</text>
            <text class="detail-value">{{ item.consumptionTime }}</text>
          </view>
          <view class="balance-row">
            <view class="balance-item">
              <text class="balance-label">账前金额:</text>
              <text class="balance-value">
                ¥{{ item.beforeBalance.toFixed(2) }}
              </text>
            </view>
            <view class="balance-item">
              <text class="balance-label">账后金额:</text>
              <text class="balance-value">
                ¥{{ item.afterBalance.toFixed(2) }}
              </text>
            </view>
          </view>
        </view>
      </view>
    </view>

    <!-- 空状态 -->
    <view v-if="filteredConsumptions.length === 0" class="empty-state">
      <u-icon name="file-text" size="60" color="#ccc"></u-icon>
      <text class="empty-text">暂无消费记录</text>
    </view>

    <!-- 加载更多 -->
    <view v-if="hasMore && filteredConsumptions.length > 0" class="load-more">
      <u-button
        type="default"
        size="small"
        :loading="loading"
        @click="loadMore"
      >
        {{ loading ? "加载中..." : "加载更多" }}
      </u-button>
    </view>
  </view>
</template>

<script setup>
import { computed, onMounted, ref } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { useAuthStore, useUserStore } from "@/store";
import { regions } from "/static/json/regions.js";
import HeaderCustom from "/components/HeaderCustom/HeaderCustom.vue";
import RPC from "@/utils/request";

const authStore = useAuthStore();
const userStore = useUserStore();

// 响应式数据
const activeTab = ref("all");
const loading = ref(false);
const hasMore = ref(true);
const consumptions = ref([
  {
    id: 1,
    title: "乘客电梯图纸生成",
    amount: -30.0,
    consumptionNumber: "CONS20230516024",
    consumptionTime: "2025-05-16 14:30:22",
    beforeBalance: 1250.0,
    afterBalance: 1220.0,
    type: "generate",
  },
  {
    id: 2,
    title: "货运电梯图纸生成",
    amount: -45.0,
    consumptionNumber: "CONS20230516024",
    consumptionTime: "2025-05-16 14:30:22",
    beforeBalance: 1295.0,
    afterBalance: 1250.0,
    type: "generate",
  },
  {
    id: 3,
    title: "包年会员订阅",
    amount: -45.0,
    consumptionNumber: "CONS20230516024",
    consumptionTime: "2025-05-16 14:30:22",
    beforeBalance: 1295.0,
    afterBalance: 1250.0,
    type: "member",
  },
  {
    id: 4,
    title: "账户充值",
    amount: 1000.0,
    consumptionNumber: "CONS20230516024",
    consumptionTime: "2025-05-16 14:30:22",
    beforeBalance: 1795.0,
    afterBalance: 2795.0,
    type: "other",
  },
]);

// 计算过滤后的消费记录
const filteredConsumptions = computed(() => {
  if (activeTab.value === "all") {
    return consumptions.value;
  }
  return consumptions.value.filter((item) => item.type === activeTab.value);
});

// 切换标签
const switchTab = (tab) => {
  activeTab.value = tab;
};

// 加载更多数据
const loadMore = async () => {
  if (loading.value) return;

  loading.value = true;
  try {
    // 模拟API调用
    // const result = await RPC.get('/api/consumptions', {
    //   page: currentPage.value + 1,
    //   type: activeTab.value
    // })

    // 模拟加载延迟
    await new Promise((resolve) => setTimeout(resolve, 1000));

    // 模拟没有更多数据
    hasMore.value = false;

    uni.showToast({
      title: "没有更多数据了",
      icon: "none",
    });
  } catch (error) {
    console.error("加载更多失败:", error);
    uni.showToast({
      title: "加载失败，请重试",
      icon: "none",
    });
  } finally {
    loading.value = false;
  }
};

// 加载消费记录
const loadConsumptions = async () => {
  try {
    // 调用获取消费记录API
    // const result = await RPC.get('/api/consumptions', {
    //   type: activeTab.value
    // })
    // consumptions.value = result.data
  } catch (error) {
    console.error("加载消费记录失败:", error);
    uni.showToast({
      title: "加载失败，请重试",
      icon: "none",
    });
  }
};

// 下拉刷新
const onRefresh = async () => {
  hasMore.value = true;
  await loadConsumptions();
};

onMounted(() => {
  loadConsumptions();
});

onShow(() => {
  // 页面显示时刷新数据
  loadConsumptions();
});
</script>

<style lang="scss" scoped>
.container {
  font-size: 14px;
  min-height: 100vh;
  background-color: #f8f8f8;
}

.filter-tabs {
  display: flex;
  background: white;
  padding: 0 16px;
  border-bottom: 1px solid #e5e5e5;

  .tab-item {
    flex: 1;
    text-align: center;
    padding: 16px 0;
    color: #666;
    font-size: 14px;
    position: relative;

    &.active {
      color: #4285f4;
      font-weight: 500;

      &::after {
        content: "";
        position: absolute;
        bottom: 0;
        left: 50%;
        transform: translateX(-50%);
        width: 20px;
        height: 2px;
        background: #4285f4;
        border-radius: 1px;
      }
    }
  }
}

.consumption-list {
  padding: 16px;

  .consumption-item {
    background: white;
    border-radius: 12px;
    padding: 16px;
    margin-bottom: 12px;

    .item-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 12px;

      .item-title {
        font-size: 16px;
        color: #333;
        font-weight: 500;
      }

      .item-amount {
        font-size: 16px;
        font-weight: bold;

        &.positive {
          color: #52c41a;
        }

        &.negative {
          color: #ff4d4f;
        }
      }
    }

    .item-details {
      .detail-row {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 6px;

        .detail-label {
          color: #999;
          font-size: 13px;
        }

        .detail-value {
          color: #666;
          font-size: 13px;
        }
      }

      .balance-row {
        display: flex;
        justify-content: space-between;
        margin-top: 8px;

        .balance-item {
          display: flex;
          align-items: center;
          gap: 4px;

          .balance-label {
            color: #999;
            font-size: 13px;
          }

          .balance-value {
            color: #333;
            font-size: 13px;
            font-weight: 500;
          }
        }
      }
    }
  }
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 20px;

  .empty-text {
    color: #999;
    font-size: 14px;
    margin-top: 16px;
  }
}

.load-more {
  padding: 20px;
  text-align: center;
}
</style>Xl#x ED)Yx% 100644 login.vue =S}қqة{#bxV Ќ)>2F>%S'e
		>&console.log('from',from)
		$? '#

		v?(??I x$ 100644 mine.vue ^Jțkn--,q<XZ 7xVdiv class="avatar"></div>
				<!--        <image
          class="avatar"
         6
          mode="aspectFill"
        ></image> -->
p)$年会员 (有效期至: 2026-05-15)ac50.00G_cents-
͓h5'getPlanList()YoorderInfo.appId/:!l)=',{)xM
				if(1==1) {
					console.log('orderResult',orderResult)
					return
				}+*.wechatPayInfo*
(
-+-u6/>/});/C.0+5570		});

	0601<>KskyblueAsMx ximage class="avatar"a mode="aspectFill"></image$ %y
				if (1 == 1) {V&  orderResult)
					return&r :}2!(Mx% 100644 order.vue }Fi0	UX[xM
Ɋ[*!-- 顶部筛选标签 -->
		<view class="filter-tabs">
			<view class="tab-item" :class="{ active: activeTab === 'all' }" @click="switchTab('all')">
				全部
			</view>
			<view class="tab-item" :class="{ active: activeTab === 'recharge' }" @click="switchTab('recharge')">
				充值
			</view>
			<view class="tab-item" :class="{ active: activeTab === 'monthly' }" @click="switchTab('monthly')">
				包月
			</view>
			<view class="tab-item" :class="{ active: activeTab === 'season' }" @click="switchTab('season')">
				包季
			</view>
			<view class="tab-item" :class="{ active: activeTab === 'yearly' }" @click=""switchTab('yearly')">
				包年"[filteredOrdersNumber.F,order.status">
						{{ order.statusText }}.NampU9IdqZ48TnՓ
6j6{{ ' ? '创建时间:' : '支付时间:' }}m	#^	payTimpErt]Y/U9-待支付订单底部 -->
				<!-- 				<viewA!" class="pending-footer"a	countdown*t)Zpending-actions">
						<uv-button 
							type="default" 
							size="large"
							
						>
uv-button 
							type="error" 
							size="large"
							@click="payOrder(order)"
						>
							去支付
						</uv-by --@filteredOrders.length === 0Cxh/{
		regions
	} from '/static/json/regions.js'nJK@// 响应式数据
	const activeTab = ref('all')
	const ordersn计算过滤后的订单
	const filteredOrders = computed(() => {
		if (activeTab.value === 'all') {
			return orders.valueO
		}
		return orders.value.filter(order => order.type === activeTab.value)
	}v8activeTab.value = tabSDcancelh&W(d9led'
							orders.value[index].statusText = '已取消'1 =73* V/payment/payment?orderI!载订单数据
	const loadOrders = async () => {
		try {
			// 调用获取订单列表API
			// const result = await RP6C.get('/api/orders')
			// orders.value = result.data3console.error('加载 4'加载!icon: 'none'
			})
		}7		loadOrders()
	})8@	oadOrders{9filter-tabsmD;padding: 0 16px;
		border-bottom: 1px solid #e5e5e5;

		.tab-item {
			flex: 1;
			text-align: center;
			padding: 16px 0;
			color: #666
Eposition: relative;

			&.active {
				color: #4285f4;
				font-weight: 500;

				&::after {
					content: '';
					position: absolute;
					bottom: 0;
					left: 50%;
					transform: translateX(-50%);
					width: 20px;
					height: 2px;
		8			background: #4285f4;
					border-radius: 1px;
				}H;
ђXD-^x#[W%
		<uv-sticky bgColor="#fff" offsetTop="0">
			<div class="tabBox">
				<div class="tabItem" :class="{selected:active==='全部'}" @click="() => active = '全部'">全部</div>
				<div class="tabItem" :class="{selected:active==='已支付'}" @click="() => active = '已支付'">已支付</div>
				<div class="tabItem" :class="{selected:active==='待支付'}" @click="() => active8 = '待支付'">待支付</div>
			</div>
		</uv-sticky>Hab
	const active = ref('全部')
	
	.tabBox {
		height: 50px;
		background-color: #fff;
		display: flex;
	
		.tabItem {
			height: 100%;
			font-weight: 600;
			display: flex;
1+
	:-5
			flex: 1;
	
			&.selected {
				color: #5479ED;
		!5479ED;
			}
		}
	}#	0x6 =	zL2Äc)@+|\<Q6eךvj,eic)mux/ 100644 generate-record.vue Ox6\RAx ){0x( 100644 recharge.vue oȽmP5}YM?<uxLC<template>
  <view class="container">
    <!-- 顶部余额显示 -->
    <view class="balance-section">
      <view class="balance-card">
        <view class="balance-info">
          <view class="balance-label">当前余额</view>
          <view class="balance-amount">¥{{ currentBalance }}</view>
        </view>
        <view class="balance-icon">
          <uv-icon name="empty-coupon" color="#4285f4" size="40"></uv-icon>
        </view>
      </view>
    </view>

    <!-- 充值金额选择 -->
    <view class="recharge-section">
      <view class="section-title">选择充值金额</view>
      <view class="amount-grid">
        <view 
          class="amount-item" 
          :class="{ active: selectedAmount === item.value }"
          v-for="item in rechargeAmounts" 
          :key="item.value"
          @click="selectAmount(item.value)"
        >
          <view class="amount-value">¥{{ item.value }}</view>
          <!-- <view v-if="item.bonus" class="amount-bonus">送{{ item.bonus }}元</view> -->
        </view>
      </view>
      
      <!-- 自定义金额 -->
      <view class="custom-amount">
        <view class="custom-label">自定义金额</view>
        <view class="custom-input">
          <text class="currency">¥</text>
          <input 
            class="amount-input" 
            v-model="customAmount" 
            type="number" 
            placeholder="请输入充值金额"
            @input="onCustomAmountInput"
          />
        </view>
        <view class="amount-tips">充值金额范围：¥1 - ¥50000</view>
      </view>
    </view>

    <!-- 支付方式 -->
    <view class="payment-section">
      <view class="section-title">选择支付方式</view>
      <view class="payment-list">
        <!-- 微信支付 -->
        <view 
          class="payment-item" 
          :class="{ active: selectedPayment === 'wechat' }"
          @click="selectPayment('wechat')"
        >
          <view class="payment-info">
            <uv-icon name="weixin-fill" color="#07c160" size="28"></uv-icon>
            <view class="payment-details">
              <view class="payment-name">微信支付</view>
              <view class="payment-desc">安全快捷，支持零钱和银行卡</view>
            </view>
          </view>
          <uv-icon 
            name="checkmark-circle-fill" 
            :color="selectedPayment === 'wechat' ? '#4285f4' : '#ccc'" 
            size="20"
          ></uv-icon>
        </view>
        
        <!-- 支付宝支付 - 仅H5显示 -->
        <view 
          v-if="showAlipay"
          class="payment-item" 
          :class="{ active: selectedPayment === 'alipay' }"
          @click="selectPayment('alipay')"
        >
          <view class="payment-info">
            <uv-icon name="/static/imgs/alipay.png" color="#1677ff" size="28"></uv-icon>
            <view class="payment-details">
              <view class="payment-name">支付宝</view>
              <view class="payment-desc">便民生活，轻松支付</view>
            </view>
          </view>
          <uv-icon 
            name="checkmark-circle-fill" 
            :color="selectedPayment === 'alipay' ? '#4285f4' : '#ccc'" 
            size="20"
          ></uv-icon>
        </view>
      </view>
    </view>

    <!-- 充值说明 -->
    <view class="notice-section">
      <view class="section-title">充值说明</view>
      <view class="notice-list">
        <view class="notice-item">
          <uv-icon name="info-circle" color="#999" size="16"></uv-icon>
          <text class="notice-text">充值金额将实时到账，可用于购买会员服务</text>
        </view>
        <view class="notice-item">
          <uv-icon name="info-circle" color="#999" size="16"></uv-icon>
          <text class="notice-text">充值金额不可提现，请根据需要合理充值</text>
        </view>
        <view class="notice-item">
          <uv-icon name="info-circle" color="#999" size="16"></uv-icon>
          <text class="notice-text">如有疑问，请联系客服处理</text>
        </view>
      </view>
    </view>

    <!-- 底部充值按钮 -->
    <view class="bottom-section">
      <view class="recharge-info">
        <text class="recharge-text">充值金额：¥{{ finalAmount }}</text>
        <!-- <text v-if="bonusAmount > 0" class="bonus-text">（含赠送¥{{ bonusAmount }}）</text> -->
      </view>
      <uv-button 
        type="primary" 
        size="large" 
        @click="confirmRecharge"
        :loading="recharging"
        :disabled="finalAmount <= 0"
      >
        立即充值
      </uv-button>
    </view>
  </view>
</template>

<script setup>
import { ref, computed, onMounted } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { useAuthStore, useUserStore } from "@/store";
import RPC from "@/utils/request";

const authStore = useAuthStore();
const userStore = useUserStore();

// 响应式数据
const currentBalance = ref(50.00);
const selectedAmount = ref(0);
const customAmount = ref('');
const selectedPayment = ref('wechat');
const recharging = ref(false);
const showAlipay = ref(true);

// 充值金额选项
const rechargeAmounts = ref([
  { value: 10, bonus: 0 },
  { value: 50, bonus: 0 },
  { value: 100, bonus: 0 },
  { value: 200, bonus: 0 },
  { value: 500, bonus: 0 },
  { value: 1000, bonus: 0 }
]);

// 计算最终充值金额
const finalAmount = computed(() => {
  if (customAmount.value && parseFloat(customAmount.value) > 0) {
    return parseFloat(customAmount.value);
  }
  return selectedAmount.value;
});

// 计算赠送金额
const bonusAmount = computed(() => {
  if (selectedAmount.value > 0) {
    const selected = rechargeAmounts.value.find(item => item.value === selectedAmount.value);
    return selected ? selected.bonus : 0;
  }
  return 0;
});

// 选择充值金额
const selectAmount = (amount) => {
  selectedAmount.value = amount;
  customAmount.value = '';
};

// 自定义金额输入
const onCustomAmountInput = () => {
  selectedAmount.value = 0;
  
  // 限制输入范围
  const amount = parseFloat(customAmount.value);
  if (amount > 50000) {
    customAmount.value = '50000';
    uni.showToast({
      title: '充值金额不能超过50000元',
      icon: 'none'
    });
  }
};

// 选择支付方式
const selectPayment = (payment) => {
  selectedPayment.value = payment;
};

// 检查环境
const checkEnvironment = () => {
  // #ifdef MP-WEIXIN
  // 微信小程序环境，隐藏支付宝选项
  showAlipay.value = false;
  selectedPayment.value = 'wechat';
  // #endif
  
  // #ifdef H5
  // H5环境，显示所有支付选项
  showAlipay.value = true;
  // 如果在微信浏览器内，默认选择微信支付
  const ua = navigator.userAgent.toLowerCase();
  const isWechat = ua.indexOf('micromessenger') !== -1;
  selectedPayment.value = isWechat ? 'wechat' : 'alipay';
  // #endif
};

// 微信支付
const wechatPay = async (orderInfo) => {
  // #ifdef MP-WEIXIN
  // 微信小程序支付
  try {
    const paymentResult = await uni.requestPayment({
      provider: 'wxpay',
      timeStamp: orderInfo.timeStamp,
      nonceStr: orderInfo.nonceStr,
      package: orderInfo.package,
      signType: orderInfo.signType,
      paySign: orderInfo.paySign
    });
    
    console.log('微信支付成功:', paymentResult);
    return { success: true, data: paymentResult };
  } catch (error) {
    console.error('微信支付失败:', error);
    if (error.errMsg === 'requestPayment:fail cancel') {
      throw new Error('用户取消支付');
    }
    throw new Error('微信支付失败');
  }
  // #endif

  // #ifdef H5
  // H5微信支付
  if (typeof WeixinJSBridge !== 'undefined') {
    return new Promise((resolve, reject) => {
      WeixinJSBridge.invoke('getBrandWCPayRequest', {
        appId: orderInfo.appId,
        timeStamp: orderInfo.timeStamp,
        nonceStr: orderInfo.nonceStr,
        package: orderInfo.package,
        signType: orderInfo.signType,
        paySign: orderInfo.paySign
      }, (res) => {
        if (res.err_msg === 'get_brand_wcpay_request:ok') {
          resolve({ success: true, data: res });
        } else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
          reject(new Error('用户取消支付'));
        } else {
          reject(new Error('微信支付失败'));
        }
      });
    });
  } else {
    // 不在微信环境，跳转到支付页面
    const payUrl = orderInfo.mwebUrl;
    window.location.href = payUrl;
    return { success: true, redirect: true };
  }
  // #endif
};

// 支付宝支付（仅H5环境）
const alipayPay = async (orderInfo) => {
  // #ifdef H5
  // H5支付宝支付
  const payUrl = orderInfo.payUrl;
  window.location.href = payUrl;
  return { success: true, redirect: true };
  // #endif
};

// 确认充值
const confirmRecharge = async () => {
  if (finalAmount.value <= 0) {
    uni.showToast({
      title: '请选择充值金额',
      icon: 'none'
    });
    return;
  }

  if (finalAmount.value < 1) {
    uni.showToast({
      title: '充值金额不能少于1元',
      icon: 'none'
    });
    return;
  }

  if (!selectedPayment.value) {
    uni.showToast({
      title: '请选择支付方式',
      icon: 'none'
    });
    return;
  }

  recharging.value = true;

  try {
    // 创建充值订单参数
    const orderParams = {
      type: 'recharge',
      amount: finalAmount.value,
      bonusAmount: bonusAmount.value,
      paymentMethod: selectedPayment.value,
      userId: userStore.userInfo?.id || 'mock_user_id',
      // #ifdef MP-WEIXIN
      platform: 'mp-weixin',
      // #endif
      // #ifdef H5
      platform: 'h5',
      // #endif
    };

    uni.showLoading({
      title: '正在创建订单...'
    });

    // 调用后端创建充值订单API
    // const orderResult = await RPC.post('/api/recharge/create', orderParams);
    
    // 模拟创建订单返回的数据
    const orderResult = {
      orderId: 'RECHARGE_' + Date.now(),
      amount: orderParams.amount,
      // 微信支付参数
      wechatPayInfo: {
        appId: 'wx1234567890',
        timeStamp: String(Date.now()),
        nonceStr: 'random_string_' + Date.now(),
        package: 'prepay_id=wx_prepay_id_123456',
        signType: 'RSA',
        paySign: 'mock_pay_sign_123456',
        mwebUrl: 'https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx_prepay_id_123456'
      },
      // 支付宝支付参数
      alipayInfo: {
        payUrl: 'https://openapi.alipay.com/gateway.do?mock_recharge_url'
      }
    };

    uni.hideLoading();

    // 根据支付方式调用对应的支付方法
    let paymentResult;
    
    if (selectedPayment.value === 'wechat') {
      uni.showLoading({
        title: '正在跳转微信支付...'
      });
      paymentResult = await wechatPay(orderResult.wechatPayInfo);
    } else if (selectedPayment.value === 'alipay') {
      uni.showLoading({
        title: '正在跳转支付宝...'
      });
      paymentResult = await alipayPay(orderResult.alipayInfo);
    }

    uni.hideLoading();

    // 处理支付结果
    if (paymentResult.success) {
      if (paymentResult.redirect) {
        // H5跳转支付
        uni.showToast({
          title: '正在跳转支付页面...',
          icon: 'loading',
          duration: 2000
        });
      } else {
        // 支付成功
        uni.showToast({
          title: '充值成功',
          icon: 'success'
        });

        // 更新余额
        currentBalance.value += finalAmount.value + bonusAmount.value;
        
        // 重置选择
        selectedAmount.value = 0;
        customAmount.value = '';

        // 延迟返回上一页
        setTimeout(() => {
          uni.navigateBack();
        }, 1500);
      }
    }

  } catch (error) {
    uni.hideLoading();
    console.error('充值失败:', error);
    
    let errorMessage = '充值失败，请重试';
    if (error.message === '用户取消支付') {
      errorMessage = '支付已取消';
    } else if (error.message) {
      errorMessage = error.message;
    }
    
    uni.showToast({
      title: errorMessage,
      icon: 'none'
    });
  } finally {
    recharging.value = false;
  }
};

// 处理支付回调
const handlePaymentCallback = () => {
  // #ifdef H5
  const urlParams = new URLSearchParams(window.location.search);
  const orderId = urlParams.get('orderId');
  const payResult = urlParams.get('payResult');
  
  if (orderId && payResult) {
    // 清理URL参数
    const url = new URL(window.location);
    url.searchParams.delete('orderId');
    url.searchParams.delete('payResult');
    window.history.replaceState({}, document.title, url.pathname + url.search);
    
    // 检查支付结果
    if (payResult === 'success') {
      uni.showToast({
        title: '充值成功',
        icon: 'success'
      });
      
      // 刷新余额
      loadUserBalance();
      
      // 重置选择
      selectedAmount.value = 0;
      customAmount.value = '';
    } else {
      uni.showToast({
        title: '充值失败或取消',
        icon: 'none'
      });
    }
  }
  // #endif
};

// 加载用户余额
const loadUserBalance = async () => {
  try {
    // 调用获取用户余额API
    // const result = await RPC.get('/api/user/balance');
    // currentBalance.value = result.data.balance;
  } catch (error) {
    console.error('加载余额失败:', error);
  }
};

onMounted(() => {
  checkEnvironment();
  loadUserBalance();
  handlePaymentCallback();
});

onShow(() => {
  handlePaymentCallback();
});
</script>

<style lang="scss" scoped>
.container {
  min-height: 100vh;
  background-color: #f8f8f8;
  padding-bottom: 120px;
}

.balance-section {
  padding: 20px 16px;
  background: linear-gradient(135deg, #4285f4 0%, #6fa8f5 100%);
  
  .balance-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    padding: 20px;
    
    .balance-info {
      .balance-label {
        color: rgba(255, 255, 255, 0.8);
        font-size: 14px;
        margin-bottom: 8px;
      }
      
      .balance-amount {
        color: white;
        font-size: 32px;
        font-weight: bold;
      }
    }
    
    .balance-icon {
      opacity: 0.8;
    }
  }
}

.recharge-section,
.payment-section,
.notice-section {
  margin: 16px;
  background: white;
  border-radius: 12px;
  padding: 20px;
  
  .section-title {
    font-size: 16px;
    font-weight: bold;
    color: #333;
    margin-bottom: 16px;
  }
}

.amount-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-bottom: 20px;
  
  .amount-item {
    background: #f8f9fa;
    border: 2px solid transparent;
    border-radius: 8px;
    padding: 16px 8px;
    text-align: center;
    transition: all 0.3s;
    
    &.active {
      border-color: #4285f4;
      background-color: #f0f7ff;
    }
    
    .amount-value {
      font-size: 18px;
      font-weight: bold;
      color: #333;
      margin-bottom: 4px;
    }
    
    .amount-bonus {
      font-size: 12px;
      color: #ff4d4f;
    }
  }
}

.custom-amount {
  .custom-label {
    font-size: 14px;
    color: #666;
    margin-bottom: 12px;
  }
  
  .custom-input {
    display: flex;
    align-items: center;
    background: #f8f9fa;
    border-radius: 8px;
    padding: 0 16px;
    margin-bottom: 8px;
    
    .currency {
      font-size: 18px;
      color: #333;
      margin-right: 8px;
    }
    
    .amount-input {
      flex: 1;
      height: 48px;
      font-size: 16px;
      border: none;
      background: transparent;
    }
  }
  
  .amount-tips {
    font-size: 12px;
    color: #999;
  }
}

.payment-list {
  .payment-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px;
    border: 1px solid #e5e5e5;
    border-radius: 8px;
    margin-bottom: 12px;
    transition: all 0.3s;
    
    &.active {
      border-color: #4285f4;
      background-color: #f0f7ff;
    }
    
    &:last-child {
      margin-bottom: 0;
    }
    
    .payment-info {
      display: flex;
      align-items: center;
      gap: 12px;
      
      .payment-details {
        .payment-name {
          font-size: 16px;
          color: #333;
          margin-bottom: 4px;
        }
        
        .payment-desc {
          font-size: 12px;
          color: #999;
        }
      }
    }
  }
}

.notice-list {
  .notice-item {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-bottom: 12px;
    
    &:last-child {
      margin-bottom: 0;
    }
    
    .notice-text {
      flex: 1;
      font-size: 13px;
      color: #666;
      line-height: 1.4;
    }
  }
}

.bottom-section {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: white;
  padding: 16px;
  border-top: 1px solid #e5e5e5;
  
  .recharge-info {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 12px;
    
    .recharge-text {
      font-size: 16px;
      color: #333;
      font-weight: 500;
    }
    
    .bonus-text {
      font-size: 14px;
      color: #ff4d4f;
      margin-left: 4px;
    }
  }
}
</style>cK5xB 		/51>BVMMqeՖ40000 pagesA SrYd)^)vRdAYx A}{U [o0x% 100644 order.vue Wl}\_e`sSl	x [[(al#[x =]f!4iqyWQsx/ 100644 generate-record.vue t[2Gޓh_#s};x" BBisi	ܔxZ 		/5jʲJĩ NFX|40000 pagesA {-n6& }dPFX]e.;u&(fNE~<
!x <40000 404 WȽ߯ DYQ{A40000 consumption O_K({40000 index &{+sOy4S40000 login QNK_p_2n
40000 mine 濠ITʊ640000 order \}@E:m[*Ux+ 100644 consumption.vue $&AzUjLkx% 100644 login.vue "V[\e0ēLL7x7[
    q-!  'd//   uni.login({
		//     provider: "weixin",
		//     success: (loginRes) => {
		//       console.log("微信登录成功:", loginRes);
		//       // @-//       uni.getUserProfile({
		//         desc: "用于完善用户资料",
		//         success: (userRes) => {
		//      H     console.log("获取用户信息成功:", userRes);
		//           ."//           showBindPhoneModalq        },
		//         fail: (err) => {
		//           console.error("获取用户信息失败:", err);
		//           uni.showToast({
		//             title: "获取用户信息失败",
		//             icon: "none",
		//           });
		//     K    },
		//       });
		//     },
		//     fail: (err) => {
		//       A0登录失败:", err);
		//       uni.showToast({
		//         title: "微信登录失败",
		//         icon: "none",
		// $      });
		//     },
		//   });
PwechatH5Login(0@YOUR_WECHAT_APP_ID&0-'"6#
			-'	const userInfo = {
			-+. '.-
	};

			d.F.$Q;

			."/+n/_/n/'/%// 	);
			0"%G>$S'g&		if (code && showWechatLogin.value) {''

		v?(??g]n[x% 100644 order.vue 	i;2UjW=_7*Nx ;40000 edit-profile  Фmlzb6X6e40000 generate-record 
l}Iv40000 order-detail .l2D2Wu(=#C0d40000 recharge Qf$7A40000 user-agreement 0bA~kkQ:x, 100644 edit-profile.vue u6P,P@*NAxec电话~3	editPhone}'话9sXiyD}Nc
iDX
Info.value
Info.valueF
Info.valuef

  // 验证格式
  if (editType.value === "phone" && !/^1[3-9]\d{9}$/.test(editValue.value)) {
#:正确的手机号Q2o

  if (
    editType.value === "email" &&
    !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(editValue.value)
  ) {
#:正确的邮箱地址Q2
l( 2 -b ,  // })

   9#!
K});

 \!(&!#!&W'"Яx/ 100644 generate-record.vue A8#mC<a6x/x\ BA
  // #ifndef H5"Precord.result_url	"DsaveFile({
          tempF^wx( 100644 recharge.vue }.Z&^-{p]xp ̆I	!X
CS:5 },
  { value: 200, bonus: 15 },
  { value: 500, bonus: 512a."Cx& 100644 regions.js Χ	q`㧴#^tx   export const regions = [{"id":"35","name":"河北省","code":"130000","parentId":"0","children":[{"id":"36","name":"石家庄市","code":"130100","parentId":"35","children":[{"id":"37","name":"长安区","code":"130102","parentId":"36"},{"id":"38","name":"桥西区","code":"130104","parentId":"36"},{"id":"39","name":"新华区","code":"130105","parentId":"36"},{"id":"40","name":"井陉矿区","code":"130107","parentId":"36"},{"id":"41","name":"裕华区","code":"130108","parentId":"36"},{"id":"42","name":"藁城区","code":"130109","parentId":"36"},{"id":"43","name":"鹿泉区","code":"130110","parentId":"36"},{"id":"44","name":"栾城区","code":"130111","parentId":"36"},{"id":"45","name":"井陉县","code":"130121","parentId":"36"},{"id":"46","name":"正定县","code":"130123","parentId":"36"},{"id":"47","name":"行唐县","code":"130125","parentId":"36"},{"id":"48","name":"灵寿县","code":"130126","parentId":"36"},{"id":"49","name":"高邑县","code":"130127","parentId":"36"},{"id":"50","name":"深泽县","code":"130128","parentId":"36"},{"id":"51","name":"赞皇县","code":"130129","parentId":"36"},{"id":"52","name":"无极县","code":"130130","parentId":"36"},{"id":"53","name":"平山县","code":"130131","parentId":"36"},{"id":"54","name":"元氏县","code":"130132","parentId":"36"},{"id":"55","name":"赵县","code":"130133","parentId":"36"},{"id":"56","name":"辛集市","code":"130181","parentId":"36"},{"id":"57","name":"晋州市","code":"130183","parentId":"36"},{"id":"58","name":"新乐市","code":"130184","parentId":"36"}]},{"id":"59","name":"唐山市","code":"130200","parentId":"35","children":[{"id":"60","name":"路南区","code":"130202","parentId":"59"},{"id":"61","name":"路北区","code":"130203","parentId":"59"},{"id":"62","name":"古冶区","code":"130204","parentId":"59"},{"id":"63","name":"开平区","code":"130205","parentId":"59"},{"id":"64","name":"丰南区","code":"130207","parentId":"59"},{"id":"65","name":"丰润区","code":"130208","parentId":"59"},{"id":"66","name":"曹妃甸区","code":"130209","parentId":"59"},{"id":"67","name":"滦县","code":"130223","parentId":"59"},{"id":"68","name":"滦南县","code":"130224","parentId":"59"},{"id":"69","name":"乐亭县","code":"130225","parentId":"59"},{"id":"70","name":"迁西县","code":"130227","parentId":"59"},{"id":"71","name":"玉田县","code":"130229","parentId":"59"},{"id":"72","name":"遵化市","code":"130281","parentId":"59"},{"id":"73","name":"迁安市","code":"130283","parentId":"59"}]},{"id":"74","name":"秦皇岛市","code":"130300","parentId":"35","children":[{"id":"75","name":"海港区","code":"130302","parentId":"74"},{"id":"76","name":"山海关区","code":"130303","parentId":"74"},{"id":"77","name":"北戴河区","code":"130304","parentId":"74"},{"id":"78","name":"抚宁区","code":"130306","parentId":"74"},{"id":"79","name":"青龙满族自治县","code":"130321","parentId":"74"},{"id":"80","name":"昌黎县","code":"130322","parentId":"74"},{"id":"81","name":"卢龙县","code":"130324","parentId":"74"}]},{"id":"82","name":"邯郸市","code":"130400","parentId":"35","children":[{"id":"83","name":"邯山区","code":"130402","parentId":"82"},{"id":"84","name":"丛台区","code":"130403","parentId":"82"},{"id":"85","name":"复兴区","code":"130404","parentId":"82"},{"id":"86","name":"峰峰矿区","code":"130406","parentId":"82"},{"id":"87","name":"肥乡区","code":"130407","parentId":"82"},{"id":"88","name":"永年区","code":"130408","parentId":"82"},{"id":"89","name":"临漳县","code":"130423","parentId":"82"},{"id":"90","name":"成安县","code":"130424","parentId":"82"},{"id":"91","name":"大名县","code":"130425","parentId":"82"},{"id":"92","name":"涉县","code":"130426","parentId":"82"},{"id":"93","name":"磁县","code":"130427","parentId":"82"},{"id":"94","name":"邱县","code":"130430","parentId":"82"},{"id":"95","name":"鸡泽县","code":"130431","parentId":"82"},{"id":"96","name":"广平县","code":"130432","parentId":"82"},{"id":"97","name":"馆陶县","code":"130433","parentId":"82"},{"id":"98","name":"魏县","code":"130434","parentId":"82"},{"id":"99","name":"曲周县","code":"130435","parentId":"82"},{"id":"100","name":"武安市","code":"130481","parentId":"82"}]},{"id":"101","name":"邢台市","code":"130500","parentId":"35","children":[{"id":"102","name":"桥东区","code":"130502","parentId":"101"},{"id":"103","name":"桥西区","code":"130503","parentId":"101"},{"id":"104","name":"邢台县","code":"130521","parentId":"101"},{"id":"105","name":"临城县","code":"130522","parentId":"101"},{"id":"106","name":"内丘县","code":"130523","parentId":"101"},{"id":"107","name":"柏乡县","code":"130524","parentId":"101"},{"id":"108","name":"隆尧县","code":"130525","parentId":"101"},{"id":"109","name":"任县","code":"130526","parentId":"101"},{"id":"110","name":"南和县","code":"130527","parentId":"101"},{"id":"111","name":"宁晋县","code":"130528","parentId":"101"},{"id":"112","name":"巨鹿县","code":"130529","parentId":"101"},{"id":"113","name":"新河县","code":"130530","parentId":"101"},{"id":"114","name":"广宗县","code":"130531","parentId":"101"},{"id":"115","name":"平乡县","code":"130532","parentId":"101"},{"id":"116","name":"威县","code":"130533","parentId":"101"},{"id":"117","name":"清河县","code":"130534","parentId":"101"},{"id":"118","name":"临西县","code":"130535","parentId":"101"},{"id":"119","name":"南宫市","code":"130581","parentId":"101"},{"id":"120","name":"沙河市","code":"130582","parentId":"101"}]},{"id":"121","name":"保定市","code":"130600","parentId":"35","children":[{"id":"122","name":"竞秀区","code":"130602","parentId":"121"},{"id":"123","name":"莲池区","code":"130606","parentId":"121"},{"id":"124","name":"满城区","code":"130607","parentId":"121"},{"id":"125","name":"清苑区","code":"130608","parentId":"121"},{"id":"126","name":"徐水区","code":"130609","parentId":"121"},{"id":"127","name":"涞水县","code":"130623","parentId":"121"},{"id":"128","name":"阜平县","code":"130624","parentId":"121"},{"id":"129","name":"定兴县","code":"130626","parentId":"121"},{"id":"130","name":"唐县","code":"130627","parentId":"121"},{"id":"131","name":"高阳县","code":"130628","parentId":"121"},{"id":"132","name":"容城县","code":"130629","parentId":"121"},{"id":"133","name":"涞源县","code":"130630","parentId":"121"},{"id":"134","name":"望都县","code":"130631","parentId":"121"},{"id":"135","name":"安新县","code":"130632","parentId":"121"},{"id":"136","name":"易县","code":"130633","parentId":"121"},{"id":"137","name":"曲阳县","code":"130634","parentId":"121"},{"id":"138","name":"蠡县","code":"130635","parentId":"121"},{"id":"139","name":"顺平县","code":"130636","parentId":"121"},{"id":"140","name":"博野县","code":"130637","parentId":"121"},{"id":"141","name":"雄县","code":"130638","parentId":"121"},{"id":"142","name":"涿州市","code":"130681","parentId":"121"},{"id":"143","name":"定州市","code":"130682","parentId":"121"},{"id":"144","name":"安国市","code":"130683","parentId":"121"},{"id":"145","name":"高碑店市","code":"130684","parentId":"121"}]},{"id":"146","name":"张家口市","code":"130700","parentId":"35","children":[{"id":"147","name":"桥东区","code":"130702","parentId":"146"},{"id":"148","name":"桥西区","code":"130703","parentId":"146"},{"id":"149","name":"宣化区","code":"130705","parentId":"146"},{"id":"150","name":"下花园区","code":"130706","parentId":"146"},{"id":"151","name":"万全区","code":"130708","parentId":"146"},{"id":"152","name":"崇礼区","code":"130709","parentId":"146"},{"id":"153","name":"张北县","code":"130722","parentId":"146"},{"id":"154","name":"康保县","code":"130723","parentId":"146"},{"id":"155","name":"沽源县","code":"130724","parentId":"146"},{"id":"156","name":"尚义县","code":"130725","parentId":"146"},{"id":"157","name":"蔚县","code":"130726","parentId":"146"},{"id":"158","name":"阳原县","code":"130727","parentId":"146"},{"id":"159","name":"怀安县","code":"130728","parentId":"146"},{"id":"160","name":"怀来县","code":"130730","parentId":"146"},{"id":"161","name":"涿鹿县","code":"130731","parentId":"146"},{"id":"162","name":"赤城县","code":"130732","parentId":"146"}]},{"id":"163","name":"承德市","code":"130800","parentId":"35","children":[{"id":"164","name":"双桥区","code":"130802","parentId":"163"},{"id":"165","name":"双滦区","code":"130803","parentId":"163"},{"id":"166","name":"鹰手营子矿区","code":"130804","parentId":"163"},{"id":"167","name":"承德县","code":"130821","parentId":"163"},{"id":"168","name":"兴隆县","code":"130822","parentId":"163"},{"id":"169","name":"滦平县","code":"130824","parentId":"163"},{"id":"170","name":"隆化县","code":"130825","parentId":"163"},{"id":"171","name":"丰宁满族自治县","code":"130826","parentId":"163"},{"id":"172","name":"宽城满族自治县","code":"130827","parentId":"163"},{"id":"173","name":"围场满族蒙古族自治县","code":"130828","parentId":"163"},{"id":"174","name":"平泉市","code":"130881","parentId":"163"}]},{"id":"175","name":"沧州市","code":"130900","parentId":"35","children":[{"id":"176","name":"新华区","code":"130902","parentId":"175"},{"id":"177","name":"运河区","code":"130903","parentId":"175"},{"id":"178","name":"沧县","code":"130921","parentId":"175"},{"id":"179","name":"青县","code":"130922","parentId":"175"},{"id":"180","name":"东光县","code":"130923","parentId":"175"},{"id":"181","name":"海兴县","code":"130924","parentId":"175"},{"id":"182","name":"盐山县","code":"130925","parentId":"175"},{"id":"183","name":"肃宁县","code":"130926","parentId":"175"},{"id":"184","name":"南皮县","code":"130927","parentId":"175"},{"id":"185","name":"吴桥县","code":"130928","parentId":"175"},{"id":"186","name":"献县","code":"130929","parentId":"175"},{"id":"187","name":"孟村回族自治县","code":"130930","parentId":"175"},{"id":"188","name":"泊头市","code":"130981","parentId":"175"},{"id":"189","name":"任丘市","code":"130982","parentId":"175"},{"id":"190","name":"黄骅市","code":"130983","parentId":"175"},{"id":"191","name":"河间市","code":"130984","parentId":"175"}]},{"id":"192","name":"廊坊市","code":"131000","parentId":"35","children":[{"id":"193","name":"安次区","code":"131002","parentId":"192"},{"id":"194","name":"广阳区","code":"131003","parentId":"192"},{"id":"195","name":"固安县","code":"131022","parentId":"192"},{"id":"196","name":"永清县","code":"131023","parentId":"192"},{"id":"197","name":"香河县","code":"131024","parentId":"192"},{"id":"198","name":"大城县","code":"131025","parentId":"192"},{"id":"199","name":"文安县","code":"131026","parentId":"192"},{"id":"200","name":"大厂回族自治县","code":"131028","parentId":"192"},{"id":"201","name":"霸州市","code":"131081","parentId":"192"},{"id":"202","name":"三河市","code":"131082","parentId":"192"}]},{"id":"203","name":"衡水市","code":"131100","parentId":"35","children":[{"id":"204","name":"桃城区","code":"131102","parentId":"203"},{"id":"205","name":"冀州区","code":"131103","parentId":"203"},{"id":"206","name":"枣强县","code":"131121","parentId":"203"},{"id":"207","name":"武邑县","code":"131122","parentId":"203"},{"id":"208","name":"武强县","code":"131123","parentId":"203"},{"id":"209","name":"饶阳县","code":"131124","parentId":"203"},{"id":"210","name":"安平县","code":"131125","parentId":"203"},{"id":"211","name":"故城县","code":"131126","parentId":"203"},{"id":"212","name":"景县","code":"131127","parentId":"203"},{"id":"213","name":"阜城县","code":"131128","parentId":"203"},{"id":"214","name":"深州市","code":"131182","parentId":"203"}]}]},{"id":"215","name":"山西省","code":"140000","parentId":"0","children":[{"id":"216","name":"太原市","code":"140100","parentId":"215","children":[{"id":"217","name":"小店区","code":"140105","parentId":"216"},{"id":"218","name":"迎泽区","code":"140106","parentId":"216"},{"id":"219","name":"杏花岭区","code":"140107","parentId":"216"},{"id":"220","name":"尖草坪区","code":"140108","parentId":"216"},{"id":"221","name":"万柏林区","code":"140109","parentId":"216"},{"id":"222","name":"晋源区","code":"140110","parentId":"216"},{"id":"223","name":"清徐县","code":"140121","parentId":"216"},{"id":"224","name":"阳曲县","code":"140122","parentId":"216"},{"id":"225","name":"娄烦县","code":"140123","parentId":"216"},{"id":"226","name":"古交市","code":"140181","parentId":"216"}]},{"id":"227","name":"大同市","code":"140200","parentId":"215","children":[{"id":"228","name":"城区","code":"140202","parentId":"227"},{"id":"229","name":"矿区","code":"140203","parentId":"227"},{"id":"230","name":"南郊区","code":"140211","parentId":"227"},{"id":"231","name":"新荣区","code":"140212","parentId":"227"},{"id":"232","name":"阳高县","code":"140221","parentId":"227"},{"id":"233","name":"天镇县","code":"140222","parentId":"227"},{"id":"234","name":"广灵县","code":"140223","parentId":"227"},{"id":"235","name":"灵丘县","code":"140224","parentId":"227"},{"id":"236","name":"浑源县","code":"140225","parentId":"227"},{"id":"237","name":"左云县","code":"140226","parentId":"227"},{"id":"238","name":"大同县","code":"140227","parentId":"227"}]},{"id":"239","name":"阳泉市","code":"140300","parentId":"215","children":[{"id":"240","name":"城区","code":"140302","parentId":"239"},{"id":"241","name":"矿区","code":"140303","parentId":"239"},{"id":"242","name":"郊区","code":"140311","parentId":"239"},{"id":"243","name":"平定县","code":"140321","parentId":"239"},{"id":"244","name":"盂县","code":"140322","parentId":"239"}]},{"id":"245","name":"长治市","code":"140400","parentId":"215","children":[{"id":"246","name":"城区","code":"140402","parentId":"245"},{"id":"247","name":"郊区","code":"140411","parentId":"245"},{"id":"248","name":"长治县","code":"140421","parentId":"245"},{"id":"249","name":"襄垣县","code":"140423","parentId":"245"},{"id":"250","name":"屯留县","code":"140424","parentId":"245"},{"id":"251","name":"平顺县","code":"140425","parentId":"245"},{"id":"252","name":"黎城县","code":"140426","parentId":"245"},{"id":"253","name":"壶关县","code":"140427","parentId":"245"},{"id":"254","name":"长子县","code":"140428","parentId":"245"},{"id":"255","name":"武乡县","code":"140429","parentId":"245"},{"id":"256","name":"沁县","code":"140430","parentId":"245"},{"id":"257","name":"沁源县","code":"140431","parentId":"245"},{"id":"258","name":"潞城市","code":"140481","parentId":"245"}]},{"id":"259","name":"晋城市","code":"140500","parentId":"215","children":[{"id":"260","name":"城区","code":"140502","parentId":"259"},{"id":"261","name":"沁水县","code":"140521","parentId":"259"},{"id":"262","name":"阳城县","code":"140522","parentId":"259"},{"id":"263","name":"陵川县","code":"140524","parentId":"259"},{"id":"264","name":"泽州县","code":"140525","parentId":"259"},{"id":"265","name":"高平市","code":"140581","parentId":"259"}]},{"id":"266","name":"朔州市","code":"140600","parentId":"215","children":[{"id":"267","name":"朔城区","code":"140602","parentId":"266"},{"id":"268","name":"平鲁区","code":"140603","parentId":"266"},{"id":"269","name":"山阴县","code":"140621","parentId":"266"},{"id":"270","name":"应县","code":"140622","parentId":"266"},{"id":"271","name":"右玉县","code":"140623","parentId":"266"},{"id":"272","name":"怀仁县","code":"140624","parentId":"266"}]},{"id":"273","name":"晋中市","code":"140700","parentId":"215","children":[{"id":"274","name":"榆次区","code":"140702","parentId":"273"},{"id":"275","name":"榆社县","code":"140721","parentId":"273"},{"id":"276","name":"左权县","code":"140722","parentId":"273"},{"id":"277","name":"和顺县","code":"140723","parentId":"273"},{"id":"278","name":"昔阳县","code":"140724","parentId":"273"},{"id":"279","name":"寿阳县","code":"140725","parentId":"273"},{"id":"280","name":"太谷县","code":"140726","parentId":"273"},{"id":"281","name":"祁县","code":"140727","parentId":"273"},{"id":"282","name":"平遥县","code":"140728","parentId":"273"},{"id":"283","name":"灵石县","code":"140729","parentId":"273"},{"id":"284","name":"介休市","code":"140781","parentId":"273"}]},{"id":"285","name":"运城市","code":"140800","parentId":"215","children":[{"id":"286","name":"盐湖区","code":"140802","parentId":"285"},{"id":"287","name":"临猗县","code":"140821","parentId":"285"},{"id":"288","name":"万荣县","code":"140822","parentId":"285"},{"id":"289","name":"闻喜县","code":"140823","parentId":"285"},{"id":"290","name":"稷山县","code":"140824","parentId":"285"},{"id":"291","name":"新绛县","code":"140825","parentId":"285"},{"id":"292","name":"绛县","code":"140826","parentId":"285"},{"id":"293","name":"垣曲县","code":"140827","parentId":"285"},{"id":"294","name":"夏县","code":"140828","parentId":"285"},{"id":"295","name":"平陆县","code":"140829","parentId":"285"},{"id":"296","name":"芮城县","code":"140830","parentId":"285"},{"id":"297","name":"永济市","code":"140881","parentId":"285"},{"id":"298","name":"河津市","code":"140882","parentId":"285"}]},{"id":"299","name":"忻州市","code":"140900","parentId":"215","children":[{"id":"300","name":"忻府区","code":"140902","parentId":"299"},{"id":"301","name":"定襄县","code":"140921","parentId":"299"},{"id":"302","name":"五台县","code":"140922","parentId":"299"},{"id":"303","name":"代县","code":"140923","parentId":"299"},{"id":"304","name":"繁峙县","code":"140924","parentId":"299"},{"id":"305","name":"宁武县","code":"140925","parentId":"299"},{"id":"306","name":"静乐县","code":"140926","parentId":"299"},{"id":"307","name":"神池县","code":"140927","parentId":"299"},{"id":"308","name":"五寨县","code":"140928","parentId":"299"},{"id":"309","name":"岢岚县","code":"140929","parentId":"299"},{"id":"310","name":"河曲县","code":"140930","parentId":"299"},{"id":"311","name":"保德县","code":"140931","parentId":"299"},{"id":"312","name":"偏关县","code":"140932","parentId":"299"},{"id":"313","name":"原平市","code":"140981","parentId":"299"}]},{"id":"314","name":"临汾市","code":"141000","parentId":"215","children":[{"id":"315","name":"尧都区","code":"141002","parentId":"314"},{"id":"316","name":"曲沃县","code":"141021","parentId":"314"},{"id":"317","name":"翼城县","code":"141022","parentId":"314"},{"id":"318","name":"襄汾县","code":"141023","parentId":"314"},{"id":"319","name":"洪洞县","code":"141024","parentId":"314"},{"id":"320","name":"古县","code":"141025","parentId":"314"},{"id":"321","name":"安泽县","code":"141026","parentId":"314"},{"id":"322","name":"浮山县","code":"141027","parentId":"314"},{"id":"323","name":"吉县","code":"141028","parentId":"314"},{"id":"324","name":"乡宁县","code":"141029","parentId":"314"},{"id":"325","name":"大宁县","code":"141030","parentId":"314"},{"id":"326","name":"隰县","code":"141031","parentId":"314"},{"id":"327","name":"永和县","code":"141032","parentId":"314"},{"id":"328","name":"蒲县","code":"141033","parentId":"314"},{"id":"329","name":"汾西县","code":"141034","parentId":"314"},{"id":"330","name":"侯马市","code":"141081","parentId":"314"},{"id":"331","name":"霍州市","code":"141082","parentId":"314"}]},{"id":"332","name":"吕梁市","code":"141100","parentId":"215","children":[{"id":"333","name":"离石区","code":"141102","parentId":"332"},{"id":"334","name":"文水县","code":"141121","parentId":"332"},{"id":"335","name":"交城县","code":"141122","parentId":"332"},{"id":"336","name":"兴县","code":"141123","parentId":"332"},{"id":"337","name":"临县","code":"141124","parentId":"332"},{"id":"338","name":"柳林县","code":"141125","parentId":"332"},{"id":"339","name":"石楼县","code":"141126","parentId":"332"},{"id":"340","name":"岚县","code":"141127","parentId":"332"},{"id":"341","name":"方山县","code":"141128","parentId":"332"},{"id":"342","name":"中阳县","code":"141129","parentId":"332"},{"id":"343","name":"交口县","code":"141130","parentId":"332"},{"id":"344","name":"孝义市","code":"141181","parentId":"332"},{"id":"345","name":"汾阳市","code":"141182","parentId":"332"}]}]},{"id":"346","name":"内蒙古自治区","code":"150000","parentId":"0","children":[{"id":"347","name":"呼和浩特市","code":"150100","parentId":"346","children":[{"id":"348","name":"新城区","code":"150102","parentId":"347"},{"id":"349","name":"回民区","code":"150103","parentId":"347"},{"id":"350","name":"玉泉区","code":"150104","parentId":"347"},{"id":"351","name":"赛罕区","code":"150105","parentId":"347"},{"id":"352","name":"土默特左旗","code":"150121","parentId":"347"},{"id":"353","name":"托克托县","code":"150122","parentId":"347"},{"id":"354","name":"和林格尔县","code":"150123","parentId":"347"},{"id":"355","name":"清水河县","code":"150124","parentId":"347"},{"id":"356","name":"武川县","code":"150125","parentId":"347"}]},{"id":"357","name":"包头市","code":"150200","parentId":"346","children":[{"id":"358","name":"东河区","code":"150202","parentId":"357"},{"id":"359","name":"昆都仑区","code":"150203","parentId":"357"},{"id":"360","name":"青山区","code":"150204","parentId":"357"},{"id":"361","name":"石拐区","code":"150205","parentId":"357"},{"id":"362","name":"白云鄂博矿区","code":"150206","parentId":"357"},{"id":"363","name":"九原区","code":"150207","parentId":"357"},{"id":"364","name":"土默特右旗","code":"150221","parentId":"357"},{"id":"365","name":"固阳县","code":"150222","parentId":"357"},{"id":"366","name":"达尔罕茂明安联合旗","code":"150223","parentId":"357"}]},{"id":"367","name":"乌海市","code":"150300","parentId":"346","children":[{"id":"368","name":"海勃湾区","code":"150302","parentId":"367"},{"id":"369","name":"海南区","code":"150303","parentId":"367"},{"id":"370","name":"乌达区","code":"150304","parentId":"367"}]},{"id":"371","name":"赤峰市","code":"150400","parentId":"346","children":[{"id":"372","name":"红山区","code":"150402","parentId":"371"},{"id":"373","name":"元宝山区","code":"150403","parentId":"371"},{"id":"374","name":"松山区","code":"150404","parentId":"371"},{"id":"375","name":"阿鲁科尔沁旗","code":"150421","parentId":"371"},{"id":"376","name":"巴林左旗","code":"150422","parentId":"371"},{"id":"377","name":"巴林右旗","code":"150423","parentId":"371"},{"id":"378","name":"林西县","code":"150424","parentId":"371"},{"id":"379","name":"克什克腾旗","code":"150425","parentId":"371"},{"id":"380","name":"翁牛特旗","code":"150426","parentId":"371"},{"id":"381","name":"喀喇沁旗","code":"150428","parentId":"371"},{"id":"382","name":"宁城县","code":"150429","parentId":"371"},{"id":"383","name":"敖汉旗","code":"150430","parentId":"371"}]},{"id":"384","name":"通辽市","code":"150500","parentId":"346","children":[{"id":"385","name":"科尔沁区","code":"150502","parentId":"384"},{"id":"386","name":"科尔沁左翼中旗","code":"150521","parentId":"384"},{"id":"387","name":"科尔沁左翼后旗","code":"150522","parentId":"384"},{"id":"388","name":"开鲁县","code":"150523","parentId":"384"},{"id":"389","name":"库伦旗","code":"150524","parentId":"384"},{"id":"390","name":"奈曼旗","code":"150525","parentId":"384"},{"id":"391","name":"扎鲁特旗","code":"150526","parentId":"384"},{"id":"392","name":"霍林郭勒市","code":"150581","parentId":"384"}]},{"id":"393","name":"鄂尔多斯市","code":"150600","parentId":"346","children":[{"id":"394","name":"东胜区","code":"150602","parentId":"393"},{"id":"395","name":"康巴什区","code":"150603","parentId":"393"},{"id":"396","name":"达拉特旗","code":"150621","parentId":"393"},{"id":"397","name":"准格尔旗","code":"150622","parentId":"393"},{"id":"398","name":"鄂托克前旗","code":"150623","parentId":"393"},{"id":"399","name":"鄂托克旗","code":"150624","parentId":"393"},{"id":"400","name":"杭锦旗","code":"150625","parentId":"393"},{"id":"401","name":"乌审旗","code":"150626","parentId":"393"},{"id":"402","name":"伊金霍洛旗","code":"150627","parentId":"393"}]},{"id":"403","name":"呼伦贝尔市","code":"150700","parentId":"346","children":[{"id":"404","name":"海拉尔区","code":"150702","parentId":"403"},{"id":"405","name":"扎赉诺尔区","code":"150703","parentId":"403"},{"id":"406","name":"阿荣旗","code":"150721","parentId":"403"},{"id":"407","name":"莫力达瓦达斡尔族自治旗","code":"150722","parentId":"403"},{"id":"408","name":"鄂伦春自治旗","code":"150723","parentId":"403"},{"id":"409","name":"鄂温克族自治旗","code":"150724","parentId":"403"},{"id":"410","name":"陈巴尔虎旗","code":"150725","parentId":"403"},{"id":"411","name":"新巴尔虎左旗","code":"150726","parentId":"403"},{"id":"412","name":"新巴尔虎右旗","code":"150727","parentId":"403"},{"id":"413","name":"满洲里市","code":"150781","parentId":"403"},{"id":"414","name":"牙克石市","code":"150782","parentId":"403"},{"id":"415","name":"扎兰屯市","code":"150783","parentId":"403"},{"id":"416","name":"额尔古纳市","code":"150784","parentId":"403"},{"id":"417","name":"根河市","code":"150785","parentId":"403"}]},{"id":"418","name":"巴彦淖尔市","code":"150800","parentId":"346","children":[{"id":"419","name":"临河区","code":"150802","parentId":"418"},{"id":"420","name":"五原县","code":"150821","parentId":"418"},{"id":"421","name":"磴口县","code":"150822","parentId":"418"},{"id":"422","name":"乌拉特前旗","code":"150823","parentId":"418"},{"id":"423","name":"乌拉特中旗","code":"150824","parentId":"418"},{"id":"424","name":"乌拉特后旗","code":"150825","parentId":"418"},{"id":"425","name":"杭锦后旗","code":"150826","parentId":"418"}]},{"id":"426","name":"乌兰察布市","code":"150900","parentId":"346","children":[{"id":"427","name":"集宁区","code":"150902","parentId":"426"},{"id":"428","name":"卓资县","code":"150921","parentId":"426"},{"id":"429","name":"化德县","code":"150922","parentId":"426"},{"id":"430","name":"商都县","code":"150923","parentId":"426"},{"id":"431","name":"兴和县","code":"150924","parentId":"426"},{"id":"432","name":"凉城县","code":"150925","parentId":"426"},{"id":"433","name":"察哈尔右翼前旗","code":"150926","parentId":"426"},{"id":"434","name":"察哈尔右翼中旗","code":"150927","parentId":"426"},{"id":"435","name":"察哈尔右翼后旗","code":"150928","parentId":"426"},{"id":"436","name":"四子王旗","code":"150929","parentId":"426"},{"id":"437","name":"丰镇市","code":"150981","parentId":"426"}]},{"id":"438","name":"兴安盟","code":"152200","parentId":"346","children":[{"id":"439","name":"乌兰浩特市","code":"152201","parentId":"438"},{"id":"440","name":"阿尔山市","code":"152202","parentId":"438"},{"id":"441","name":"科尔沁右翼前旗","code":"152221","parentId":"438"},{"id":"442","name":"科尔沁右翼中旗","code":"152222","parentId":"438"},{"id":"443","name":"扎赉特旗","code":"152223","parentId":"438"},{"id":"444","name":"突泉县","code":"152224","parentId":"438"}]},{"id":"445","name":"锡林郭勒盟","code":"152500","parentId":"346","children":[{"id":"446","name":"二连浩特市","code":"152501","parentId":"445"},{"id":"447","name":"锡林浩特市","code":"152502","parentId":"445"},{"id":"448","name":"阿巴嘎旗","code":"152522","parentId":"445"},{"id":"449","name":"苏尼特左旗","code":"152523","parentId":"445"},{"id":"450","name":"苏尼特右旗","code":"152524","parentId":"445"},{"id":"451","name":"东乌珠穆沁旗","code":"152525","parentId":"445"},{"id":"452","name":"西乌珠穆沁旗","code":"152526","parentId":"445"},{"id":"453","name":"太仆寺旗","code":"152527","parentId":"445"},{"id":"454","name":"镶黄旗","code":"152528","parentId":"445"},{"id":"455","name":"正镶白旗","code":"152529","parentId":"445"},{"id":"456","name":"正蓝旗","code":"152530","parentId":"445"},{"id":"457","name":"多伦县","code":"152531","parentId":"445"}]},{"id":"458","name":"阿拉善盟","code":"152900","parentId":"346","children":[{"id":"459","name":"阿拉善左旗","code":"152921","parentId":"458"},{"id":"460","name":"阿拉善右旗","code":"152922","parentId":"458"},{"id":"461","name":"额济纳旗","code":"152923","parentId":"458"}]}]},{"id":"462","name":"辽宁省","code":"210000","parentId":"0","children":[{"id":"463","name":"沈阳市","code":"210100","parentId":"462","children":[{"id":"464","name":"和平区","code":"210102","parentId":"463"},{"id":"465","name":"沈河区","code":"210103","parentId":"463"},{"id":"466","name":"大东区","code":"210104","parentId":"463"},{"id":"467","name":"皇姑区","code":"210105","parentId":"463"},{"id":"468","name":"铁西区","code":"210106","parentId":"463"},{"id":"469","name":"苏家屯区","code":"210111","parentId":"463"},{"id":"470","name":"浑南区","code":"210112","parentId":"463"},{"id":"471","name":"沈北新区","code":"210113","parentId":"463"},{"id":"472","name":"于洪区","code":"210114","parentId":"463"},{"id":"473","name":"辽中区","code":"210115","parentId":"463"},{"id":"474","name":"康平县","code":"210123","parentId":"463"},{"id":"475","name":"法库县","code":"210124","parentId":"463"},{"id":"476","name":"新民市","code":"210181","parentId":"463"}]},{"id":"477","name":"大连市","code":"210200","parentId":"462","children":[{"id":"478","name":"中山区","code":"210202","parentId":"477"},{"id":"479","name":"西岗区","code":"210203","parentId":"477"},{"id":"480","name":"沙河口区","code":"210204","parentId":"477"},{"id":"481","name":"甘井子区","code":"210211","parentId":"477"},{"id":"482","name":"旅顺口区","code":"210212","parentId":"477"},{"id":"483","name":"金普新区","code":"210213","parentId":"477"},{"id":"484","name":"普兰店区","code":"210214","parentId":"477"},{"id":"485","name":"长海县","code":"210224","parentId":"477"},{"id":"486","name":"瓦房店市","code":"210281","parentId":"477"},{"id":"487","name":"庄河市","code":"210283","parentId":"477"}]},{"id":"488","name":"鞍山市","code":"210300","parentId":"462","children":[{"id":"489","name":"铁东区","code":"210302","parentId":"488"},{"id":"490","name":"铁西区","code":"210303","parentId":"488"},{"id":"491","name":"立山区","code":"210304","parentId":"488"},{"id":"492","name":"千山区","code":"210311","parentId":"488"},{"id":"493","name":"台安县","code":"210321","parentId":"488"},{"id":"494","name":"岫岩满族自治县","code":"210323","parentId":"488"},{"id":"495","name":"海城市","code":"210381","parentId":"488"}]},{"id":"496","name":"抚顺市","code":"210400","parentId":"462","children":[{"id":"497","name":"新抚区","code":"210402","parentId":"496"},{"id":"498","name":"东洲区","code":"210403","parentId":"496"},{"id":"499","name":"望花区","code":"210404","parentId":"496"},{"id":"500","name":"顺城区","code":"210411","parentId":"496"},{"id":"501","name":"抚顺县","code":"210421","parentId":"496"},{"id":"502","name":"新宾满族自治县","code":"210422","parentId":"496"},{"id":"503","name":"清原满族自治县","code":"210423","parentId":"496"}]},{"id":"504","name":"本溪市","code":"210500","parentId":"462","children":[{"id":"505","name":"平山区","code":"210502","parentId":"504"},{"id":"506","name":"溪湖区","code":"210503","parentId":"504"},{"id":"507","name":"明山区","code":"210504","parentId":"504"},{"id":"508","name":"南芬区","code":"210505","parentId":"504"},{"id":"509","name":"本溪满族自治县","code":"210521","parentId":"504"},{"id":"510","name":"桓仁满族自治县","code":"210522","parentId":"504"}]},{"id":"511","name":"丹东市","code":"210600","parentId":"462","children":[{"id":"512","name":"元宝区","code":"210602","parentId":"511"},{"id":"513","name":"振兴区","code":"210603","parentId":"511"},{"id":"514","name":"振安区","code":"210604","parentId":"511"},{"id":"515","name":"宽甸满族自治县","code":"210624","parentId":"511"},{"id":"516","name":"东港市","code":"210681","parentId":"511"},{"id":"517","name":"凤城市","code":"210682","parentId":"511"}]},{"id":"518","name":"锦州市","code":"210700","parentId":"462","children":[{"id":"519","name":"古塔区","code":"210702","parentId":"518"},{"id":"520","name":"凌河区","code":"210703","parentId":"518"},{"id":"521","name":"太和区","code":"210711","parentId":"518"},{"id":"522","name":"黑山县","code":"210726","parentId":"518"},{"id":"523","name":"义县","code":"210727","parentId":"518"},{"id":"524","name":"凌海市","code":"210781","parentId":"518"},{"id":"525","name":"北镇市","code":"210782","parentId":"518"}]},{"id":"526","name":"营口市","code":"210800","parentId":"462","children":[{"id":"527","name":"站前区","code":"210802","parentId":"526"},{"id":"528","name":"西市区","code":"210803","parentId":"526"},{"id":"529","name":"鲅鱼圈区","code":"210804","parentId":"526"},{"id":"530","name":"老边区","code":"210811","parentId":"526"},{"id":"531","name":"盖州市","code":"210881","parentId":"526"},{"id":"532","name":"大石桥市","code":"210882","parentId":"526"}]},{"id":"533","name":"阜新市","code":"210900","parentId":"462","children":[{"id":"534","name":"海州区","code":"210902","parentId":"533"},{"id":"535","name":"新邱区","code":"210903","parentId":"533"},{"id":"536","name":"太平区","code":"210904","parentId":"533"},{"id":"537","name":"清河门区","code":"210905","parentId":"533"},{"id":"538","name":"细河区","code":"210911","parentId":"533"},{"id":"539","name":"阜新蒙古族自治县","code":"210921","parentId":"533"},{"id":"540","name":"彰武县","code":"210922","parentId":"533"}]},{"id":"541","name":"辽阳市","code":"211000","parentId":"462","children":[{"id":"542","name":"白塔区","code":"211002","parentId":"541"},{"id":"543","name":"文圣区","code":"211003","parentId":"541"},{"id":"544","name":"宏伟区","code":"211004","parentId":"541"},{"id":"545","name":"弓长岭区","code":"211005","parentId":"541"},{"id":"546","name":"太子河区","code":"211011","parentId":"541"},{"id":"547","name":"辽阳县","code":"211021","parentId":"541"},{"id":"548","name":"灯塔市","code":"211081","parentId":"541"}]},{"id":"549","name":"盘锦市","code":"211100","parentId":"462","children":[{"id":"550","name":"双台子区","code":"211102","parentId":"549"},{"id":"551","name":"兴隆台区","code":"211103","parentId":"549"},{"id":"552","name":"大洼区","code":"211104","parentId":"549"},{"id":"553","name":"盘山县","code":"211122","parentId":"549"}]},{"id":"554","name":"铁岭市","code":"211200","parentId":"462","children":[{"id":"555","name":"银州区","code":"211202","parentId":"554"},{"id":"556","name":"清河区","code":"211204","parentId":"554"},{"id":"557","name":"铁岭县","code":"211221","parentId":"554"},{"id":"558","name":"西丰县","code":"211223","parentId":"554"},{"id":"559","name":"昌图县","code":"211224","parentId":"554"},{"id":"560","name":"调兵山市","code":"211281","parentId":"554"},{"id":"561","name":"开原市","code":"211282","parentId":"554"}]},{"id":"562","name":"朝阳市","code":"211300","parentId":"462","children":[{"id":"563","name":"双塔区","code":"211302","parentId":"562"},{"id":"564","name":"龙城区","code":"211303","parentId":"562"},{"id":"565","name":"朝阳县","code":"211321","parentId":"562"},{"id":"566","name":"建平县","code":"211322","parentId":"562"},{"id":"567","name":"喀喇沁左翼蒙古族自治县","code":"211324","parentId":"562"},{"id":"568","name":"北票市","code":"211381","parentId":"562"},{"id":"569","name":"凌源市","code":"211382","parentId":"562"}]},{"id":"570","name":"葫芦岛市","code":"211400","parentId":"462","children":[{"id":"571","name":"连山区","code":"211402","parentId":"570"},{"id":"572","name":"龙港区","code":"211403","parentId":"570"},{"id":"573","name":"南票区","code":"211404","parentId":"570"},{"id":"574","name":"绥中县","code":"211421","parentId":"570"},{"id":"575","name":"建昌县","code":"211422","parentId":"570"},{"id":"576","name":"兴城市","code":"211481","parentId":"570"}]}]},{"id":"577","name":"吉林省","code":"220000","parentId":"0","children":[{"id":"578","name":"长春市","code":"220100","parentId":"577","children":[{"id":"579","name":"南关区","code":"220102","parentId":"578"},{"id":"580","name":"宽城区","code":"220103","parentId":"578"},{"id":"581","name":"朝阳区","code":"220104","parentId":"578"},{"id":"582","name":"二道区","code":"220105","parentId":"578"},{"id":"583","name":"绿园区","code":"220106","parentId":"578"},{"id":"584","name":"双阳区","code":"220112","parentId":"578"},{"id":"585","name":"九台区","code":"220113","parentId":"578"},{"id":"586","name":"农安县","code":"220122","parentId":"578"},{"id":"587","name":"榆树市","code":"220182","parentId":"578"},{"id":"588","name":"德惠市","code":"220183","parentId":"578"}]},{"id":"589","name":"吉林市","code":"220200","parentId":"577","children":[{"id":"590","name":"昌邑区","code":"220202","parentId":"589"},{"id":"591","name":"龙潭区","code":"220203","parentId":"589"},{"id":"592","name":"船营区","code":"220204","parentId":"589"},{"id":"593","name":"丰满区","code":"220211","parentId":"589"},{"id":"594","name":"永吉县","code":"220221","parentId":"589"},{"id":"595","name":"蛟河市","code":"220281","parentId":"589"},{"id":"596","name":"桦甸市","code":"220282","parentId":"589"},{"id":"597","name":"舒兰市","code":"220283","parentId":"589"},{"id":"598","name":"磐石市","code":"220284","parentId":"589"}]},{"id":"599","name":"四平市","code":"220300","parentId":"577","children":[{"id":"600","name":"铁西区","code":"220302","parentId":"599"},{"id":"601","name":"铁东区","code":"220303","parentId":"599"},{"id":"602","name":"梨树县","code":"220322","parentId":"599"},{"id":"603","name":"伊通满族自治县","code":"220323","parentId":"599"},{"id":"604","name":"公主岭市","code":"220381","parentId":"599"},{"id":"605","name":"双辽市","code":"220382","parentId":"599"}]},{"id":"606","name":"辽源市","code":"220400","parentId":"577","children":[{"id":"607","name":"龙山区","code":"220402","parentId":"606"},{"id":"608","name":"西安区","code":"220403","parentId":"606"},{"id":"609","name":"东丰县","code":"220421","parentId":"606"},{"id":"610","name":"东辽县","code":"220422","parentId":"606"}]},{"id":"611","name":"通化市","code":"220500","parentId":"577","children":[{"id":"612","name":"东昌区","code":"220502","parentId":"611"},{"id":"613","name":"二道江区","code":"220503","parentId":"611"},{"id":"614","name":"通化县","code":"220521","parentId":"611"},{"id":"615","name":"辉南县","code":"220523","parentId":"611"},{"id":"616","name":"柳河县","code":"220524","parentId":"611"},{"id":"617","name":"梅河口市","code":"220581","parentId":"611"},{"id":"618","name":"集安市","code":"220582","parentId":"611"}]},{"id":"619","name":"白山市","code":"220600","parentId":"577","children":[{"id":"620","name":"浑江区","code":"220602","parentId":"619"},{"id":"621","name":"江源区","code":"220605","parentId":"619"},{"id":"622","name":"抚松县","code":"220621","parentId":"619"},{"id":"623","name":"靖宇县","code":"220622","parentId":"619"},{"id":"624","name":"长白朝鲜族自治县","code":"220623","parentId":"619"},{"id":"625","name":"临江市","code":"220681","parentId":"619"}]},{"id":"626","name":"松原市","code":"220700","parentId":"577","children":[{"id":"627","name":"宁江区","code":"220702","parentId":"626"},{"id":"628","name":"前郭尔罗斯蒙古族自治县","code":"220721","parentId":"626"},{"id":"629","name":"长岭县","code":"220722","parentId":"626"},{"id":"630","name":"乾安县","code":"220723","parentId":"626"},{"id":"631","name":"扶余市","code":"220781","parentId":"626"}]},{"id":"632","name":"白城市","code":"220800","parentId":"577","children":[{"id":"633","name":"洮北区","code":"220802","parentId":"632"},{"id":"634","name":"镇赉县","code":"220821","parentId":"632"},{"id":"635","name":"通榆县","code":"220822","parentId":"632"},{"id":"636","name":"洮南市","code":"220881","parentId":"632"},{"id":"637","name":"大安市","code":"220882","parentId":"632"}]},{"id":"638","name":"延边朝鲜族自治州","code":"222400","parentId":"577","children":[{"id":"639","name":"延吉市","code":"222401","parentId":"638"},{"id":"640","name":"图们市","code":"222402","parentId":"638"},{"id":"641","name":"敦化市","code":"222403","parentId":"638"},{"id":"642","name":"珲春市","code":"222404","parentId":"638"},{"id":"643","name":"龙井市","code":"222405","parentId":"638"},{"id":"644","name":"和龙市","code":"222406","parentId":"638"},{"id":"645","name":"汪清县","code":"222424","parentId":"638"},{"id":"646","name":"安图县","code":"222426","parentId":"638"}]}]},{"id":"647","name":"黑龙江省","code":"230000","parentId":"0","children":[{"id":"648","name":"哈尔滨市","code":"230100","parentId":"647","children":[{"id":"649","name":"道里区","code":"230102","parentId":"648"},{"id":"650","name":"南岗区","code":"230103","parentId":"648"},{"id":"651","name":"道外区","code":"230104","parentId":"648"},{"id":"652","name":"平房区","code":"230108","parentId":"648"},{"id":"653","name":"松北区","code":"230109","parentId":"648"},{"id":"654","name":"香坊区","code":"230110","parentId":"648"},{"id":"655","name":"呼兰区","code":"230111","parentId":"648"},{"id":"656","name":"阿城区","code":"230112","parentId":"648"},{"id":"657","name":"双城区","code":"230113","parentId":"648"},{"id":"658","name":"依兰县","code":"230123","parentId":"648"},{"id":"659","name":"方正县","code":"230124","parentId":"648"},{"id":"660","name":"宾县","code":"230125","parentId":"648"},{"id":"661","name":"巴彦县","code":"230126","parentId":"648"},{"id":"662","name":"木兰县","code":"230127","parentId":"648"},{"id":"663","name":"通河县","code":"230128","parentId":"648"},{"id":"664","name":"延寿县","code":"230129","parentId":"648"},{"id":"665","name":"尚志市","code":"230183","parentId":"648"},{"id":"666","name":"五常市","code":"230184","parentId":"648"}]},{"id":"667","name":"齐齐哈尔市","code":"230200","parentId":"647","children":[{"id":"668","name":"龙沙区","code":"230202","parentId":"667"},{"id":"669","name":"建华区","code":"230203","parentId":"667"},{"id":"670","name":"铁锋区","code":"230204","parentId":"667"},{"id":"671","name":"昂昂溪区","code":"230205","parentId":"667"},{"id":"672","name":"富拉尔基区","code":"230206","parentId":"667"},{"id":"673","name":"碾子山区","code":"230207","parentId":"667"},{"id":"674","name":"梅里斯达斡尔族区","code":"230208","parentId":"667"},{"id":"675","name":"龙江县","code":"230221","parentId":"667"},{"id":"676","name":"依安县","code":"230223","parentId":"667"},{"id":"677","name":"泰来县","code":"230224","parentId":"667"},{"id":"678","name":"甘南县","code":"230225","parentId":"667"},{"id":"679","name":"富裕县","code":"230227","parentId":"667"},{"id":"680","name":"克山县","code":"230229","parentId":"667"},{"id":"681","name":"克东县","code":"230230","parentId":"667"},{"id":"682","name":"拜泉县","code":"230231","parentId":"667"},{"id":"683","name":"讷河市","code":"230281","parentId":"667"}]},{"id":"684","name":"鸡西市","code":"230300","parentId":"647","children":[{"id":"685","name":"鸡冠区","code":"230302","parentId":"684"},{"id":"686","name":"恒山区","code":"230303","parentId":"684"},{"id":"687","name":"滴道区","code":"230304","parentId":"684"},{"id":"688","name":"梨树区","code":"230305","parentId":"684"},{"id":"689","name":"城子河区","code":"230306","parentId":"684"},{"id":"690","name":"麻山区","code":"230307","parentId":"684"},{"id":"691","name":"鸡东县","code":"230321","parentId":"684"},{"id":"692","name":"虎林市","code":"230381","parentId":"684"},{"id":"693","name":"密山市","code":"230382","parentId":"684"}]},{"id":"694","name":"鹤岗市","code":"230400","parentId":"647","children":[{"id":"695","name":"向阳区","code":"230402","parentId":"694"},{"id":"696","name":"工农区","code":"230403","parentId":"694"},{"id":"697","name":"南山区","code":"230404","parentId":"694"},{"id":"698","name":"兴安区","code":"230405","parentId":"694"},{"id":"699","name":"东山区","code":"230406","parentId":"694"},{"id":"700","name":"兴山区","code":"230407","parentId":"694"},{"id":"701","name":"萝北县","code":"230421","parentId":"694"},{"id":"702","name":"绥滨县","code":"230422","parentId":"694"}]},{"id":"703","name":"双鸭山市","code":"230500","parentId":"647","children":[{"id":"704","name":"尖山区","code":"230502","parentId":"703"},{"id":"705","name":"岭东区","code":"230503","parentId":"703"},{"id":"706","name":"四方台区","code":"230505","parentId":"703"},{"id":"707","name":"宝山区","code":"230506","parentId":"703"},{"id":"708","name":"集贤县","code":"230521","parentId":"703"},{"id":"709","name":"友谊县","code":"230522","parentId":"703"},{"id":"710","name":"宝清县","code":"230523","parentId":"703"},{"id":"711","name":"饶河县","code":"230524","parentId":"703"}]},{"id":"712","name":"大庆市","code":"230600","parentId":"647","children":[{"id":"713","name":"萨尔图区","code":"230602","parentId":"712"},{"id":"714","name":"龙凤区","code":"230603","parentId":"712"},{"id":"715","name":"让胡路区","code":"230604","parentId":"712"},{"id":"716","name":"红岗区","code":"230605","parentId":"712"},{"id":"717","name":"大同区","code":"230606","parentId":"712"},{"id":"718","name":"肇州县","code":"230621","parentId":"712"},{"id":"719","name":"肇源县","code":"230622","parentId":"712"},{"id":"720","name":"林甸县","code":"230623","parentId":"712"},{"id":"721","name":"杜尔伯特蒙古族自治县","code":"230624","parentId":"712"}]},{"id":"722","name":"伊春市","code":"230700","parentId":"647","children":[{"id":"723","name":"伊春区","code":"230702","parentId":"722"},{"id":"724","name":"南岔区","code":"230703","parentId":"722"},{"id":"725","name":"友好区","code":"230704","parentId":"722"},{"id":"726","name":"西林区","code":"230705","parentId":"722"},{"id":"727","name":"翠峦区","code":"230706","parentId":"722"},{"id":"728","name":"新青区","code":"230707","parentId":"722"},{"id":"729","name":"美溪区","code":"230708","parentId":"722"},{"id":"730","name":"金山屯区","code":"230709","parentId":"722"},{"id":"731","name":"五营区","code":"230710","parentId":"722"},{"id":"732","name":"乌马河区","code":"230711","parentId":"722"},{"id":"733","name":"汤旺河区","code":"230712","parentId":"722"},{"id":"734","name":"带岭区","code":"230713","parentId":"722"},{"id":"735","name":"乌伊岭区","code":"230714","parentId":"722"},{"id":"736","name":"红星区","code":"230715","parentId":"722"},{"id":"737","name":"上甘岭区","code":"230716","parentId":"722"},{"id":"738","name":"嘉荫县","code":"230722","parentId":"722"},{"id":"739","name":"铁力市","code":"230781","parentId":"722"}]},{"id":"740","name":"佳木斯市","code":"230800","parentId":"647","children":[{"id":"741","name":"向阳区","code":"230803","parentId":"740"},{"id":"742","name":"前进区","code":"230804","parentId":"740"},{"id":"743","name":"东风区","code":"230805","parentId":"740"},{"id":"744","name":"郊区","code":"230811","parentId":"740"},{"id":"745","name":"桦南县","code":"230822","parentId":"740"},{"id":"746","name":"桦川县","code":"230826","parentId":"740"},{"id":"747","name":"汤原县","code":"230828","parentId":"740"},{"id":"748","name":"同江市","code":"230881","parentId":"740"},{"id":"749","name":"富锦市","code":"230882","parentId":"740"},{"id":"750","name":"抚远市","code":"230883","parentId":"740"}]},{"id":"751","name":"七台河市","code":"230900","parentId":"647","children":[{"id":"752","name":"新兴区","code":"230902","parentId":"751"},{"id":"753","name":"桃山区","code":"230903","parentId":"751"},{"id":"754","name":"茄子河区","code":"230904","parentId":"751"},{"id":"755","name":"勃利县","code":"230921","parentId":"751"}]},{"id":"756","name":"牡丹江市","code":"231000","parentId":"647","children":[{"id":"757","name":"东安区","code":"231002","parentId":"756"},{"id":"758","name":"阳明区","code":"231003","parentId":"756"},{"id":"759","name":"爱民区","code":"231004","parentId":"756"},{"id":"760","name":"西安区","code":"231005","parentId":"756"},{"id":"761","name":"林口县","code":"231025","parentId":"756"},{"id":"762","name":"绥芬河市","code":"231081","parentId":"756"},{"id":"763","name":"海林市","code":"231083","parentId":"756"},{"id":"764","name":"宁安市","code":"231084","parentId":"756"},{"id":"765","name":"穆棱市","code":"231085","parentId":"756"},{"id":"766","name":"东宁市","code":"231086","parentId":"756"}]},{"id":"767","name":"黑河市","code":"231100","parentId":"647","children":[{"id":"768","name":"爱辉区","code":"231102","parentId":"767"},{"id":"769","name":"嫩江县","code":"231121","parentId":"767"},{"id":"770","name":"逊克县","code":"231123","parentId":"767"},{"id":"771","name":"孙吴县","code":"231124","parentId":"767"},{"id":"772","name":"北安市","code":"231181","parentId":"767"},{"id":"773","name":"五大连池市","code":"231182","parentId":"767"}]},{"id":"774","name":"绥化市","code":"231200","parentId":"647","children":[{"id":"775","name":"北林区","code":"231202","parentId":"774"},{"id":"776","name":"望奎县","code":"231221","parentId":"774"},{"id":"777","name":"兰西县","code":"231222","parentId":"774"},{"id":"778","name":"青冈县","code":"231223","parentId":"774"},{"id":"779","name":"庆安县","code":"231224","parentId":"774"},{"id":"780","name":"明水县","code":"231225","parentId":"774"},{"id":"781","name":"绥棱县","code":"231226","parentId":"774"},{"id":"782","name":"安达市","code":"231281","parentId":"774"},{"id":"783","name":"肇东市","code":"231282","parentId":"774"},{"id":"784","name":"海伦市","code":"231283","parentId":"774"}]},{"id":"785","name":"大兴安岭地区","code":"232700","parentId":"647","children":[{"id":"786","name":"呼玛县","code":"232721","parentId":"785"},{"id":"787","name":"塔河县","code":"232722","parentId":"785"},{"id":"788","name":"漠河县","code":"232723","parentId":"785"}]}]},{"id":"806","name":"江苏省","code":"320000","parentId":"0","children":[{"id":"807","name":"南京市","code":"320100","parentId":"806","children":[{"id":"808","name":"玄武区","code":"320102","parentId":"807"},{"id":"809","name":"秦淮区","code":"320104","parentId":"807"},{"id":"810","name":"建邺区","code":"320105","parentId":"807"},{"id":"811","name":"鼓楼区","code":"320106","parentId":"807"},{"id":"812","name":"浦口区","code":"320111","parentId":"807"},{"id":"813","name":"栖霞区","code":"320113","parentId":"807"},{"id":"814","name":"雨花台区","code":"320114","parentId":"807"},{"id":"815","name":"江宁区","code":"320115","parentId":"807"},{"id":"816","name":"六合区","code":"320116","parentId":"807"},{"id":"817","name":"溧水区","code":"320117","parentId":"807"},{"id":"818","name":"高淳区","code":"320118","parentId":"807"}]},{"id":"819","name":"无锡市","code":"320200","parentId":"806","children":[{"id":"820","name":"锡山区","code":"320205","parentId":"819"},{"id":"821","name":"惠山区","code":"320206","parentId":"819"},{"id":"822","name":"滨湖区","code":"320211","parentId":"819"},{"id":"823","name":"梁溪区","code":"320213","parentId":"819"},{"id":"824","name":"新吴区","code":"320214","parentId":"819"},{"id":"825","name":"江阴市","code":"320281","parentId":"819"},{"id":"826","name":"宜兴市","code":"320282","parentId":"819"}]},{"id":"827","name":"徐州市","code":"320300","parentId":"806","children":[{"id":"828","name":"鼓楼区","code":"320302","parentId":"827"},{"id":"829","name":"云龙区","code":"320303","parentId":"827"},{"id":"830","name":"贾汪区","code":"320305","parentId":"827"},{"id":"831","name":"泉山区","code":"320311","parentId":"827"},{"id":"832","name":"铜山区","code":"320312","parentId":"827"},{"id":"833","name":"丰县","code":"320321","parentId":"827"},{"id":"834","name":"沛县","code":"320322","parentId":"827"},{"id":"835","name":"睢宁县","code":"320324","parentId":"827"},{"id":"836","name":"新沂市","code":"320381","parentId":"827"},{"id":"837","name":"邳州市","code":"320382","parentId":"827"}]},{"id":"838","name":"常州市","code":"320400","parentId":"806","children":[{"id":"839","name":"天宁区","code":"320402","parentId":"838"},{"id":"840","name":"钟楼区","code":"320404","parentId":"838"},{"id":"841","name":"新北区","code":"320411","parentId":"838"},{"id":"842","name":"武进区","code":"320412","parentId":"838"},{"id":"843","name":"金坛区","code":"320413","parentId":"838"},{"id":"844","name":"溧阳市","code":"320481","parentId":"838"}]},{"id":"845","name":"苏州市","code":"320500","parentId":"806","children":[{"id":"846","name":"虎丘区","code":"320505","parentId":"845"},{"id":"847","name":"吴中区","code":"320506","parentId":"845"},{"id":"848","name":"相城区","code":"320507","parentId":"845"},{"id":"849","name":"姑苏区","code":"320508","parentId":"845"},{"id":"850","name":"吴江区","code":"320509","parentId":"845"},{"id":"851","name":"常熟市","code":"320581","parentId":"845"},{"id":"852","name":"张家港市","code":"320582","parentId":"845"},{"id":"853","name":"昆山市","code":"320583","parentId":"845"},{"id":"854","name":"太仓市","code":"320585","parentId":"845"}]},{"id":"855","name":"南通市","code":"320600","parentId":"806","children":[{"id":"856","name":"崇川区","code":"320602","parentId":"855"},{"id":"857","name":"港闸区","code":"320611","parentId":"855"},{"id":"858","name":"通州区","code":"320612","parentId":"855"},{"id":"859","name":"海安县","code":"320621","parentId":"855"},{"id":"860","name":"如东县","code":"320623","parentId":"855"},{"id":"861","name":"启东市","code":"320681","parentId":"855"},{"id":"862","name":"如皋市","code":"320682","parentId":"855"},{"id":"863","name":"海门市","code":"320684","parentId":"855"}]},{"id":"864","name":"连云港市","code":"320700","parentId":"806","children":[{"id":"865","name":"连云区","code":"320703","parentId":"864"},{"id":"866","name":"海州区","code":"320706","parentId":"864"},{"id":"867","name":"赣榆区","code":"320707","parentId":"864"},{"id":"868","name":"东海县","code":"320722","parentId":"864"},{"id":"869","name":"灌云县","code":"320723","parentId":"864"},{"id":"870","name":"灌南县","code":"320724","parentId":"864"}]},{"id":"871","name":"淮安市","code":"320800","parentId":"806","children":[{"id":"872","name":"淮安区","code":"320803","parentId":"871"},{"id":"873","name":"淮阴区","code":"320804","parentId":"871"},{"id":"874","name":"清江浦区","code":"320812","parentId":"871"},{"id":"875","name":"洪泽区","code":"320813","parentId":"871"},{"id":"876","name":"涟水县","code":"320826","parentId":"871"},{"id":"877","name":"盱眙县","code":"320830","parentId":"871"},{"id":"878","name":"金湖县","code":"320831","parentId":"871"}]},{"id":"879","name":"盐城市","code":"320900","parentId":"806","children":[{"id":"880","name":"亭湖区","code":"320902","parentId":"879"},{"id":"881","name":"盐都区","code":"320903","parentId":"879"},{"id":"882","name":"大丰区","code":"320904","parentId":"879"},{"id":"883","name":"响水县","code":"320921","parentId":"879"},{"id":"884","name":"滨海县","code":"320922","parentId":"879"},{"id":"885","name":"阜宁县","code":"320923","parentId":"879"},{"id":"886","name":"射阳县","code":"320924","parentId":"879"},{"id":"887","name":"建湖县","code":"320925","parentId":"879"},{"id":"888","name":"东台市","code":"320981","parentId":"879"}]},{"id":"889","name":"扬州市","code":"321000","parentId":"806","children":[{"id":"890","name":"广陵区","code":"321002","parentId":"889"},{"id":"891","name":"邗江区","code":"321003","parentId":"889"},{"id":"892","name":"江都区","code":"321012","parentId":"889"},{"id":"893","name":"宝应县","code":"321023","parentId":"889"},{"id":"894","name":"仪征市","code":"321081","parentId":"889"},{"id":"895","name":"高邮市","code":"321084","parentId":"889"}]},{"id":"896","name":"镇江市","code":"321100","parentId":"806","children":[{"id":"897","name":"京口区","code":"321102","parentId":"896"},{"id":"898","name":"润州区","code":"321111","parentId":"896"},{"id":"899","name":"丹徒区","code":"321112","parentId":"896"},{"id":"900","name":"丹阳市","code":"321181","parentId":"896"},{"id":"901","name":"扬中市","code":"321182","parentId":"896"},{"id":"902","name":"句容市","code":"321183","parentId":"896"}]},{"id":"903","name":"泰州市","code":"321200","parentId":"806","children":[{"id":"904","name":"海陵区","code":"321202","parentId":"903"},{"id":"905","name":"高港区","code":"321203","parentId":"903"},{"id":"906","name":"姜堰区","code":"321204","parentId":"903"},{"id":"907","name":"兴化市","code":"321281","parentId":"903"},{"id":"908","name":"靖江市","code":"321282","parentId":"903"},{"id":"909","name":"泰兴市","code":"321283","parentId":"903"}]},{"id":"910","name":"宿迁市","code":"321300","parentId":"806","children":[{"id":"911","name":"宿城区","code":"321302","parentId":"910"},{"id":"912","name":"宿豫区","code":"321311","parentId":"910"},{"id":"913","name":"沭阳县","code":"321322","parentId":"910"},{"id":"914","name":"泗阳县","code":"321323","parentId":"910"},{"id":"915","name":"泗洪县","code":"321324","parentId":"910"}]}]},{"id":"916","name":"浙江省","code":"330000","parentId":"0","children":[{"id":"917","name":"杭州市","code":"330100","parentId":"916","children":[{"id":"918","name":"上城区","code":"330102","parentId":"917"},{"id":"919","name":"下城区","code":"330103","parentId":"917"},{"id":"920","name":"江干区","code":"330104","parentId":"917"},{"id":"921","name":"拱墅区","code":"330105","parentId":"917"},{"id":"922","name":"西湖区","code":"330106","parentId":"917"},{"id":"923","name":"滨江区","code":"330108","parentId":"917"},{"id":"924","name":"萧山区","code":"330109","parentId":"917"},{"id":"925","name":"余杭区","code":"330110","parentId":"917"},{"id":"926","name":"富阳区","code":"330111","parentId":"917"},{"id":"927","name":"临安区","code":"330112","parentId":"917"},{"id":"928","name":"桐庐县","code":"330122","parentId":"917"},{"id":"929","name":"淳安县","code":"330127","parentId":"917"},{"id":"930","name":"建德市","code":"330182","parentId":"917"}]},{"id":"931","name":"宁波市","code":"330200","parentId":"916","children":[{"id":"932","name":"海曙区","code":"330203","parentId":"931"},{"id":"933","name":"江北区","code":"330205","parentId":"931"},{"id":"934","name":"北仑区","code":"330206","parentId":"931"},{"id":"935","name":"镇海区","code":"330211","parentId":"931"},{"id":"936","name":"鄞州区","code":"330212","parentId":"931"},{"id":"937","name":"奉化区","code":"330213","parentId":"931"},{"id":"938","name":"象山县","code":"330225","parentId":"931"},{"id":"939","name":"宁海县","code":"330226","parentId":"931"},{"id":"940","name":"余姚市","code":"330281","parentId":"931"},{"id":"941","name":"慈溪市","code":"330282","parentId":"931"}]},{"id":"942","name":"温州市","code":"330300","parentId":"916","children":[{"id":"943","name":"鹿城区","code":"330302","parentId":"942"},{"id":"944","name":"龙湾区","code":"330303","parentId":"942"},{"id":"945","name":"瓯海区","code":"330304","parentId":"942"},{"id":"946","name":"洞头区","code":"330305","parentId":"942"},{"id":"947","name":"永嘉县","code":"330324","parentId":"942"},{"id":"948","name":"平阳县","code":"330326","parentId":"942"},{"id":"949","name":"苍南县","code":"330327","parentId":"942"},{"id":"950","name":"文成县","code":"330328","parentId":"942"},{"id":"951","name":"泰顺县","code":"330329","parentId":"942"},{"id":"952","name":"瑞安市","code":"330381","parentId":"942"},{"id":"953","name":"乐清市","code":"330382","parentId":"942"}]},{"id":"954","name":"嘉兴市","code":"330400","parentId":"916","children":[{"id":"955","name":"南湖区","code":"330402","parentId":"954"},{"id":"956","name":"秀洲区","code":"330411","parentId":"954"},{"id":"957","name":"嘉善县","code":"330421","parentId":"954"},{"id":"958","name":"海盐县","code":"330424","parentId":"954"},{"id":"959","name":"海宁市","code":"330481","parentId":"954"},{"id":"960","name":"平湖市","code":"330482","parentId":"954"},{"id":"961","name":"桐乡市","code":"330483","parentId":"954"}]},{"id":"962","name":"湖州市","code":"330500","parentId":"916","children":[{"id":"963","name":"吴兴区","code":"330502","parentId":"962"},{"id":"964","name":"南浔区","code":"330503","parentId":"962"},{"id":"965","name":"德清县","code":"330521","parentId":"962"},{"id":"966","name":"长兴县","code":"330522","parentId":"962"},{"id":"967","name":"安吉县","code":"330523","parentId":"962"}]},{"id":"968","name":"绍兴市","code":"330600","parentId":"916","children":[{"id":"969","name":"越城区","code":"330602","parentId":"968"},{"id":"970","name":"柯桥区","code":"330603","parentId":"968"},{"id":"971","name":"上虞区","code":"330604","parentId":"968"},{"id":"972","name":"新昌县","code":"330624","parentId":"968"},{"id":"973","name":"诸暨市","code":"330681","parentId":"968"},{"id":"974","name":"嵊州市","code":"330683","parentId":"968"}]},{"id":"975","name":"金华市","code":"330700","parentId":"916","children":[{"id":"976","name":"婺城区","code":"330702","parentId":"975"},{"id":"977","name":"金东区","code":"330703","parentId":"975"},{"id":"978","name":"武义县","code":"330723","parentId":"975"},{"id":"979","name":"浦江县","code":"330726","parentId":"975"},{"id":"980","name":"磐安县","code":"330727","parentId":"975"},{"id":"981","name":"兰溪市","code":"330781","parentId":"975"},{"id":"982","name":"义乌市","code":"330782","parentId":"975"},{"id":"983","name":"东阳市","code":"330783","parentId":"975"},{"id":"984","name":"永康市","code":"330784","parentId":"975"}]},{"id":"985","name":"衢州市","code":"330800","parentId":"916","children":[{"id":"986","name":"柯城区","code":"330802","parentId":"985"},{"id":"987","name":"衢江区","code":"330803","parentId":"985"},{"id":"988","name":"常山县","code":"330822","parentId":"985"},{"id":"989","name":"开化县","code":"330824","parentId":"985"},{"id":"990","name":"龙游县","code":"330825","parentId":"985"},{"id":"991","name":"江山市","code":"330881","parentId":"985"}]},{"id":"992","name":"舟山市","code":"330900","parentId":"916","children":[{"id":"993","name":"定海区","code":"330902","parentId":"992"},{"id":"994","name":"普陀区","code":"330903","parentId":"992"},{"id":"995","name":"岱山县","code":"330921","parentId":"992"},{"id":"996","name":"嵊泗县","code":"330922","parentId":"992"}]},{"id":"997","name":"台州市","code":"331000","parentId":"916","children":[{"id":"998","name":"椒江区","code":"331002","parentId":"997"},{"id":"999","name":"黄岩区","code":"331003","parentId":"997"},{"id":"1000","name":"路桥区","code":"331004","parentId":"997"},{"id":"1001","name":"三门县","code":"331022","parentId":"997"},{"id":"1002","name":"天台县","code":"331023","parentId":"997"},{"id":"1003","name":"仙居县","code":"331024","parentId":"997"},{"id":"1004","name":"温岭市","code":"331081","parentId":"997"},{"id":"1005","name":"临海市","code":"331082","parentId":"997"},{"id":"1006","name":"玉环市","code":"331083","parentId":"997"}]},{"id":"1007","name":"丽水市","code":"331100","parentId":"916","children":[{"id":"1008","name":"莲都区","code":"331102","parentId":"1007"},{"id":"1009","name":"青田县","code":"331121","parentId":"1007"},{"id":"1010","name":"缙云县","code":"331122","parentId":"1007"},{"id":"1011","name":"遂昌县","code":"331123","parentId":"1007"},{"id":"1012","name":"松阳县","code":"331124","parentId":"1007"},{"id":"1013","name":"云和县","code":"331125","parentId":"1007"},{"id":"1014","name":"庆元县","code":"331126","parentId":"1007"},{"id":"1015","name":"景宁畲族自治县","code":"331127","parentId":"1007"},{"id":"1016","name":"龙泉市","code":"331181","parentId":"1007"}]}]},{"id":"1017","name":"安徽省","code":"340000","parentId":"0","children":[{"id":"1018","name":"合肥市","code":"340100","parentId":"1017","children":[{"id":"1019","name":"瑶海区","code":"340102","parentId":"1018"},{"id":"1020","name":"庐阳区","code":"340103","parentId":"1018"},{"id":"1021","name":"蜀山区","code":"340104","parentId":"1018"},{"id":"1022","name":"包河区","code":"340111","parentId":"1018"},{"id":"1023","name":"长丰县","code":"340121","parentId":"1018"},{"id":"1024","name":"肥东县","code":"340122","parentId":"1018"},{"id":"1025","name":"肥西县","code":"340123","parentId":"1018"},{"id":"1026","name":"庐江县","code":"340124","parentId":"1018"},{"id":"1027","name":"巢湖市","code":"340181","parentId":"1018"}]},{   "id":"1028","name":"芜湖市","code":"340200","parentId":"1017","children":[{"id":"1029","name":"镜湖区","code":"340202","parentId":"1028"},{"id":"1030","name":"弋江区","code":"340203","parentId":"1028"},{"id":"1031","name":"鸠江区","code":"340207","parentId":"1028"},{"id":"1032","name":"三山区","code":"340208","parentId":"1028"},{"id":"1033","name":"芜湖县","code":"340221","parentId":"1028"},{"id":"1034","name":"繁昌县","code":"340222","parentId":"1028"},{"id":"1035","name":"南陵县","code":"340223","parentId":"1028"},{"id":"1036","name":"无为县","code":"340225","parentId":"1028"}]},{"id":"1037","name":"蚌埠市","code":"340300","parentId":"1017","children":[{"id":"1038","name":"龙子湖区","code":"340302","parentId":"1037"},{"id":"1039","name":"蚌山区","code":"340303","parentId":"1037"},{"id":"1040","name":"禹会区","code":"340304","parentId":"1037"},{"id":"1041","name":"淮上区","code":"340311","parentId":"1037"},{"id":"1042","name":"怀远县","code":"340321","parentId":"1037"},{"id":"1043","name":"五河县","code":"340322","parentId":"1037"},{"id":"1044","name":"固镇县","code":"340323","parentId":"1037"}]},{"id":"1045","name":"淮南市","code":"340400","parentId":"1017","children":[{"id":"1046","name":"大通区","code":"340402","parentId":"1045"},{"id":"1047","name":"田家庵区","code":"340403","parentId":"1045"},{"id":"1048","name":"谢家集区","code":"340404","parentId":"1045"},{"id":"1049","name":"八公山区","code":"340405","parentId":"1045"},{"id":"1050","name":"潘集区","code":"340406","parentId":"1045"},{"id":"1051","name":"凤台县","code":"340421","parentId":"1045"},{"id":"1052","name":"寿县","code":"340422","parentId":"1045"}]},{"id":"1053","name":"马鞍山市","code":"340500","parentId":"1017","children":[{"id":"1054","name":"花山区","code":"340503","parentId":"1053"},{"id":"1055","name":"雨山区","code":"340504","parentId":"1053"},{"id":"1056","name":"博望区","code":"340506","parentId":"1053"},{"id":"1057","name":"当涂县","code":"340521","parentId":"1053"},{"id":"1058","name":"含山县","code":"340522","parentId":"1053"},{"id":"1059","name":"和县","code":"340523","parentId":"1053"}]},{"id":"1060","name":"淮北市","code":"340600","parentId":"1017","children":[{"id":"1061","name":"杜集区","code":"340602","parentId":"1060"},{"id":"1062","name":"相山区","code":"340603","parentId":"1060"},{"id":"1063","name":"烈山区","code":"340604","parentId":"1060"},{"id":"1064","name":"濉溪县","code":"340621","parentId":"1060"}]},{"id":"1065","name":"铜陵市","code":"340700","parentId":"1017","children":[{"id":"1066","name":"铜官区","code":"340705","parentId":"1065"},{"id":"1067","name":"义安区","code":"340706","parentId":"1065"},{"id":"1068","name":"郊区","code":"340711","parentId":"1065"},{"id":"1069","name":"枞阳县","code":"340722","parentId":"1065"}]},{"id":"1070","name":"安庆市","code":"340800","parentId":"1017","children":[{"id":"1071","name":"迎江区","code":"340802","parentId":"1070"},{"id":"1072","name":"大观区","code":"340803","parentId":"1070"},{"id":"1073","name":"宜秀区","code":"340811","parentId":"1070"},{"id":"1074","name":"怀宁县","code":"340822","parentId":"1070"},{"id":"1075","name":"潜山县","code":"340824","parentId":"1070"},{"id":"1076","name":"太湖县","code":"340825","parentId":"1070"},{"id":"1077","name":"宿松县","code":"340826","parentId":"1070"},{"id":"1078","name":"望江县","code":"340827","parentId":"1070"},{"id":"1079","name":"岳西县","code":"340828","parentId":"1070"},{"id":"1080","name":"桐城市","code":"340881","parentId":"1070"}]},{"id":"1081","name":"黄山市","code":"341000","parentId":"1017","children":[{"id":"1082","name":"屯溪区","code":"341002","parentId":"1081"},{"id":"1083","name":"黄山区","code":"341003","parentId":"1081"},{"id":"1084","name":"徽州区","code":"341004","parentId":"1081"},{"id":"1085","name":"歙县","code":"341021","parentId":"1081"},{"id":"1086","name":"休宁县","code":"341022","parentId":"1081"},{"id":"1087","name":"黟县","code":"341023","parentId":"1081"},{"id":"1088","name":"祁门县","code":"341024","parentId":"1081"}]},{"id":"1089","name":"滁州市","code":"341100","parentId":"1017","children":[{"id":"1090","name":"琅琊区","code":"341102","parentId":"1089"},{"id":"1091","name":"南谯区","code":"341103","parentId":"1089"},{"id":"1092","name":"来安县","code":"341122","parentId":"1089"},{"id":"1093","name":"全椒县","code":"341124","parentId":"1089"},{"id":"1094","name":"定远县","code":"341125","parentId":"1089"},{"id":"1095","name":"凤阳县","code":"341126","parentId":"1089"},{"id":"1096","name":"天长市","code":"341181","parentId":"1089"},{"id":"1097","name":"明光市","code":"341182","parentId":"1089"}]},{"id":"1098","name":"阜阳市","code":"341200","parentId":"1017","children":[{"id":"1099","name":"颍州区","code":"341202","parentId":"1098"},{"id":"1100","name":"颍东区","code":"341203","parentId":"1098"},{"id":"1101","name":"颍泉区","code":"341204","parentId":"1098"},{"id":"1102","name":"临泉县","code":"341221","parentId":"1098"},{"id":"1103","name":"太和县","code":"341222","parentId":"1098"},{"id":"1104","name":"阜南县","code":"341225","parentId":"1098"},{"id":"1105","name":"颍上县","code":"341226","parentId":"1098"},{"id":"1106","name":"界首市","code":"341282","parentId":"1098"}]},{"id":"1107","name":"宿州市","code":"341300","parentId":"1017","children":[{"id":"1108","name":"埇桥区","code":"341302","parentId":"1107"},{"id":"1109","name":"砀山县","code":"341321","parentId":"1107"},{"id":"1110","name":"萧县","code":"341322","parentId":"1107"},{"id":"1111","name":"灵璧县","code":"341323","parentId":"1107"},{"id":"1112","name":"泗县","code":"341324","parentId":"1107"}]},{"id":"1113","name":"六安市","code":"341500","parentId":"1017","children":[{"id":"1114","name":"金安区","code":"341502","parentId":"1113"},{"id":"1115","name":"裕安区","code":"341503","parentId":"1113"},{"id":"1116","name":"叶集区","code":"341504","parentId":"1113"},{"id":"1117","name":"霍邱县","code":"341522","parentId":"1113"},{"id":"1118","name":"舒城县","code":"341523","parentId":"1113"},{"id":"1119","name":"金寨县","code":"341524","parentId":"1113"},{"id":"1120","name":"霍山县","code":"341525","parentId":"1113"}]},{"id":"1121","name":"亳州市","code":"341600","parentId":"1017","children":[{"id":"1122","name":"谯城区","code":"341602","parentId":"1121"},{"id":"1123","name":"涡阳县","code":"341621","parentId":"1121"},{"id":"1124","name":"蒙城县","code":"341622","parentId":"1121"},{"id":"1125","name":"利辛县","code":"341623","parentId":"1121"}]},{"id":"1126","name":"池州市","code":"341700","parentId":"1017","children":[{"id":"1127","name":"贵池区","code":"341702","parentId":"1126"},{"id":"1128","name":"东至县","code":"341721","parentId":"1126"},{"id":"1129","name":"石台县","code":"341722","parentId":"1126"},{"id":"1130","name":"青阳县","code":"341723","parentId":"1126"}]},{"id":"1131","name":"宣城市","code":"341800","parentId":"1017","children":[{"id":"1132","name":"宣州区","code":"341802","parentId":"1131"},{"id":"1133","name":"郎溪县","code":"341821","parentId":"1131"},{"id":"1134","name":"广德县","code":"341822","parentId":"1131"},{"id":"1135","name":"泾县","code":"341823","parentId":"1131"},{"id":"1136","name":"绩溪县","code":"341824","parentId":"1131"},{"id":"1137","name":"旌德县","code":"341825","parentId":"1131"},{"id":"1138","name":"宁国市","code":"341881","parentId":"1131"}]}]},{"id":"1139","name":"福建省","code":"350000","parentId":"0","children":[{"id":"1140","name":"福州市","code":"350100","parentId":"1139","children":[{"id":"1141","name":"鼓楼区","code":"350102","parentId":"1140"},{"id":"1142","name":"台江区","code":"350103","parentId":"1140"},{"id":"1143","name":"仓山区","code":"350104","parentId":"1140"},{"id":"1144","name":"马尾区","code":"350105","parentId":"1140"},{"id":"1145","name":"晋安区","code":"350111","parentId":"1140"},{"id":"1146","name":"长乐区","code":"350112","parentId":"1140"},{"id":"1147","name":"闽侯县","code":"350121","parentId":"1140"},{"id":"1148","name":"连江县","code":"350122","parentId":"1140"},{"id":"1149","name":"罗源县","code":"350123","parentId":"1140"},{"id":"1150","name":"闽清县","code":"350124","parentId":"1140"},{"id":"1151","name":"永泰县","code":"350125","parentId":"1140"},{"id":"1152","name":"平潭县","code":"350128","parentId":"1140"},{"id":"1153","name":"福清市","code":"350181","parentId":"1140"}]},{"id":"1154","name":"厦门市","code":"350200","parentId":"1139","children":[{"id":"1155","name":"思明区","code":"350203","parentId":"1154"},{"id":"1156","name":"海沧区","code":"350205","parentId":"1154"},{"id":"1157","name":"湖里区","code":"350206","parentId":"1154"},{"id":"1158","name":"集美区","code":"350211","parentId":"1154"},{"id":"1159","name":"同安区","code":"350212","parentId":"1154"},{"id":"1160","name":"翔安区","code":"350213","parentId":"1154"}]},{"id":"1161","name":"莆田市","code":"350300","parentId":"1139","children":[{"id":"1162","name":"城厢区","code":"350302","parentId":"1161"},{"id":"1163","name":"涵江区","code":"350303","parentId":"1161"},{"id":"1164","name":"荔城区","code":"350304","parentId":"1161"},{"id":"1165","name":"秀屿区","code":"350305","parentId":"1161"},{"id":"1166","name":"仙游县","code":"350322","parentId":"1161"}]},{"id":"1167","name":"三明市","code":"350400","parentId":"1139","children":[{"id":"1168","name":"梅列区","code":"350402","parentId":"1167"},{"id":"1169","name":"三元区","code":"350403","parentId":"1167"},{"id":"1170","name":"明溪县","code":"350421","parentId":"1167"},{"id":"1171","name":"清流县","code":"350423","parentId":"1167"},{"id":"1172","name":"宁化县","code":"350424","parentId":"1167"},{"id":"1173","name":"大田县","code":"350425","parentId":"1167"},{"id":"1174","name":"尤溪县","code":"350426","parentId":"1167"},{"id":"1175","name":"沙县","code":"350427","parentId":"1167"},{"id":"1176","name":"将乐县","code":"350428","parentId":"1167"},{"id":"1177","name":"泰宁县","code":"350429","parentId":"1167"},{"id":"1178","name":"建宁县","code":"350430","parentId":"1167"},{"id":"1179","name":"永安市","code":"350481","parentId":"1167"}]},{"id":"1180","name":"泉州市","code":"350500","parentId":"1139","children":[{"id":"1181","name":"鲤城区","code":"350502","parentId":"1180"},{"id":"1182","name":"丰泽区","code":"350503","parentId":"1180"},{"id":"1183","name":"洛江区","code":"350504","parentId":"1180"},{"id":"1184","name":"泉港区","code":"350505","parentId":"1180"},{"id":"1185","name":"惠安县","code":"350521","parentId":"1180"},{"id":"1186","name":"安溪县","code":"350524","parentId":"1180"},{"id":"1187","name":"永春县","code":"350525","parentId":"1180"},{"id":"1188","name":"德化县","code":"350526","parentId":"1180"},{"id":"1189","name":"金门县","code":"350527","parentId":"1180"},{"id":"1190","name":"石狮市","code":"350581","parentId":"1180"},{"id":"1191","name":"晋江市","code":"350582","parentId":"1180"},{"id":"1192","name":"南安市","code":"350583","parentId":"1180"}]},{"id":"1193","name":"漳州市","code":"350600","parentId":"1139","children":[{"id":"1194","name":"芗城区","code":"350602","parentId":"1193"},{"id":"1195","name":"龙文区","code":"350603","parentId":"1193"},{"id":"1196","name":"云霄县","code":"350622","parentId":"1193"},{"id":"1197","name":"漳浦县","code":"350623","parentId":"1193"},{"id":"1198","name":"诏安县","code":"350624","parentId":"1193"},{"id":"1199","name":"长泰县","code":"350625","parentId":"1193"},{"id":"1200","name":"东山县","code":"350626","parentId":"1193"},{"id":"1201","name":"南靖县","code":"350627","parentId":"1193"},{"id":"1202","name":"平和县","code":"350628","parentId":"1193"},{"id":"1203","name":"华安县","code":"350629","parentId":"1193"},{"id":"1204","name":"龙海市","code":"350681","parentId":"1193"}]},{"id":"1205","name":"南平市","code":"350700","parentId":"1139","children":[{"id":"1206","name":"延平区","code":"350702","parentId":"1205"},{"id":"1207","name":"建阳区","code":"350703","parentId":"1205"},{"id":"1208","name":"顺昌县","code":"350721","parentId":"1205"},{"id":"1209","name":"浦城县","code":"350722","parentId":"1205"},{"id":"1210","name":"光泽县","code":"350723","parentId":"1205"},{"id":"1211","name":"松溪县","code":"350724","parentId":"1205"},{"id":"1212","name":"政和县","code":"350725","parentId":"1205"},{"id":"1213","name":"邵武市","code":"350781","parentId":"1205"},{"id":"1214","name":"武夷山市","code":"350782","parentId":"1205"},{"id":"1215","name":"建瓯市","code":"350783","parentId":"1205"}]},{"id":"1216","name":"龙岩市","code":"350800","parentId":"1139","children":[{"id":"1217","name":"新罗区","code":"350802","parentId":"1216"},{"id":"1218","name":"永定区","code":"350803","parentId":"1216"},{"id":"1219","name":"长汀县","code":"350821","parentId":"1216"},{"id":"1220","name":"上杭县","code":"350823","parentId":"1216"},{"id":"1221","name":"武平县","code":"350824","parentId":"1216"},{"id":"1222","name":"连城县","code":"350825","parentId":"1216"},{"id":"1223","name":"漳平市","code":"350881","parentId":"1216"}]},{"id":"1224","name":"宁德市","code":"350900","parentId":"1139","children":[{"id":"1225","name":"蕉城区","code":"350902","parentId":"1224"},{"id":"1226","name":"霞浦县","code":"350921","parentId":"1224"},{"id":"1227","name":"古田县","code":"350922","parentId":"1224"},{"id":"1228","name":"屏南县","code":"350923","parentId":"1224"},{"id":"1229","name":"寿宁县","code":"350924","parentId":"1224"},{"id":"1230","name":"周宁县","code":"350925","parentId":"1224"},{"id":"1231","name":"柘荣县","code":"350926","parentId":"1224"},{"id":"1232","name":"福安市","code":"350981","parentId":"1224"},{"id":"1233","name":"福鼎市","code":"350982","parentId":"1224"}]}]},{"id":"1234","name":"江西省","code":"360000","parentId":"0","children":[{"id":"1235","name":"南昌市","code":"360100","parentId":"1234","children":[{"id":"1236","name":"东湖区","code":"360102","parentId":"1235"},{"id":"1237","name":"西湖区","code":"360103","parentId":"1235"},{"id":"1238","name":"青云谱区","code":"360104","parentId":"1235"},{"id":"1239","name":"湾里区","code":"360105","parentId":"1235"},{"id":"1240","name":"青山湖区","code":"360111","parentId":"1235"},{"id":"1241","name":"新建区","code":"360112","parentId":"1235"},{"id":"1242","name":"南昌县","code":"360121","parentId":"1235"},{"id":"1243","name":"安义县","code":"360123","parentId":"1235"},{"id":"1244","name":"进贤县","code":"360124","parentId":"1235"}]},{"id":"1245","name":"景德镇市","code":"360200","parentId":"1234","children":[{"id":"1246","name":"昌江区","code":"360202","parentId":"1245"},{"id":"1247","name":"珠山区","code":"360203","parentId":"1245"},{"id":"1248","name":"浮梁县","code":"360222","parentId":"1245"},{"id":"1249","name":"乐平市","code":"360281","parentId":"1245"}]},{"id":"1250","name":"萍乡市","code":"360300","parentId":"1234","children":[{"id":"1251","name":"安源区","code":"360302","parentId":"1250"},{"id":"1252","name":"湘东区","code":"360313","parentId":"1250"},{"id":"1253","name":"莲花县","code":"360321","parentId":"1250"},{"id":"1254","name":"上栗县","code":"360322","parentId":"1250"},{"id":"1255","name":"芦溪县","code":"360323","parentId":"1250"}]},{"id":"1256","name":"九江市","code":"360400","parentId":"1234","children":[{"id":"1257","name":"濂溪区","code":"360402","parentId":"1256"},{"id":"1258","name":"浔阳区","code":"360403","parentId":"1256"},{"id":"1259","name":"柴桑区","code":"360404","parentId":"1256"},{"id":"1260","name":"武宁县","code":"360423","parentId":"1256"},{"id":"1261","name":"修水县","code":"360424","parentId":"1256"},{"id":"1262","name":"永修县","code":"360425","parentId":"1256"},{"id":"1263","name":"德安县","code":"360426","parentId":"1256"},{"id":"1264","name":"都昌县","code":"360428","parentId":"1256"},{"id":"1265","name":"湖口县","code":"360429","parentId":"1256"},{"id":"1266","name":"彭泽县","code":"360430","parentId":"1256"},{"id":"1267","name":"瑞昌市","code":"360481","parentId":"1256"},{"id":"1268","name":"共青城市","code":"360482","parentId":"1256"},{"id":"1269","name":"庐山市","code":"360483","parentId":"1256"}]},{"id":"1270","name":"新余市","code":"360500","parentId":"1234","children":[{"id":"1271","name":"渝水区","code":"360502","parentId":"1270"},{"id":"1272","name":"分宜县","code":"360521","parentId":"1270"}]},{"id":"1273","name":"鹰潭市","code":"360600","parentId":"1234","children":[{"id":"1274","name":"月湖区","code":"360602","parentId":"1273"},{"id":"1275","name":"余江县","code":"360622","parentId":"1273"},{"id":"1276","name":"贵溪市","code":"360681","parentId":"1273"}]},{"id":"1277","name":"赣州市","code":"360700","parentId":"1234","children":[{"id":"1278","name":"章贡区","code":"360702","parentId":"1277"},{"id":"1279","name":"南康区","code":"360703","parentId":"1277"},{"id":"1280","name":"赣县区","code":"360704","parentId":"1277"},{"id":"1281","name":"信丰县","code":"360722","parentId":"1277"},{"id":"1282","name":"大余县","code":"360723","parentId":"1277"},{"id":"1283","name":"上犹县","code":"360724","parentId":"1277"},{"id":"1284","name":"崇义县","code":"360725","parentId":"1277"},{"id":"1285","name":"安远县","code":"360726","parentId":"1277"},{"id":"1286","name":"龙南县","code":"360727","parentId":"1277"},{"id":"1287","name":"定南县","code":"360728","parentId":"1277"},{"id":"1288","name":"全南县","code":"360729","parentId":"1277"},{"id":"1289","name":"宁都县","code":"360730","parentId":"1277"},{"id":"1290","name":"于都县","code":"360731","parentId":"1277"},{"id":"1291","name":"兴国县","code":"360732","parentId":"1277"},{"id":"1292","name":"会昌县","code":"360733","parentId":"1277"},{"id":"1293","name":"寻乌县","code":"360734","parentId":"1277"},{"id":"1294","name":"石城县","code":"360735","parentId":"1277"},{"id":"1295","name":"瑞金市","code":"360781","parentId":"1277"}]},{"id":"1296","name":"吉安市","code":"360800","parentId":"1234","children":[{"id":"1297","name":"吉州区","code":"360802","parentId":"1296"},{"id":"1298","name":"青原区","code":"360803","parentId":"1296"},{"id":"1299","name":"吉安县","code":"360821","parentId":"1296"},{"id":"1300","name":"吉水县","code":"360822","parentId":"1296"},{"id":"1301","name":"峡江县","code":"360823","parentId":"1296"},{"id":"1302","name":"新干县","code":"360824","parentId":"1296"},{"id":"1303","name":"永丰县","code":"360825","parentId":"1296"},{"id":"1304","name":"泰和县","code":"360826","parentId":"1296"},{"id":"1305","name":"遂川县","code":"360827","parentId":"1296"},{"id":"1306","name":"万安县","code":"360828","parentId":"1296"},{"id":"1307","name":"安福县","code":"360829","parentId":"1296"},{"id":"1308","name":"永新县","code":"360830","parentId":"1296"},{"id":"1309","name":"井冈山市","code":"360881","parentId":"1296"}]},{"id":"1310","name":"宜春市","code":"360900","parentId":"1234","children":[{"id":"1311","name":"袁州区","code":"360902","parentId":"1310"},{"id":"1312","name":"奉新县","code":"360921","parentId":"1310"},{"id":"1313","name":"万载县","code":"360922","parentId":"1310"},{"id":"1314","name":"上高县","code":"360923","parentId":"1310"},{"id":"1315","name":"宜丰县","code":"360924","parentId":"1310"},{"id":"1316","name":"靖安县","code":"360925","parentId":"1310"},{"id":"1317","name":"铜鼓县","code":"360926","parentId":"1310"},{"id":"1318","name":"丰城市","code":"360981","parentId":"1310"},{"id":"1319","name":"樟树市","code":"360982","parentId":"1310"},{"id":"1320","name":"高安市","code":"360983","parentId":"1310"}]},{"id":"1321","name":"抚州市","code":"361000","parentId":"1234","children":[{"id":"1322","name":"临川区","code":"361002","parentId":"1321"},{"id":"1323","name":"东乡区","code":"361003","parentId":"1321"},{"id":"1324","name":"南城县","code":"361021","parentId":"1321"},{"id":"1325","name":"黎川县","code":"361022","parentId":"1321"},{"id":"1326","name":"南丰县","code":"361023","parentId":"1321"},{"id":"1327","name":"崇仁县","code":"361024","parentId":"1321"},{"id":"1328","name":"乐安县","code":"361025","parentId":"1321"},{"id":"1329","name":"宜黄县","code":"361026","parentId":"1321"},{"id":"1330","name":"金溪县","code":"361027","parentId":"1321"},{"id":"1331","name":"资溪县","code":"361028","parentId":"1321"},{"id":"1332","name":"广昌县","code":"361030","parentId":"1321"}]},{"id":"1333","name":"上饶市","code":"361100","parentId":"1234","children":[{"id":"1334","name":"信州区","code":"361102","parentId":"1333"},{"id":"1335","name":"广丰区","code":"361103","parentId":"1333"},{"id":"1336","name":"上饶县","code":"361121","parentId":"1333"},{"id":"1337","name":"玉山县","code":"361123","parentId":"1333"},{"id":"1338","name":"铅山县","code":"361124","parentId":"1333"},{"id":"1339","name":"横峰县","code":"361125","parentId":"1333"},{"id":"1340","name":"弋阳县","code":"361126","parentId":"1333"},{"id":"1341","name":"余干县","code":"361127","parentId":"1333"},{"id":"1342","name":"鄱阳县","code":"361128","parentId":"1333"},{"id":"1343","name":"万年县","code":"361129","parentId":"1333"},{"id":"1344","name":"婺源县","code":"361130","parentId":"1333"},{"id":"1345","name":"德兴市","code":"361181","parentId":"1333"}]}]},{"id":"1346","name":"山东省","code":"370000","parentId":"0","children":[{"id":"1347","name":"济南市","code":"370100","parentId":"1346","children":[{"id":"1348","name":"历下区","code":"370102","parentId":"1347"},{"id":"1349","name":"市中区","code":"370103","parentId":"1347"},{"id":"1350","name":"槐荫区","code":"370104","parentId":"1347"},{"id":"1351","name":"天桥区","code":"370105","parentId":"1347"},{"id":"1352","name":"历城区","code":"370112","parentId":"1347"},{"id":"1353","name":"长清区","code":"370113","parentId":"1347"},{"id":"1354","name":"章丘区","code":"370114","parentId":"1347"},{"id":"1355","name":"平阴县","code":"370124","parentId":"1347"},{"id":"1356","name":"济阳县","code":"370125","parentId":"1347"},{"id":"1357","name":"商河县","code":"370126","parentId":"1347"}]},{"id":"1358","name":"青岛市","code":"370200","parentId":"1346","children":[{"id":"1359","name":"市南区","code":"370202","parentId":"1358"},{"id":"1360","name":"市北区","code":"370203","parentId":"1358"},{"id":"1361","name":"黄岛区","code":"370211","parentId":"1358"},{"id":"1362","name":"崂山区","code":"370212","parentId":"1358"},{"id":"1363","name":"李沧区","code":"370213","parentId":"1358"},{"id":"1364","name":"城阳区","code":"370214","parentId":"1358"},{"id":"1365","name":"即墨区","code":"370215","parentId":"1358"},{"id":"1366","name":"胶州市","code":"370281","parentId":"1358"},{"id":"1367","name":"平度市","code":"370283","parentId":"1358"},{"id":"1368","name":"莱西市","code":"370285","parentId":"1358"}]},{"id":"1369","name":"淄博市","code":"370300","parentId":"1346","children":[{"id":"1370","name":"淄川区","code":"370302","parentId":"1369"},{"id":"1371","name":"张店区","code":"370303","parentId":"1369"},{"id":"1372","name":"博山区","code":"370304","parentId":"1369"},{"id":"1373","name":"临淄区","code":"370305","parentId":"1369"},{"id":"1374","name":"周村区","code":"370306","parentId":"1369"},{"id":"1375","name":"桓台县","code":"370321","parentId":"1369"},{"id":"1376","name":"高青县","code":"370322","parentId":"1369"},{"id":"1377","name":"沂源县","code":"370323","parentId":"1369"}]},{"id":"1378","name":"枣庄市","code":"370400","parentId":"1346","children":[{"id":"1379","name":"市中区","code":"370402","parentId":"1378"},{"id":"1380","name":"薛城区","code":"370403","parentId":"1378"},{"id":"1381","name":"峄城区","code":"370404","parentId":"1378"},{"id":"1382","name":"台儿庄区","code":"370405","parentId":"1378"},{"id":"1383","name":"山亭区","code":"370406","parentId":"1378"},{"id":"1384","name":"滕州市","code":"370481","parentId":"1378"}]},{"id":"1385","name":"东营市","code":"370500","parentId":"1346","children":[{"id":"1386","name":"东营区","code":"370502","parentId":"1385"},{"id":"1387","name":"河口区","code":"370503","parentId":"1385"},{"id":"1388","name":"垦利区","code":"370505","parentId":"1385"},{"id":"1389","name":"利津县","code":"370522","parentId":"1385"},{"id":"1390","name":"广饶县","code":"370523","parentId":"1385"}]},{"id":"1391","name":"烟台市","code":"370600","parentId":"1346","children":[{"id":"1392","name":"芝罘区","code":"370602","parentId":"1391"},{"id":"1393","name":"福山区","code":"370611","parentId":"1391"},{"id":"1394","name":"牟平区","code":"370612","parentId":"1391"},{"id":"1395","name":"莱山区","code":"370613","parentId":"1391"},{"id":"1396","name":"长岛县","code":"370634","parentId":"1391"},{"id":"1397","name":"龙口市","code":"370681","parentId":"1391"},{"id":"1398","name":"莱阳市","code":"370682","parentId":"1391"},{"id":"1399","name":"莱州市","code":"370683","parentId":"1391"},{"id":"1400","name":"蓬莱市","code":"370684","parentId":"1391"},{"id":"1401","name":"招远市","code":"370685","parentId":"1391"},{"id":"1402","name":"栖霞市","code":"370686","parentId":"1391"},{"id":"1403","name":"海阳市","code":"370687","parentId":"1391"}]},{"id":"1404","name":"潍坊市","code":"370700","parentId":"1346","children":[{"id":"1405","name":"潍城区","code":"370702","parentId":"1404"},{"id":"1406","name":"寒亭区","code":"370703","parentId":"1404"},{"id":"1407","name":"坊子区","code":"370704","parentId":"1404"},{"id":"1408","name":"奎文区","code":"370705","parentId":"1404"},{"id":"1409","name":"临朐县","code":"370724","parentId":"1404"},{"id":"1410","name":"昌乐县","code":"370725","parentId":"1404"},{"id":"1411","name":"青州市","code":"370781","parentId":"1404"},{"id":"1412","name":"诸城市","code":"370782","parentId":"1404"},{"id":"1413","name":"寿光市","code":"370783","parentId":"1404"},{"id":"1414","name":"安丘市","code":"370784","parentId":"1404"},{"id":"1415","name":"高密市","code":"370785","parentId":"1404"},{"id":"1416","name":"昌邑市","code":"370786","parentId":"1404"}]},{"id":"1417","name":"济宁市","code":"370800","parentId":"1346","children":[{"id":"1418","name":"任城区","code":"370811","parentId":"1417"},{"id":"1419","name":"兖州区","code":"370812","parentId":"1417"},{"id":"1420","name":"微山县","code":"370826","parentId":"1417"},{"id":"1421","name":"鱼台县","code":"370827","parentId":"1417"},{"id":"1422","name":"金乡县","code":"370828","parentId":"1417"},{"id":"1423","name":"嘉祥县","code":"370829","parentId":"1417"},{"id":"1424","name":"汶上县","code":"370830","parentId":"1417"},{"id":"1425","name":"泗水县","code":"370831","parentId":"1417"},{"id":"1426","name":"梁山县","code":"370832","parentId":"1417"},{"id":"1427","name":"曲阜市","code":"370881","parentId":"1417"},{"id":"1428","name":"邹城市","code":"370883","parentId":"1417"}]},{"id":"1429","name":"泰安市","code":"370900","parentId":"1346","children":[{"id":"1430","name":"泰山区","code":"370902","parentId":"1429"},{"id":"1431","name":"岱岳区","code":"370911","parentId":"1429"},{"id":"1432","name":"宁阳县","code":"370921","parentId":"1429"},{"id":"1433","name":"东平县","code":"370923","parentId":"1429"},{"id":"1434","name":"新泰市","code":"370982","parentId":"1429"},{"id":"1435","name":"肥城市","code":"370983","parentId":"1429"}]},{"id":"1436","name":"威海市","code":"371000","parentId":"1346","children":[{"id":"1437","name":"环翠区","code":"371002","parentId":"1436"},{"id":"1438","name":"文登区","code":"371003","parentId":"1436"},{"id":"1439","name":"荣成市","code":"371082","parentId":"1436"},{"id":"1440","name":"乳山市","code":"371083","parentId":"1436"}]},{"id":"1441","name":"日照市","code":"371100","parentId":"1346","children":[{"id":"1442","name":"东港区","code":"371102","parentId":"1441"},{"id":"1443","name":"岚山区","code":"371103","parentId":"1441"},{"id":"1444","name":"五莲县","code":"371121","parentId":"1441"},{"id":"1445","name":"莒县","code":"371122","parentId":"1441"}]},{"id":"1446","name":"莱芜市","code":"371200","parentId":"1346","children":[{"id":"1447","name":"莱城区","code":"371202","parentId":"1446"},{"id":"1448","name":"钢城区","code":"371203","parentId":"1446"}]},{"id":"1449","name":"临沂市","code":"371300","parentId":"1346","children":[{"id":"1450","name":"兰山区","code":"371302","parentId":"1449"},{"id":"1451","name":"罗庄区","code":"371311","parentId":"1449"},{"id":"1452","name":"河东区","code":"371312","parentId":"1449"},{"id":"1453","name":"沂南县","code":"371321","parentId":"1449"},{"id":"1454","name":"郯城县","code":"371322","parentId":"1449"},{"id":"1455","name":"沂水县","code":"371323","parentId":"1449"},{"id":"1456","name":"兰陵县","code":"371324","parentId":"1449"},{"id":"1457","name":"费县","code":"371325","parentId":"1449"},{"id":"1458","name":"平邑县","code":"371326","parentId":"1449"},{"id":"1459","name":"莒南县","code":"371327","parentId":"1449"},{"id":"1460","name":"蒙阴县","code":"371328","parentId":"1449"},{"id":"1461","name":"临沭县","code":"371329","parentId":"1449"}]},{"id":"1462","name":"德州市","code":"371400","parentId":"1346","children":[{"id":"1463","name":"德城区","code":"371402","parentId":"1462"},{"id":"1464","name":"陵城区","code":"371403","parentId":"1462"},{"id":"1465","name":"宁津县","code":"371422","parentId":"1462"},{"id":"1466","name":"庆云县","code":"371423","parentId":"1462"},{"id":"1467","name":"临邑县","code":"371424","parentId":"1462"},{"id":"1468","name":"齐河县","code":"371425","parentId":"1462"},{"id":"1469","name":"平原县","code":"371426","parentId":"1462"},{"id":"1470","name":"夏津县","code":"371427","parentId":"1462"},{"id":"1471","name":"武城县","code":"371428","parentId":"1462"},{"id":"1472","name":"乐陵市","code":"371481","parentId":"1462"},{"id":"1473","name":"禹城市","code":"371482","parentId":"1462"}]},{"id":"1474","name":"聊城市","code":"371500","parentId":"1346","children":[{"id":"1475","name":"东昌府区","code":"371502","parentId":"1474"},{"id":"1476","name":"阳谷县","code":"371521","parentId":"1474"},{"id":"1477","name":"莘县","code":"371522","parentId":"1474"},{"id":"1478","name":"茌平县","code":"371523","parentId":"1474"},{"id":"1479","name":"东阿县","code":"371524","parentId":"1474"},{"id":"1480","name":"冠县","code":"371525","parentId":"1474"},{"id":"1481","name":"高唐县","code":"371526","parentId":"1474"},{"id":"1482","name":"临清市","code":"371581","parentId":"1474"}]},{"id":"1483","name":"滨州市","code":"371600","parentId":"1346","children":[{"id":"1484","name":"滨城区","code":"371602","parentId":"1483"},{"id":"1485","name":"沾化区","code":"371603","parentId":"1483"},{"id":"1486","name":"惠民县","code":"371621","parentId":"1483"},{"id":"1487","name":"阳信县","code":"371622","parentId":"1483"},{"id":"1488","name":"无棣县","code":"371623","parentId":"1483"},{"id":"1489","name":"博兴县","code":"371625","parentId":"1483"},{"id":"1490","name":"邹平县","code":"371626","parentId":"1483"}]},{"id":"1491","name":"菏泽市","code":"371700","parentId":"1346","children":[{"id":"1492","name":"牡丹区","code":"371702","parentId":"1491"},{"id":"1493","name":"定陶区","code":"371703","parentId":"1491"},{"id":"1494","name":"曹县","code":"371721","parentId":"1491"},{"id":"1495","name":"单县","code":"371722","parentId":"1491"},{"id":"1496","name":"成武县","code":"371723","parentId":"1491"},{"id":"1497","name":"巨野县","code":"371724","parentId":"1491"},{"id":"1498","name":"郓城县","code":"371725","parentId":"1491"},{"id":"1499","name":"鄄城县","code":"371726","parentId":"1491"},{"id":"1500","name":"东明县","code":"371728","parentId":"1491"}]}]},{"id":"1501","name":"河南省","code":"410000","parentId":"0","children":[{"id":"1502","name":"郑州市","code":"410100","parentId":"1501","children":[{"id":"1503","name":"中原区","code":"410102","parentId":"1502"},{"id":"1504","name":"二七区","code":"410103","parentId":"1502"},{"id":"1505","name":"管城回族区","code":"410104","parentId":"1502"},{"id":"1506","name":"金水区","code":"410105","parentId":"1502"},{"id":"1507","name":"上街区","code":"410106","parentId":"1502"},{"id":"1508","name":"惠济区","code":"410108","parentId":"1502"},{"id":"1509","name":"中牟县","code":"410122","parentId":"1502"},{"id":"1510","name":"巩义市","code":"410181","parentId":"1502"},{"id":"1511","name":"荥阳市","code":"410182","parentId":"1502"},{"id":"1512","name":"新密市","code":"410183","parentId":"1502"},{"id":"1513","name":"新郑市","code":"410184","parentId":"1502"},{"id":"1514","name":"登封市","code":"410185","parentId":"1502"}]},{"id":"1515","name":"开封市","code":"410200","parentId":"1501","children":[{"id":"1516","name":"龙亭区","code":"410202","parentId":"1515"},{"id":"1517","name":"顺河回族区","code":"410203","parentId":"1515"},{"id":"1518","name":"鼓楼区","code":"410204","parentId":"1515"},{"id":"1519","name":"禹王台区","code":"410205","parentId":"1515"},{"id":"1520","name":"祥符区","code":"410212","parentId":"1515"},{"id":"1521","name":"杞县","code":"410221","parentId":"1515"},{"id":"1522","name":"通许县","code":"410222","parentId":"1515"},{"id":"1523","name":"尉氏县","code":"410223","parentId":"1515"},{"id":"1524","name":"兰考县","code":"410225","parentId":"1515"}]},{"id":"1525","name":"洛阳市","code":"410300","parentId":"1501","children":[{"id":"1526","name":"老城区","code":"410302","parentId":"1525"},{"id":"1527","name":"西工区","code":"410303","parentId":"1525"},{"id":"1528","name":"瀍河回族区","code":"410304","parentId":"1525"},{"id":"1529","name":"涧西区","code":"410305","parentId":"1525"},{"id":"1530","name":"吉利区","code":"410306","parentId":"1525"},{"id":"1531","name":"洛龙区","code":"410311","parentId":"1525"},{"id":"1532","name":"孟津县","code":"410322","parentId":"1525"},{"id":"1533","name":"新安县","code":"410323","parentId":"1525"},{"id":"1534","name":"栾川县","code":"410324","parentId":"1525"},{"id":"1535","name":"嵩县","code":"410325","parentId":"1525"},{"id":"1536","name":"汝阳县","code":"410326","parentId":"1525"},{"id":"1537","name":"宜阳县","code":"410327","parentId":"1525"},{"id":"1538","name":"洛宁县","code":"410328","parentId":"1525"},{"id":"1539","name":"伊川县","code":"410329","parentId":"1525"},{"id":"1540","name":"偃师市","code":"410381","parentId":"1525"}]},{"id":"1541","name":"平顶山市","code":"410400","parentId":"1501","children":[{"id":"1542","name":"新华区","code":"410402","parentId":"1541"},{"id":"1543","name":"卫东区","code":"410403","parentId":"1541"},{"id":"1544","name":"石龙区","code":"410404","parentId":"1541"},{"id":"1545","name":"湛河区","code":"410411","parentId":"1541"},{"id":"1546","name":"宝丰县","code":"410421","parentId":"1541"},{"id":"1547","name":"叶县","code":"410422","parentId":"1541"},{"id":"1548","name":"鲁山县","code":"410423","parentId":"1541"},{"id":"1549","name":"郏县","code":"410425","parentId":"1541"},{"id":"1550","name":"舞钢市","code":"410481","parentId":"1541"},{"id":"1551","name":"汝州市","code":"410482","parentId":"1541"}]},{"id":"1552","name":"安阳市","code":"410500","parentId":"1501","children":[{"id":"1553","name":"文峰区","code":"410502","parentId":"1552"},{"id":"1554","name":"北关区","code":"410503","parentId":"1552"},{"id":"1555","name":"殷都区","code":"410505","parentId":"1552"},{"id":"1556","name":"龙安区","code":"410506","parentId":"1552"},{"id":"1557","name":"安阳县","code":"410522","parentId":"1552"},{"id":"1558","name":"汤阴县","code":"410523","parentId":"1552"},{"id":"1559","name":"滑县","code":"410526","parentId":"1552"},{"id":"1560","name":"内黄县","code":"410527","parentId":"1552"},{"id":"1561","name":"林州市","code":"410581","parentId":"1552"}]},{"id":"1562","name":"鹤壁市","code":"410600","parentId":"1501","children":[{"id":"1563","name":"鹤山区","code":"410602","parentId":"1562"},{"id":"1564","name":"山城区","code":"410603","parentId":"1562"},{"id":"1565","name":"淇滨区","code":"410611","parentId":"1562"},{"id":"1566","name":"浚县","code":"410621","parentId":"1562"},{"id":"1567","name":"淇县","code":"410622","parentId":"1562"}]},{"id":"1568","name":"新乡市","code":"410700","parentId":"1501","children":[{"id":"1569","name":"红旗区","code":"410702","parentId":"1568"},{"id":"1570","name":"卫滨区","code":"410703","parentId":"1568"},{"id":"1571","name":"凤泉区","code":"410704","parentId":"1568"},{"id":"1572","name":"牧野区","code":"410711","parentId":"1568"},{"id":"1573","name":"新乡县","code":"410721","parentId":"1568"},{"id":"1574","name":"获嘉县","code":"410724","parentId":"1568"},{"id":"1575","name":"原阳县","code":"410725","parentId":"1568"},{"id":"1576","name":"延津县","code":"410726","parentId":"1568"},{"id":"1577","name":"封丘县","code":"410727","parentId":"1568"},{"id":"1578","name":"长垣县","code":"410728","parentId":"1568"},{"id":"1579","name":"卫辉市","code":"410781","parentId":"1568"},{"id":"1580","name":"辉县市","code":"410782","parentId":"1568"}]},{"id":"1581","name":"焦作市","code":"410800","parentId":"1501","children":[{"id":"1582","name":"解放区","code":"410802","parentId":"1581"},{"id":"1583","name":"中站区","code":"410803","parentId":"1581"},{"id":"1584","name":"马村区","code":"410804","parentId":"1581"},{"id":"1585","name":"山阳区","code":"410811","parentId":"1581"},{"id":"1586","name":"修武县","code":"410821","parentId":"1581"},{"id":"1587","name":"博爱县","code":"410822","parentId":"1581"},{"id":"1588","name":"武陟县","code":"410823","parentId":"1581"},{"id":"1589","name":"温县","code":"410825","parentId":"1581"},{"id":"1590","name":"沁阳市","code":"410882","parentId":"1581"},{"id":"1591","name":"孟州市","code":"410883","parentId":"1581"}]},{"id":"1592","name":"濮阳市","code":"410900","parentId":"1501","children":[{"id":"1593","name":"华龙区","code":"410902","parentId":"1592"},{"id":"1594","name":"清丰县","code":"410922","parentId":"1592"},{"id":"1595","name":"南乐县","code":"410923","parentId":"1592"},{"id":"1596","name":"范县","code":"410926","parentId":"1592"},{"id":"1597","name":"台前县","code":"410927","parentId":"1592"},{"id":"1598","name":"濮阳县","code":"410928","parentId":"1592"}]},{"id":"1599","name":"许昌市","code":"411000","parentId":"1501","children":[{"id":"1600","name":"魏都区","code":"411002","parentId":"1599"},{"id":"1601","name":"建安区","code":"411003","parentId":"1599"},{"id":"1602","name":"鄢陵县","code":"411024","parentId":"1599"},{"id":"1603","name":"襄城县","code":"411025","parentId":"1599"},{"id":"1604","name":"禹州市","code":"411081","parentId":"1599"},{"id":"1605","name":"长葛市","code":"411082","parentId":"1599"}]},{"id":"1606","name":"漯河市","code":"411100","parentId":"1501","children":[{"id":"1607","name":"源汇区","code":"411102","parentId":"1606"},{"id":"1608","name":"郾城区","code":"411103","parentId":"1606"},{"id":"1609","name":"召陵区","code":"411104","parentId":"1606"},{"id":"1610","name":"舞阳县","code":"411121","parentId":"1606"},{"id":"1611","name":"临颍县","code":"411122","parentId":"1606"}]},{"id":"1612","name":"三门峡市","code":"411200","parentId":"1501","children":[{"id":"1613","name":"湖滨区","code":"411202","parentId":"1612"},{"id":"1614","name":"陕州区","code":"411203","parentId":"1612"},{"id":"1615","name":"渑池县","code":"411221","parentId":"1612"},{"id":"1616","name":"卢氏县","code":"411224","parentId":"1612"},{"id":"1617","name":"义马市","code":"411281","parentId":"1612"},{"id":"1618","name":"灵宝市","code":"411282","parentId":"1612"}]},{"id":"1619","name":"南阳市","code":"411300","parentId":"1501","children":[{"id":"1620","name":"宛城区","code":"411302","parentId":"1619"},{"id":"1621","name":"卧龙区","code":"411303","parentId":"1619"},{"id":"1622","name":"南召县","code":"411321","parentId":"1619"},{"id":"1623","name":"方城县","code":"411322","parentId":"1619"},{"id":"1624","name":"西峡县","code":"411323","parentId":"1619"},{"id":"1625","name":"镇平县","code":"411324","parentId":"1619"},{"id":"1626","name":"内乡县","code":"411325","parentId":"1619"},{"id":"1627","name":"淅川县","code":"411326","parentId":"1619"},{"id":"1628","name":"社旗县","code":"411327","parentId":"1619"},{"id":"1629","name":"唐河县","code":"411328","parentId":"1619"},{"id":"1630","name":"新野县","code":"411329","parentId":"1619"},{"id":"1631","name":"桐柏县","code":"411330","parentId":"1619"},{"id":"1632","name":"邓州市","code":"411381","parentId":"1619"}]},{"id":"1633","name":"商丘市","code":"411400","parentId":"1501","children":[{"id":"1634","name":"梁园区","code":"411402","parentId":"1633"},{"id":"1635","name":"睢阳区","code":"411403","parentId":"1633"},{"id":"1636","name":"民权县","code":"411421","parentId":"1633"},{"id":"1637","name":"睢县","code":"411422","parentId":"1633"},{"id":"1638","name":"宁陵县","code":"411423","parentId":"1633"},{"id":"1639","name":"柘城县","code":"411424","parentId":"1633"},{"id":"1640","name":"虞城县","code":"411425","parentId":"1633"},{"id":"1641","name":"夏邑县","code":"411426","parentId":"1633"},{"id":"1642","name":"永城市","code":"411481","parentId":"1633"}]},{"id":"1643","name":"信阳市","code":"411500","parentId":"1501","children":[{"id":"1644","name":"浉河区","code":"411502","parentId":"1643"},{"id":"1645","name":"平桥区","code":"411503","parentId":"1643"},{"id":"1646","name":"罗山县","code":"411521","parentId":"1643"},{"id":"1647","name":"光山县","code":"411522","parentId":"1643"},{"id":"1648","name":"新县","code":"411523","parentId":"1643"},{"id":"1649","name":"商城县","code":"411524","parentId":"1643"},{"id":"1650","name":"固始县","code":"411525","parentId":"1643"},{"id":"1651","name":"潢川县","code":"411526","parentId":"1643"},{"id":"1652","name":"淮滨县","code":"411527","parentId":"1643"},{"id":"1653","name":"息县","code":"411528","parentId":"1643"}]},{"id":"1654","name":"周口市","code":"411600","parentId":"1501","children":[{"id":"1655","name":"川汇区","code":"411602","parentId":"1654"},{"id":"1656","name":"扶沟县","code":"411621","parentId":"1654"},{"id":"1657","name":"西华县","code":"411622","parentId":"1654"},{"id":"1658","name":"商水县","code":"411623","parentId":"1654"},{"id":"1659","name":"沈丘县","code":"411624","parentId":"1654"},{"id":"1660","name":"郸城县","code":"411625","parentId":"1654"},{"id":"1661","name":"淮阳县","code":"411626","parentId":"1654"},{"id":"1662","name":"太康县","code":"411627","parentId":"1654"},{"id":"1663","name":"鹿邑县","code":"411628","parentId":"1654"},{"id":"1664","name":"项城市","code":"411681","parentId":"1654"}]},{"id":"1665","name":"驻马店市","code":"411700","parentId":"1501","children":[{"id":"1666","name":"驿城区","code":"411702","parentId":"1665"},{"id":"1667","name":"西平县","code":"411721","parentId":"1665"},{"id":"1668","name":"上蔡县","code":"411722","parentId":"1665"},{"id":"1669","name":"平舆县","code":"411723","parentId":"1665"},{"id":"1670","name":"正阳县","code":"411724","parentId":"1665"},{"id":"1671","name":"确山县","code":"411725","parentId":"1665"},{"id":"1672","name":"泌阳县","code":"411726","parentId":"1665"},{"id":"1673","name":"汝南县","code":"411727","parentId":"1665"},{"id":"1674","name":"遂平县","code":"411728","parentId":"1665"},{"id":"1675","name":"新蔡县","code":"411729","parentId":"1665"}]},{"id":"1676","name":"济源市","code":"419001","parentId":"1501","children":[{"id":"3465","name":"辖区","code":"-1","parentId":"1676"}]}]},{"id":"1677","name":"湖北省","code":"420000","parentId":"0","children":[{"id":"1678","name":"武汉市","code":"420100","parentId":"1677","children":[{"id":"1679","name":"江岸区","code":"420102","parentId":"1678"},{"id":"1680","name":"江汉区","code":"420103","parentId":"1678"},{"id":"1681","name":"硚口区","code":"420104","parentId":"1678"},{"id":"1682","name":"汉阳区","code":"420105","parentId":"1678"},{"id":"1683","name":"武昌区","code":"420106","parentId":"1678"},{"id":"1684","name":"青山区","code":"420107","parentId":"1678"},{"id":"1685","name":"洪山区","code":"420111","parentId":"1678"},{"id":"1686","name":"东西湖区","code":"420112","parentId":"1678"},{"id":"1687","name":"汉南区","code":"420113","parentId":"1678"},{"id":"1688","name":"蔡甸区","code":"420114","parentId":"1678"},{"id":"1689","name":"江夏区","code":"420115","parentId":"1678"},{"id":"1690","name":"黄陂区","code":"420116","parentId":"1678"},{"id":"1691","name":"新洲区","code":"420117","parentId":"1678"}]},{"id":"1692","name":"黄石市","code":"420200","parentId":"1677","children":[{"id":"1693","name":"黄石港区","code":"420202","parentId":"1692"},{"id":"1694","name":"西塞山区","code":"420203","parentId":"1692"},{"id":"1695","name":"下陆区","code":"420204","parentId":"1692"},{"id":"1696","name":"铁山区","code":"420205","parentId":"1692"},{"id":"1697","name":"阳新县","code":"420222","parentId":"1692"},{"id":"1698","name":"大冶市","code":"420281","parentId":"1692"}]},{"id":"1699","name":"十堰市","code":"420300","parentId":"1677","children":[{"id":"1700","name":"茅箭区","code":"420302","parentId":"1699"},{"id":"1701","name":"张湾区","code":"420303","parentId":"1699"},{"id":"1702","name":"郧阳区","code":"420304","parentId":"1699"},{"id":"1703","name":"郧西县","code":"420322","parentId":"1699"},{"id":"1704","name":"竹山县","code":"420323","parentId":"1699"},{"id":"1705","name":"竹溪县","code":"420324","parentId":"1699"},{"id":"1706","name":"房县","code":"420325","parentId":"1699"},{"id":"1707","name":"丹江口市","code":"420381","parentId":"1699"}]},{"id":"1708","name":"宜昌市","code":"420500","parentId":"1677","children":[{"id":"1709","name":"西陵区","code":"420502","parentId":"1708"},{"id":"1710","name":"伍家岗区","code":"420503","parentId":"1708"},{"id":"1711","name":"点军区","code":"420504","parentId":"1708"},{"id":"1712","name":"猇亭区","code":"420505","parentId":"1708"},{"id":"1713","name":"夷陵区","code":"420506","parentId":"1708"},{"id":"1714","name":"远安县","code":"420525","parentId":"1708"},{"id":"1715","name":"兴山县","code":"420526","parentId":"1708"},{"id":"1716","name":"秭归县","code":"420527","parentId":"1708"},{"id":"1717","name":"长阳土家族自治县","code":"420528","parentId":"1708"},{"id":"1718","name":"五峰土家族自治县","code":"420529","parentId":"1708"},{"id":"1719","name":"宜都市","code":"420581","parentId":"1708"},{"id":"1720","name":"当阳市","code":"420582","parentId":"1708"},{"id":"1721","name":"枝江市","code":"420583","parentId":"1708"}]},{"id":"1722","name":"襄阳市","code":"420600","parentId":"1677","children":[{"id":"1723","name":"襄城区","code":"420602","parentId":"1722"},{"id":"1724","name":"樊城区","code":"420606","parentId":"1722"},{"id":"1725","name":"襄州区","code":"420607","parentId":"1722"},{"id":"1726","name":"南漳县","code":"420624","parentId":"1722"},{"id":"1727","name":"谷城县","code":"420625","parentId":"1722"},{"id":"1728","name":"保康县","code":"420626","parentId":"1722"},{"id":"1729","name":"老河口市","code":"420682","parentId":"1722"},{"id":"1730","name":"枣阳市","code":"420683","parentId":"1722"},{"id":"1731","name":"宜城市","code":"420684","parentId":"1722"}]},{"id":"1732","name":"鄂州市","code":"420700","parentId":"1677","children":[{"id":"1733","name":"梁子湖区","code":"420702","parentId":"1732"},{"id":"1734","name":"华容区","code":"420703","parentId":"1732"},{"id":"1735","name":"鄂城区","code":"420704","parentId":"1732"}]},{"id":"1736","name":"荆门市","code":"420800","parentId":"1677","children":[{"id":"1737","name":"东宝区","code":"420802","parentId":"1736"},{"id":"1738","name":"掇刀区","code":"420804","parentId":"1736"},{"id":"1739","name":"京山县","code":"420821","parentId":"1736"},{"id":"1740","name":"沙洋县","code":"420822","parentId":"1736"},{"id":"1741","name":"钟祥市","code":"420881","parentId":"1736"}]},{"id":"1742","name":"孝感市","code":"420900","parentId":"1677","children":[{"id":"1743","name":"孝南区","code":"420902","parentId":"1742"},{"id":"1744","name":"孝昌县","code":"420921","parentId":"1742"},{"id":"1745","name":"大悟县","code":"420922","parentId":"1742"},{"id":"1746","name":"云梦县","code":"420923","parentId":"1742"},{"id":"1747","name":"应城市","code":"420981","parentId":"1742"},{"id":"1748","name":"安陆市","code":"420982","parentId":"1742"},{"id":"1749","name":"汉川市","code":"420984","parentId":"1742"}]},{"id":"1750","name":"荆州市","code":"421000","parentId":"1677","children":[{"id":"1751","name":"沙市区","code":"421002","parentId":"1750"},{"id":"1752","name":"荆州区","code":"421003","parentId":"1750"},{"id":"1753","name":"公安县","code":"421022","parentId":"1750"},{"id":"1754","name":"监利县","code":"421023","parentId":"1750"},{"id":"1755","name":"江陵县","code":"421024","parentId":"1750"},{"id":"1756","name":"石首市","code":"421081","parentId":"1750"},{"id":"1757","name":"洪湖市","code":"421083","parentId":"1750"},{"id":"1758","name":"松滋市","code":"421087","parentId":"1750"}]},{"id":"1759","name":"黄冈市","code":"421100","parentId":"1677","children":[{"id":"1760","name":"黄州区","code":"421102","parentId":"1759"},{"id":"1761","name":"团风县","code":"421121","parentId":"1759"},{"id":"1762","name":"红安县","code":"421122","parentId":"1759"},{"id":"1763","name":"罗田县","code":"421123","parentId":"1759"},{"id":"1764","name":"英山县","code":"421124","parentId":"1759"},{"id":"1765","name":"浠水县","code":"421125","parentId":"1759"},{"id":"1766","name":"蕲春县","code":"421126","parentId":"1759"},{"id":"1767","name":"黄梅县","code":"421127","parentId":"1759"},{"id":"1768","name":"麻城市","code":"421181","parentId":"1759"},{"id":"1769","name":"武穴市","code":"421182","parentId":"1759"}]},{"id":"1770","name":"咸宁市","code":"421200","parentId":"1677","children":[{"id":"1771","name":"咸安区","code":"421202","parentId":"1770"},{"id":"1772","name":"嘉鱼县","code":"421221","parentId":"1770"},{"id":"1773","name":"通城县","code":"421222","parentId":"1770"},{"id":"1774","name":"崇阳县","code":"421223","parentId":"1770"},{"id":"1775","name":"通山县","code":"421224","parentId":"1770"},{"id":"1776","name":"赤壁市","code":"421281","parentId":"1770"}]},{"id":"1777","name":"随州市","code":"421300","parentId":"1677","children":[{"id":"1778","name":"曾都区","code":"421303","parentId":"1777"},{"id":"1779","name":"随县","code":"421321","parentId":"1777"},{"id":"1780","name":"广水市","code":"421381","parentId":"1777"}]},{"id":"1781","name":"恩施土家族苗族自治州","code":"422800","parentId":"1677","children":[{"id":"1782","name":"恩施市","code":"422801","parentId":"1781"},{"id":"1783","name":"利川市","code":"422802","parentId":"1781"},{"id":"1784","name":"建始县","code":"422822","parentId":"1781"},{"id":"1785","name":"巴东县","code":"422823","parentId":"1781"},{"id":"1786","name":"宣恩县","code":"422825","parentId":"1781"},{"id":"1787","name":"咸丰县","code":"422826","parentId":"1781"},{"id":"1788","name":"来凤县","code":"422827","parentId":"1781"},{"id":"1789","name":"鹤峰县","code":"422828","parentId":"1781"}]},{"id":"1790","name":"仙桃市","code":"429004","parentId":"1677","children":[{"id":"3466","name":"辖区","code":"-1","parentId":"1790"}]},{"id":"1791","name":"潜江市","code":"429005","parentId":"1677","children":[{"id":"3467","name":"辖区","code":"-1","parentId":"1791"}]},{"id":"1792","name":"天门市","code":"429006","parentId":"1677","children":[{"id":"3468","name":"辖区","code":"-1","parentId":"1792"}]},{"id":"1793","name":"神农架林区","code":"429021","parentId":"1677","children":[{"id":"3469","name":"辖区","code":"-1","parentId":"1793"}]}]},{"id":"1794","name":"湖南省","code":"430000","parentId":"0","children":[{"id":"1795","name":"长沙市","code":"430100","parentId":"1794","children":[{"id":"1796","name":"芙蓉区","code":"430102","parentId":"1795"},{"id":"1797","name":"天心区","code":"430103","parentId":"1795"},{"id":"1798","name":"岳麓区","code":"430104","parentId":"1795"},{"id":"1799","name":"开福区","code":"430105","parentId":"1795"},{"id":"1800","name":"雨花区","code":"430111","parentId":"1795"},{"id":"1801","name":"望城区","code":"430112","parentId":"1795"},{"id":"1802","name":"长沙县","code":"430121","parentId":"1795"},{"id":"1803","name":"浏阳市","code":"430181","parentId":"1795"},{"id":"1804","name":"宁乡市","code":"430182","parentId":"1795"}]},{"id":"1805","name":"株洲市","code":"430200","parentId":"1794","children":[{"id":"1806","name":"荷塘区","code":"430202","parentId":"1805"},{"id":"1807","name":"芦淞区","code":"430203","parentId":"1805"},{"id":"1808","name":"石峰区","code":"430204","parentId":"1805"},{"id":"1809","name":"天元区","code":"430211","parentId":"1805"},{"id":"1810","name":"株洲县","code":"430221","parentId":"1805"},{"id":"1811","name":"攸县","code":"430223","parentId":"1805"},{"id":"1812","name":"茶陵县","code":"430224","parentId":"1805"},{"id":"1813","name":"炎陵县","code":"430225","parentId":"1805"},{"id":"1814","name":"醴陵市","code":"430281","parentId":"1805"}]},{"id":"1815","name":"湘潭市","code":"430300","parentId":"1794","children":[{"id":"1816","name":"雨湖区","code":"430302","parentId":"1815"},{"id":"1817","name":"岳塘区","code":"430304","parentId":"1815"},{"id":"1818","name":"湘潭县","code":"430321","parentId":"1815"},{"id":"1819","name":"湘乡市","code":"430381","parentId":"1815"},{"id":"1820","name":"韶山市","code":"430382","parentId":"1815"}]},{"id":"1821","name":"衡阳市","code":"430400","parentId":"1794","children":[{"id":"1822","name":"珠晖区","code":"430405","parentId":"1821"},{"id":"1823","name":"雁峰区","code":"430406","parentId":"1821"},{"id":"1824","name":"石鼓区","code":"430407","parentId":"1821"},{"id":"1825","name":"蒸湘区","code":"430408","parentId":"1821"},{"id":"1826","name":"南岳区","code":"430412","parentId":"1821"},{"id":"1827","name":"衡阳县","code":"430421","parentId":"1821"},{"id":"1828","name":"衡南县","code":"430422","parentId":"1821"},{"id":"1829","name":"衡山县","code":"430423","parentId":"1821"},{"id":"1830","name":"衡东县","code":"430424","parentId":"1821"},{"id":"1831","name":"祁东县","code":"430426","parentId":"1821"},{"id":"1832","name":"耒阳市","code":"430481","parentId":"1821"},{"id":"1833","name":"常宁市","code":"430482","parentId":"1821"}]},{"id":"1834","name":"邵阳市","code":"430500","parentId":"1794","children":[{"id":"1835","name":"双清区","code":"430502","parentId":"1834"},{"id":"1836","name":"大祥区","code":"430503","parentId":"1834"},{"id":"1837","name":"北塔区","code":"430511","parentId":"1834"},{"id":"1838","name":"邵东县","code":"430521","parentId":"1834"},{"id":"1839","name":"新邵县","code":"430522","parentId":"1834"},{"id":"1840","name":"邵阳县","code":"430523","parentId":"1834"},{"id":"1841","name":"隆回县","code":"430524","parentId":"1834"},{"id":"1842","name":"洞口县","code":"430525","parentId":"1834"},{"id":"1843","name":"绥宁县","code":"430527","parentId":"1834"},{"id":"1844","name":"新宁县","code":"430528","parentId":"1834"},{"id":"1845","name":"城步苗族自治县","code":"430529","parentId":"1834"},{"id":"1846","name":"武冈市","code":"430581","parentId":"1834"}]},{"id":"1847","name":"岳阳市","code":"430600","parentId":"1794","children":[{"id":"1848","name":"岳阳楼区","code":"430602","parentId":"1847"},{"id":"1849","name":"云溪区","code":"430603","parentId":"1847"},{"id":"1850","name":"君山区","code":"430611","parentId":"1847"},{"id":"1851","name":"岳阳县","code":"430621","parentId":"1847"},{"id":"1852","name":"华容县","code":"430623","parentId":"1847"},{"id":"1853","name":"湘阴县","code":"430624","parentId":"1847"},{"id":"1854","name":"平江县","code":"430626","parentId":"1847"},{"id":"1855","name":"汨罗市","code":"430681","parentId":"1847"},{"id":"1856","name":"临湘市","code":"430682","parentId":"1847"}]},{"id":"1857","name":"常德市","code":"430700","parentId":"1794","children":[{"id":"1858","name":"武陵区","code":"430702","parentId":"1857"},{"id":"1859","name":"鼎城区","code":"430703","parentId":"1857"},{"id":"1860","name":"安乡县","code":"430721","parentId":"1857"},{"id":"1861","name":"汉寿县","code":"430722","parentId":"1857"},{"id":"1862","name":"澧县","code":"430723","parentId":"1857"},{"id":"1863","name":"临澧县","code":"430724","parentId":"1857"},{"id":"1864","name":"桃源县","code":"430725","parentId":"1857"},{"id":"1865","name":"石门县","code":"430726","parentId":"1857"},{"id":"1866","name":"津市市","code":"430781","parentId":"1857"}]},{"id":"1867","name":"张家界市","code":"430800","parentId":"1794","children":[{"id":"1868","name":"永定区","code":"430802","parentId":"1867"},{"id":"1869","name":"武陵源区","code":"430811","parentId":"1867"},{"id":"1870","name":"慈利县","code":"430821","parentId":"1867"},{"id":"1871","name":"桑植县","code":"430822","parentId":"1867"}]},{"id":"1872","name":"益阳市","code":"430900","parentId":"1794","children":[{"id":"1873","name":"资阳区","code":"430902","parentId":"1872"},{"id":"1874","name":"赫山区","code":"430903","parentId":"1872"},{"id":"1875","name":"南县","code":"430921","parentId":"1872"},{"id":"1876","name":"桃江县","code":"430922","parentId":"1872"},{"id":"1877","name":"安化县","code":"430923","parentId":"1872"},{"id":"1878","name":"沅江市","code":"430981","parentId":"1872"}]},{"id":"1879","name":"郴州市","code":"431000","parentId":"1794","children":[{"id":"1880","name":"北湖区","code":"431002","parentId":"1879"},{"id":"1881","name":"苏仙区","code":"431003","parentId":"1879"},{"id":"1882","name":"桂阳县","code":"431021","parentId":"1879"},{"id":"1883","name":"宜章县","code":"431022","parentId":"1879"},{"id":"1884","name":"永兴县","code":"431023","parentId":"1879"},{"id":"1885","name":"嘉禾县","code":"431024","parentId":"1879"},{"id":"1886","name":"临武县","code":"431025","parentId":"1879"},{"id":"1887","name":"汝城县","code":"431026","parentId":"1879"},{"id":"1888","name":"桂东县","code":"431027","parentId":"1879"},{"id":"1889","name":"安仁县","code":"431028","parentId":"1879"},{"id":"1890","name":"资兴市","code":"431081","parentId":"1879"}]},{"id":"1891","name":"永州市","code":"431100","parentId":"1794","children":[{"id":"1892","name":"零陵区","code":"431102","parentId":"1891"},{"id":"1893","name":"冷水滩区","code":"431103","parentId":"1891"},{"id":"1894","name":"祁阳县","code":"431121","parentId":"1891"},{"id":"1895","name":"东安县","code":"431122","parentId":"1891"},{"id":"1896","name":"双牌县","code":"431123","parentId":"1891"},{"id":"1897","name":"道县","code":"431124","parentId":"1891"},{"id":"1898","name":"江永县","code":"431125","parentId":"1891"},{"id":"1899","name":"宁远县","code":"431126","parentId":"1891"},{"id":"1900","name":"蓝山县","code":"431127","parentId":"1891"},{"id":"1901","name":"新田县","code":"431128","parentId":"1891"},{"id":"1902","name":"江华瑶族自治县","code":"431129","parentId":"1891"}]},{"id":"1903","name":"怀化市","code":"431200","parentId":"1794","children":[{"id":"1904","name":"鹤城区","code":"431202","parentId":"1903"},{"id":"1905","name":"中方县","code":"431221","parentId":"1903"},{"id":"1906","name":"沅陵县","code":"431222","parentId":"1903"},{"id":"1907","name":"辰溪县","code":"431223","parentId":"1903"},{"id":"1908","name":"溆浦县","code":"431224","parentId":"1903"},{"id":"1909","name":"会同县","code":"431225","parentId":"1903"},{"id":"1910","name":"麻阳苗族自治县","code":"431226","parentId":"1903"},{"id":"1911","name":"新晃侗族自治县","code":"431227","parentId":"1903"},{"id":"1912","name":"芷江侗族自治县","code":"431228","parentId":"1903"},{"id":"1913","name":"靖州苗族侗族自治县","code":"431229","parentId":"1903"},{"id":"1914","name":"通道侗族自治县","code":"431230","parentId":"1903"},{"id":"1915","name":"洪江市","code":"431281","parentId":"1903"}]},{"id":"1916","name":"娄底市","code":"431300","parentId":"1794","children":[{"id":"1917","name":"娄星区","code":"431302","parentId":"1916"},{"id":"1918","name":"双峰县","code":"431321","parentId":"1916"},{"id":"1919","name":"新化县","code":"431322","parentId":"1916"},{"id":"1920","name":"冷水江市","code":"431381","parentId":"1916"},{"id":"1921","name":"涟源市","code":"431382","parentId":"1916"}]},{"id":"1922","name":"湘西土家族苗族自治州","code":"433100","parentId":"1794","children":[{"id":"1923","name":"吉首市","code":"433101","parentId":"1922"},{"id":"1924","name":"泸溪县","code":"433122","parentId":"1922"},{"id":"1925","name":"凤凰县","code":"433123","parentId":"1922"},{"id":"1926","name":"花垣县","code":"433124","parentId":"1922"},{"id":"1927","name":"保靖县","code":"433125","parentId":"1922"},{"id":"1928","name":"古丈县","code":"433126","parentId":"1922"},{"id":"1929","name":"永顺县","code":"433127","parentId":"1922"},{"id":"1930","name":"龙山县","code":"433130","parentId":"1922"}]}]},{"id":"1931","name":"广东省","code":"440000","parentId":"0","children":[{"id":"1932","name":"广州市","code":"440100","parentId":"1931","children":[{"id":"1933","name":"荔湾区","code":"440103","parentId":"1932"},{"id":"1934","name":"越秀区","code":"440104","parentId":"1932"},{"id":"1935","name":"海珠区","code":"440105","parentId":"1932"},{"id":"1936","name":"天河区","code":"440106","parentId":"1932"},{"id":"1937","name":"白云区","code":"440111","parentId":"1932"},{"id":"1938","name":"黄埔区","code":"440112","parentId":"1932"},{"id":"1939","name":"番禺区","code":"440113","parentId":"1932"},{"id":"1940","name":"花都区","code":"440114","parentId":"1932"},{"id":"1941","name":"南沙区","code":"440115","parentId":"1932"},{"id":"1942","name":"从化区","code":"440117","parentId":"1932"},{"id":"1943","name":"增城区","code":"440118","parentId":"1932"}]},{"id":"1944","name":"韶关市","code":"440200","parentId":"1931","children":[{"id":"1945","name":"武江区","code":"440203","parentId":"1944"},{"id":"1946","name":"浈江区","code":"440204","parentId":"1944"},{"id":"1947","name":"曲江区","code":"440205","parentId":"1944"},{"id":"1948","name":"始兴县","code":"440222","parentId":"1944"},{"id":"1949","name":"仁化县","code":"440224","parentId":"1944"},{"id":"1950","name":"翁源县","code":"440229","parentId":"1944"},{"id":"1951","name":"乳源瑶族自治县","code":"440232","parentId":"1944"},{"id":"1952","name":"新丰县","code":"440233","parentId":"1944"},{"id":"1953","name":"乐昌市","code":"440281","parentId":"1944"},{"id":"1954","name":"南雄市","code":"440282","parentId":"1944"}]},{"id":"1955","name":"深圳市","code":"440300","parentId":"1931","children":[{"id":"1956","name":"罗湖区","code":"440303","parentId":"1955"},{"id":"1957","name":"福田区","code":"440304","parentId":"1955"},{"id":"1958","name":"南山区","code":"440305","parentId":"1955"},{"id":"1959","name":"宝安区","code":"440306","parentId":"1955"},{"id":"1960","name":"龙岗区","code":"440307","parentId":"1955"},{"id":"1961","name":"盐田区","code":"440308","parentId":"1955"},{"id":"1962","name":"龙华区","code":"440309","parentId":"1955"},{"id":"1963","name":"坪山区","code":"440310","parentId":"1955"},{"id":"3489","name":"光明区","code":"440311","parentId":"1955"}]},{"id":"1964","name":"珠海市","code":"440400","parentId":"1931","children":[{"id":"1965","name":"香洲区","code":"440402","parentId":"1964"},{"id":"1966","name":"斗门区","code":"440403","parentId":"1964"},{"id":"1967","name":"金湾区","code":"440404","parentId":"1964"}]},{"id":"1968","name":"汕头市","code":"440500","parentId":"1931","children":[{"id":"1969","name":"龙湖区","code":"440507","parentId":"1968"},{"id":"1970","name":"金平区","code":"440511","parentId":"1968"},{"id":"1971","name":"濠江区","code":"440512","parentId":"1968"},{"id":"1972","name":"潮阳区","code":"440513","parentId":"1968"},{"id":"1973","name":"潮南区","code":"440514","parentId":"1968"},{"id":"1974","name":"澄海区","code":"440515","parentId":"1968"},{"id":"1975","name":"南澳县","code":"440523","parentId":"1968"}]},{"id":"1976","name"   :"佛山市","code":"440600","parentId":"1931","children":[{"id":"1977","name":"禅城区","code":"440604","parentId":"1976"},{"id":"1978","name":"南海区","code":"440605","parentId":"1976"},{"id":"1979","name":"顺德区","code":"440606","parentId":"1976"},{"id":"1980","name":"三水区","code":"440607","parentId":"1976"},{"id":"1981","name":"高明区","code":"440608","parentId":"1976"}]},{"id":"1982","name":"江门市","code":"440700","parentId":"1931","children":[{"id":"1983","name":"蓬江区","code":"440703","parentId":"1982"},{"id":"1984","name":"江海区","code":"440704","parentId":"1982"},{"id":"1985","name":"新会区","code":"440705","parentId":"1982"},{"id":"1986","name":"台山市","code":"440781","parentId":"1982"},{"id":"1987","name":"开平市","code":"440783","parentId":"1982"},{"id":"1988","name":"鹤山市","code":"440784","parentId":"1982"},{"id":"1989","name":"恩平市","code":"440785","parentId":"1982"}]},{"id":"1990","name":"湛江市","code":"440800","parentId":"1931","children":[{"id":"1991","name":"赤坎区","code":"440802","parentId":"1990"},{"id":"1992","name":"霞山区","code":"440803","parentId":"1990"},{"id":"1993","name":"坡头区","code":"440804","parentId":"1990"},{"id":"1994","name":"麻章区","code":"440811","parentId":"1990"},{"id":"1995","name":"遂溪县","code":"440823","parentId":"1990"},{"id":"1996","name":"徐闻县","code":"440825","parentId":"1990"},{"id":"1997","name":"廉江市","code":"440881","parentId":"1990"},{"id":"1998","name":"雷州市","code":"440882","parentId":"1990"},{"id":"1999","name":"吴川市","code":"440883","parentId":"1990"}]},{"id":"2000","name":"茂名市","code":"440900","parentId":"1931","children":[{"id":"2001","name":"茂南区","code":"440902","parentId":"2000"},{"id":"2002","name":"电白区","code":"440904","parentId":"2000"},{"id":"2003","name":"高州市","code":"440981","parentId":"2000"},{"id":"2004","name":"化州市","code":"440982","parentId":"2000"},{"id":"2005","name":"信宜市","code":"440983","parentId":"2000"}]},{"id":"2006","name":"肇庆市","code":"441200","parentId":"1931","children":[{"id":"2007","name":"端州区","code":"441202","parentId":"2006"},{"id":"2008","name":"鼎湖区","code":"441203","parentId":"2006"},{"id":"2009","name":"高要区","code":"441204","parentId":"2006"},{"id":"2010","name":"广宁县","code":"441223","parentId":"2006"},{"id":"2011","name":"怀集县","code":"441224","parentId":"2006"},{"id":"2012","name":"封开县","code":"441225","parentId":"2006"},{"id":"2013","name":"德庆县","code":"441226","parentId":"2006"},{"id":"2014","name":"四会市","code":"441284","parentId":"2006"}]},{"id":"2015","name":"惠州市","code":"441300","parentId":"1931","children":[{"id":"2016","name":"惠城区","code":"441302","parentId":"2015"},{"id":"2017","name":"惠阳区","code":"441303","parentId":"2015"},{"id":"2018","name":"博罗县","code":"441322","parentId":"2015"},{"id":"2019","name":"惠东县","code":"441323","parentId":"2015"},{"id":"2020","name":"龙门县","code":"441324","parentId":"2015"}]},{"id":"2021","name":"梅州市","code":"441400","parentId":"1931","children":[{"id":"2022","name":"梅江区","code":"441402","parentId":"2021"},{"id":"2023","name":"梅县区","code":"441403","parentId":"2021"},{"id":"2024","name":"大埔县","code":"441422","parentId":"2021"},{"id":"2025","name":"丰顺县","code":"441423","parentId":"2021"},{"id":"2026","name":"五华县","code":"441424","parentId":"2021"},{"id":"2027","name":"平远县","code":"441426","parentId":"2021"},{"id":"2028","name":"蕉岭县","code":"441427","parentId":"2021"},{"id":"2029","name":"兴宁市","code":"441481","parentId":"2021"}]},{"id":"2030","name":"汕尾市","code":"441500","parentId":"1931","children":[{"id":"2031","name":"城区","code":"441502","parentId":"2030"},{"id":"2032","name":"海丰县","code":"441521","parentId":"2030"},{"id":"2033","name":"陆河县","code":"441523","parentId":"2030"},{"id":"2034","name":"陆丰市","code":"441581","parentId":"2030"}]},{"id":"2035","name":"河源市","code":"441600","parentId":"1931","children":[{"id":"2036","name":"源城区","code":"441602","parentId":"2035"},{"id":"2037","name":"紫金县","code":"441621","parentId":"2035"},{"id":"2038","name":"龙川县","code":"441622","parentId":"2035"},{"id":"2039","name":"连平县","code":"441623","parentId":"2035"},{"id":"2040","name":"和平县","code":"441624","parentId":"2035"},{"id":"2041","name":"东源县","code":"441625","parentId":"2035"}]},{"id":"2042","name":"阳江市","code":"441700","parentId":"1931","children":[{"id":"2043","name":"江城区","code":"441702","parentId":"2042"},{"id":"2044","name":"阳东区","code":"441704","parentId":"2042"},{"id":"2045","name":"阳西县","code":"441721","parentId":"2042"},{"id":"2046","name":"阳春市","code":"441781","parentId":"2042"}]},{"id":"2047","name":"清远市","code":"441800","parentId":"1931","children":[{"id":"2048","name":"清城区","code":"441802","parentId":"2047"},{"id":"2049","name":"清新区","code":"441803","parentId":"2047"},{"id":"2050","name":"佛冈县","code":"441821","parentId":"2047"},{"id":"2051","name":"阳山县","code":"441823","parentId":"2047"},{"id":"2052","name":"连山壮族瑶族自治县","code":"441825","parentId":"2047"},{"id":"2053","name":"连南瑶族自治县","code":"441826","parentId":"2047"},{"id":"2054","name":"英德市","code":"441881","parentId":"2047"},{"id":"2055","name":"连州市","code":"441882","parentId":"2047"}]},{"id":"2056","name":"东莞市","code":"441900","parentId":"1931","children":[{"id":"3449","code":"441901","name":"辖区","parentId":"2056"}]},{"id":"2057","name":"中山市","code":"442000","parentId":"1931","children":[{"id":"3450","code":"442001","name":"辖区","parentId":"2057"}]},{"id":"2058","name":"潮州市","code":"445100","parentId":"1931","children":[{"id":"2059","name":"湘桥区","code":"445102","parentId":"2058"},{"id":"2060","name":"潮安区","code":"445103","parentId":"2058"},{"id":"2061","name":"饶平县","code":"445122","parentId":"2058"}]},{"id":"2062","name":"揭阳市","code":"445200","parentId":"1931","children":[{"id":"2063","name":"榕城区","code":"445202","parentId":"2062"},{"id":"2064","name":"揭东区","code":"445203","parentId":"2062"},{"id":"2065","name":"揭西县","code":"445222","parentId":"2062"},{"id":"2066","name":"惠来县","code":"445224","parentId":"2062"},{"id":"2067","name":"普宁市","code":"445281","parentId":"2062"}]},{"id":"2068","name":"云浮市","code":"445300","parentId":"1931","children":[{"id":"2069","name":"云城区","code":"445302","parentId":"2068"},{"id":"2070","name":"云安区","code":"445303","parentId":"2068"},{"id":"2071","name":"新兴县","code":"445321","parentId":"2068"},{"id":"2072","name":"郁南县","code":"445322","parentId":"2068"},{"id":"2073","name":"罗定市","code":"445381","parentId":"2068"}]}]},{"id":"2074","name":"广西壮族自治区","code":"450000","parentId":"0","children":[{"id":"2075","name":"南宁市","code":"450100","parentId":"2074","children":[{"id":"2076","name":"兴宁区","code":"450102","parentId":"2075"},{"id":"2077","name":"青秀区","code":"450103","parentId":"2075"},{"id":"2078","name":"江南区","code":"450105","parentId":"2075"},{"id":"2079","name":"西乡塘区","code":"450107","parentId":"2075"},{"id":"2080","name":"良庆区","code":"450108","parentId":"2075"},{"id":"2081","name":"邕宁区","code":"450109","parentId":"2075"},{"id":"2082","name":"武鸣区","code":"450110","parentId":"2075"},{"id":"2083","name":"隆安县","code":"450123","parentId":"2075"},{"id":"2084","name":"马山县","code":"450124","parentId":"2075"},{"id":"2085","name":"上林县","code":"450125","parentId":"2075"},{"id":"2086","name":"宾阳县","code":"450126","parentId":"2075"},{"id":"2087","name":"横县","code":"450127","parentId":"2075"}]},{"id":"2088","name":"柳州市","code":"450200","parentId":"2074","children":[{"id":"2089","name":"城中区","code":"450202","parentId":"2088"},{"id":"2090","name":"鱼峰区","code":"450203","parentId":"2088"},{"id":"2091","name":"柳南区","code":"450204","parentId":"2088"},{"id":"2092","name":"柳北区","code":"450205","parentId":"2088"},{"id":"2093","name":"柳江区","code":"450206","parentId":"2088"},{"id":"2094","name":"柳城县","code":"450222","parentId":"2088"},{"id":"2095","name":"鹿寨县","code":"450223","parentId":"2088"},{"id":"2096","name":"融安县","code":"450224","parentId":"2088"},{"id":"2097","name":"融水苗族自治县","code":"450225","parentId":"2088"},{"id":"2098","name":"三江侗族自治县","code":"450226","parentId":"2088"}]},{"id":"2099","name":"桂林市","code":"450300","parentId":"2074","children":[{"id":"2100","name":"秀峰区","code":"450302","parentId":"2099"},{"id":"2101","name":"叠彩区","code":"450303","parentId":"2099"},{"id":"2102","name":"象山区","code":"450304","parentId":"2099"},{"id":"2103","name":"七星区","code":"450305","parentId":"2099"},{"id":"2104","name":"雁山区","code":"450311","parentId":"2099"},{"id":"2105","name":"临桂区","code":"450312","parentId":"2099"},{"id":"2106","name":"阳朔县","code":"450321","parentId":"2099"},{"id":"2107","name":"灵川县","code":"450323","parentId":"2099"},{"id":"2108","name":"全州县","code":"450324","parentId":"2099"},{"id":"2109","name":"兴安县","code":"450325","parentId":"2099"},{"id":"2110","name":"永福县","code":"450326","parentId":"2099"},{"id":"2111","name":"灌阳县","code":"450327","parentId":"2099"},{"id":"2112","name":"龙胜各族自治县","code":"450328","parentId":"2099"},{"id":"2113","name":"资源县","code":"450329","parentId":"2099"},{"id":"2114","name":"平乐县","code":"450330","parentId":"2099"},{"id":"2115","name":"荔浦县","code":"450331","parentId":"2099"},{"id":"2116","name":"恭城瑶族自治县","code":"450332","parentId":"2099"}]},{"id":"2117","name":"梧州市","code":"450400","parentId":"2074","children":[{"id":"2118","name":"万秀区","code":"450403","parentId":"2117"},{"id":"2119","name":"长洲区","code":"450405","parentId":"2117"},{"id":"2120","name":"龙圩区","code":"450406","parentId":"2117"},{"id":"2121","name":"苍梧县","code":"450421","parentId":"2117"},{"id":"2122","name":"藤县","code":"450422","parentId":"2117"},{"id":"2123","name":"蒙山县","code":"450423","parentId":"2117"},{"id":"2124","name":"岑溪市","code":"450481","parentId":"2117"}]},{"id":"2125","name":"北海市","code":"450500","parentId":"2074","children":[{"id":"2126","name":"海城区","code":"450502","parentId":"2125"},{"id":"2127","name":"银海区","code":"450503","parentId":"2125"},{"id":"2128","name":"铁山港区","code":"450512","parentId":"2125"},{"id":"2129","name":"合浦县","code":"450521","parentId":"2125"}]},{"id":"2130","name":"防城港市","code":"450600","parentId":"2074","children":[{"id":"2131","name":"港口区","code":"450602","parentId":"2130"},{"id":"2132","name":"防城区","code":"450603","parentId":"2130"},{"id":"2133","name":"上思县","code":"450621","parentId":"2130"},{"id":"2134","name":"东兴市","code":"450681","parentId":"2130"}]},{"id":"2135","name":"钦州市","code":"450700","parentId":"2074","children":[{"id":"2136","name":"钦南区","code":"450702","parentId":"2135"},{"id":"2137","name":"钦北区","code":"450703","parentId":"2135"},{"id":"2138","name":"灵山县","code":"450721","parentId":"2135"},{"id":"2139","name":"浦北县","code":"450722","parentId":"2135"}]},{"id":"2140","name":"贵港市","code":"450800","parentId":"2074","children":[{"id":"2141","name":"港北区","code":"450802","parentId":"2140"},{"id":"2142","name":"港南区","code":"450803","parentId":"2140"},{"id":"2143","name":"覃塘区","code":"450804","parentId":"2140"},{"id":"2144","name":"平南县","code":"450821","parentId":"2140"},{"id":"2145","name":"桂平市","code":"450881","parentId":"2140"}]},{"id":"2146","name":"玉林市","code":"450900","parentId":"2074","children":[{"id":"2147","name":"玉州区","code":"450902","parentId":"2146"},{"id":"2148","name":"福绵区","code":"450903","parentId":"2146"},{"id":"2149","name":"容县","code":"450921","parentId":"2146"},{"id":"2150","name":"陆川县","code":"450922","parentId":"2146"},{"id":"2151","name":"博白县","code":"450923","parentId":"2146"},{"id":"2152","name":"兴业县","code":"450924","parentId":"2146"},{"id":"2153","name":"北流市","code":"450981","parentId":"2146"}]},{"id":"2154","name":"百色市","code":"451000","parentId":"2074","children":[{"id":"2155","name":"右江区","code":"451002","parentId":"2154"},{"id":"2156","name":"田阳县","code":"451021","parentId":"2154"},{"id":"2157","name":"田东县","code":"451022","parentId":"2154"},{"id":"2158","name":"平果县","code":"451023","parentId":"2154"},{"id":"2159","name":"德保县","code":"451024","parentId":"2154"},{"id":"2160","name":"那坡县","code":"451026","parentId":"2154"},{"id":"2161","name":"凌云县","code":"451027","parentId":"2154"},{"id":"2162","name":"乐业县","code":"451028","parentId":"2154"},{"id":"2163","name":"田林县","code":"451029","parentId":"2154"},{"id":"2164","name":"西林县","code":"451030","parentId":"2154"},{"id":"2165","name":"隆林各族自治县","code":"451031","parentId":"2154"},{"id":"2166","name":"靖西市","code":"451081","parentId":"2154"}]},{"id":"2167","name":"贺州市","code":"451100","parentId":"2074","children":[{"id":"2168","name":"八步区","code":"451102","parentId":"2167"},{"id":"2169","name":"平桂区","code":"451103","parentId":"2167"},{"id":"2170","name":"昭平县","code":"451121","parentId":"2167"},{"id":"2171","name":"钟山县","code":"451122","parentId":"2167"},{"id":"2172","name":"富川瑶族自治县","code":"451123","parentId":"2167"}]},{"id":"2173","name":"河池市","code":"451200","parentId":"2074","children":[{"id":"2174","name":"金城江区","code":"451202","parentId":"2173"},{"id":"2175","name":"宜州区","code":"451203","parentId":"2173"},{"id":"2176","name":"南丹县","code":"451221","parentId":"2173"},{"id":"2177","name":"天峨县","code":"451222","parentId":"2173"},{"id":"2178","name":"凤山县","code":"451223","parentId":"2173"},{"id":"2179","name":"东兰县","code":"451224","parentId":"2173"},{"id":"2180","name":"罗城仫佬族自治县","code":"451225","parentId":"2173"},{"id":"2181","name":"环江毛南族自治县","code":"451226","parentId":"2173"},{"id":"2182","name":"巴马瑶族自治县","code":"451227","parentId":"2173"},{"id":"2183","name":"都安瑶族自治县","code":"451228","parentId":"2173"},{"id":"2184","name":"大化瑶族自治县","code":"451229","parentId":"2173"}]},{"id":"2185","name":"来宾市","code":"451300","parentId":"2074","children":[{"id":"2186","name":"兴宾区","code":"451302","parentId":"2185"},{"id":"2187","name":"忻城县","code":"451321","parentId":"2185"},{"id":"2188","name":"象州县","code":"451322","parentId":"2185"},{"id":"2189","name":"武宣县","code":"451323","parentId":"2185"},{"id":"2190","name":"金秀瑶族自治县","code":"451324","parentId":"2185"},{"id":"2191","name":"合山市","code":"451381","parentId":"2185"}]},{"id":"2192","name":"崇左市","code":"451400","parentId":"2074","children":[{"id":"2193","name":"江州区","code":"451402","parentId":"2192"},{"id":"2194","name":"扶绥县","code":"451421","parentId":"2192"},{"id":"2195","name":"宁明县","code":"451422","parentId":"2192"},{"id":"2196","name":"龙州县","code":"451423","parentId":"2192"},{"id":"2197","name":"大新县","code":"451424","parentId":"2192"},{"id":"2198","name":"天等县","code":"451425","parentId":"2192"},{"id":"2199","name":"凭祥市","code":"451481","parentId":"2192"}]}]},{"id":"2200","name":"海南省","code":"460000","parentId":"0","children":[{"id":"2201","name":"海口市","code":"460100","parentId":"2200","children":[{"id":"2202","name":"秀英区","code":"460105","parentId":"2201"},{"id":"2203","name":"龙华区","code":"460106","parentId":"2201"},{"id":"2204","name":"琼山区","code":"460107","parentId":"2201"},{"id":"2205","name":"美兰区","code":"460108","parentId":"2201"}]},{"id":"2206","name":"三亚市","code":"460200","parentId":"2200","children":[{"id":"2207","name":"海棠区","code":"460202","parentId":"2206"},{"id":"2208","name":"吉阳区","code":"460203","parentId":"2206"},{"id":"2209","name":"天涯区","code":"460204","parentId":"2206"},{"id":"2210","name":"崖州区","code":"460205","parentId":"2206"}]},{"id":"2211","name":"三沙市","code":"460300","parentId":"2200","children":[{"id":"2212","name":"西沙群岛","code":"460321","parentId":"2211"},{"id":"2213","name":"南沙群岛","code":"460322","parentId":"2211"},{"id":"2214","name":"中沙群岛","code":"460323","parentId":"2211"},{"id":"2215","name":"永乐群岛","code":"460324","parentId":"2211"}]},{"id":"2216","name":"儋州市","code":"460400","parentId":"2200","children":[{"id":"3449","name":"辖区","code":"460401","parentId":"2216"}]},{"id":"2217","name":"五指山市","code":"469001","parentId":"2200","children":[{"id":"3450","name":"辖区","code":"-1","parentId":"2217"}]},{"id":"2218","name":"琼海市","code":"469002","parentId":"2200","children":[{"id":"3451","name":"辖区","code":"-1","parentId":"2218"}]},{"id":"2219","name":"文昌市","code":"469005","parentId":"2200","children":[{"id":"3452","name":"辖区","code":"-1","parentId":"2219"}]},{"id":"2220","name":"万宁市","code":"469006","parentId":"2200","children":[{"id":"3453","name":"辖区","code":"-1","parentId":"2220"}]},{"id":"2221","name":"东方市","code":"469007","parentId":"2200","children":[{"id":"3454","name":"辖区","code":"-1","parentId":"2221"}]},{"id":"2222","name":"定安县","code":"469021","parentId":"2200","children":[{"id":"3455","name":"辖区","code":"-1","parentId":"2222"}]},{"id":"2223","name":"屯昌县","code":"469022","parentId":"2200","children":[{"id":"3456","name":"辖区","code":"-1","parentId":"2223"}]},{"id":"2224","name":"澄迈县","code":"469023","parentId":"2200","children":[{"id":"3457","name":"辖区","code":"-1","parentId":"2224"}]},{"id":"2225","name":"临高县","code":"469024","parentId":"2200","children":[{"id":"3458","name":"辖区","code":"-1","parentId":"2225"}]},{"id":"2226","name":"白沙黎族自治县","code":"469025","parentId":"2200","children":[{"id":"3459","name":"辖区","code":"-1","parentId":"2226"}]},{"id":"2227","name":"昌江黎族自治县","code":"469026","parentId":"2200","children":[{"id":"3460","name":"辖区","code":"-1","parentId":"2227"}]},{"id":"2228","name":"乐东黎族自治县","code":"469027","parentId":"2200","children":[{"id":"3461","name":"辖区","code":"-1","parentId":"2228"}]},{"id":"2229","name":"陵水黎族自治县","code":"469028","parentId":"2200","children":[{"id":"3462","name":"辖区","code":"-1","parentId":"2229"}]},{"id":"2230","name":"保亭黎族苗族自治县","code":"469029","parentId":"2200","children":[{"id":"3463","name":"辖区","code":"-1","parentId":"2230"}]},{"id":"2231","name":"琼中黎族苗族自治县","code":"469030","parentId":"2200","children":[{"id":"3464","name":"辖区","code":"-1","parentId":"2231"}]}]},{"id":"2271","name":"四川省","code":"510000","parentId":"0","children":[{"id":"2272","name":"成都市","code":"510100","parentId":"2271","children":[{"id":"2273","name":"锦江区","code":"510104","parentId":"2272"},{"id":"2274","name":"青羊区","code":"510105","parentId":"2272"},{"id":"2275","name":"金牛区","code":"510106","parentId":"2272"},{"id":"2276","name":"武侯区","code":"510107","parentId":"2272"},{"id":"2277","name":"成华区","code":"510108","parentId":"2272"},{"id":"2278","name":"龙泉驿区","code":"510112","parentId":"2272"},{"id":"2279","name":"青白江区","code":"510113","parentId":"2272"},{"id":"2280","name":"新都区","code":"510114","parentId":"2272"},{"id":"2281","name":"温江区","code":"510115","parentId":"2272"},{"id":"2282","name":"双流区","code":"510116","parentId":"2272"},{"id":"2283","name":"郫都区","code":"510117","parentId":"2272"},{"id":"2284","name":"金堂县","code":"510121","parentId":"2272"},{"id":"2285","name":"大邑县","code":"510129","parentId":"2272"},{"id":"2286","name":"蒲江县","code":"510131","parentId":"2272"},{"id":"2287","name":"新津县","code":"510132","parentId":"2272"},{"id":"2288","name":"都江堰市","code":"510181","parentId":"2272"},{"id":"2289","name":"彭州市","code":"510182","parentId":"2272"},{"id":"2290","name":"邛崃市","code":"510183","parentId":"2272"},{"id":"2291","name":"崇州市","code":"510184","parentId":"2272"},{"id":"2292","name":"简阳市","code":"510185","parentId":"2272"}]},{"id":"2293","name":"自贡市","code":"510300","parentId":"2271","children":[{"id":"2294","name":"自流井区","code":"510302","parentId":"2293"},{"id":"2295","name":"贡井区","code":"510303","parentId":"2293"},{"id":"2296","name":"大安区","code":"510304","parentId":"2293"},{"id":"2297","name":"沿滩区","code":"510311","parentId":"2293"},{"id":"2298","name":"荣县","code":"510321","parentId":"2293"},{"id":"2299","name":"富顺县","code":"510322","parentId":"2293"}]},{"id":"2300","name":"攀枝花市","code":"510400","parentId":"2271","children":[{"id":"2301","name":"东区","code":"510402","parentId":"2300"},{"id":"2302","name":"西区","code":"510403","parentId":"2300"},{"id":"2303","name":"仁和区","code":"510411","parentId":"2300"},{"id":"2304","name":"米易县","code":"510421","parentId":"2300"},{"id":"2305","name":"盐边县","code":"510422","parentId":"2300"}]},{"id":"2306","name":"泸州市","code":"510500","parentId":"2271","children":[{"id":"2307","name":"江阳区","code":"510502","parentId":"2306"},{"id":"2308","name":"纳溪区","code":"510503","parentId":"2306"},{"id":"2309","name":"龙马潭区","code":"510504","parentId":"2306"},{"id":"2310","name":"泸县","code":"510521","parentId":"2306"},{"id":"2311","name":"合江县","code":"510522","parentId":"2306"},{"id":"2312","name":"叙永县","code":"510524","parentId":"2306"},{"id":"2313","name":"古蔺县","code":"510525","parentId":"2306"}]},{"id":"2314","name":"德阳市","code":"510600","parentId":"2271","children":[{"id":"2315","name":"旌阳区","code":"510603","parentId":"2314"},{"id":"2316","name":"中江县","code":"510623","parentId":"2314"},{"id":"2317","name":"罗江县","code":"510626","parentId":"2314"},{"id":"2318","name":"广汉市","code":"510681","parentId":"2314"},{"id":"2319","name":"什邡市","code":"510682","parentId":"2314"},{"id":"2320","name":"绵竹市","code":"510683","parentId":"2314"}]},{"id":"2321","name":"绵阳市","code":"510700","parentId":"2271","children":[{"id":"2322","name":"涪城区","code":"510703","parentId":"2321"},{"id":"2323","name":"游仙区","code":"510704","parentId":"2321"},{"id":"2324","name":"安州区","code":"510705","parentId":"2321"},{"id":"2325","name":"三台县","code":"510722","parentId":"2321"},{"id":"2326","name":"盐亭县","code":"510723","parentId":"2321"},{"id":"2327","name":"梓潼县","code":"510725","parentId":"2321"},{"id":"2328","name":"北川羌族自治县","code":"510726","parentId":"2321"},{"id":"2329","name":"平武县","code":"510727","parentId":"2321"},{"id":"2330","name":"江油市","code":"510781","parentId":"2321"}]},{"id":"2331","name":"广元市","code":"510800","parentId":"2271","children":[{"id":"2332","name":"利州区","code":"510802","parentId":"2331"},{"id":"2333","name":"昭化区","code":"510811","parentId":"2331"},{"id":"2334","name":"朝天区","code":"510812","parentId":"2331"},{"id":"2335","name":"旺苍县","code":"510821","parentId":"2331"},{"id":"2336","name":"青川县","code":"510822","parentId":"2331"},{"id":"2337","name":"剑阁县","code":"510823","parentId":"2331"},{"id":"2338","name":"苍溪县","code":"510824","parentId":"2331"}]},{"id":"2339","name":"遂宁市","code":"510900","parentId":"2271","children":[{"id":"2340","name":"船山区","code":"510903","parentId":"2339"},{"id":"2341","name":"安居区","code":"510904","parentId":"2339"},{"id":"2342","name":"蓬溪县","code":"510921","parentId":"2339"},{"id":"2343","name":"射洪县","code":"510922","parentId":"2339"},{"id":"2344","name":"大英县","code":"510923","parentId":"2339"}]},{"id":"2345","name":"内江市","code":"511000","parentId":"2271","children":[{"id":"2346","name":"市中区","code":"511002","parentId":"2345"},{"id":"2347","name":"东兴区","code":"511011","parentId":"2345"},{"id":"2348","name":"威远县","code":"511024","parentId":"2345"},{"id":"2349","name":"资中县","code":"511025","parentId":"2345"},{"id":"2350","name":"隆昌市","code":"511083","parentId":"2345"}]},{"id":"2351","name":"乐山市","code":"511100","parentId":"2271","children":[{"id":"2352","name":"市中区","code":"511102","parentId":"2351"},{"id":"2353","name":"沙湾区","code":"511111","parentId":"2351"},{"id":"2354","name":"五通桥区","code":"511112","parentId":"2351"},{"id":"2355","name":"金口河区","code":"511113","parentId":"2351"},{"id":"2356","name":"犍为县","code":"511123","parentId":"2351"},{"id":"2357","name":"井研县","code":"511124","parentId":"2351"},{"id":"2358","name":"夹江县","code":"511126","parentId":"2351"},{"id":"2359","name":"沐川县","code":"511129","parentId":"2351"},{"id":"2360","name":"峨边彝族自治县","code":"511132","parentId":"2351"},{"id":"2361","name":"马边彝族自治县","code":"511133","parentId":"2351"},{"id":"2362","name":"峨眉山市","code":"511181","parentId":"2351"}]},{"id":"2363","name":"南充市","code":"511300","parentId":"2271","children":[{"id":"2364","name":"顺庆区","code":"511302","parentId":"2363"},{"id":"2365","name":"高坪区","code":"511303","parentId":"2363"},{"id":"2366","name":"嘉陵区","code":"511304","parentId":"2363"},{"id":"2367","name":"南部县","code":"511321","parentId":"2363"},{"id":"2368","name":"营山县","code":"511322","parentId":"2363"},{"id":"2369","name":"蓬安县","code":"511323","parentId":"2363"},{"id":"2370","name":"仪陇县","code":"511324","parentId":"2363"},{"id":"2371","name":"西充县","code":"511325","parentId":"2363"},{"id":"2372","name":"阆中市","code":"511381","parentId":"2363"}]},{"id":"2373","name":"眉山市","code":"511400","parentId":"2271","children":[{"id":"2374","name":"东坡区","code":"511402","parentId":"2373"},{"id":"2375","name":"彭山区","code":"511403","parentId":"2373"},{"id":"2376","name":"仁寿县","code":"511421","parentId":"2373"},{"id":"2377","name":"洪雅县","code":"511423","parentId":"2373"},{"id":"2378","name":"丹棱县","code":"511424","parentId":"2373"},{"id":"2379","name":"青神县","code":"511425","parentId":"2373"}]},{"id":"2380","name":"宜宾市","code":"511500","parentId":"2271","children":[{"id":"2381","name":"翠屏区","code":"511502","parentId":"2380"},{"id":"2382","name":"南溪区","code":"511503","parentId":"2380"},{"id":"2383","name":"宜宾县","code":"511521","parentId":"2380"},{"id":"2384","name":"江安县","code":"511523","parentId":"2380"},{"id":"2385","name":"长宁县","code":"511524","parentId":"2380"},{"id":"2386","name":"高县","code":"511525","parentId":"2380"},{"id":"2387","name":"珙县","code":"511526","parentId":"2380"},{"id":"2388","name":"筠连县","code":"511527","parentId":"2380"},{"id":"2389","name":"兴文县","code":"511528","parentId":"2380"},{"id":"2390","name":"屏山县","code":"511529","parentId":"2380"}]},{"id":"2391","name":"广安市","code":"511600","parentId":"2271","children":[{"id":"2392","name":"广安区","code":"511602","parentId":"2391"},{"id":"2393","name":"前锋区","code":"511603","parentId":"2391"},{"id":"2394","name":"岳池县","code":"511621","parentId":"2391"},{"id":"2395","name":"武胜县","code":"511622","parentId":"2391"},{"id":"2396","name":"邻水县","code":"511623","parentId":"2391"},{"id":"2397","name":"华蓥市","code":"511681","parentId":"2391"}]},{"id":"2398","name":"达州市","code":"511700","parentId":"2271","children":[{"id":"2399","name":"通川区","code":"511702","parentId":"2398"},{"id":"2400","name":"达川区","code":"511703","parentId":"2398"},{"id":"2401","name":"宣汉县","code":"511722","parentId":"2398"},{"id":"2402","name":"开江县","code":"511723","parentId":"2398"},{"id":"2403","name":"大竹县","code":"511724","parentId":"2398"},{"id":"2404","name":"渠县","code":"511725","parentId":"2398"},{"id":"2405","name":"万源市","code":"511781","parentId":"2398"}]},{"id":"2406","name":"雅安市","code":"511800","parentId":"2271","children":[{"id":"2407","name":"雨城区","code":"511802","parentId":"2406"},{"id":"2408","name":"名山区","code":"511803","parentId":"2406"},{"id":"2409","name":"荥经县","code":"511822","parentId":"2406"},{"id":"2410","name":"汉源县","code":"511823","parentId":"2406"},{"id":"2411","name":"石棉县","code":"511824","parentId":"2406"},{"id":"2412","name":"天全县","code":"511825","parentId":"2406"},{"id":"2413","name":"芦山县","code":"511826","parentId":"2406"},{"id":"2414","name":"宝兴县","code":"511827","parentId":"2406"}]},{"id":"2415","name":"巴中市","code":"511900","parentId":"2271","children":[{"id":"2416","name":"巴州区","code":"511902","parentId":"2415"},{"id":"2417","name":"恩阳区","code":"511903","parentId":"2415"},{"id":"2418","name":"通江县","code":"511921","parentId":"2415"},{"id":"2419","name":"南江县","code":"511922","parentId":"2415"},{"id":"2420","name":"平昌县","code":"511923","parentId":"2415"}]},{"id":"2421","name":"资阳市","code":"512000","parentId":"2271","children":[{"id":"2422","name":"雁江区","code":"512002","parentId":"2421"},{"id":"2423","name":"安岳县","code":"512021","parentId":"2421"},{"id":"2424","name":"乐至县","code":"512022","parentId":"2421"}]},{"id":"2425","name":"阿坝藏族羌族自治州","code":"513200","parentId":"2271","children":[{"id":"2426","name":"马尔康市","code":"513201","parentId":"2425"},{"id":"2427","name":"汶川县","code":"513221","parentId":"2425"},{"id":"2428","name":"理县","code":"513222","parentId":"2425"},{"id":"2429","name":"茂县","code":"513223","parentId":"2425"},{"id":"2430","name":"松潘县","code":"513224","parentId":"2425"},{"id":"2431","name":"九寨沟县","code":"513225","parentId":"2425"},{"id":"2432","name":"金川县","code":"513226","parentId":"2425"},{"id":"2433","name":"小金县","code":"513227","parentId":"2425"},{"id":"2434","name":"黑水县","code":"513228","parentId":"2425"},{"id":"2435","name":"壤塘县","code":"513230","parentId":"2425"},{"id":"2436","name":"阿坝县","code":"513231","parentId":"2425"},{"id":"2437","name":"若尔盖县","code":"513232","parentId":"2425"},{"id":"2438","name":"红原县","code":"513233","parentId":"2425"}]},{"id":"2439","name":"甘孜藏族自治州","code":"513300","parentId":"2271","children":[{"id":"2440","name":"康定市","code":"513301","parentId":"2439"},{"id":"2441","name":"泸定县","code":"513322","parentId":"2439"},{"id":"2442","name":"丹巴县","code":"513323","parentId":"2439"},{"id":"2443","name":"九龙县","code":"513324","parentId":"2439"},{"id":"2444","name":"雅江县","code":"513325","parentId":"2439"},{"id":"2445","name":"道孚县","code":"513326","parentId":"2439"},{"id":"2446","name":"炉霍县","code":"513327","parentId":"2439"},{"id":"2447","name":"甘孜县","code":"513328","parentId":"2439"},{"id":"2448","name":"新龙县","code":"513329","parentId":"2439"},{"id":"2449","name":"德格县","code":"513330","parentId":"2439"},{"id":"2450","name":"白玉县","code":"513331","parentId":"2439"},{"id":"2451","name":"石渠县","code":"513332","parentId":"2439"},{"id":"2452","name":"色达县","code":"513333","parentId":"2439"},{"id":"2453","name":"理塘县","code":"513334","parentId":"2439"},{"id":"2454","name":"巴塘县","code":"513335","parentId":"2439"},{"id":"2455","name":"乡城县","code":"513336","parentId":"2439"},{"id":"2456","name":"稻城县","code":"513337","parentId":"2439"},{"id":"2457","name":"得荣县","code":"513338","parentId":"2439"}]},{"id":"2458","name":"凉山彝族自治州","code":"513400","parentId":"2271","children":[{"id":"2459","name":"西昌市","code":"513401","parentId":"2458"},{"id":"2460","name":"木里藏族自治县","code":"513422","parentId":"2458"},{"id":"2461","name":"盐源县","code":"513423","parentId":"2458"},{"id":"2462","name":"德昌县","code":"513424","parentId":"2458"},{"id":"2463","name":"会理县","code":"513425","parentId":"2458"},{"id":"2464","name":"会东县","code":"513426","parentId":"2458"},{"id":"2465","name":"宁南县","code":"513427","parentId":"2458"},{"id":"2466","name":"普格县","code":"513428","parentId":"2458"},{"id":"2467","name":"布拖县","code":"513429","parentId":"2458"},{"id":"2468","name":"金阳县","code":"513430","parentId":"2458"},{"id":"2469","name":"昭觉县","code":"513431","parentId":"2458"},{"id":"2470","name":"喜德县","code":"513432","parentId":"2458"},{"id":"2471","name":"冕宁县","code":"513433","parentId":"2458"},{"id":"2472","name":"越西县","code":"513434","parentId":"2458"},{"id":"2473","name":"甘洛县","code":"513435","parentId":"2458"},{"id":"2474","name":"美姑县","code":"513436","parentId":"2458"},{"id":"2475","name":"雷波县","code":"513437","parentId":"2458"}]}]},{"id":"2476","name":"贵州省","code":"520000","parentId":"0","children":[{"id":"2477","name":"贵阳市","code":"520100","parentId":"2476","children":[{"id":"2478","name":"南明区","code":"520102","parentId":"2477"},{"id":"2479","name":"云岩区","code":"520103","parentId":"2477"},{"id":"2480","name":"花溪区","code":"520111","parentId":"2477"},{"id":"2481","name":"乌当区","code":"520112","parentId":"2477"},{"id":"2482","name":"白云区","code":"520113","parentId":"2477"},{"id":"2483","name":"观山湖区","code":"520115","parentId":"2477"},{"id":"2484","name":"开阳县","code":"520121","parentId":"2477"},{"id":"2485","name":"息烽县","code":"520122","parentId":"2477"},{"id":"2486","name":"修文县","code":"520123","parentId":"2477"},{"id":"2487","name":"清镇市","code":"520181","parentId":"2477"}]},{"id":"2488","name":"六盘水市","code":"520200","parentId":"2476","children":[{"id":"2489","name":"钟山区","code":"520201","parentId":"2488"},{"id":"2490","name":"六枝特区","code":"520203","parentId":"2488"},{"id":"2491","name":"水城县","code":"520221","parentId":"2488"},{"id":"2492","name":"盘州市","code":"520281","parentId":"2488"}]},{"id":"2493","name":"遵义市","code":"520300","parentId":"2476","children":[{"id":"2494","name":"红花岗区","code":"520302","parentId":"2493"},{"id":"2495","name":"汇川区","code":"520303","parentId":"2493"},{"id":"2496","name":"播州区","code":"520304","parentId":"2493"},{"id":"2497","name":"桐梓县","code":"520322","parentId":"2493"},{"id":"2498","name":"绥阳县","code":"520323","parentId":"2493"},{"id":"2499","name":"正安县","code":"520324","parentId":"2493"},{"id":"2500","name":"道真仡佬族苗族自治县","code":"520325","parentId":"2493"},{"id":"2501","name":"务川仡佬族苗族自治县","code":"520326","parentId":"2493"},{"id":"2502","name":"凤冈县","code":"520327","parentId":"2493"},{"id":"2503","name":"湄潭县","code":"520328","parentId":"2493"},{"id":"2504","name":"余庆县","code":"520329","parentId":"2493"},{"id":"2505","name":"习水县","code":"520330","parentId":"2493"},{"id":"2506","name":"赤水市","code":"520381","parentId":"2493"},{"id":"2507","name":"仁怀市","code":"520382","parentId":"2493"}]},{"id":"2508","name":"安顺市","code":"520400","parentId":"2476","children":[{"id":"2509","name":"西秀区","code":"520402","parentId":"2508"},{"id":"2510","name":"平坝区","code":"520403","parentId":"2508"},{"id":"2511","name":"普定县","code":"520422","parentId":"2508"},{"id":"2512","name":"镇宁布依族苗族自治县","code":"520423","parentId":"2508"},{"id":"2513","name":"关岭布依族苗族自治县","code":"520424","parentId":"2508"},{"id":"2514","name":"紫云苗族布依族自治县","code":"520425","parentId":"2508"}]},{"id":"2515","name":"毕节市","code":"520500","parentId":"2476","children":[{"id":"2516","name":"七星关区","code":"520502","parentId":"2515"},{"id":"2517","name":"大方县","code":"520521","parentId":"2515"},{"id":"2518","name":"黔西县","code":"520522","parentId":"2515"},{"id":"2519","name":"金沙县","code":"520523","parentId":"2515"},{"id":"2520","name":"织金县","code":"520524","parentId":"2515"},{"id":"2521","name":"纳雍县","code":"520525","parentId":"2515"},{"id":"2522","name":"威宁彝族回族苗族自治县","code":"520526","parentId":"2515"},{"id":"2523","name":"赫章县","code":"520527","parentId":"2515"}]},{"id":"2524","name":"铜仁市","code":"520600","parentId":"2476","children":[{"id":"2525","name":"碧江区","code":"520602","parentId":"2524"},{"id":"2526","name":"万山区","code":"520603","parentId":"2524"},{"id":"2527","name":"江口县","code":"520621","parentId":"2524"},{"id":"2528","name":"玉屏侗族自治县","code":"520622","parentId":"2524"},{"id":"2529","name":"石阡县","code":"520623","parentId":"2524"},{"id":"2530","name":"思南县","code":"520624","parentId":"2524"},{"id":"2531","name":"印江土家族苗族自治县","code":"520625","parentId":"2524"},{"id":"2532","name":"德江县","code":"520626","parentId":"2524"},{"id":"2533","name":"沿河土家族自治县","code":"520627","parentId":"2524"},{"id":"2534","name":"松桃苗族自治县","code":"520628","parentId":"2524"}]},{"id":"2535","name":"黔西南布依族苗族自治州","code":"522300","parentId":"2476","children":[{"id":"2536","name":"兴义市","code":"522301","parentId":"2535"},{"id":"2537","name":"兴仁县","code":"522322","parentId":"2535"},{"id":"2538","name":"普安县","code":"522323","parentId":"2535"},{"id":"2539","name":"晴隆县","code":"522324","parentId":"2535"},{"id":"2540","name":"贞丰县","code":"522325","parentId":"2535"},{"id":"2541","name":"望谟县","code":"522326","parentId":"2535"},{"id":"2542","name":"册亨县","code":"522327","parentId":"2535"},{"id":"2543","name":"安龙县","code":"522328","parentId":"2535"}]},{"id":"2544","name":"黔东南苗族侗族自治州","code":"522600","parentId":"2476","children":[{"id":"2545","name":"凯里市","code":"522601","parentId":"2544"},{"id":"2546","name":"黄平县","code":"522622","parentId":"2544"},{"id":"2547","name":"施秉县","code":"522623","parentId":"2544"},{"id":"2548","name":"三穗县","code":"522624","parentId":"2544"},{"id":"2549","name":"镇远县","code":"522625","parentId":"2544"},{"id":"2550","name":"岑巩县","code":"522626","parentId":"2544"},{"id":"2551","name":"天柱县","code":"522627","parentId":"2544"},{"id":"2552","name":"锦屏县","code":"522628","parentId":"2544"},{"id":"2553","name":"剑河县","code":"522629","parentId":"2544"},{"id":"2554","name":"台江县","code":"522630","parentId":"2544"},{"id":"2555","name":"黎平县","code":"522631","parentId":"2544"},{"id":"2556","name":"榕江县","code":"522632","parentId":"2544"},{"id":"2557","name":"从江县","code":"522633","parentId":"2544"},{"id":"2558","name":"雷山县","code":"522634","parentId":"2544"},{"id":"2559","name":"麻江县","code":"522635","parentId":"2544"},{"id":"2560","name":"丹寨县","code":"522636","parentId":"2544"}]},{"id":"2561","name":"黔南布依族苗族自治州","code":"522700","parentId":"2476","children":[{"id":"2562","name":"都匀市","code":"522701","parentId":"2561"},{"id":"2563","name":"福泉市","code":"522702","parentId":"2561"},{"id":"2564","name":"荔波县","code":"522722","parentId":"2561"},{"id":"2565","name":"贵定县","code":"522723","parentId":"2561"},{"id":"2566","name":"瓮安县","code":"522725","parentId":"2561"},{"id":"2567","name":"独山县","code":"522726","parentId":"2561"},{"id":"2568","name":"平塘县","code":"522727","parentId":"2561"},{"id":"2569","name":"罗甸县","code":"522728","parentId":"2561"},{"id":"2570","name":"长顺县","code":"522729","parentId":"2561"},{"id":"2571","name":"龙里县","code":"522730","parentId":"2561"},{"id":"2572","name":"惠水县","code":"522731","parentId":"2561"},{"id":"2573","name":"三都水族自治县","code":"522732","parentId":"2561"}]}]},{"id":"2574","name":"云南省","code":"530000","parentId":"0","children":[{"id":"2575","name":"昆明市","code":"530100","parentId":"2574","children":[{"id":"2576","name":"五华区","code":"530102","parentId":"2575"},{"id":"2577","name":"盘龙区","code":"530103","parentId":"2575"},{"id":"2578","name":"官渡区","code":"530111","parentId":"2575"},{"id":"2579","name":"西山区","code":"530112","parentId":"2575"},{"id":"2580","name":"东川区","code":"530113","parentId":"2575"},{"id":"2581","name":"呈贡区","code":"530114","parentId":"2575"},{"id":"2582","name":"晋宁区","code":"530115","parentId":"2575"},{"id":"2583","name":"富民县","code":"530124","parentId":"2575"},{"id":"2584","name":"宜良县","code":"530125","parentId":"2575"},{"id":"2585","name":"石林彝族自治县","code":"530126","parentId":"2575"},{"id":"2586","name":"嵩明县","code":"530127","parentId":"2575"},{"id":"2587","name":"禄劝彝族苗族自治县","code":"530128","parentId":"2575"},{"id":"2588","name":"寻甸回族彝族自治县","code":"530129","parentId":"2575"},{"id":"2589","name":"安宁市","code":"530181","parentId":"2575"}]},{"id":"2590","name":"曲靖市","code":"530300","parentId":"2574","children":[{"id":"2591","name":"麒麟区","code":"530302","parentId":"2590"},{"id":"2592","name":"沾益区","code":"530303","parentId":"2590"},{"id":"2593","name":"马龙县","code":"530321","parentId":"2590"},{"id":"2594","name":"陆良县","code":"530322","parentId":"2590"},{"id":"2595","name":"师宗县","code":"530323","parentId":"2590"},{"id":"2596","name":"罗平县","code":"530324","parentId":"2590"},{"id":"2597","name":"富源县","code":"530325","parentId":"2590"},{"id":"2598","name":"会泽县","code":"530326","parentId":"2590"},{"id":"2599","name":"宣威市","code":"530381","parentId":"2590"}]},{"id":"2600","name":"玉溪市","code":"530400","parentId":"2574","children":[{"id":"2601","name":"红塔区","code":"530402","parentId":"2600"},{"id":"2602","name":"江川区","code":"530403","parentId":"2600"},{"id":"2603","name":"澄江县","code":"530422","parentId":"2600"},{"id":"2604","name":"通海县","code":"530423","parentId":"2600"},{"id":"2605","name":"华宁县","code":"530424","parentId":"2600"},{"id":"2606","name":"易门县","code":"530425","parentId":"2600"},{"id":"2607","name":"峨山彝族自治县","code":"530426","parentId":"2600"},{"id":"2608","name":"新平彝族傣族自治县","code":"530427","parentId":"2600"},{"id":"2609","name":"元江哈尼族彝族傣族自治县","code":"530428","parentId":"2600"}]},{"id":"2610","name":"保山市","code":"530500","parentId":"2574","children":[{"id":"2611","name":"隆阳区","code":"530502","parentId":"2610"},{"id":"2612","name":"施甸县","code":"530521","parentId":"2610"},{"id":"2613","name":"龙陵县","code":"530523","parentId":"2610"},{"id":"2614","name":"昌宁县","code":"530524","parentId":"2610"},{"id":"2615","name":"腾冲市","code":"530581","parentId":"2610"}]},{"id":"2616","name":"昭通市","code":"530600","parentId":"2574","children":[{"id":"2617","name":"昭阳区","code":"530602","parentId":"2616"},{"id":"2618","name":"鲁甸县","code":"530621","parentId":"2616"},{"id":"2619","name":"巧家县","code":"530622","parentId":"2616"},{"id":"2620","name":"盐津县","code":"530623","parentId":"2616"},{"id":"2621","name":"大关县","code":"530624","parentId":"2616"},{"id":"2622","name":"永善县","code":"530625","parentId":"2616"},{"id":"2623","name":"绥江县","code":"530626","parentId":"2616"},{"id":"2624","name":"镇雄县","code":"530627","parentId":"2616"},{"id":"2625","name":"彝良县","code":"530628","parentId":"2616"},{"id":"2626","name":"威信县","code":"530629","parentId":"2616"},{"id":"2627","name":"水富县","code":"530630","parentId":"2616"}]},{"id":"2628","name":"丽江市","code":"530700","parentId":"2574","children":[{"id":"2629","name":"古城区","code":"530702","parentId":"2628"},{"id":"2630","name":"玉龙纳西族自治县","code":"530721","parentId":"2628"},{"id":"2631","name":"永胜县","code":"530722","parentId":"2628"},{"id":"2632","name":"华坪县","code":"530723","parentId":"2628"},{"id":"2633","name":"宁蒗彝族自治县","code":"530724","parentId":"2628"}]},{"id":"2634","name":"普洱市","code":"530800","parentId":"2574","children":[{"id":"2635","name":"思茅区","code":"530802","parentId":"2634"},{"id":"2636","name":"宁洱哈尼族彝族自治县","code":"530821","parentId":"2634"},{"id":"2637","name":"墨江哈尼族自治县","code":"530822","parentId":"2634"},{"id":"2638","name":"景东彝族自治县","code":"530823","parentId":"2634"},{"id":"2639","name":"景谷傣族彝族自治县","code":"530824","parentId":"2634"},{"id":"2640","name":"镇沅彝族哈尼族拉祜族自治县","code":"530825","parentId":"2634"},{"id":"2641","name":"江城哈尼族彝族自治县","code":"530826","parentId":"2634"},{"id":"2642","name":"孟连傣族拉祜族佤族自治县","code":"530827","parentId":"2634"},{"id":"2643","name":"澜沧拉祜族自治县","code":"530828","parentId":"2634"},{"id":"2644","name":"西盟佤族自治县","code":"530829","parentId":"2634"}]},{"id":"2645","name":"临沧市","code":"530900","parentId":"2574","children":[{"id":"2646","name":"临翔区","code":"530902","parentId":"2645"},{"id":"2647","name":"凤庆县","code":"530921","parentId":"2645"},{"id":"2648","name":"云县","code":"530922","parentId":"2645"},{"id":"2649","name":"永德县","code":"530923","parentId":"2645"},{"id":"2650","name":"镇康县","code":"530924","parentId":"2645"},{"id":"2651","name":"双江拉祜族佤族布朗族傣族自治县","code":"530925","parentId":"2645"},{"id":"2652","name":"耿马傣族佤族自治县","code":"530926","parentId":"2645"},{"id":"2653","name":"沧源佤族自治县","code":"530927","parentId":"2645"}]},{"id":"2654","name":"楚雄彝族自治州","code":"532300","parentId":"2574","children":[{"id":"2655","name":"楚雄市","code":"532301","parentId":"2654"},{"id":"2656","name":"双柏县","code":"532322","parentId":"2654"},{"id":"2657","name":"牟定县","code":"532323","parentId":"2654"},{"id":"2658","name":"南华县","code":"532324","parentId":"2654"},{"id":"2659","name":"姚安县","code":"532325","parentId":"2654"},{"id":"2660","name":"大姚县","code":"532326","parentId":"2654"},{"id":"2661","name":"永仁县","code":"532327","parentId":"2654"},{"id":"2662","name":"元谋县","code":"532328","parentId":"2654"},{"id":"2663","name":"武定县","code":"532329","parentId":"2654"},{"id":"2664","name":"禄丰县","code":"532331","parentId":"2654"}]},{"id":"2665","name":"红河哈尼族彝族自治州","code":"532500","parentId":"2574","children":[{"id":"2666","name":"个旧市","code":"532501","parentId":"2665"},{"id":"2667","name":"开远市","code":"532502","parentId":"2665"},{"id":"2668","name":"蒙自市","code":"532503","parentId":"2665"},{"id":"2669","name":"弥勒市","code":"532504","parentId":"2665"},{"id":"2670","name":"屏边苗族自治县","code":"532523","parentId":"2665"},{"id":"2671","name":"建水县","code":"532524","parentId":"2665"},{"id":"2672","name":"石屏县","code":"532525","parentId":"2665"},{"id":"2673","name":"泸西县","code":"532527","parentId":"2665"},{"id":"2674","name":"元阳县","code":"532528","parentId":"2665"},{"id":"2675","name":"红河县","code":"532529","parentId":"2665"},{"id":"2676","name":"金平苗族瑶族傣族自治县","code":"532530","parentId":"2665"},{"id":"2677","name":"绿春县","code":"532531","parentId":"2665"},{"id":"2678","name":"河口瑶族自治县","code":"532532","parentId":"2665"}]},{"id":"2679","name":"文山壮族苗族自治州","code":"532600","parentId":"2574","children":[{"id":"2680","name":"文山市","code":"532601","parentId":"2679"},{"id":"2681","name":"砚山县","code":"532622","parentId":"2679"},{"id":"2682","name":"西畴县","code":"532623","parentId":"2679"},{"id":"2683","name":"麻栗坡县","code":"532624","parentId":"2679"},{"id":"2684","name":"马关县","code":"532625","parentId":"2679"},{"id":"2685","name":"丘北县","code":"532626","parentId":"2679"},{"id":"2686","name":"广南县","code":"532627","parentId":"2679"},{"id":"2687","name":"富宁县","code":"532628","parentId":"2679"}]},{"id":"2688","name":"西双版纳傣族自治州","code":"532800","parentId":"2574","children":[{"id":"2689","name":"景洪市","code":"532801","parentId":"2688"},{"id":"2690","name":"勐海县","code":"532822","parentId":"2688"},{"id":"2691","name":"勐腊县","code":"532823","parentId":"2688"}]},{"id":"2692","name":"大理白族自治州","code":"532900","parentId":"2574","children":[{"id":"2693","name":"大理市","code":"532901","parentId":"2692"},{"id":"2694","name":"漾濞彝族自治县","code":"532922","parentId":"2692"},{"id":"2695","name":"祥云县","code":"532923","parentId":"2692"},{"id":"2696","name":"宾川县","code":"532924","parentId":"2692"},{"id":"2697","name":"弥渡县","code":"532925","parentId":"2692"},{"id":"2698","name":"南涧彝族自治县","code":"532926","parentId":"2692"},{"id":"2699","name":"巍山彝族回族自治县","code":"532927","parentId":"2692"},{"id":"2700","name":"永平县","code":"532928","parentId":"2692"},{"id":"2701","name":"云龙县","code":"532929","parentId":"2692"},{"id":"2702","name":"洱源县","code":"532930","parentId":"2692"},{"id":"2703","name":"剑川县","code":"532931","parentId":"2692"},{"id":"2704","name":"鹤庆县","code":"532932","parentId":"2692"}]},{"id":"2705","name":"德宏傣族景颇族自治州","code":"533100","parentId":"2574","children":[{"id":"2706","name":"瑞丽市","code":"533102","parentId":"2705"},{"id":"2707","name":"芒市","code":"533103","parentId":"2705"},{"id":"2708","name":"梁河县","code":"533122","parentId":"2705"},{"id":"2709","name":"盈江县","code":"533123","parentId":"2705"},{"id":"2710","name":"陇川县","code":"533124","parentId":"2705"}]},{"id":"2711","name":"怒江傈僳族自治州","code":"533300","parentId":"2574","children":[{"id":"2712","name":"泸水市","code":"533301","parentId":"2711"},{"id":"2713","name":"福贡县","code":"533323","parentId":"2711"},{"id":"2714","name":"贡山独龙族怒族自治县","code":"533324","parentId":"2711"},{"id":"2715","name":"兰坪白族普米族自治县","code":"533325","parentId":"2711"}]},{"id":"2716","name":"迪庆藏族自治州","code":"533400","parentId":"2574","children":[{"id":"2717","name":"香格里拉市","code":"533401","parentId":"2716"},{"id":"2718","name":"德钦县","code":"533422","parentId":"2716"},{"id":"2719","name":"维西傈僳族自治县","code":"533423","parentId":"2716"}]}]},{"id":"2720","name":"西藏自治区","code":"540000","parentId":"0","children":[{"id":"2721","name":"拉萨市","code":"540100","parentId":"2720","children":[{"id":"2722","name":"城关区","code":"540102","parentId":"2721"},{"id":"2723","name":"堆龙德庆区","code":"540103","parentId":"2721"},{"id":"2724","name":"达孜区","code":"540104","parentId":"2721"},{"id":"2725","name":"林周县","code":"540121","parentId":"2721"},{"id":"2726","name":"当雄县","code":"540122","parentId":"2721"},{"id":"2727","name":"尼木县","code":"540123","parentId":"2721"},{"id":"2728","name":"曲水县","code":"540124","parentId":"2721"},{"id":"2729","name":"墨竹工卡县","code":"540127","parentId":"2721"}]},{"id":"2730","name":"日喀则市","code":"540200","parentId":"2720","children":[{"id":"2731","name":"桑珠孜区","code":"540202","parentId":"2730"},{"id":"2732","name":"南木林县","code":"540221","parentId":"2730"},{"id":"2733","name":"江孜县","code":"540222","parentId":"2730"},{"id":"2734","name":"定日县","code":"540223","parentId":"2730"},{"id":"2735","name":"萨迦县","code":"540224","parentId":"2730"},{"id":"2736","name":"拉孜县","code":"540225","parentId":"2730"},{"id":"2737","name":"昂仁县","code":"540226","parentId":"2730"},{"id":"2738","name":"谢通门县","code":"540227","parentId":"2730"},{"id":"2739","name":"白朗县","code":"540228","parentId":"2730"},{"id":"2740","name":"仁布县","code":"540229","parentId":"2730"},{"id":"2741","name":"康马县","code":"540230","parentId":"2730"},{"id":"2742","name":"定结县","code":"540231","parentId":"2730"},{"id":"2743","name":"仲巴县","code":"540232","parentId":"2730"},{"id":"2744","name":"亚东县","code":"540233","parentId":"2730"},{"id":"2745","name":"吉隆县","code":"540234","parentId":"2730"},{"id":"2746","name":"聂拉木县","code":"540235","parentId":"2730"},{"id":"2747","name":"萨嘎县","code":"540236","parentId":"2730"},{"id":"2748","name":"岗巴县","code":"540237","parentId":"2730"}]},{"id":"2749","name":"昌都市","code":"540300","parentId":"2720","children":[{"id":"2750","name":"卡若区","code":"540302","parentId":"2749"},{"id":"2751","name":"江达县","code":"540321","parentId":"2749"},{"id":"2752","name":"贡觉县","code":"540322","parentId":"2749"},{"id":"2753","name":"类乌齐县","code":"540323","parentId":"2749"},{"id":"2754","name":"丁青县","code":"540324","parentId":"2749"},{"id":"2755","name":"察雅县","code":"540325","parentId":"2749"},{"id":"2756","name":"八宿县","code":"540326","parentId":"2749"},{"id":"2757","name":"左贡县","code":"540327","parentId":"2749"},{"id":"2758","name":"芒康县","code":"540328","parentId":"2749"},{"id":"2759","name":"洛隆县","code":"540329","parentId":"2749"},{"id":"2760","name":"边坝县","code":"540330","parentId":"2749"}]},{"id":"2761","name":"林芝市","code":"540400","parentId":"2720","children":[{"id":"2762","name":"巴宜区","code":"540402","parentId":"2761"},{"id":"2763","name":"工布江达县","code":"540421","parentId":"2761"},{"id":"2764","name":"米林县","code":"540422","parentId":"2761"},{"id":"2765","name":"墨脱县","code":"540423","parentId":"2761"},{"id":"2766","name":"波密县","code":"540424","parentId":"2761"},{"id":"2767","name":"察隅县","code":"540425","parentId":"2761"},{"id":"2768","name":"朗县","code":"540426","parentId":"2761"}]},{"id":"2769","name":"山南市","code":"540500","parentId":"2720","children":[{"id":"2770","name":"乃东区","code":"540502","parentId":"2769"},{"id":"2771","name":"扎囊县","code":"540521","parentId":"2769"},{"id":"2772","name":"贡嘎县","code":"540522","parentId":"2769"},{"id":"2773","name":"桑日县","code":"540523","parentId":"2769"},{"id":"2774","name":"琼结县","code":"540524","parentId":"2769"},{"id":"2775","name":"曲松县","code":"540525","parentId":"2769"},{"id":"2776","name":"措美县","code":"540526","parentId":"2769"},{"id":"2777","name":"洛扎县","code":"540527","parentId":"2769"},{"id":"2778","name":"加查县","code":"540528","parentId":"2769"},{"id":"2779","name":"隆子县","code":"540529","parentId":"2769"},{"id":"2780","name":"错那县","code":"540530","parentId":"2769"},{"id":"2781","name":"浪卡子县","code":"540531","parentId":"2769"}]},{"id":"2782","name":"那曲市","code":"540600","parentId":"2720","children":[{"id":"2783","name":"色尼区","code":"540602","parentId":"2782"},{"id":"2784","name":"嘉黎县","code":"540621","parentId":"2782"},{"id":"2785","name":"比如县","code":"540622","parentId":"2782"},{"id":"2786","name":"聂荣县","code":"540623","parentId":"2782"},{"id":"2787","name":"安多县","code":"540624","parentId":"2782"},{"id":"2788","name":"申扎县","code":"540625","parentId":"2782"},{"id":"2789","name":"索县","code":"540626","parentId":"2782"},{"id":"2790","name":"班戈县","code":"540627","parentId":"2782"},{"id":"2791","name":"巴青县","code":"540628","parentId":"2782"},{"id":"2792","name":"尼玛县","code":"540629","parentId":"2782"},{"id":"2793","name":"双湖县","code":"540630","parentId":"2782"}]},{"id":"2794","name":"阿里地区","code":"542500","parentId":"2720","children":[{"id":"2795","name":"普兰县","code":"542521","parentId":"2794"},{"id":"2796","name":"札达县","code":"542522","parentId":"2794"},{"id":"2797","name":"噶尔县","code":"542523","parentId":"2794"},{"id":"2798","name":"日土县","code":"542524","parentId":"2794"},{"id":"2799","name":"革吉县","code":"542525","parentId":"2794"},{"id":"2800","name":"改则县","code":"542526","parentId":"2794"},{"id":"2801","name":"措勤县","code":"542527","parentId":"2794"}]}]},{"id":"2802","name":"陕西省","code":"610000","parentId":"0","children":[{"id":"2803","name":"西安市","code":"610100","parentId":"2802","children":[{"id":"2804","name":"新城区","code":"610102","parentId":"2803"},{"id":"2805","name":"碑林区","code":"610103","parentId":"2803"},{"id":"2806","name":"莲湖区","code":"610104","parentId":"2803"},{"id":"2807","name":"灞桥区","code":"610111","parentId":"2803"},{"id":"2808","name":"未央区","code":"610112","parentId":"2803"},{"id":"2809","name":"雁塔区","code":"610113","parentId":"2803"},{"id":"2810","name":"阎良区","code":"610114","parentId":"2803"},{"id":"2811","name":"临潼区","code":"610115","parentId":"2803"},{"id":"2812","name":"长安区","code":"610116","parentId":"2803"},{"id":"2813","name":"高陵区","code":"610117","parentId":"2803"},{"id":"2814","name":"鄠邑区","code":"610118","parentId":"2803"},{"id":"2815","name":"蓝田县","code":"610122","parentId":"2803"},{"id":"2816","name":"周至县","code":"610124","parentId":"2803"}]},{"id":"2817","name":"铜川市","code":"610200","parentId":"2802","children":[{"id":"2818","name":"王益区","code":"610202","parentId":"2817"},{"id":"2819","name":"印台区","code":"610203","parentId":"2817"},{"id":"2820","name":"耀州区","code":"610204","parentId":"2817"},{"id":"2821","name":"宜君县","code":"610222","parentId":"2817"}]},{"id":"2822","name":"宝鸡市","code":"610300","parentId":"2802","children":[{"id":"2823","name":"渭滨区","code":"610302","parentId":"2822"},{"id":"2824","name":"金台区","code":"610303","parentId":"2822"},{"id":"2825","name":"陈仓区","code":"610304","parentId":"2822"},{"id":"2826","name":"凤翔县","code":"610322","parentId":"2822"},{"id":"2827","name":"岐山县","code":"610323","parentId":"2822"},{"id":"2828","name":"扶风县","code":"610324","parentId":"2822"},{"id":"2829","name":"眉县","code":"610326","parentId":"2822"},{"id":"2830","name":"陇县","code":"610327","parentId":"2822"},{"id":"2831","name":"千阳县","code":"610328","parentId":"2822"},{"id":"2832","name":"麟游县","code":"610329","parentId":"2822"},{"id":"2833","name":"凤县","code":"610330","parentId":"2822"},{"id":"2834","name":"太白县","code":"610331","parentId":"2822"}]},{"id":"2835","name":"咸阳市","code":"610400","parentId":"2802","children":[{"id":"2836","name":"秦都区","code":"610402","parentId":"2835"},{"id":"2837","name":"杨陵区","code":"610403","parentId":"2835"},{"id":"2838","name":"渭城区","code":"610404","parentId":"2835"},{"id":"2839","name":"三原县","code":"610422","parentId":"2835"},{"id":"2840","name":"泾阳县","code":"610423","parentId":"2835"},{"id":"2841","name":"乾县","code":"610424","parentId":"2835"},{"id":"2842","name":"礼泉县","code":"610425","parentId":"2835"},{"id":"2843","name":"永寿县","code":"610426","parentId":"2835"},{"id":"2844","name":"彬县","code":"610427","parentId":"2835"},{"id":"2845","name":"长武县","code":"610428","parentId":"2835"},{"id":"2846","name":"旬邑县","code":"610429","parentId":"2835"},{"id":"2847","name":"淳化县","code":"610430","parentId":"2835"},{"id":"2848","name":"武功县","code":"610431","parentId":"2835"},{"id":"2849","name":"兴平市","code":"610481","parentId":"2835"}]},{"id":"2850","name":"渭南市","code":"610500","parentId":"2802","children":[{"id":"2851","name":"临渭区","code":"610502","parentId":"2850"},{"id":"2852","name":"华州区","code":"610503","parentId":"2850"},{"id":"2853","name":"潼关县","code":"610522","parentId":"2850"},{"id":"2854","name":"大荔县","code":"610523","parentId":"2850"},{"id":"2855","name":"合阳县","code":"610524","parentId":"2850"},{"id":"2856","name":"澄城县","code":"610525","parentId":"2850"},{"id":"2857","name":"蒲城县","code":"610526","parentId":"2850"},{"id":"2858","name":"白水县","code":"610527","parentId":"2850"},{"id":"2859","name":"富平县","code":"610528","parentId":"2850"},{"id":"2860","name":"韩城市","code":"610581","parentId":"2850"},{"id":"2861","name":"华阴市","code":"610582","parentId":"2850"}]},{"id":"2862","name":"延安市","code":"610600","parentId":"2802","children":[{"id":"2863","name":"宝塔区","code":"610602","parentId":"2862"},{"id":"2864","name":"安塞区","code":"610603","parentId":"2862"},{"id":"2865","name":"延长县","code":"610621","parentId":"2862"},{"id":"2866","name":"延川县","code":"610622","parentId":"2862"},{"id":"2867","name":"子长县","code":"610623","parentId":"2862"},{"id":"2868","name":"志丹县","code":"610625","parentId":"2862"},{"id":"2869","name":"吴起县","code":"610626","parentId":"2862"},{"id":"2870","name":"甘泉县","code":"610627","parentId":"2862"},{"id":"2871","name":"富县","code":"610628","parentId":"2862"},{"id":"2872","name":"洛川县","code":"610629","parentId":"2862"},{"id":"2873","name":"宜川县","code":"610630","parentId":"2862"},{"id":"2874","name":"黄龙县","code":"610631","parentId":"2862"},{"id":"2875","name":"黄陵县","code":"610632","parentId":"2862"}]},{"id":"2876","name":"汉中市","code":"610700","parentId":"2802","children":[{"id":"2877","name":"汉台区","code":"610702","parentId":"2876"},{"id":"2878","name":"南郑区","code":"610703","parentId":"2876"},{"id":"2879","name":"城固县","code":"610722","parentId":"2876"},{"id":"2880","name":"洋县","code":"610723","parentId":"2876"},{"id":"2881","name":"西乡县","code":"610724","parentId":"2876"},{"id":"2882","name":"勉县","code":"610725","parentId":"2876"},{"id":"2883","name":"宁强县","code":"610726","parentId":"2876"},{"id":"2884","name":"略阳县","code":"610727","parentId":"2876"},{"id":"2885","name":"镇巴县","code":"610728","parentId":"2876"},{"id":"2886","name":"留坝县","code":"610729","parentId":"2876"},{"id":"2887","name":"佛坪县","code":"610730","parentId":"2876"}]},{"id":"2888","name":"榆林市","code":"610800","parentId":"2802","children":[{"id":"2889","name":"榆阳区","code":"610802","parentId":"2888"},{"id":"2890","name":"横山区","code":"610803","parentId":"2888"},{"id":"2891","name":"府谷县","code":"610822","parentId":"2888"},{"id":"2892","name":"靖边县","code":"610824","parentId":"2888"},{"id":"2893","name":"定边县","code":"610825","parentId":"2888"},{"id":"2894","name":"绥德县","code":"610826","parentId":"2888"},{"id":"2895","name":"米脂县","code":"610827","parentId":"2888"},{"id":"2896","name":"佳县","code":"610828","parentId":"2888"},{"id":"2897","name":"吴堡县","code":"610829","parentId":"2888"},{"id":"2898","name":"清涧县","code":"610830","parentId":"2888"},{"id":"2899","name":"子洲县","code":"610831","parentId":"2888"},{"id":"2900","name":"神木市","code":"610881","parentId":"2888"}]},{"id":"2901","name":"安康市","code":"610900","parentId":"2802","children":[{"id":"2902","name":"汉滨区","code":"610902","parentId":"2901"},{"id":"2903","name":"汉阴县","code":"610921","parentId":"2901"},{"id":"2904","name":"石泉县","code":"610922","parentId":"2901"},{"id":"2905","name":"宁陕县","code":"610923","parentId":"2901"},{"id":"2906","name":"紫阳县","code":"610924","parentId":"2901"},{"id":"2907","name":"岚皋县","code":"610925","parentId":"2901"},{"id":"2908","name":"平利县","code":"610926","parentId":"2901"},{"id":"2909","name":"镇坪县","code":"610927","parentId":"2901"},{"id":"2910","name":"旬阳县","code":"610928","parentId":"2901"},{"id":"2911","name":"白河县","code":"610929","parentId":"2901"}]},{"id":"2912","name":"商洛市","code":"611000","parentId":"2802","children":[{"id":"2913","name":"商州区","code":"611002","parentId":"2912"},{"id":"2914","name":"洛南县","code":"611021","parentId":"2912"},{"id":"2915","name":"丹凤县","code":"611022","parentId":"2912"},{"id":"2916","name":"商南县","code":"611023","parentId":"2912"},{"id":"2917","name":"山阳县","code":"611024","parentId":"2912"},{"id":"2918","name":"镇安县","code":"611025","parentId":"2912"},{"id":"2919","name":"柞水县","code":"611026","parentId":"2912"}]}]},{"id":"2920","name":"甘肃省","code":"620000","parentId":"0","children":[{"id":"2921","name":"兰州市","code":"620100","parentId":"2920","children":[{"id":"2922","name":"城关区","code":"620102","parentId":"2921"},{"id":"2923","name":"七里河区","code":"620103","parentId":"2921"},{"id":"2924","name":"西固区","code":"620104","parentId":"2921"},{"id":"2925","name":"安宁区","code":"620105","parentId":"2921"},{"id":"2926","name":"红古区","code":"620111","parentId":"2921"},{"id":"2927","name":"永登县","code":"620121","parentId":"2921"},{"id":"2928","name":"皋兰县","code":"620122","parentId":"2921"},{"id":"2929","name":"榆中县","code":"620123","parentId":"2921"}]},{"id":"2930","name":"嘉峪关市","code":"620200","parentId":"2920","children":[{"id":"3470","name":"辖区","code":"-1","parentId":"2930"}]},{"id":"2931","name":"金昌市","code":"620300","parentId":"2920","children":[{"id":"2932","name":"金川区","code":"620302","~XparentId":"2931"},{"id":"2933","name":"永昌县","code":"620321","parentId":"2931"}]},{"id":"2934","name":"白银市","code":"620400","parentId":"2920","children":[{"id":"2935","name":"白银区","code":"620402","parentId":"2934"},{"id":"2936","name":"平川区","code":"620403","parentId":"2934"},{"id":"2937","name":"靖远县","code":"620421","parentId":"2934"},{"id":"2938","name":"会宁县","code":"620422","parentId":"2934"},{"id":"2939","name":"景泰县","code":"620423","parentId":"2934"}]},{"id":"2940","name":"天水市","code":"620500","parentId":"2920","children":[{"id":"2941","name":"秦州区","code":"620502","parentId":"2940"},{"id":"2942","name":"麦积区","code":"620503","parentId":"2940"},{"id":"2943","name":"清水县","code":"620521","parentId":"2940"},{"id":"2944","name":"秦安县","code":"620522","parentId":"2940"},{"id":"2945","name":"甘谷县","code":"620523","parentId":"2940"},{"id":"2946","name":"武山县","code":"620524","parentId":"2940"},{"id":"2947","name":"张家川回族自治县","code":"620525","parentId":"2940"}]},{"id":"2948","name":"武威市","code":"620600","parentId":"2920","children":[{"id":"2949","name":"凉州区","code":"620602","parentId":"2948"},{"id":"2950","name":"民勤县","code":"620621","parentId":"2948"},{"id":"2951","name":"古浪县","code":"620622","parentId":"2948"},{"id":"2952","name":"天祝藏族自治县","code":"620623","parentId":"2948"}]},{"id":"2953","name":"张掖市","code":"620700","parentId":"2920","children":[{"id":"2954","name":"甘州区","code":"620702","parentId":"2953"},{"id":"2955","name":"肃南裕固族自治县","code":"620721","parentId":"2953"},{"id":"2956","name":"民乐县","code":"620722","parentId":"2953"},{"id":"2957","name":"临泽县","code":"620723","parentId":"2953"},{"id":"2958","name":"高台县","code":"620724","parentId":"2953"},{"id":"2959","name":"山丹县","code":"620725","parentId":"2953"}]},{"id":"2960","name":"平凉市","code":"620800","parentId":"2920","children":[{"id":"2961","name":"崆峒区","code":"620802","parentId":"2960"},{"id":"2962","name":"泾川县","code":"620821","parentId":"2960"},{"id":"2963","name":"灵台县","code":"620822","parentId":"2960"},{"id":"2964","name":"崇信县","code":"620823","parentId":"2960"},{"id":"2965","name":"华亭县","code":"620824","parentId":"2960"},{"id":"2966","name":"庄浪县","code":"620825","parentId":"2960"},{"id":"2967","name":"静宁县","code":"620826","parentId":"2960"}]},{"id":"2968","name":"酒泉市","code":"620900","parentId":"2920","children":[{"id":"2969","name":"肃州区","code":"620902","parentId":"2968"},{"id":"2970","name":"金塔县","code":"620921","parentId":"2968"},{"id":"2971","name":"瓜州县","code":"620922","parentId":"2968"},{"id":"2972","name":"肃北蒙古族自治县","code":"620923","parentId":"2968"},{"id":"2973","name":"阿克塞哈萨克族自治县","code":"620924","parentId":"2968"},{"id":"2974","name":"玉门市","code":"620981","parentId":"2968"},{"id":"2975","name":"敦煌市","code":"620982","parentId":"2968"}]},{"id":"2976","name":"庆阳市","code":"621000","parentId":"2920","children":[{"id":"2977","name":"西峰区","code":"621002","parentId":"2976"},{"id":"2978","name":"庆城县","code":"621021","parentId":"2976"},{"id":"2979","name":"环县","code":"621022","parentId":"2976"},{"id":"2980","name":"华池县","code":"621023","parentId":"2976"},{"id":"2981","name":"合水县","code":"621024","parentId":"2976"},{"id":"2982","name":"正宁县","code":"621025","parentId":"2976"},{"id":"2983","name":"宁县","code":"621026","parentId":"2976"},{"id":"2984","name":"镇原县","code":"621027","parentId":"2976"}]},{"id":"2985","name":"定西市","code":"621100","parentId":"2920","children":[{"id":"2986","name":"安定区","code":"621102","parentId":"2985"},{"id":"2987","name":"通渭县","code":"621121","parentId":"2985"},{"id":"2988","name":"陇西县","code":"621122","parentId":"2985"},{"id":"2989","name":"渭源县","code":"621123","parentId":"2985"},{"id":"2990","name":"临洮县","code":"621124","parentId":"2985"},{"id":"2991","name":"漳县","code":"621125","parentId":"2985"},{"id":"2992","name":"岷县","code":"621126","parentId":"2985"}]},{"id":"2993","name":"陇南市","code":"621200","parentId":"2920","children":[{"id":"2994","name":"武都区","code":"621202","parentId":"2993"},{"id":"2995","name":"成县","code":"621221","parentId":"2993"},{"id":"2996","name":"文县","code":"621222","parentId":"2993"},{"id":"2997","name":"宕昌县","code":"621223","parentId":"2993"},{"id":"2998","name":"康县","code":"621224","parentId":"2993"},{"id":"2999","name":"西和县","code":"621225","parentId":"2993"},{"id":"3000","name":"礼县","code":"621226","parentId":"2993"},{"id":"3001","name":"徽县","code":"621227","parentId":"2993"},{"id":"3002","name":"两当县","code":"621228","parentId":"2993"}]},{"id":"3003","name":"临夏回族自治州","code":"622900","parentId":"2920","children":[{"id":"3004","name":"临夏市","code":"622901","parentId":"3003"},{"id":"3005","name":"临夏县","code":"622921","parentId":"3003"},{"id":"3006","name":"康乐县","code":"622922","parentId":"3003"},{"id":"3007","name":"永靖县","code":"622923","parentId":"3003"},{"id":"3008","name":"广河县","code":"622924","parentId":"3003"},{"id":"3009","name":"和政县","code":"622925","parentId":"3003"},{"id":"3010","name":"东乡族自治县","code":"622926","parentId":"3003"},{"id":"3011","name":"积石山保安族东乡族撒拉族自治县","code":"622927","parentId":"3003"}]},{"id":"3012","name":"甘南藏族自治州","code":"623000","parentId":"2920","children":[{"id":"3013","name":"合作市","code":"623001","parentId":"3012"},{"id":"3014","name":"临潭县","code":"623021","parentId":"3012"},{"id":"3015","name":"卓尼县","code":"623022","parentId":"3012"},{"id":"3016","name":"舟曲县","code":"623023","parentId":"3012"},{"id":"3017","name":"迭部县","code":"623024","parentId":"3012"},{"id":"3018","name":"玛曲县","code":"623025","parentId":"3012"},{"id":"3019","name":"碌曲县","code":"623026","parentId":"3012"},{"id":"3020","name":"夏河县","code":"623027","parentId":"3012"}]}]},{"id":"3021","name":"青海省","code":"630000","parentId":"0","children":[{"id":"3022","name":"西宁市","code":"630100","parentId":"3021","children":[{"id":"3023","name":"城东区","code":"630102","parentId":"3022"},{"id":"3024","name":"城中区","code":"630103","parentId":"3022"},{"id":"3025","name":"城西区","code":"630104","parentId":"3022"},{"id":"3026","name":"城北区","code":"630105","parentId":"3022"},{"id":"3027","name":"大通回族土族自治县","code":"630121","parentId":"3022"},{"id":"3028","name":"湟中县","code":"630122","parentId":"3022"},{"id":"3029","name":"湟源县","code":"630123","parentId":"3022"}]},{"id":"3030","name":"海东市","code":"630200","parentId":"3021","children":[{"id":"3031","name":"乐都区","code":"630202","parentId":"3030"},{"id":"3032","name":"平安区","code":"630203","parentId":"3030"},{"id":"3033","name":"民和回族土族自治县","code":"630222","parentId":"3030"},{"id":"3034","name":"互助土族自治县","code":"630223","parentId":"3030"},{"id":"3035","name":"化隆回族自治县","code":"630224","parentId":"3030"},{"id":"3036","name":"循化撒拉族自治县","code":"630225","parentId":"3030"}]},{"id":"3037","name":"海北藏族自治州","code":"632200","parentId":"3021","children":[{"id":"3038","name":"门源回族自治县","code":"632221","parentId":"3037"},{"id":"3039","name":"祁连县","code":"632222","parentId":"3037"},{"id":"3040","name":"海晏县","code":"632223","parentId":"3037"},{"id":"3041","name":"刚察县","code":"632224","parentId":"3037"}]},{"id":"3042","name":"黄南藏族自治州","code":"632300","parentId":"3021","children":[{"id":"3043","name":"同仁县","code":"632321","parentId":"3042"},{"id":"3044","name":"尖扎县","code":"632322","parentId":"3042"},{"id":"3045","name":"泽库县","code":"632323","parentId":"3042"},{"id":"3046","name":"河南蒙古族自治县","code":"632324","parentId":"3042"}]},{"id":"3047","name":"海南藏族自治州","code":"632500","parentId":"3021","children":[{"id":"3048","name":"共和县","code":"632521","parentId":"3047"},{"id":"3049","name":"同德县","code":"632522","parentId":"3047"},{"id":"3050","name":"贵德县","code":"632523","parentId":"3047"},{"id":"3051","name":"兴海县","code":"632524","parentId":"3047"},{"id":"3052","name":"贵南县","code":"632525","parentId":"3047"}]},{"id":"3053","name":"果洛藏族自治州","code":"632600","parentId":"3021","children":[{"id":"3054","name":"玛沁县","code":"632621","parentId":"3053"},{"id":"3055","name":"班玛县","code":"632622","parentId":"3053"},{"id":"3056","name":"甘德县","code":"632623","parentId":"3053"},{"id":"3057","name":"达日县","code":"632624","parentId":"3053"},{"id":"3058","name":"久治县","code":"632625","parentId":"3053"},{"id":"3059","name":"玛多县","code":"632626","parentId":"3053"}]},{"id":"3060","name":"玉树藏族自治州","code":"632700","parentId":"3021","children":[{"id":"3061","name":"玉树市","code":"632701","parentId":"3060"},{"id":"3062","name":"杂多县","code":"632722","parentId":"3060"},{"id":"3063","name":"称多县","code":"632723","parentId":"3060"},{"id":"3064","name":"治多县","code":"632724","parentId":"3060"},{"id":"3065","name":"囊谦县","code":"632725","parentId":"3060"},{"id":"3066","name":"曲麻莱县","code":"632726","parentId":"3060"}]},{"id":"3067","name":"海西蒙古族藏族自治州","code":"632800","parentId":"3021","children":[{"id":"3068","name":"格尔木市","code":"632801","parentId":"3067"},{"id":"3069","name":"德令哈市","code":"632802","parentId":"3067"},{"id":"3070","name":"乌兰县","code":"632821","parentId":"3067"},{"id":"3071","name":"都兰县","code":"632822","parentId":"3067"},{"id":"3072","name":"天峻县","code":"632823","parentId":"3067"}]}]},{"id":"3073","name":"宁夏回族自治区","code":"640000","parentId":"0","children":[{"id":"3074","name":"银川市","code":"640100","parentId":"3073","children":[{"id":"3075","name":"兴庆区","code":"640104","parentId":"3074"},{"id":"3076","name":"西夏区","code":"640105","parentId":"3074"},{"id":"3077","name":"金凤区","code":"640106","parentId":"3074"},{"id":"3078","name":"永宁县","code":"640121","parentId":"3074"},{"id":"3079","name":"贺兰县","code":"640122","parentId":"3074"},{"id":"3080","name":"灵武市","code":"640181","parentId":"3074"}]},{"id":"3081","name":"石嘴山市","code":"640200","parentId":"3073","children":[{"id":"3082","name":"大武口区","code":"640202","parentId":"3081"},{"id":"3083","name":"惠农区","code":"640205","parentId":"3081"},{"id":"3084","name":"平罗县","code":"640221","parentId":"3081"}]},{"id":"3085","name":"吴忠市","code":"640300","parentId":"3073","children":[{"id":"3086","name":"利通区","code":"640302","parentId":"3085"},{"id":"3087","name":"红寺堡区","code":"640303","parentId":"3085"},{"id":"3088","name":"盐池县","code":"640323","parentId":"3085"},{"id":"3089","name":"同心县","code":"640324","parentId":"3085"},{"id":"3090","name":"青铜峡市","code":"640381","parentId":"3085"}]},{"id":"3091","name":"固原市","code":"640400","parentId":"3073","children":[{"id":"3092","name":"原州区","code":"640402","parentId":"3091"},{"id":"3093","name":"西吉县","code":"640422","parentId":"3091"},{"id":"3094","name":"隆德县","code":"640423","parentId":"3091"},{"id":"3095","name":"泾源县","code":"640424","parentId":"3091"},{"id":"3096","name":"彭阳县","code":"640425","parentId":"3091"}]},{"id":"3097","name":"中卫市","code":"640500","parentId":"3073","children":[{"id":"3098","name":"沙坡头区","code":"640502","parentId":"3097"},{"id":"3099","name":"中宁县","code":"640521","parentId":"3097"},{"id":"3100","name":"海原县","code":"640522","parentId":"3097"}]}]},{"id":"3101","name":"新疆维吾尔自治区","code":"650000","parentId":"0","children":[{"id":"3102","name":"乌鲁木齐市","code":"650100","parentId":"3101","children":[{"id":"3103","name":"天山区","code":"650102","parentId":"3102"},{"id":"3104","name":"沙依巴克区","code":"650103","parentId":"3102"},{"id":"3105","name":"新市区","code":"650104","parentId":"3102"},{"id":"3106","name":"水磨沟区","code":"650105","parentId":"3102"},{"id":"3107","name":"头屯河区","code":"650106","parentId":"3102"},{"id":"3108","name":"达坂城区","code":"650107","parentId":"3102"},{"id":"3109","name":"米东区","code":"650109","parentId":"3102"},{"id":"3110","name":"乌鲁木齐县","code":"650121","parentId":"3102"}]},{"id":"3111","name":"克拉玛依市","code":"650200","parentId":"3101","children":[{"id":"3112","name":"独山子区","code":"650202","parentId":"3111"},{"id":"3113","name":"克拉玛依区","code":"650203","parentId":"3111"},{"id":"3114","name":"白碱滩区","code":"650204","parentId":"3111"},{"id":"3115","name":"乌尔禾区","code":"650205","parentId":"3111"}]},{"id":"3116","name":"吐鲁番市","code":"650400","parentId":"3101","children":[{"id":"3117","name":"高昌区","code":"650402","parentId":"3116"},{"id":"3118","name":"鄯善县","code":"650421","parentId":"3116"},{"id":"3119","name":"托克逊县","code":"650422","parentId":"3116"}]},{"id":"3120","name":"哈密市","code":"650500","parentId":"3101","children":[{"id":"3121","name":"伊州区","code":"650502","parentId":"3120"},{"id":"3122","name":"巴里坤哈萨克自治县","code":"650521","parentId":"3120"},{"id":"3123","name":"伊吾县","code":"650522","parentId":"3120"}]},{"id":"3124","name":"昌吉回族自治州","code":"652300","parentId":"3101","children":[{"id":"3125","name":"昌吉市","code":"652301","parentId":"3124"},{"id":"3126","name":"阜康市","code":"652302","parentId":"3124"},{"id":"3127","name":"呼图壁县","code":"652323","parentId":"3124"},{"id":"3128","name":"玛纳斯县","code":"652324","parentId":"3124"},{"id":"3129","name":"奇台县","code":"652325","parentId":"3124"},{"id":"3130","name":"吉木萨尔县","code":"652327","parentId":"3124"},{"id":"3131","name":"木垒哈萨克自治县","code":"652328","parentId":"3124"}]},{"id":"3132","name":"博尔塔拉蒙古自治州","code":"652700","parentId":"3101","children":[{"id":"3133","name":"博乐市","code":"652701","parentId":"3132"},{"id":"3134","name":"阿拉山口市","code":"652702","parentId":"3132"},{"id":"3135","name":"精河县","code":"652722","parentId":"3132"},{"id":"3136","name":"温泉县","code":"652723","parentId":"3132"}]},{"id":"3137","name":"巴音郭楞蒙古自治州","code":"652800","parentId":"3101","children":[{"id":"3138","name":"库尔勒市","code":"652801","parentId":"3137"},{"id":"3139","name":"轮台县","code":"652822","parentId":"3137"},{"id":"3140","name":"尉犁县","code":"652823","parentId":"3137"},{"id":"3141","name":"若羌县","code":"652824","parentId":"3137"},{"id":"3142","name":"且末县","code":"652825","parentId":"3137"},{"id":"3143","name":"焉耆回族自治县","code":"652826","parentId":"3137"},{"id":"3144","name":"和静县","code":"652827","parentId":"3137"},{"id":"3145","name":"和硕县","code":"652828","parentId":"3137"},{"id":"3146","name":"博湖县","code":"652829","parentId":"3137"}]},{"id":"3147","name":"阿克苏地区","code":"652900","parentId":"3101","children":[{"id":"3148","name":"阿克苏市","code":"652901","parentId":"3147"},{"id":"3149","name":"温宿县","code":"652922","parentId":"3147"},{"id":"3150","name":"库车县","code":"652923","parentId":"3147"},{"id":"3151","name":"沙雅县","code":"652924","parentId":"3147"},{"id":"3152","name":"新和县","code":"652925","parentId":"3147"},{"id":"3153","name":"拜城县","code":"652926","parentId":"3147"},{"id":"3154","name":"乌什县","code":"652927","parentId":"3147"},{"id":"3155","name":"阿瓦提县","code":"652928","parentId":"3147"},{"id":"3156","name":"柯坪县","code":"652929","parentId":"3147"}]},{"id":"3157","name":"克孜勒苏柯尔克孜自治州","code":"653000","parentId":"3101","children":[{"id":"3158","name":"阿图什市","code":"653001","parentId":"3157"},{"id":"3159","name":"阿克陶县","code":"653022","parentId":"3157"},{"id":"3160","name":"阿合奇县","code":"653023","parentId":"3157"},{"id":"3161","name":"乌恰县","code":"653024","parentId":"3157"}]},{"id":"3162","name":"喀什地区","code":"653100","parentId":"3101","children":[{"id":"3163","name":"喀什市","code":"653101","parentId":"3162"},{"id":"3164","name":"疏附县","code":"653121","parentId":"3162"},{"id":"3165","name":"疏勒县","code":"653122","parentId":"3162"},{"id":"3166","name":"英吉沙县","code":"653123","parentId":"3162"},{"id":"3167","name":"泽普县","code":"653124","parentId":"3162"},{"id":"3168","name":"莎车县","code":"653125","parentId":"3162"},{"id":"3169","name":"叶城县","code":"653126","parentId":"3162"},{"id":"3170","name":"麦盖提县","code":"653127","parentId":"3162"},{"id":"3171","name":"岳普湖县","code":"653128","parentId":"3162"},{"id":"3172","name":"伽师县","code":"653129","parentId":"3162"},{"id":"3173","name":"巴楚县","code":"653130","parentId":"3162"},{"id":"3174","name":"塔什库尔干塔吉克自治县","code":"653131","parentId":"3162"}]},{"id":"3175","name":"和田地区","code":"653200","parentId":"3101","children":[{"id":"3176","name":"和田市","code":"653201","parentId":"3175"},{"id":"3177","name":"和田县","code":"653221","parentId":"3175"},{"id":"3178","name":"墨玉县","code":"653222","parentId":"3175"},{"id":"3179","name":"皮山县","code":"653223","parentId":"3175"},{"id":"3180","name":"洛浦县","code":"653224","parentId":"3175"},{"id":"3181","name":"策勒县","code":"653225","parentId":"3175"},{"id":"3182","name":"于田县","code":"653226","parentId":"3175"},{"id":"3183","name":"民丰县","code":"653227","parentId":"3175"}]},{"id":"3184","name":"伊犁哈萨克自治州","code":"654000","parentId":"3101","children":[{"id":"3185","name":"伊宁市","code":"654002","parentId":"3184"},{"id":"3186","name":"奎屯市","code":"654003","parentId":"3184"},{"id":"3187","name":"霍尔果斯市","code":"654004","parentId":"3184"},{"id":"3188","name":"伊宁县","code":"654021","parentId":"3184"},{"id":"3189","name":"察布查尔锡伯自治县","code":"654022","parentId":"3184"},{"id":"3190","name":"霍城县","code":"654023","parentId":"3184"},{"id":"3191","name":"巩留县","code":"654024","parentId":"3184"},{"id":"3192","name":"新源县","code":"654025","parentId":"3184"},{"id":"3193","name":"昭苏县","code":"654026","parentId":"3184"},{"id":"3194","name":"特克斯县","code":"654027","parentId":"3184"},{"id":"3195","name":"尼勒克县","code":"654028","parentId":"3184"}]},{"id":"3196","name":"塔城地区","code":"654200","parentId":"3101","children":[{"id":"3197","name":"塔城市","code":"654201","parentId":"3196"},{"id":"3198","name":"乌苏市","code":"654202","parentId":"3196"},{"id":"3199","name":"额敏县","code":"654221","parentId":"3196"},{"id":"3200","name":"沙湾县","code":"654223","parentId":"3196"},{"id":"3201","name":"托里县","code":"654224","parentId":"3196"},{"id":"3202","name":"裕民县","code":"654225","parentId":"3196"},{"id":"3203","name":"和布克赛尔蒙古自治县","code":"654226","parentId":"3196"}]},{"id":"3204","name":"阿勒泰地区","code":"654300","parentId":"3101","children":[{"id":"3205","name":"阿勒泰市","code":"654301","parentId":"3204"},{"id":"3206","name":"布尔津县","code":"654321","parentId":"3204"},{"id":"3207","name":"富蕴县","code":"654322","parentId":"3204"},{"id":"3208","name":"福海县","code":"654323","parentId":"3204"},{"id":"3209","name":"哈巴河县","code":"654324","parentId":"3204"},{"id":"3210","name":"青河县","code":"654325","parentId":"3204"},{"id":"3211","name":"吉木乃县","code":"654326","parentId":"3204"}]},{"id":"3212","name":"石河子市","code":"659001","parentId":"3101","children":[{"id":"3472","name":"辖区","code":"-1","parentId":"3212"}]},{"id":"3213","name":"阿拉尔市","code":"659002","parentId":"3101","children":[{"id":"3474","name":"辖区","code":"-1","parentId":"3213"}]},{"id":"3214","name":"图木舒克市","code":"659003","parentId":"3101","children":[{"id":"3476","name":"辖区","code":"-1","parentId":"3214"}]},{"id":"3215","name":"五家渠市","code":"659004","parentId":"3101","children":[{"id":"3478","name":"辖区","code":"-1","parentId":"3215"}]},{"id":"3216","name":"北屯市","code":"659005","parentId":"3101","children":[{"id":"3480","name":"辖区","code":"-1","parentId":"3216"}]},{"id":"3217","name":"铁门关市","code":"659006","parentId":"3101","children":[{"id":"3482","name":"辖区","code":"-1","parentId":"3217"}]},{"id":"3218","name":"双河市","code":"659007","parentId":"3101","children":[{"id":"3484","name":"辖区","code":"-1","parentId":"3218"}]},{"id":"3219","name":"可克达拉市","code":"659008","parentId":"3101","children":[{"id":"3486","name":"辖区","code":"-1","parentId":"3219"}]},{"id":"3220","name":"昆玉市","code":"659009","parentId":"3101","children":[{"id":"3488","name":"辖区","code":"-1","parentId":"3220"}]}]},{"id":"3221","name":"台湾省","code":"710000","parentId":"0","children":[{"id":"3222","name":"台北市","code":"710100","parentId":"3221","children":[{"id":"3223","name":"中正区","code":"710101","parentId":"3222"},{"id":"3224","name":"大同区","code":"710102","parentId":"3222"},{"id":"3225","name":"中山区","code":"710103","parentId":"3222"},{"id":"3226","name":"万华区","code":"710104","parentId":"3222"},{"id":"3227","name":"信义区","code":"710105","parentId":"3222"},{"id":"3228","name":"松山区","code":"710106","parentId":"3222"},{"id":"3229","name":"大安区","code":"710107","parentId":"3222"},{"id":"3230","name":"南港区","code":"710108","parentId":"3222"},{"id":"3231","name":"北投区","code":"710109","parentId":"3222"},{"id":"3232","name":"内湖区","code":"710110","parentId":"3222"},{"id":"3233","name":"士林区","code":"710111","parentId":"3222"},{"id":"3234","name":"文山区","code":"710112","parentId":"3222"}]},{"id":"3235","name":"新北市","code":"710200","parentId":"3221","children":[{"id":"3236","name":"板桥区","code":"710201","parentId":"3235"},{"id":"3237","name":"土城区","code":"710202","parentId":"3235"},{"id":"3238","name":"新庄区","code":"710203","parentId":"3235"},{"id":"3239","name":"新店区","code":"710204","parentId":"3235"},{"id":"3240","name":"深坑区","code":"710205","parentId":"3235"},{"id":"3241","name":"石碇区","code":"710206","parentId":"3235"},{"id":"3242","name":"坪林区","code":"710207","parentId":"3235"},{"id":"3243","name":"乌来区","code":"710208","parentId":"3235"},{"id":"3244","name":"五股区","code":"710209","parentId":"3235"},{"id":"3245","name":"八里区","code":"710210","parentId":"3235"},{"id":"3246","name":"林口区","code":"710211","parentId":"3235"},{"id":"3247","name":"淡水区","code":"710212","parentId":"3235"},{"id":"3248","name":"中和区","code":"710213","parentId":"3235"},{"id":"3249","name":"永和区","code":"710214","parentId":"3235"},{"id":"3250","name":"三重区","code":"710215","parentId":"3235"},{"id":"3251","name":"芦洲区","code":"710216","parentId":"3235"},{"id":"3252","name":"泰山区","code":"710217","parentId":"3235"},{"id":"3253","name":"树林区","code":"710218","parentId":"3235"},{"id":"3254","name":"莺歌区","code":"710219","parentId":"3235"},{"id":"3255","name":"三峡区","code":"710220","parentId":"3235"},{"id":"3256","name":"汐止区","code":"710221","parentId":"3235"},{"id":"3257","name":"金山区","code":"710222","parentId":"3235"},{"id":"3258","name":"万里区","code":"710223","parentId":"3235"},{"id":"3259","name":"三芝区","code":"710224","parentId":"3235"},{"id":"3260","name":"石门区","code":"710225","parentId":"3235"},{"id":"3261","name":"瑞芳区","code":"710226","parentId":"3235"},{"id":"3262","name":"贡寮区","code":"710227","parentId":"3235"},{"id":"3263","name":"双溪区","code":"710228","parentId":"3235"},{"id":"3264","name":"平溪区","code":"710229","parentId":"3235"}]},{"id":"3265","name":"桃园市","code":"710300","parentId":"3221","children":[{"id":"3266","name":"桃园区","code":"710301","parentId":"3265"},{"id":"3267","name":"中坜区","code":"710302","parentId":"3265"},{"id":"3268","name":"平镇区","code":"710303","parentId":"3265"},{"id":"3269","name":"八德区","code":"710304","parentId":"3265"},{"id":"3270","name":"杨梅区","code":"710305","parentId":"3265"},{"id":"3271","name":"芦竹区","code":"710306","parentId":"3265"},{"id":"3272","name":"大溪区","code":"710307","parentId":"3265"},{"id":"3273","name":"龙潭区","code":"710308","parentId":"3265"},{"id":"3274","name":"龟山区","code":"710309","parentId":"3265"},{"id":"3275","name":"大园区","code":"710310","parentId":"3265"},{"id":"3276","name":"观音区","code":"710311","parentId":"3265"},{"id":"3277","name":"新屋区","code":"710312","parentId":"3265"},{"id":"3278","name":"复兴区","code":"710313","parentId":"3265"}]},{"id":"3279","name":"台中市","code":"710400","parentId":"3221","children":[{"id":"3280","name":"中区","code":"710401","parentId":"3279"},{"id":"3281","name":"东区","code":"710402","parentId":"3279"},{"id":"3282","name":"西区","code":"710403","parentId":"3279"},{"id":"3283","name":"南区","code":"710404","parentId":"3279"},{"id":"3284","name":"北区","code":"710405","parentId":"3279"},{"id":"3285","name":"西屯区","code":"710406","parentId":"3279"},{"id":"3286","name":"南屯区","code":"710407","parentId":"3279"},{"id":"3287","name":"北屯区","code":"710408","parentId":"3279"},{"id":"3288","name":"丰原区","code":"710409","parentId":"3279"},{"id":"3289","name":"大里区","code":"710410","parentId":"3279"},{"id":"3290","name":"太平区","code":"710411","parentId":"3279"},{"id":"3291","name":"东势区","code":"710412","parentId":"3279"},{"id":"3292","name":"大甲区","code":"710413","parentId":"3279"},{"id":"3293","name":"清水区","code":"710414","parentId":"3279"},{"id":"3294","name":"沙鹿区","code":"710415","parentId":"3279"},{"id":"3295","name":"梧栖区","code":"710416","parentId":"3279"},{"id":"3296","name":"后里区","code":"710417","parentId":"3279"},{"id":"3297","name":"神冈区","code":"710418","parentId":"3279"},{"id":"3298","name":"潭子区","code":"710419","parentId":"3279"},{"id":"3299","name":"大雅区","code":"710420","parentId":"3279"},{"id":"3300","name":"新小区","code":"710421","parentId":"3279"},{"id":"3301","name":"石冈区","code":"710422","parentId":"3279"},{"id":"3302","name":"外埔区","code":"710423","parentId":"3279"},{"id":"3303","name":"大安区","code":"710424","parentId":"3279"},{"id":"3304","name":"乌日区","code":"710425","parentId":"3279"},{"id":"3305","name":"大肚区","code":"710426","parentId":"3279"},{"id":"3306","name":"龙井区","code":"710427","parentId":"3279"},{"id":"3307","name":"雾峰区","code":"710428","parentId":"3279"},{"id":"3308","name":"和平区","code":"710429","parentId":"3279"}]},{"id":"3309","name":"台南市","code":"710500","parentId":"3221","children":[{"id":"3310","name":"中西区","code":"710501","parentId":"3309"},{"id":"3311","name":"东区","code":"710502","parentId":"3309"},{"id":"3312","name":"南区","code":"710503","parentId":"3309"},{"id":"3313","name":"北区","code":"710504","parentId":"3309"},{"id":"3314","name":"安平区","code":"710505","parentId":"3309"},{"id":"3315","name":"安南区","code":"710506","parentId":"3309"},{"id":"3316","name":"永康区","code":"710507","parentId":"3309"},{"id":"3317","name":"归仁区","code":"710508","parentId":"3309"},{"id":"3318","name":"新化区","code":"710509","parentId":"3309"},{"id":"3319","name":"左镇区","code":"710510","parentId":"3309"},{"id":"3320","name":"玉井区","code":"710511","parentId":"3309"},{"id":"3321","name":"楠西区","code":"710512","parentId":"3309"},{"id":"3322","name":"南化区","code":"710513","parentId":"3309"},{"id":"3323","name":"仁德区","code":"710514","parentId":"3309"},{"id":"3324","name":"关庙区","code":"710515","parentId":"3309"},{"id":"3325","name":"龙崎区","code":"710516","parentId":"3309"},{"id":"3326","name":"官田区","code":"710517","parentId":"3309"},{"id":"3327","name":"麻豆区","code":"710518","parentId":"3309"},{"id":"3328","name":"佳里区","code":"710519","parentId":"3309"},{"id":"3329","name":"西港区","code":"710520","parentId":"3309"},{"id":"3330","name":"七股区","code":"710521","parentId":"3309"},{"id":"3331","name":"将军区","code":"710522","parentId":"3309"},{"id":"3332","name":"学甲区","code":"710523","parentId":"3309"},{"id":"3333","name":"北门区","code":"710524","parentId":"3309"},{"id":"3334","name":"新营区","code":"710525","parentId":"3309"},{"id":"3335","name":"后壁区","code":"710526","parentId":"3309"},{"id":"3336","name":"白河区","code":"710527","parentId":"3309"},{"id":"3337","name":"东山区","code":"710528","parentId":"3309"},{"id":"3338","name":"六甲区","code":"710529","parentId":"3309"},{"id":"3339","name":"下营区","code":"710530","parentId":"3309"},{"id":"3340","name":"柳营区","code":"710531","parentId":"3309"},{"id":"3341","name":"盐水区","code":"710532","parentId":"3309"},{"id":"3342","name":"善化区","code":"710533","parentId":"3309"},{"id":"3343","name":"大内区","code":"710534","parentId":"3309"},{"id":"3344","name":"山上区","code":"710535","parentId":"3309"},{"id":"3345","name":"新市区","code":"710536","parentId":"3309"},{"id":"3346","name":"安定区","code":"710537","parentId":"3309"}]},{"id":"3347","name":"高雄市","code":"710600","parentId":"3221","children":[{"id":"3348","name":"楠梓区","code":"710601","parentId":"3347"},{"id":"3349","name":"左营区","code":"710602","parentId":"3347"},{"id":"3350","name":"鼓山区","code":"710603","parentId":"3347"},{"id":"3351","name":"三民区","code":"710604","parentId":"3347"},{"id":"3352","name":"盐埕区","code":"710605","parentId":"3347"},{"id":"3353","name":"前金区","code":"710606","parentId":"3347"},{"id":"3354","name":"新兴区","code":"710607","parentId":"3347"},{"id":"3355","name":"苓雅区","code":"710608","parentId":"3347"},{"id":"3356","name":"前镇区","code":"710609","parentId":"3347"},{"id":"3357","name":"旗津区","code":"710610","parentId":"3347"},{"id":"3358","name":"小港区","code":"710611","parentId":"3347"},{"id":"3359","name":"凤山区","code":"710612","parentId":"3347"},{"id":"3360","name":"大寮区","code":"710613","parentId":"3347"},{"id":"3361","name":"鸟松区","code":"710614","parentId":"3347"},{"id":"3362","name":"林园区","code":"710615","parentId":"3347"},{"id":"3363","name":"仁武区","code":"710616","parentId":"3347"},{"id":"3364","name":"大树区","code":"710617","parentId":"3347"},{"id":"3365","name":"大社区","code":"710618","parentId":"3347"},{"id":"3366","name":"冈山区","code":"710619","parentId":"3347"},{"id":"3367","name":"路竹区","code":"710620","parentId":"3347"},{"id":"3368","name":"桥头区","code":"710621","parentId":"3347"},{"id":"3369","name":"梓官区","code":"710622","parentId":"3347"},{"id":"3370","name":"弥陀区","code":"710623","parentId":"3347"},{"id":"3371","name":"永安区","code":"710624","parentId":"3347"},{"id":"3372","name":"燕巢区","code":"710625","parentId":"3347"},{"id":"3373","name":"阿莲区","code":"710626","parentId":"3347"},{"id":"3374","name":"茄萣区","code":"710627","parentId":"3347"},{"id":"3375","name":"湖内区","code":"710628","parentId":"3347"},{"id":"3376","name":"旗山区","code":"710629","parentId":"3347"},{"id":"3377","name":"美浓区","code":"710630","parentId":"3347"},{"id":"3378","name":"内门区","code":"710631","parentId":"3347"},{"id":"3379","name":"杉林区","code":"710632","parentId":"3347"},{"id":"3380","name":"甲仙区","code":"710633","parentId":"3347"},{"id":"3381","name":"六龟区","code":"710634","parentId":"3347"},{"id":"3382","name":"茂林区","code":"710635","parentId":"3347"},{"id":"3383","name":"桃源区","code":"710636","parentId":"3347"},{"id":"3384","name":"那玛夏区","code":"710637","parentId":"3347"}]},{"id":"3385","name":"基隆市","code":"710700","parentId":"3221","children":[{"id":"3386","name":"中正区","code":"710701","parentId":"3385"},{"id":"3387","name":"七堵区","code":"710702","parentId":"3385"},{"id":"3388","name":"暖暖区","code":"710703","parentId":"3385"},{"id":"3389","name":"仁爱区","code":"710704","parentId":"3385"},{"id":"3390","name":"中山区","code":"710705","parentId":"3385"},{"id":"3391","name":"安乐区","code":"710706","parentId":"3385"},{"id":"3392","name":"信义区","code":"710707","parentId":"3385"}]},{"id":"3393","name":"新竹市","code":"710800","parentId":"3221","children":[{"id":"3394","name":"东区","code":"710801","parentId":"3393"},{"id":"3395","name":"北区","code":"710802","parentId":"3393"},{"id":"3396","name":"香山区","code":"710803","parentId":"3393"}]},{"id":"3397","name":"嘉义市","code":"710900","parentId":"3221","children":[{"id":"3398","name":"东区","code":"710901","parentId":"3397"},{"id":"3399","name":"西区","code":"710902","parentId":"3397"}]},{"id":"3400","name":"宜兰县","code":"719001","parentId":"3221","children":[]},{"id":"3401","name":"新竹县","code":"719002","parentId":"3221","children":[]},{"id":"3402","name":"苗栗县","code":"719003","parentId":"3221","children":[]},{"id":"3403","name":"彰化县","code":"719004","parentId":"3221","children":[]},{"id":"3404","name":"南投县","code":"719005","parentId":"3221","children":[]},{"id":"3405","name":"嘉义县","code":"719006","parentId":"3221","children":[]},{"id":"3406","name":"云林县","code":"719007","parentId":"3221","children":[]},{"id":"3407","name":"屏东县","code":"719008","parentId":"3221","children":[]},{"id":"3408","name":"台东县","code":"719009","parentId":"3221","children":[]},{"id":"3409","name":"花莲县","code":"719010","parentId":"3221","children":[]},{"id":"3410","name":"澎湖县","code":"719011","parentId":"3221","children":[]},{"id":"3411","name":"金门县","code":"719012","parentId":"3221","children":[]},{"id":"3412","name":"连江县","code":"719013","parentId":"3221","children":[]}]},{"id":"3432","name":"中国澳门","code":"820000","parentId":"0","children":[{"id":"3446","name":"澳门半岛","code":"8201","parentId":"3432","children":[{"id":"3433","name":"花地玛堂区","code":"820101","parentId":"3446"},{"id":"3434","name":"圣安多尼堂区","code":"820102","parentId":"3446"},{"id":"3435","name":"大堂区","code":"820103","parentId":"3446"},{"id":"3436","name":"望德堂区","code":"820104","parentId":"3446"},{"id":"3437","name":"风顺堂区","code":"820105","parentId":"3446"},{"id":"3441","name":"澳门新城","code":"820109","parentId":"3446"}]},{"id":"3447","name":"离岛","code":"8202","parentId":"3432","children":[{"id":"3438","name":"嘉模堂区","code":"820106","parentId":"3447"},{"id":"3439","name":"圣方济各堂区","code":"820107","parentId":"3447"},{"id":"3440","name":"路氹城","code":"820108","parentId":"3447"}]}]},{"id":"3442","name":"北京","code":"100","parentId":"0","children":[{"id":"1","name":"北京市","code":"110000","parentId":"3442","children":[{"id":"2","name":"东城区","code":"110101","parentId":"1"},{"id":"3","name":"西城区","code":"110102","parentId":"1"},{"id":"4","name":"朝阳区","code":"110105","parentId":"1"},{"id":"5","name":"丰台区","code":"110106","parentId":"1"},{"id":"6","name":"石景山区","code":"110107","parentId":"1"},{"id":"7","name":"海淀区","code":"110108","parentId":"1"},{"id":"8","name":"门头沟区","code":"110109","parentId":"1"},{"id":"9","name":"房山区","code":"110111","parentId":"1"},{"id":"10","name":"通州区","code":"110112","parentId":"1"},{"id":"11","name":"顺义区","code":"110113","parentId":"1"},{"id":"12","name":"昌平区","code":"110114","parentId":"1"},{"id":"13","name":"大兴区","code":"110115","parentId":"1"},{"id":"14","name":"怀柔区","code":"110116","parentId":"1"},{"id":"15","name":"平谷区","code":"110117","parentId":"1"},{"id":"16","name":"密云区","code":"110118","parentId":"1"},{"id":"17","name":"延庆区","code":"110119","parentId":"1"}]}]},{"id":"3443","name":"天津","code":"120","parentId":"0","children":[{"id":"18","name":"天津市","code":"120000","parentId":"3443","children":[{"id":"19","name":"和平区","code":"120101","parentId":"18"},{"id":"20","name":"河东区","code":"120102","parentId":"18"},{"id":"21","name":"河西区","code":"120103","parentId":"18"},{"id":"22","name":"南开区","code":"120104","parentId":"18"},{"id":"23","name":"河北区","code":"120105","parentId":"18"},{"id":"24","name":"红桥区","code":"120106","parentId":"18"},{"id":"25","name":"东丽区","code":"120110","parentId":"18"},{"id":"26","name":"西青区","code":"120111","parentId":"18"},{"id":"27","name":"津南区","code":"120112","parentId":"18"},{"id":"28","name":"北辰区","code":"120113","parentId":"18"},{"id":"29","name":"武清区","code":"120114","parentId":"18"},{"id":"30","name":"宝坻区","code":"120115","parentId":"18"},{"id":"31","name":"滨海新区","code":"120116","parentId":"18"},{"id":"32","name":"宁河区","code":"120117","parentId":"18"},{"id":"33","name":"静海区","code":"120118","parentId":"18"},{"id":"34","name":"蓟州区","code":"120119","parentId":"18"}]}]},{"id":"3444","name":"重庆","code":"500","parentId":"0","children":[{"id":"2232","name":"重庆市","code":"500000","parentId":"3444","children":[{"id":"2233","name":"万州区","code":"500101","parentId":"2232"},{"id":"2234","name":"涪陵区","code":"500102","parentId":"2232"},{"id":"2235","name":"渝中区","code":"500103","parentId":"2232"},{"id":"2236","name":"大渡口区","code":"500104","parentId":"2232"},{"id":"2237","name":"江北区","code":"500105","parentId":"2232"},{"id":"2238","name":"沙坪坝区","code":"500106","parentId":"2232"},{"id":"2239","name":"九龙坡区","code":"500107","parentId":"2232"},{"id":"2240","name":"南岸区","code":"500108","parentId":"2232"},{"id":"2241","name":"北碚区","code":"500109","parentId":"2232"},{"id":"2242","name":"綦江区","code":"500110","parentId":"2232"},{"id":"2243","name":"大足区","code":"500111","parentId":"2232"},{"id":"2244","name":"渝北区","code":"500112","parentId":"2232"},{"id":"2245","name":"巴南区","code":"500113","parentId":"2232"},{"id":"2246","name":"黔江区","code":"500114","parentId":"2232"},{"id":"2247","name":"长寿区","code":"500115","parentId":"2232"},{"id":"2248","name":"江津区","code":"500116","parentId":"2232"},{"id":"2249","name":"合川区","code":"500117","parentId":"2232"},{"id":"2250","name":"永川区","code":"500118","parentId":"2232"},{"id":"2251","name":"南川区","code":"500119","parentId":"2232"},{"id":"2252","name":"璧山区","code":"500120","parentId":"2232"},{"id":"2253","name":"铜梁区","code":"500151","parentId":"2232"},{"id":"2254","name":"潼南区","code":"500152","parentId":"2232"},{"id":"2255","name":"荣昌区","code":"500153","parentId":"2232"},{"id":"2256","name":"开州区","code":"500154","parentId":"2232"},{"id":"2257","name":"梁平区","code":"500155","parentId":"2232"},{"id":"2258","name":"武隆区","code":"500156","parentId":"2232"},{"id":"2259","name":"城口县","code":"500229","parentId":"2232"},{"id":"2260","name":"丰都县","code":"500230","parentId":"2232"},{"id":"2261","name":"垫江县","code":"500231","parentId":"2232"},{"id":"2262","name":"忠县","code":"500233","parentId":"2232"},{"id":"2263","name":"云阳县","code":"500235","parentId":"2232"},{"id":"2264","name":"奉节县","code":"500236","parentId":"2232"},{"id":"2265","name":"巫山县","code":"500237","parentId":"2232"},{"id":"2266","name":"巫溪县","code":"500238","parentId":"2232"},{"id":"2267","name":"石柱土家族自治县","code":"500240","parentId":"2232"},{"id":"2268","name":"秀山土家族苗族自治县","code":"500241","parentId":"2232"},{"id":"2269","name":"酉阳土家族苗族自治县","code":"500242","parentId":"2232"},{"id":"2270","name":"彭水苗族土家族自治县","code":"500243","parentId":"2232"}]}]},{"id":"3445","name":"上海","code":"140","parentId":"0","children":[{"id":"789","name":"上海市","code":"310000","parentId":"3445","children":[{"id":"790","name":"黄浦区","code":"310101","parentId":"789"},{"id":"791","name":"徐汇区","code":"310104","parentId":"789"},{"id":"792","name":"长宁区","code":"310105","parentId":"789"},{"id":"793","name":"静安区","code":"310106","parentId":"789"},{"id":"794","name":"普陀区","code":"310107","parentId":"789"},{"id":"795","name":"虹口区","code":"310109","parentId":"789"},{"id":"796","name":"杨浦区","code":"310110","parentId":"789"},{"id":"797","name":"闵行区","code":"310112","parentId":"789"},{"id":"798","name":"宝山区","code":"310113","parentId":"789"},{"id":"799","name":"嘉定区","code":"310114","parentId":"789"},{"id":"800","name":"浦东新区","code":"310115","parentId":"789"},{"id":"801","name":"金山区","code":"310116","parentId":"789"},{"id":"802","name":"松江区","code":"310117","parentId":"789"},{"id":"803","name":"青浦区","code":"310118","parentId":"789"},{"id":"804","name":"奉贤区","code":"310120","parentId":"789"},{"id":"805","name":"崇明区","code":"310151","parentId":"789"}]}]},{"id":"3448","name":"中国香港","code":"810","parentId":"0","children":[{"id":"3413","name":"香港特别行政区","code":"810000","parentId":"3448","children":[{"id":"3414","name":"中西区","code":"810101","parentId":"3413"},{"id":"3415","name":"湾仔区","code":"810102","parentId":"3413"},{"id":"3416","name":"东区","code":"810103","parentId":"3413"},{"id":"3417","name":"南区","code":"810104","parentId":"3413"},{"id":"3418","name":"油尖旺区","code":"810105","parentId":"3413"},{"id":"3419","name":"深水埗区","code":"810106","parentId":"3413"},{"id":"3420","name":"九龙城区","code":"810107","parentId":"3413"},{"id":"3421","name":"黄大仙区","code":"810108","parentId":"3413"},{"id":"3422","name":"观塘区","code":"810109","parentId":"3413"},{"id":"3423","name":"北区","code":"810110","parentId":"3413"},{"id":"3424","name":"大埔区","code":"810111","parentId":"3413"},{"id":"3425","name":"沙田区","code":"810112","parentId":"3413"},{"id":"3426","name":"西贡区","code":"810113","parentId":"3413"},{"id":"3427","name":"荃湾区","code":"810114","parentId":"3413"},{"id":"3428","name":"屯门区","code":"810115","parentId":"3413"},{"id":"3429","name":"元朗区","code":"810116","parentId":"3413"},{"id":"3430","name":"葵青区","code":"810117","parentId":"3413"},{"id":"3431","name":"离岛区","code":"810118","parentId":"3413"}]}]}]Qxs 		"4	Q7DZ51tA.PIg440000 pagesA ; LCQydP=6z$)F; #̿(Y3^x' A3A16C1CH+	2c04ebae2099b3d	};x; 4LCQnO:a؛ct40000 order \}@E:m[<x$ 100644 mine.vue :ɉZ|kQWx ;40000 edit-profile BFz,u33hz40000 generate-record 
l}Iv40000 order-detail :?e̈́z$UJDq40000 recharge Qf$7A40000 user-agreement 0bA~kkQx, 100644 edit-profile.vue E å^Hn~WGsx) cc)R`c)	`9-fԬx, 100644 order-detail.vue U{-O%dR`Xx) 55q:src="orderDetail.userAvatar@Myx }100644 404.png 0)~%\40000 imgs )tYV,kF40000 json y.)E:ƾy"X-40000 tabbar )$7ume/yxn1i6x8q, $bx; 		6Vu&2q]nq$O\'=l%NG?ldAI,x?<script setup>
import {
  onLaunch,
  onShow,
  onHide,
  onError,
  onPageNotFound,
} from "@dcloudio/uni-app";
import { checkForUpdate } from "@/utils";

onLaunch(() => {
  console.log("App Launch");
  // #ifdef MP-WEIXIN
  checkForUpdate();
  // #endif
});

onShow(() => {
  console.log("App Show");
});

onHide(() => {
  console.log("App Hide");
});

onError((error) => {
  console.error("App Error", error);
});

onPageNotFound((res) => {
  console.error("PageNotFound", res);
  uni.redirectTo({
    url: "/pages/404/404",
  });
});
</script>

<style lang="scss">
/* 每个页面公共css */
page {
  height: 100%;
}

/* uv-ui基础样式 */
@import "@/uni_modules/uv-ui-tools/index.scss";
</style>
"epx =HK;Fİ lp1Qsix/ 100644 generate-record.vue {tTzT,?b] }	vnxUkUlhk&nڙiwgvfHkj1b!D)fٙunc\D)EU*`H}E|Vi@⃯;3_;w|9A..WM_Zrq;n^G:L~]ΜI:%HHE|ѮTK5:QLkDM럐<;=vgؽ?`<?ꍙR<dN	Z갌9seg135:,ڳpWNrLru5yJ1q/oͱ=pDiJ*h!=ȖS9 L,~?˞=ǆ`9X8.Y03K4ͩ4`~c˱X6etjb#Ts-q%X͢s0E	`LiSei*狹B5Ǔq5啱]*cS,YNMXAS!ټS9E/di9MG8Sp )
rU7пW4y*G
E@`Q!ZC^ϑT\=\nlyjA'<`" ػ.l߾RXzLl"7aЗڬ溹n!'W0-6}}VhÍl&ENK_b`}ˑL['orsتـiyd|ذ/iK@b5x*#Njj	(dbe/F}DvG;߽om}əu!Mfg\5*@/<L=hWz-2ije$u\OC&Fc$ #m\{x.s-ԪmsQ!YCB寰I7ML->
{Hx"hOVc{zA.4>"Gy@kM $$E#BPh?<tZO_|tQ!@`ZjZC :wf	O::]$J%{&1e&RIX
A$(Wpxs<>vh ta??W.:zk%j3b() c:`x[ 		/5ldX:?_?t40000 pagesA eڡv?³drvZvֺl5jOkyݓ{*P)px <40000 404 WȽ߯ DYQ{A40000 consumption O_K({40000 index Y tɞHS7qDA40000 login QNK_p_2n
40000 mine ?!<- ?*3JGx40000 order \}@E:m[pMxK 100644 index.vue N%ӑNw8rbsjWN100644 index1.vue U$YVxIhC'x` MJ|currentTemplate.params"xres.rows || []res.rows res.rows
# @%]x$ 100644 mine.vue c./BUL%d*l1lZ	x#Jܵ<template>
  <view class="container">
    <!-- 顶部标题 -->
    <view class="header">
      <view class="header-title">管理您的账户信息和服务</view>
    </view>

    <!-- 用户信息卡片 -->
    <view class="user-card">
      <view class="user-info">
        <div class="avatar"></div>
        <!--        <image
          class="avatar"
          src="/static/imgs/avatar.png"
          mode="aspectFill"
        ></image> -->
        <view class="user-details">
          <view class="username">
            {{userStore.userInfo.username}}
            <u-icon
              name="checkmark-circle-fill"
              color="#ffa500"
              size="16"
            ></u-icon>
          </view>
          <view class="user-id">用户ID: {{userStore.userInfo.id}}</view>
          <view class="membership">
            会员等级: 年会员 (有效期至: 2026-05-15)
          </view>
        </view>
      </view>
      <view class="edit-btn" @click="editProfile">
        <text>点击编辑资料</text>
      </view>
    </view>

    <!-- 账户余额 -->
    <view class="balance-card">
      <div>
        <view class="balance-header">
          <view class="balance-label">账户余额</view>
        </view>
        <view class="balance-amount">¥50.00</view>
      </div>
      <uv-button
        type="primary"
        color="#fff"
        customStyle="color:#000;width:90px"
        shape="circle"
        @click="recharge"
      >
        充值
      </uv-button>
    </view>

    <!-- 会员套餐 -->
    <view class="membership-section">
      <view class="membership-grid">
        <view
          class="membership-item"
          :class="{ active: selectedPlan === 'monthly' }"
          @click="selectPlan('monthly')"
        >
          <view class="tag">新人特惠</view>
          <view class="plan-name">包月会员</view>
          <view class="plan-price">¥120</view>
        </view>
        <view
          class="membership-item"
          :class="{ active: selectedPlan === 'season' }"
          @click="selectPlan('season')"
        >
          <view class="tag">最受欢迎</view>
          <view class="plan-name">包季会员</view>
          <view class="plan-price">¥300</view>
          <view class="plan-discount">立减¥60</view>
        </view>
        <view
          class="membership-item"
          :class="{ active: selectedPlan === 'yearly' }"
          @click="selectPlan('yearly')"
        >
          <view class="tag">年度首享</view>
          <view class="plan-name">包年会员</view>
          <view class="plan-price">¥1000</view>
          <view class="plan-discount">立减¥440</view>
        </view>
      </view>
    </view>

    <!-- 支付方式 -->
    <view class="payment-section">
      <!-- 微信支付 -->
      <view
        class="payment-item"
        :class="{ active: selectedPayment === 'wechat' }"
        @click="selectPayment('wechat')"
      >
        <view class="payment-info">
          <uv-icon name="weixin-fill" color="#07c160" size="24"></uv-icon>
          <text class="payment-name">微信支付</text>
        </view>
        <uv-icon
          name="checkmark-circle-fill"
          :color="selectedPayment === 'wechat' ? '#ff3333' : '#ccc'"
          size="20"
        ></uv-icon>
      </view>

      <!-- 支付宝支付 - 仅在H5环境显示 -->
      <view
        v-if="showAlipay"
        class="payment-item"
        :class="{ active: selectedPayment === 'alipay' }"
        @click="selectPayment('alipay')"
      >
        <view class="payment-info">
          <uv-icon
            name="/static/imgs/alipay.png"
            color="#1677ff"
            size="24"
          ></uv-icon>
          <text class="payment-name">支付宝</text>
        </view>
        <uv-icon
          name="checkmark-circle-fill"
          :color="selectedPayment === 'alipay' ? '#ff3333' : '#ccc'"
          size="20"
        ></uv-icon>
      </view>
    </view>

    <!-- 底部按钮 -->
    <view class="bottom-section">
      <uv-button
        type="primary"
        size="large"
        @click="confirmPayment"
        :loading="paying"
      >
        确认支付
      </uv-button>
      <view class="agreement">
        购买前请仔细阅读
        <text class="link" @click="showAgreement">《会员服务协议》</text>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted } from "vue";
import { onShow } from "@dcloudio/uni-app";
import HeaderCustom from "/components/HeaderCustom/HeaderCustom.vue";
import { useAuthStore, useUserStore } from "@/store";
import RPC from "@/utils/request";

const modal = ref(null);
const authStore = useAuthStore();
const userStore = useUserStore();

// 响应式数据
const selectedPlan = ref("season"); // 默认选中包季会员
const selectedPayment = ref("wechat"); // 默认选中微信支付
const paying = ref(false);
const showAlipay = ref(true); // 控制是否显示支付宝选项

// 选择会员套餐
const selectPlan = (plan) => {
  selectedPlan.value = plan;
};

// 选择支付方式
const selectPayment = (payment) => {
  selectedPayment.value = payment;
};

// 编辑资料
const editProfile = () => {
  uni.navigateTo({
    url: "/pagesA/edit-profile/edit-profile",
  });
};

// 充值
const recharge = () => {
  uni.navigateTo({
    url: "/pagesA/recharge/recharge",
  });
};

// 获取套餐价格
const getPlanPrice = (plan) => {
  const prices = {
    monthly: 120,
    season: 300,
    yearly: 1000,
  };
  return prices[plan] || 0;
};

// 获取套餐名称
const getPlanName = (plan) => {
  const names = {
    monthly: "包月会员",
    season: "包季会员",
    yearly: "包年会员",
  };
  return names[plan] || "";
};

// 创建订单
const createOrder = async (params) => {
  try {
    // 调用后端创建订单API
    const result = await RPC.post("/api/order/create", params);
    return result.data;
  } catch (error) {
    console.error("创建订单失败:", error);
    throw error;
  }
};

// 微信支付
const wechatPay = async (orderInfo) => {
  // #ifdef MP-WEIXIN
  // 微信小程序支付
  try {
    const paymentResult = await uni.requestPayment({
      provider: "wxpay",
      timeStamp: orderInfo.timeStamp,
      nonceStr: orderInfo.nonceStr,
      package: orderInfo.package,
      signType: orderInfo.signType,
      paySign: orderInfo.paySign,
    });

    console.log("微信支付成功:", paymentResult);
    return { success: true, data: paymentResult };
  } catch (error) {
    console.error("微信支付失败:", error);
    if (error.errMsg === "requestPayment:fail cancel") {
      throw new Error("用户取消支付");
    }
    throw new Error("微信支付失败");
  }
  // #endif

  // #ifdef H5
  // H5微信支付
  if (typeof WeixinJSBridge !== "undefined") {
    return new Promise((resolve, reject) => {
      WeixinJSBridge.invoke(
        "getBrandWCPayRequest",
        {
          appId: orderInfo.appId,
          timeStamp: orderInfo.timeStamp,
          nonceStr: orderInfo.nonceStr,
          package: orderInfo.package,
          signType: orderInfo.signType,
          paySign: orderInfo.paySign,
        },
        (res) => {
          if (res.err_msg === "get_brand_wcpay_request:ok") {
            resolve({ success: true, data: res });
          } else if (res.err_msg === "get_brand_wcpay_request:cancel") {
            reject(new Error("用户取消支付"));
          } else {
            reject(new Error("微信支付失败"));
          }
        }
      );
    });
  } else {
    // 不在微信环境，跳转到支付页面
    const payUrl = orderInfo.mwebUrl; // 后端返回的H5支付链接
    window.location.href = payUrl;
    return { success: true, redirect: true };
  }
  // #endif
};

// 支付宝支付（仅H5环境）
const alipayPay = async (orderInfo) => {
  // #ifdef H5
  // H5支付宝支付
  const payUrl = orderInfo.payUrl; // 后端返回的支付宝H5支付链接
  window.location.href = payUrl;
  return { success: true, redirect: true };
  // #endif
};

// 确认支付
const confirmPayment = async () => {
  if (!selectedPlan.value) {
    uni.showToast({
      title: "请选择会员套餐",
      icon: "none",
    });
    return;
  }

  if (!selectedPayment.value) {
    uni.showToast({
      title: "请选择支付方式",
      icon: "none",
    });
    return;
  }

  paying.value = true;

  try {
    // 1. 创建订单参数
    const orderParams = {
      plan: selectedPlan.value,
      planName: getPlanName(selectedPlan.value),
      amount: getPlanPrice(selectedPlan.value),
      paymentMethod: selectedPayment.value,
      userId: userStore.userInfo?.id || "mock_user_id",
      // #ifdef MP-WEIXIN
      platform: "mp-weixin",
      // #endif
      // #ifdef H5
      platform: "h5",
      // #endif
    };

    uni.showLoading({
      title: "正在创建订单...",
    });

    // 2. 创建订单
    // const orderResult = await createOrder(orderParams);

    // 模拟创建订单返回的数据
    const orderResult = {
      orderId: "ORDER_" + Date.now(),
      amount: orderParams.amount,
      // 微信支付参数（实际应该由后端返回）
      wechatPayInfo: {
        appId: "wx1234567890",
        timeStamp: String(Date.now()),
        nonceStr: "random_string_" + Date.now(),
        package: "prepay_id=wx_prepay_id_123456",
        signType: "RSA",
        paySign: "mock_pay_sign_123456",
        // H5支付链接
        mwebUrl:
          "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx_prepay_id_123456",
      },
      // 支付宝支付参数（实际应该由后端返回）
      alipayInfo: {
        orderString: "mock_alipay_order_string_123456",
        payUrl: "https://openapi.alipay.com/gateway.do?mock_pay_url",
      },
    };

    uni.hideLoading();

    // 3. 根据支付方式调用对应的支付方法
    let paymentResult;

    if (selectedPayment.value === "wechat") {
      uni.showLoading({
        title: "正在跳转微信支付...",
      });
      paymentResult = await wechatPay(orderResult.wechatPayInfo);
    } else if (selectedPayment.value === "alipay") {
      uni.showLoading({
        title: "正在跳转支付宝...",
      });
      paymentResult = await alipayPay(orderResult.alipayInfo);
    }

    uni.hideLoading();

    // 4. 处理支付结果
    if (paymentResult.success) {
      if (paymentResult.redirect) {
        // H5跳转支付，不需要额外处理
        uni.showToast({
          title: "正在跳转支付页面...",
          icon: "loading",
          duration: 2000,
        });
      } else {
        // 支付成功
        uni.showToast({
          title: "支付成功",
          icon: "success",
        });

        // 延迟跳转到订单页面或刷新用户信息
        setTimeout(() => {
          // 可以跳转到订单详情页面
          uni.navigateTo({
            url: `/pages/order-detail/order-detail?orderId=${orderResult.orderId}`,
          });

          // 或者刷新当前页面的用户信息
          // loadUserInfo();
        }, 1500);
      }
    }
  } catch (error) {
    uni.hideLoading();
    console.error("支付失败:", error);

    let errorMessage = "支付失败，请重试";
    if (error.message === "用户取消支付") {
      errorMessage = "支付已取消";
    } else if (error.message) {
      errorMessage = error.message;
    }

    uni.showToast({
      title: errorMessage,
      icon: "none",
    });
  } finally {
    paying.value = false;
  }
};

// 显示协议
const showAgreement = () => {
  uni.navigateTo({
    url: "/pagesA/user-agreement/user-agreement",
  });
};

// 检查支付结果（用于H5支付回调）
const checkPaymentResult = async (orderId) => {
  try {
    // 调用后端接口检查支付结果
    // const result = await RPC.get(`/api/order/check-payment/${orderId}`);

    // 模拟检查结果
    const result = {
      success: true,
      status: "paid", // paid, pending, failed
    };

    if (result.status === "paid") {
      uni.showToast({
        title: "支付成功",
        icon: "success",
      });

      // 更新用户信息或跳转到成功页面
      setTimeout(() => {
        uni.navigateTo({
          url: `/pages/order-detail/order-detail?orderId=${orderId}`,
        });
      }, 1500);
    } else if (result.status === "failed") {
      uni.showToast({
        title: "支付失败",
        icon: "none",
      });
    } else {
      uni.showToast({
        title: "支付处理中，请稍后查看订单状态",
        icon: "none",
      });
    }
  } catch (error) {
    console.error("检查支付结果失败:", error);
  }
};

// 页面显示时检查是否有支付回调参数
const handlePaymentCallback = () => {
  // #ifdef H5
  const urlParams = new URLSearchParams(window.location.search);
  const orderId = urlParams.get("orderId");
  const payResult = urlParams.get("payResult");

  if (orderId && payResult) {
    // 清理URL参数
    const url = new URL(window.location);
    url.searchParams.delete("orderId");
    url.searchParams.delete("payResult");
    window.history.replaceState({}, document.title, url.pathname + url.search);

    // 检查支付结果
    if (payResult === "success") {
      checkPaymentResult(orderId);
    } else {
      uni.showToast({
        title: "支付失败或取消",
        icon: "none",
      });
    }
  }
  // #endif
};

// 检查当前环境并设置支付选项
const checkEnvironment = () => {
  // #ifdef MP-WEIXIN
  // 微信小程序环境，隐藏支付宝选项，默认选择微信支付
  showAlipay.value = false;
  selectedPayment.value = "wechat";
  // #endif

  // #ifdef H5
  // H5环境，显示所有支付选项
  showAlipay.value = true;
  // 如果在微信浏览器内，默认选择微信支付
  const ua = navigator.userAgent.toLowerCase();
  const isWechat = ua.indexOf("micromessenger") !== -1;
  selectedPayment.value = isWechat ? "wechat" : "alipay";
  // #endif
};

// 页面挂载时处理支付回调和环境检查
onMounted(() => {
  checkEnvironment();
  handlePaymentCallback();
});

// 页面显示时也检查支付回调（从其他页面返回时）
onShow(() => {
  handlePaymentCallback();
});
</script>

<style lang="scss" scoped>
.container {
  font-size: 14px;
  background: linear-gradient(180deg, #7b9cdb 0%, #f8f8f8 40%);
  padding-bottom: 120px;

  /* #ifdef H5 */
  padding-bottom: 170px; /* H5环境下需要更多空间 (底部按钮高度 + tabBar高度 + 间距) */
  /* #endif */
}

.header {
  padding: 20px 16px 16px;

  .header-title {
    color: white;
    font-size: 18px;
    font-weight: 500;
  }
}

.user-card {
  margin: 0 16px 16px;
  background: white;
  border-radius: 12px;
  padding: 16px;
  position: relative;

  .user-info {
    display: flex;
    align-items: center;
    // margin-bottom: 12px;

    .avatar {
      width: 60px;
      height: 60px;
      border-radius: 50%;
      margin-right: 12px;
      background-color: skyblue;
      overflow: hidden;

      .img {
        width: 100%;
        height: 100%;
      }
    }

    .user-details {
      flex: 1;

      .username {
        display: flex;
        align-items: center;
        gap: 4px;
        font-size: 18px;
        font-weight: bold;
        color: #333;
        margin-bottom: 4px;
      }

      .user-id {
        font-size: 12px;
        color: #999;
        margin-bottom: 2px;
      }

      .membership {
        font-size: 12px;
        color: #999;
      }
    }
  }

  .edit-btn {
    text-align: right;
    color: #4285f4;
    font-size: 14px;
    position: absolute;
    top: 10px;
    right: 20px;
  }
}

.balance-card {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 16px 16px;
  background: linear-gradient(135deg, #4285f4 0%, #6fa8f5 100%);
  border-radius: 12px;
  padding: 16px;
  color: white;

  .balance-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;

    .balance-label {
      font-size: 14px;
      opacity: 0.9;
    }
  }

  .balance-amount {
    font-size: 28px;
    font-weight: bold;
  }
}

.membership-section {
  margin: 0 16px 16px;

  .membership-grid {
    display: flex;
    gap: 8px;

    .membership-item {
      flex: 1;
      background: white;
      border-radius: 12px;
      padding: 16px 12px;
      text-align: center;
      position: relative;
      border: 2px solid transparent;
      transition: all 0.3s;
      overflow: hidden;

      &.active {
        border-color: #4285f4;
        background-color: #f0f7ff;
      }

      .tag {
        position: absolute;
        top: 0px;
        left: 0;
        padding: 2px 8px;
        border-radius: 0 0 10px 0;
        font-size: 10px;
        color: white;
        background: #ff3333;
      }

      .plan-name {
        font-size: 14px;
        color: #333;
        margin: 12px 0 8px;
      }

      .plan-price {
        font-size: 20px;
        font-weight: bold;
        color: #ff3333;
        margin-bottom: 4px;
      }

      .plan-discount {
        font-size: 12px;
        color: #999;
      }
    }
  }
}

.payment-section {
  margin: 0 16px 24px;

  .payment-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: white;
    border-radius: 12px;
    padding: 16px;
    margin-bottom: 8px;
    border: 1px solid #e5e5e5;
    transition: all 0.3s;

    &.active {
      border-color: #4285f4;
      background-color: #f0f7ff;
    }

    &:last-child {
      margin-bottom: 0;
    }

    .payment-info {
      display: flex;
      align-items: center;
      gap: 12px;

      .payment-name {
        font-size: 14px;
        color: #333;
      }
    }
  }
}

.bottom-section {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: white;
  padding: 16px;
  border-top: 1px solid #e5e5e5;

  /* #ifdef H5 */
  bottom: 50px; /* H5环境下给tabBar留出空间 */
  /* #endif */

  .agreement {
    text-align: center;
    font-size: 12px;
    color: #999;
    margin-top: 12px;

    .link {
      color: #4285f4;
    }
  }
}
</style>PVhBXx =
pH]<"G'AzQs;Mx/ 100644 generate-record.vue FO}(`ޫvQlf4x-ix 21	1
[
; x˛%?襟?h}5F Bx BAuk9<Px F		U:i$xU
96vɼp40000 pages 푢oc%xПc40000 pagesA w	C[?M&ddPUΈj7{.>d_:ͺ9xJ100644 vite.config.js o|D`_aY=3RIxh I49首页
_appointment2appointment
qappointment2appointmentR/*x <40000 404 WȽ߯ DYQ{A40000 consumption O_K({40000 index %<0-CFGiϜ40000 login ˘p.贀1|40000 mine NG捠n9;k"W+40000 order \}@E:m[9+UtxK 100644 index.vue PF7ouAr+100644 index1.vue U$YVxIhCX?xZ[s~Cl
$.'EUq2Lnٙ\$dJ)!Kp¥!W~L4{y"?!gzvW >}|}Nwώ昚wBc#<k®=UEGo_?iLgצ7. U2*}b[BV	uN%\<_##~Zd"	ls`=4]941vMm"O|+6NyK~h/(E
9S37<|Z|\]4>{<>Ӟ'\{tv%>mpL.M!?dsD;=z6Z;]0u I
!Ac<lmAb; 
vdJGI!:LH$TGAVb-iEe#ay< )Pʮ/7_üix4^Z[kppXԛߟqO^ORv1TFEo0&p|z X+clX?Kԑ25௮` 3T:$pnB)J}7h@@WOØXF5zHxl&*_1,!3a"(Qd}+|eۭ]06S+asI*VQ1qW:G
;\%[`HF_u`4Gk;⫶b6N潕oM,'gNA|>W]؅MU}d
֭[m޹iXQi--&,VN@sj{'T=y%4o@gհZNB.B|B S|xH΅)Bx[;Q55ͭK-پo
h9熛Ӎ[KN@GT||\
/ncpGo7fgrTmn=i
p(*laWIfNNOKBzŏR`={Wz=,9c4QpuAG.8I]pLZHͱ]Ad[ف74ʮ]CXUm[ k@oPBw;g
[6%>ǚ^	ZTisETqQ݁_xA[gxm(Gђ|/'sbF<"i/}ΐ4a*"Alc1e2B	@
)kD.³'<'Ũs6~JAMgMPqt1	&%G:̰L`3L˴3P)
#H=Qd2Q?_@ƕnyFk!k/6ffr,廤Kf~D&#Ck-n^;RGx`ɦAW6iy2I,Ie.,K{y~Mr Ntߏ?fXƵ$O	VvLw'I?Gs!N7P^lOϵewg	,KٽX,ӧЌkec9!9jp!
|1f^u|f
Mnڷv52fJt,Ms)ϱ/&Ŷz{8=C2V$09H|2umw@m,kͤ
hx^2?>{<G:}1z>ףIh8XOeX,AZdDjڕzcicowsowBIo:̅ؼ9T*ʙZo_4]ɡ1a|I&qH^+F1~8W@h~5#wvʩ	/=GyV 98A=ʬ9r!Vٰ>t>f噂>1'miDKme2 5=,h^\MD+?h8imڣT,8֓Ӑ)gK)g/De=R~cKgXօ31`$oa >hm}.=5	=RtfQ	
hU58jUK:hǪ*`e	rSy;0Mmd3Sƪh)>AzI8dyj)q@m_j}sw(3wFǟ#|h h:/l'n/JO  	=~נlT%ȿ?(J/o2UZ	8j]5=&Qw*%-DQƫ$ٻ-뻚kd/@
S=Q)F|+N
-mkk>!Tvq.4,;Q;-_mXߤ(x()p$eUV'$1Lx'a[oxGe˖XGVk|Vx61iA%afQ.E4'vzM*က 83n#g6$zjZNLW`LؾŋAM(,KcbJurc6G.*'LX<9;}"~'ر'WG\*$%yLb#">兲XˉGe\IZ61H楨 3?O*z S@X-ac+:R Ysd4tb_U0]`kVsb8]*:%:]-_8oK4 wx% 100644 login.vue nGɠͼ(CcpjxG<!-- #ifdef H5 -->
<!-- 可选：引入微信JS-SDK，用于更高级的微信功能 -->
<!-- <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> -->
<!-- #endif -->

<template>
  <view class="container">
    <view class="header">
      <div class="line">您好，</div>
      <div class="line">欢迎使用电梯图纸生成平台</div>
    </view>
    <div class="main">
      <view class="form">
        <uv-form
          labelAlign="right"
          labelWidth="50"
          labelPosition="top"
          :model="userInfo"
          :rules="rules"
          ref="form"
        >
          <uv-form-item prop="phone">
            <div class="formLabel">
              <img class="img" src="/static/imgs/phone.png" alt="" />
              手机号
            </div>
            <uv-input
              v-model="userInfo.phone"
              color="#000"
              border="bottom"
              :placeholderStyle="{ color: '#666778' }"
              placeholder="请输入用户名"
            ></uv-input>
          </uv-form-item>
          <uv-form-item prop="password">
            <div class="formLabel">
              <img class="img" src="/static/imgs/code.png" alt="" />
              验证码
            </div>
            <uv-input
              v-model="userInfo.password"
              color="#000"
              border="bottom"
              :placeholderStyle="{ color: '#666778' }"
              placeholder="请输入验证码"
            >
              <template v-slot:suffix>
                <uv-code
                  ref="codeRef"
                  @change="codeChange"
                  seconds="20"
                  changeText="X秒重新获取"
                ></uv-code>
                <text style="color: #4d82fd" @click="getCode">{{ tips }}</text>
              </template>
            </uv-input>
          </uv-form-item>
        </uv-form>
      </view>
      <uv-button
        @click="login"
        customStyle="margin-top:30px"
        text="登录"
        color="#3F70FF"
      ></uv-button>
      <div class="wechatBox" v-if="showWechatLogin">
        <uv-divider text="第三方登录"></uv-divider>
        <uv-icon
          name="weixin-circle-fill"
          color="#5fc157"
          size="50"
          @click="wechatLogin"
        ></uv-icon>
      </div>
    </div>

    <!-- 微信登录绑定手机号弹窗 -->
    <uv-popup
      ref="popup"
      mode="center"
      :closeOnClickOverlay="false"
      :round="10"
    >
      <view class="bind-phone-modal">
        <view class="modal-header">
          <view class="modal-title">绑定手机号</view>
          <view class="modal-subtitle">为了您的账户安全，请绑定手机号</view>
        </view>

        <view class="modal-form">
          <uv-form
            :model="bindPhoneInfo"
            :rules="bindPhoneRules"
            ref="bindPhoneForm"
          >
            <uv-form-item prop="phone">
              <uv-input
                v-model="bindPhoneInfo.phone"
                placeholder="请输入手机号"
                type="number"
                maxlength="11"
                border="surround"
              ></uv-input>
            </uv-form-item>
            <uv-form-item prop="code">
              <uv-input
                v-model="bindPhoneInfo.code"
                placeholder="请输入验证码"
                border="surround"
              >
                <template v-slot:suffix>
                  <uv-code
                    ref="bindCodeRef"
                    @change="bindCodeChange"
                    seconds="60"
                    changeText="X秒重新获取"
                  ></uv-code>
                  <text
                    style="color: #4d82fd; font-size: 12px"
                    @click="getBindCode"
                  >
                    {{ bindCodeTips }}
                  </text>
                </template>
              </uv-input>
            </uv-form-item>
          </uv-form>
        </view>

        <view class="modal-actions">
          <!-- <uv-button
            type="default"
            @click="closeBindPhoneModal"
            customStyle="margin-right: 12px;"
          >
            取消
          </uv-button> -->
          <uv-button
            type="primary"
            @click="confirmBindPhone"
            :loading="bindingPhone"
          >
            确认绑定
          </uv-button>
        </view>
      </view>
    </uv-popup>
  </view>
</template>

<script setup>
import { ref, onMounted } from "vue";
import {
  HOME_PATH,
  LOGIN_PATH,
  isTabBarPath,
  removeQueryString,
} from "@/router";
import { useAuthStore, useUserStore } from "@/store";
import { onLoad } from "@dcloudio/uni-app";

import RPC from "@/utils/request";

const authStore = useAuthStore();
const userStore = useUserStore();

// 环境判断
const showWechatLogin = ref(false);

// 微信登录绑定手机号相关
// const showBindPhoneModal = ref(false);
const popup = ref(null);
const bindingPhone = ref(false);
const bindCodeTips = ref("获取验证码");
const bindCodeRef = ref(null);
const bindPhoneForm = ref(null);
const bindPhoneInfo = ref({
  phone: "",
  code: "",
});
const bindPhoneRules = ref({
  phone: [
    {
      required: true,
      message: "请输入手机号",
      trigger: ["blur", "change"],
    },
    {
      pattern: /^1[3-9]\d{9}$/,
      message: "请输入正确的手机号",
      trigger: ["blur", "change"],
    },
  ],
  code: {
    required: true,
    message: "请输入验证码",
    trigger: ["blur", "change"],
  },
});

const tips = ref("获取验证码");
const codeChange = (text) => {
  tips.value = text;
};
const codeRef = ref(null);
const getCode = () => {
  if (!userInfo.phone) {
    uni.showToast({
      title: "请填写手机号",
      icon: "none",
    });
    return;
  }
  if (codeRef.value.canGetCode) {
    // 模拟向后端请求验证码
    uni.showLoading({
      title: "正在获取验证码",
    });
    setTimeout(() => {
      uni.hideLoading();
      // 这里此提示会被this.start()方法中的提示覆盖
      uni.showToast({
        title: "验证码已发送",
        icon: "none",
      });
      // 通知验证码组件内部开始倒计时
      codeRef.value.start();
    }, 2000);
  } else {
    uni.showToast({
      title: "倒计时结束后再发送",
      icon: "none",
    });
  }
};

const form = ref(null);
const userInfo = ref({
  phone: "",
  password: "",
});
const rules = ref({
  phone: [
    {
      required: true,
      message: "请输入手机号",
      trigger: ["blur", "change"],
    },
    {
      pattern: /^1[3-9]\d{9}$/,
      message: "请输入正确的手机号",
      trigger: ["blur", "change"],
    },
  ],
  password: {
    required: true,
    message: "请填写验证码",
    trigger: ["blur", "change"],
  },
});
let redirect = HOME_PATH;
onLoad((options) => {
  if (options.redirect && removeQueryString(options.redirect) !== LOGIN_PATH) {
    redirect = decodeURIComponent(options.redirect);
  }
});

// 检查运行环境
const checkEnvironment = () => {
  // #ifdef MP-WEIXIN
  // 微信小程序环境
  showWechatLogin.value = true;
  // #endif

  // #ifdef H5
  // H5环境，检查是否在微信内
  const ua = navigator.userAgent.toLowerCase();
  const isWechat = ua.indexOf("micromessenger") !== -1;
  showWechatLogin.value = isWechat;
  // #endif

  // #ifdef APP-PLUS
  // App环境，不显示微信登录
  showWechatLogin.value = false;
  // #endif
};

// 微信登录
const wechatLogin = () => {
  // #ifdef MP-WEIXIN
  // 微信小程序登录
  //   uni.login({
  //     provider: "weixin",
  //     success: (loginRes) => {
  //       console.log("微信登录成功:", loginRes);
  //       // 获取用户信息
  //       uni.getUserProfile({
  //         desc: "用于完善用户资料",
  //         success: (userRes) => {
  //           console.log("获取用户信息成功:", userRes);
  //           // 显示绑定手机号弹窗
  //           showBindPhoneModal.value = true;
  //         },
  //         fail: (err) => {
  //           console.error("获取用户信息失败:", err);
  //           uni.showToast({
  //             title: "获取用户信息失败",
  //             icon: "none",
  //           });
  //         },
  //       });
  //     },
  //     fail: (err) => {
  //       console.error("微信登录失败:", err);
  //       uni.showToast({
  //         title: "微信登录失败",
  //         icon: "none",
  //       });
  //     },
  //   });
  popup.value.open();
  // #endif

  // #ifdef H5
  // H5微信登录
  if (typeof WeixinJSBridge !== "undefined") {
    // 在微信内，使用微信JS-SDK进行授权登录
    wechatH5Login();
  } else {
    uni.showToast({
      title: "请在微信中打开",
      icon: "none",
    });
  }
  // #endif
};

// 获取绑定手机号验证码
const getBindCode = () => {
  if (!bindPhoneInfo.value.phone) {
    uni.showToast({
      title: "请输入手机号",
      icon: "none",
    });
    return;
  }

  if (!/^1[3-9]\d{9}$/.test(bindPhoneInfo.value.phone)) {
    uni.showToast({
      title: "请输入正确的手机号",
      icon: "none",
    });
    return;
  }

  if (bindCodeRef.value.canGetCode) {
    uni.showLoading({
      title: "正在获取验证码",
    });

    // 调用发送验证码API
    // RPC.post('/api/sms/send', {
    //   phone: bindPhoneInfo.value.phone,
    //   type: 'bind'
    // }).then(() => {
    //   uni.hideLoading()
    //   uni.showToast({
    //     title: '验证码已发送',
    //     icon: 'success'
    //   })
    //   bindCodeRef.value.start()
    // }).catch(() => {
    //   uni.hideLoading()
    //   uni.showToast({
    //     title: '发送失败，请重试',
    //     icon: 'none'
    //   })
    // })

    // 模拟发送验证码
    setTimeout(() => {
      uni.hideLoading();
      uni.showToast({
        title: "验证码已发送",
        icon: "success",
      });
      bindCodeRef.value.start();
    }, 1500);
  } else {
    uni.showToast({
      title: "倒计时结束后再发送",
      icon: "none",
    });
  }
};

// 绑定验证码倒计时回调
const bindCodeChange = (text) => {
  bindCodeTips.value = text;
};

// H5微信登录方法
const wechatH5Login = () => {
  // #ifdef H5
  // 构建微信授权URL
  const appId = "YOUR_WECHAT_APP_ID"; // 替换为你的微信公众号AppID
  const redirectUri = encodeURIComponent(
    window.location.origin + "/pages/login/login"
  ); // 授权回调地址
  const scope = "snsapi_userinfo"; // 授权作用域
  const state = "STATE" + Date.now(); // 防止CSRF攻击的随机字符串

  // 检查是否已经有授权码
  const urlParams = new URLSearchParams(window.location.search);
  const code = urlParams.get("code");

  if (code) {
    // 已经获得授权码，处理登录
    handleWechatH5Callback(code);
  } else {
    // 跳转到微信授权页面
    const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;

    uni.showLoading({
      title: "正在跳转微信授权...",
    });

    // 跳转到微信授权页面
    window.location.href = authUrl;
  }
  // #endif
};

// 处理微信H5授权回调
const handleWechatH5Callback = async (code) => {
  // #ifdef H5
  try {
    uni.showLoading({
      title: "正在获取用户信息...",
    });

    // 调用后端接口，通过code获取用户信息
    // const result = await RPC.post('/api/wechat/h5-login', {
    //   code: code
    // });

    // 模拟获取用户信息
    setTimeout(() => {
      uni.hideLoading();

      // 模拟获取到的用户信息
      const userInfo = {
        openid: "mock_openid_" + Date.now(),
        nickname: "微信用户",
        headimgurl: "/static/imgs/avatar.png",
      };

      console.log("微信H5登录成功，用户信息:", userInfo);

      // 显示绑定手机号弹窗
      popup.value.open();

      // 清除URL中的code参数
      const url = new URL(window.location);
      url.searchParams.delete("code");
      url.searchParams.delete("state");
      window.history.replaceState(
        {},
        document.title,
        url.pathname + url.search
      );
    }, 1500);
  } catch (error) {
    uni.hideLoading();
    console.error("微信H5登录失败:", error);
    uni.showToast({
      title: "微信登录失败，请重试",
      icon: "none",
    });
  }
  // #endif
};

// 初始化微信JS-SDK（可选，用于更高级的功能）
const initWechatJSSDK = () => {
  // #ifdef H5
  // 如果需要使用微信JS-SDK的其他功能，可以在这里初始化
  // 需要先引入微信JS-SDK：https://res.wx.qq.com/open/js/jweixin-1.6.0.js
  // 示例配置（需要后端提供签名等信息）
  // if (typeof wx !== 'undefined') {
  //   wx.config({
  //     debug: false,
  //     appId: 'YOUR_WECHAT_APP_ID',
  //     timestamp: timestamp,
  //     nonceStr: nonceStr,
  //     signature: signature,
  //     jsApiList: ['chooseImage', 'uploadImage', 'getLocation'] // 需要使用的JS接口列表
  //   });
  //
  //   wx.ready(() => {
  //     console.log('微信JS-SDK初始化成功');
  //   });
  //
  //   wx.error((res) => {
  //     console.error('微信JS-SDK初始化失败:', res);
  //   });
  // }
  // #endif
};

// 确认绑定手机号
const confirmBindPhone = async () => {
  try {
    await bindPhoneForm.value.validate();

    bindingPhone.value = true;

    // 调用绑定手机号API
    // const result = await RPC.post('/api/wechat/bind-phone', {
    //   phone: bindPhoneInfo.value.phone,
    //   code: bindPhoneInfo.value.code,
    //   wechatCode: wechatLoginCode // 微信登录返回的code
    // })

    // 模拟绑定过程
    setTimeout(() => {
      bindingPhone.value = false;

      uni.showToast({
        title: "绑定成功",
        icon: "success",
      });

      // 设置登录状态
      authStore.setAccessToken("wechat_access_token");
      // userStore.setUserInfo(result.userInfo)

      closeBindPhoneModal();

      // 跳转到首页
      setTimeout(() => {
        uni.$uv.route({
          type: isTabBarPath(redirect) ? "switchTab" : "redirectTo",
          url: redirect,
        });
      }, 1000);
    }, 2000);
  } catch (error) {
    console.error("绑定手机号失败:", error);
    bindingPhone.value = false;
  }
};

// 关闭绑定手机号弹窗
const closeBindPhoneModal = () => {
  popup.value.close();
  bindPhoneInfo.value = {
    phone: "",
    code: "",
  };
  bindCodeTips.value = "获取验证码";
};

const login = async () => {
  await form.value.validate();
  console.log(userInfo.value);
  // RPC.post('/account/login', {
  // 	username: userInfo.value.name,
  // 	password: userInfo.value.password,
  // }, {
  // 	custom: {
  // 		loading: true,
  // 		loadingText: '正在登录...'
  // 	},
  // }).then(res => {
  // 	authStore.setAccessToken(res.token)
  // 	userStore.setUserInfo(res)
  // 	uni.$uv.route({
  // 		type: isTabBarPath(redirect) ? "switchTab" : "redirectTo",
  // 		url: redirect,
  // 	});
  // })
  authStore.setAccessToken("accessToken");
  setTimeout(() => {
    uni.$uv.route({
      type: isTabBarPath(redirect) ? "switchTab" : "redirectTo",
      url: redirect,
    });
  }, 800);
};

onMounted(() => {
  checkEnvironment();

  // #ifdef H5
  // 检查是否是微信授权回调
  const urlParams = new URLSearchParams(window.location.search);
  const code = urlParams.get("code");
  if (code && showWechatLogin.value) {
    handleWechatH5Callback(code);
  }

  // 可选：初始化微信JS-SDK
  // initWechatJSSDK();
  // #endif
});
</script>

<style lang="scss" scoped>
.container {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: linear-gradient(
    124.92deg,
    rgba(77, 130, 253, 1) 7.66%,
    rgba(85, 184, 254, 1) 89.55%
  );

  .header {
    height: 15vh;
    color: #fff;
    display: flex;
    flex-direction: column;
    padding-left: 7vw;
    font-size: 16px;
    justify-content: center;

    .line {
      margin: 6px 0;
    }
  }

  .main {
    flex: 1;
    background-color: #fff;
    border-radius: 20px 20px 0 0;
    padding: 7vw;
    .formLabel {
      display: flex;
      align-items: center;
      margin-bottom: 4px;
      .img {
        width: 20px;
        height: 20px;
        margin-right: 6px;
      }
    }
    .wechatBox {
      position: fixed;
      width: 100%;
      left: 0;
      bottom: 15vh;
      display: flex;
      flex-direction: column;
      align-items: center;

      .uv-icon {
        cursor: pointer;
        transition: transform 0.2s;

        &:active {
          transform: scale(0.95);
        }
      }
    }
  }
}

.bind-phone-modal {
  width: 320px;
  padding: 24px;

  .modal-header {
    text-align: center;
    margin-bottom: 24px;

    .modal-title {
      font-size: 18px;
      font-weight: bold;
      color: #333;
      margin-bottom: 8px;
    }

    .modal-subtitle {
      font-size: 14px;
      color: #666;
    }
  }

  .modal-form {
    margin-bottom: 24px;

    .uv-form-item {
      margin-bottom: 16px;
    }
  }

  .modal-actions {
    display: flex;
    gap: 12px;

    .uv-button {
      flex: 1;
    }
  }
}
</style>

<style lang="scss">
.wechatBox {
  .uv-divider {
    margin-bottom: 30px;
    width: 90%;
  }
}
</style>^*#x$ 100644 mine.vue 5@1.<d+ߌfx+ "张三A	U12345678 
 M
TFx ;40000 edit-profile #̰*_ԺNq@CÌcQ40000 generate-record nu4ɦJFe-஻40000 order-detail :?e̈́z$UJDq40000 recharge Qf$7A40000 user-agreement 0bA~kkHPx, 100644 edit-profile.vue a3FpͺT@W+F`Hx cc
陆
P'Kzѯx/ 100644 generate-record.vue źV]tu-x/B?p7. v-for="record in records" :key="record.id">
V'6%title }}</view>
 4me">生成时间: {{ record.generateTime }}</view>
U<view class="status-tag" :class="record.status">
          {{ record.statusText }}
6<u 9'completed'"
Y(	")  <u-icon
0-$~H'></u-icon>
</u<u?	<u-icon
0-$~H'></u-icon>
</u-button>

          <u 9%'failed'"
            type="error"
y&<eteRecord(record)"
            style="margin-left: 8px"
  !  <u-icon
0trash"
'~H'7></u-icon>
            删除
          </u-button>
!</viewj:records-1	q\hasMore && records.length > 0" class="load-more">
      <u-button
        type="default"
}:loading="loading"
        @click="loadMore"
      >
        {{ loading ? "加载中..." : "加载更多" }}
      </u-button>
    </view	[{ onShowy
 \7hasMore = ref(true);
const records = ref([
  {
    id: 1,
    title: "乘客电梯标准图纸",
    generateTime: "2025-05-15 14:30",
    status: "completed",
    statusText: "已完成",
    downloadUrl: "/static/files/passenger-elevator.pdf",
  },
  {
    id: 2,
    title: "货运电梯专用图纸",
    generateTime: "2025-05-15 14:30",
    status: "failed",
    statusText: "未完成",
    downloadUrl: null,
  },
  {
    id: 3,
    title: "医用电梯专业图纸",
    generateTime: "2025-05-15 14:30",
    status: "completed",
    statusText: "已完成",
    downloadUrl: "/static/files/medical-elevator.pdf",
  },
  {
    id: 4,
    title: "观光电梯定制图纸",
    generateTime: "2025-05-15 14:30",
    status: "completed",
    statusText: "已完成",
    downloadUrl: "/static/files/sightseeing-elevator.pdf",
  },
  {
    id: 5,
    title: "货运电梯专用图纸",
    generateTime: "2025-05-15 14:30",
    status: "failed",
    statusText: "未完$",
    downloadUrl: null,
  },
]?=if (record.status !== "completed" || !record.downloadUrl) {
Atitle: "文件未准备好",
});
    return;
  }
0D*模拟下载过程
  setTimeout(() => {
mJ
    // 在实际项目中，这里应该调用下载API或打开文件
AOf});

    // 实际下载逻辑
    // uni.downloadFile({
    //   url: record.downloadUrl,
    ////(-//       uni.saveFile({
    //         tempF^
    //// //             title: '下载成功',
    //             icon: 'success'
    //           })
    //         }
    //       %})
    //     }
    //   },
    ////m//       title: '下载失败',
    //       icon: 'none'
    //     })
    //   }
    // })
  }, 1500);O4更多数据
const loadMore = async () => {
  if (loading.value) return;

  loading.value = true;
  try {
    // 模拟API调用
    await new Promise((resolve) => setTimeout(resolve, 1000));

    // 模拟没有更多数据
    hasMore.value = false;

A!title: "没有更多数据了",
L});
  } catch (error) {
    console.error("加载更多失败:", error);
A$title: "加载失败，请重试",
3});
  } finally {
    loading.value = false;
  }rDtry {
    // 调用获取生成记录API
    // const result = await RPC.get('/api/generate-records')
    // records.value =[ result.data
  } catch (error) {
    console.error("加载生成记录失败:", error);
A$title: "加载失败，请重试",
});
  }lAconst onRefresh = async () => {
  hasMore.value = true;
  awaitMounted(() => {<7A` 9x nWV.,]cHPf&~8
O xF j<(ʵhƨwWa100644 index_HL.png rT03j;k^1K rxgPNG

   IHDR         \rf   sRGB   !IDATx^kZIEm	 "l&°'Mq0.TRgi?@
l 
l  &@
 g(   
$V  $>[G P   q:
  <  Q  H  H|  @b @u  x +    (X 8l  @
 g(   
$V  $>[G P   Ymneo/ `8	ssp<$m?.˓~{ `R,/LKJ I=l L܆#df si):
trx* K;e@XZ ,4OV 8 (~%ҷm}0 ݛ:2 &6 &}Co !
5xJ~   Y@-6x<<><;pX6"עs /&WT䬹('. 	mM[|@cT. T
h]-#6 <$58S ǡx8d cy\Y p*ωymC~I Y"$X5:  GX( $bBE\pY pȉyB?|	 `pOܵxȧֵH ( JZt!W@G؏ 5qL`Z @D3&?G{ `t CdH~ P Qɿ,O}~m]W~*pn @}_%
w Ϛ@ 	0ٓt4W@#!χ!?*@'U *_. (ʪ% h4GW9 ;_&&(ɢ h2/ 4P׉t *$u 
tmtԌ 4U|.Jb6 
99+D+
Dj %	`@@_ VES P!+ (/Q3 H+ I:4D= \јo¯f } _K5_@T)y; pA3_n=@u'}V;*U LZZ =I5h, xגog*@ _i z#F O <^z}$כcO JJ :xJ _nH=,Z @5(\ 妘%(b
 $fy䤕'hL Lp3 _Gwj S|oV'H(O	 !{k6 <12= nT4    S~f D<Bv /s{f@栵4?cV B kH־
dU8 dR_3
 قCjQ   SP؞Y3V! @#; f2fk .~i5Z} 3>/W`V?bmGO
Kw QdO&f-u
OW M:۫3 fիqYW;f "f;{1Rfp  b>
DP D55>>/< mTșQ!0 $2h"B $h2OA $O1"A OOOGexER8Q 
 P!?Zr& 
%$QiU޷'uB`w(7O,Fc
h!!  BZ $?ɯ( @* H(.fU
<??<J	 Ƀ?<J
V@ w4(PP\ 3%
|:@Sc7 +#_QYKcw H.x,^@p-wq^ 5KB/voks^[}m; 5.}޵L.~*zIxiB <BΛwr}t盛ΉDzPUA0fԱx
mXh HHeknaK |l62p?L5HYߴA޷Pi^JUB
`Вb1u%@`%Oaxr: gݮ ֌C)?/p+҇/8%/}]px{SC+ w~RV@X=k	e: =r  dli'IuKW[E!l 	 he<d iv*P  4KFh˜MQvD Y<./ 0Q  Ԩg7Kd
Ny  ċYg \Z  fR& :U  jB)  Ú%@0
`Z @z}@J6`<dN:/6-/NZXk.A. yf;E{m`0րStnYt ׬׌Ρ'
Y( \<GO3m @lc)m50
B?Ooz @G:z$o1<B@/7@R%W׷Ѝk9@"KT rÌ'kL6ZR0n}MϞJi PmD)9EVGOU@T]T R*KLN))[׀$fi| @"!'/@g/ .b$^Ex%w<;4Ш#~sy$ɴPRKaJKr
NOX
/CB ÍGPhNI~]@z= Kef I 0SjS  |B^`~ GPC+ q9k'	 6HA0"34 Z   ZƤ9 0©_/\X @wO   & 7  @~=@?m?  D  \   ӯ' -\42`  ) @z mmE8<di

@ z{26   FVM Dr  wO .  vT T "5 FB  `d54 @$1   z	 i5 K? k'I@ 2Qc `$4   FVM Dr  wO \  vT T "5 FB  `d54 @$1   z	 i5 K? k'I@ 2Qc `$4   FVM Dr  wO \  vT T "5 FB  `d54 @$1   z	 i5 K? k'I@ 2Qc `$4   FVM DrX p8߿1gX ,EJHkeGIR~7d c[Tv2ߦ-]fyK4$h <??<J0z%k&t 	hJp os U `t   @RDBW WsfXy b @ykh ϭM	  E. Ë  Kx߉׆L^%< UA-El,z/bY \'s@ E$w\ۊŹW`MQ,(ԑ)0RO  SS]8VvGf:OP)m)󿾾>Z2wSs,4\3],BS`0 39{jn) p
vLcI`r?mG@w]wښ_R`y|,Kk P >*  p
$V  $>[G P   q:
  <  Q  H  H|  @b @u  x +    (X 8l  @
 g(   
$V  $>[G P   q:
  <  Q?tZuA    IENDB`pxyPNG

   IHDR         \rf   sRGB   @IDATx^mz:F%QvtQyTvMf[~xQ.|  ִ;g $&$>[   8l @b@u` h 	` !$&$>[   8l @b@u` h 	` !$&$>[   8l @b@࿾_^[>ϧ Lk_W~exoT[K`R &oĿŲRL`_>ٮ03] `o?G_W	_1^~UzjZLɾ` }W#>ַM0@7@7wN0Pv膾n ɏ	ԅ{o{<az` aBQ^s{[(cV@P<_He'g#y0 kƯI+|0F><@*jsB31!<L.Hi-C60!p4|,ȉymC~I@`#1XX.k
q` AB2bB  @(FN ݗtAw/ںRVЏU!0j9t }YfJ~LL4(b*pɏ	8t@CdH~LT1a NqHENz8Eו?<#Sw ;fK+L\#Zb &?&`,Fc @&{cj440$D0Z@%@ 1rV^-1Ƥ(&Xpa  I2@'V@#$$& eh@AtZ *iu 1:~1
$CWLG(OJpamyGHPaq6*c $ VESL+P/ը&a0$$&ԛ!1'I~{kL?$JGJIa r1Ylb w6b%w	^d-GZ\os%@L]0%NT#am(c aO%u ׋@@׉'JoL@@E'&JJ ubG(rE+2q(\ E1CKL,)2OGNZE"@ܟGcz@E0sNm .:xjZ 	%z)`gHi̦3 ,OL=ǟў nT4@P	'z)`fL=	 'Bg
 {2'n˽gѰ9h-X	dӐ5X$- 2V~$M_C@}d0)(}dϬ+!'9{Ƞ!=͜ef_h~i՛:k 3C-hU!`Vr#u fIĬle Ia`&Q˺E!`H#A`#5]]`tx6bT|ZϽ ^!g^@ -$Ș	h@)[\䷔cG!0		Һ,D}@a&$w?O[E]@/!}Д$`U4	|V4@y_/@@/	3  5D	'U@&.i HTR_~mFV2 y8m `M@u41 v1SB.9q3}6Bb}a0Sym	l	,/+.:c}6fn r &ev]-E	-!k؜q?7	%Ŀгl<5L쁌[O0J{X&Ђ"c	8'v.rVf֮t2>;oaUdRTvsvSWJ$tLS^ekp*U@4zx/Лl,cT&f<.T-oT=}bi<Hx|]wov}j)kC$+mVVF^*s9
ҎE$ Iz&30E0 =;YI"E_T w` e%@0
`Z	@=Y䀒)Ox1iY-Hdn0 7ԺHG^
V) <Y<./ 0!s%@(ǀi ~.D"|MKY-@KuM{%_f!/ZOw> Gm yq}f5T ?Q:*׹|ϡ3fӍb3^ I[?WGTO#׳KY.QLE_BgN!T/l b$Y^ǈx; Oƛ
Tv| ^#bB#V?9ug^^kV|XKϑJi,5@ګxR7S<oQ%eC %V^"4aBuD1:IYtg I"sRH
Q_19PS{#|bR^F >O|IA5syFcO"$hҦW$4W@gwxa `<Tqn` Nf 	º_gFb0T Zr~W0 hc )0e6
)1ӌ  jݲ% $541cc $541ccKpÖ NbL`4яU_͸ $541cc g NOىzRPp` NRMpc ^=v=1 ;p.4' H0N1 ' $541cc g NOىzRPp` NRMpc ^=v=1 ;p.4' H0N1 ' $541cc g NOىzRPp` NRMpc ^=v=1 ;p.4' H0N1 ' $541cc g NOىzRPpg eQ"uYΧ\6Za`9RRV+Z[T˲?O[y5㔮u]#zK7%L?OaW A]a ck!Pbm$.ݻ
(oL*I2z ^/e٪O`a cT DSSEhh^9
 ߻R SKifm@+[t?+:}1i=Xy<PIYFe[
su+ٚ?l^I+@+@wJZ [c +YJ< G"LWiP	l{Lo~x2Jo[[rTZuihjn#57M5UH-3ImްRa|s*7YuZ9f@@X ܑ3! Ă@ 	! '0 wL808`%p'#gB!ĉ+;9B  N,X		` șq` qbJ N pG΄C Vw;r&@@X ܑ3! Ă@ 	! '0 wL8 :jW    IENDB`'1@x˛%2=g%:铞>Xi% Xx BAxev~k9
"x  		g|({*kx˛%qE~YzrIJ6s <
x AA /index/index jf%4 x{ 		UJWUfO:SĪ40000 pages kPa*]j|	~40000 pagesA 'JL?ieHd|({*{7{lbx :% x {zf'^nox% 100644 order.vue ;̷%nw~/zp-x' [[brt	!$W*֓ %&T+yNzi;x	 W~Fgqx )		[;G̾d(G:3n*pÆ&40000 pages <)1`78p	1xO40000 pagesA 4#"40000 plugins 
NЋoޝ40000 ro&UKD?aC/	}ؓ|({*a{3x% {
    "name" : "卡叔电梯('CxP 9M	/")s9Ks:"<sM=,
				3HP:Kƥ
x Z40000 consumption O_K({40000 index 2:>$*qI_40000 login ˘p.贀1|40000 mine I #.MhcQ40000 order {zf'^HxK 100644 index.vue }vG*S0100644 index1.vue U$YVxIhC	|x>PDh			<view class="form">
			<uv-form labelAlign="left" labelWidth="auto" labelPosition="left" :model="formField" :rules="rules"
				ref="form">
				_g

					<uv-inputOLhone" color="#000" border="none"
						:placeholderStyle="{color:'#666778'}"_+>
					</uv-input>
				</uv-form-item>
				_%
					<uv-inputOG color="#000" border="none"
						:placeholderStyle="{color:'#666778'}"_+>
					</uv-input>
				</uv-form-item>
				_+
					<uv-input type="digit"OG color="#000" border="none"
						:placeholderStyle="{color:'#666778'}"_+>
					</uv-input>
				</uv-form-item>
				_;
					<uv-input type="digit"OG color="#000" border="none"
						:placeholderStyle="{color:'#666778'}"_+>
					</uv-input>
				</uv-form-item>
				_%
					<uv-input type="digit"OG color="#000" border="none"
						:placeholderStyle="{color:'#666778'}"_+>
					</uv-input>
				</uv-form-item>
				_%j
					<uv-input type="digit"OG color="#000" border="none"
						:placeholderStyle="{color:'#666778'}"_+>
					</uv-input>
				</uv-form-item>
				_L>
					<div style="margin-bottom: 4px;">备注说明</div>
					<uv-textareaO_>></uv-textarea>
				</uv-form-item>
			</uv-form>
		</view>
		M
	  <uv-button :loading="generating" @click="viewHistory" text="生成图纸" color="#3F70FF"></uv-button>
	  <uv-button @clickcyF

const generating = ref(false)

const form = ref(null)
	const formField = ref({
		phone: '',
		password: '',
	})
	const rules = ref({
		// 'phone': {
		// 	required: true,
		!$		G!6		// },
		// 'password': {
		// 	required: true,
		!验证码',
		G!		// }
	})


    
	console.log(111)  3!6
	width:70%;
	transform: translate(0, -50%);
	padding:"n
	  color: #BD9E85 # 
7$/
	j&'%&'"
  padding: 0 16px;]'z
  width: 100%;
}
</style>

<style lang="scss">
	.bottom-actions {
		.uv-button-wrapper {
			width: 48%;
		}
	}
</style>>}x$ 100644 mine.vue uvBlV?HlG3Ux" talipay+:WI	x b40000 edit-profile #̰*_ԺNq@CÌcQ40000 generate-record nu4ɦJFe-஻40000 recharge ;fQa6Ilux̙L40000 user-agreement UгK5'ERMG%N>Өx( 100644 recharge.vue aEG/lMK5x! 
alipay-circle-fill
H8Wx. 100644 user-agreement.vue OYU_wV®xn 100644 index.js mS锋	ި՘%100644 permission.js ;B@\^I100644 ui.js 10=uR|Ts00ox$ /pages/index/indexw'x_ 40000 imgs 8aFe340000 json y.)E:ƾy"X-40000 tabbar WV.,]cHPf&~8v%f*xX8ѧ ~0x! 		PjLUW]ѰdódA	x b40000 edit-profile G-c40000 generate-record nu4ɦJFe-஻40000 recharge ;fQa6Ilux̙L40000 user-agreement UгK5'ERMGCx, 100644 edit-profile.vue [`y,Ī|z8c=&SxfcV
陆
'email' ? "邮箱" : ''\action-sheet
      :show="showAvatarSheet"
      :actions="avatarActions"
      @close="showAvatarSheet = false"
      @sel,ect="onAvatarSelect"
    ></uv-action-sheetshowAvatarSheete 头像选择选项
const avatarActions = ref([
  {
    name: "拍照",
    value: "camera",
  },
  {
    name: "从相'选择",
    value: "album",
  },
]7showAvatarSheet.value = true;
};

// 头像选择回调
const onAvatarSelect = (item) => {
  showAvatarSheet.value = false%Q	item.valuu) => {
"AQ$j$$$0
</style>?f9x! 		PW8hה'dA'	x b40000 edit-profile  [v갚}=J40000 generate-record nu4ɦJFe-஻40000 recharge ;fQa6Ilux̙L40000 user-agreement UгK5'ERMG@Zx, 100644 edit-profile.vue |˛ݘ<KOCxnv_Sx	P(Avatar
'Oimage class="avatar" :src="userInfo.avatar" mode="aspectFill"></image>
					<u3~ 3~>	editPhone
label">电话OInfo.phone }}</text>
					<u3~R3@	DÓ3֓3~G3@	N	\陆
			</u	4-popup :show="showEditModalA
"邮箱$28-button>
					<u	Rn(.-action-sheet :show="showAvatarSheet" :actions="avatarActions" @close="showAvatarSheet = false"
			@select="onAvatarSelect"></u-action-sheetϓ##3showEditModal = ref(false);
	const showAvatarSheetI
	// 头像选择选项
	const avatarActions = ref([{
			name: "拍照",
			value: "camera",
		},
		{
			name: "从相'选择",
			value: "album",
		},
	]i9showAvatarSheet.value = true;
	};

	// 头像选择回调
	const onAvatarSelect = (item) => {
		showAvatarSheet.value = faK+
N	item.valu7r#*H2Info.value.username;
		showEditModal.value = true.m/Info.value.phone;
		showEditModal.value = truem/Info.value.email;
		showEditModal.value = truefushowEditModal.value = false;	!
		// 验证格式!"phone" && ^6editValue.value|!/6!.f
		if (
			editType.value === "email" &&
			!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(editValue.value)
		}!.正确的邮箱地址!0,$	$+	$%*'	// })

			// 更新本地数据
			%7!"(
});

			&H-%`&!&! &0*/)about/about"*#++y9=(</style>	Rxb 		UA0
;$3CkX40000 pages V'5/{kF2utb40000 pagesA Z<F.M#xTdA"&Yl(x [G;bx q1@g dx$ 100644 mine.vue ?ܐ~&#YZg24x /agreement/./]h x zWz#.-x! 		/&F<+5|Q}]-Cb4x qFQq%oҜԑ!ʯ4x$ 100644 mine.vue 럚cbR^q~;,	6x$G<template>
	<view class="container">
		<!-- 顶部标题 -->
		<view class="header">
			<view class="header-title">管理您的账户信息和服务</view>
		</view>

		<!-- 用户信息卡片 -->
		<view class="user-card">
			<view class="user-info">
				<div class="avatar"></div>
				<!--        <image
          class="avatar"
          src="/static/imgs/avatar.png"
          mode="aspectFill"
        ></image> -->
				<view class="user-details">
					<view class="username">
						张三
						<u-icon name="checkmark-circle-fill" color="#ffa500" size="16"></u-icon>
					</view>
					<view class="user-id">用户ID: U12345678</view>
					<view class="membership">
						会员等级: 年会员 (有效期至: 2026-05-15)
					</view>
				</view>
			</view>
			<view class="edit-btn" @click="editProfile">
				<text>点击编辑资料</text>
			</view>
		</view>

		<!-- 账户余额 -->
		<view class="balance-card">
			<div>

				<view class="balance-header">
					<view class="balance-label">账户余额</view>
				</view>
				<view class="balance-amount">¥50.00</view>
			</div>
			<uv-button type="primary" color="#fff" customStyle="color:#000;width:90px" shape="circle" @click="recharge">
				充值
			</uv-button>
		</view>

		<!-- 会员套餐 -->
		<view class="membership-section">
			<view class="membership-grid">
				<view class="membership-item" :class="{ active: selectedPlan === 'monthly' }"
					@click="selectPlan('monthly')">
					<view class="tag">新人特惠</view>
					<view class="plan-name">包月会员</view>
					<view class="plan-price">¥120</view>
				</view>
				<view class="membership-item" :class="{ active: selectedPlan === 'season' }"
					@click="selectPlan('season')">
					<view class="tag">最受欢迎</view>
					<view class="plan-name">包季会员</view>
					<view class="plan-price">¥300</view>
					<view class="plan-discount">立减¥60</view>
				</view>
				<view class="membership-item" :class="{ active: selectedPlan === 'yearly' }"
					@click="selectPlan('yearly')">
					<view class="tag">年度首享</view>
					<view class="plan-name">包年会员</view>
					<view class="plan-price">¥1000</view>
					<view class="plan-discount">立减¥440</view>
				</view>
			</view>
		</view>

		<!-- 支付方式 -->
		<view class="payment-section">
			<view class="payment-item" :class="{ active: selectedPayment === 'alipay' }"
				@click="selectPayment('alipay')">
				<view class="payment-info">
					<uv-icon name="shopping-cart-fill" color="#1677ff" size="24"></uv-icon>
					<text class="payment-name">支付宝</text>
				</view>
				<uv-icon name="checkmark-circle-fill" :color="selectedPayment === 'alipay' ? '#ff3333' : '#ccc'"
					size="20"></uv-icon>
			</view>
			<view class="payment-item" :class="{ active: selectedPayment === 'wechat' }"
				@click="selectPayment('wechat')">
				<view class="payment-info">
					<uv-icon name="weixin-fill" color="#07c160" size="24"></uv-icon>
					<text class="payment-name">微信</text>
				</view>
				<uv-icon name="checkmark-circle-fill" :color="selectedPayment === 'wechat' ? '#ff3333' : '#ccc'"
					size="20"></uv-icon>
			</view>
		</view>

		<!-- 底部按钮 -->
		<view class="bottom-section">
			<uv-button type="primary" size="large" @click="confirmPayment" :loading="paying">
				确认支付
			</uv-button>
			<view class="agreement">
				购买前请仔细阅读
				<text class="link" @click="showAgreement">《会员服务协议》</text>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		ref
	} from "vue";
	import HeaderCustom from "/components/HeaderCustom/HeaderCustom.vue";
	import {
		useAuthStore,
		useUserStore
	} from "@/store";
	import RPC from "@/utils/request";

	const modal = ref(null);
	const authStore = useAuthStore();
	const userStore = useUserStore();

	// 响应式数据
	const selectedPlan = ref("season"); // 默认选中包季会员
	const selectedPayment = ref("alipay"); // 默认选中支付宝
	const paying = ref(false);

	// 选择会员套餐
	const selectPlan = (plan) => {
		selectedPlan.value = plan;
	};

	// 选择支付方式
	const selectPayment = (payment) => {
		selectedPayment.value = payment;
	};

	// 编辑资料
	const editProfile = () => {
		uni.navigateTo({
			url: "/pagesA/edit-profile/edit-profile",
		});
	};

	// 充值
	const recharge = () => {
		uni.navigateTo({
			url: "/pages/recharge/recharge",
		});
	};

	// 确认支付
	const confirmPayment = async () => {
		if (!selectedPlan.value) {
			uni.showToast({
				title: "请选择会员套餐",
				icon: "none",
			});
			return;
		}

		if (!selectedPayment.value) {
			uni.showToast({
				title: "请选择支付方式",
				icon: "none",
			});
			return;
		}

		paying.value = true;
		try {
			const params = {
				plan: selectedPlan.value,
				paymentMethod: selectedPayment.value,
			};

			// 这里调用支付API
			// const result = await RPC.post('/api/payment', params)

			uni.showToast({
				title: "正在跳转支付...",
				icon: "loading",
				duration: 2000,
			});

			// 模拟支付过程
			setTimeout(() => {
				uni.showToast({
					title: "支付成功",
					icon: "success",
				});
				paying.value = false;
			}, 2000);
		} catch (error) {
			console.error("支付失败:", error);
			uni.showToast({
				title: "支付失败，请重试",
				icon: "none",
			});
			paying.value = false;
		}
	};

	// 显示协议
	const showAgreement = () => {
		uni.navigateTo({
			url: "/pages/agreement/agreement",
		});
	};
</script>

<style lang="scss" scoped>
	.container {
		font-size: 14px;
		background: linear-gradient(180deg, #7b9cdb 0%, #f8f8f8 40%);
		padding-bottom: 120px;
	}

	.header {
		padding: 20px 16px 16px;

		.header-title {
			color: white;
			font-size: 18px;
			font-weight: 500;
		}
	}

	.user-card {
		margin: 0 16px 16px;
		background: white;
		border-radius: 12px;
		padding: 16px;
		position: relative;

		.user-info {
			display: flex;
			align-items: center;
			// margin-bottom: 12px;

			.avatar {
				width: 60px;
				height: 60px;
				border-radius: 50%;
				margin-right: 12px;
				background-color: skyblue;
				overflow: hidden;

				.img {
					width: 100%;
					height: 100%;
				}

			}

			.user-details {
				flex: 1;

				.username {
					display: flex;
					align-items: center;
					gap: 4px;
					font-size: 18px;
					font-weight: bold;
					color: #333;
					margin-bottom: 4px;
				}

				.user-id {
					font-size: 12px;
					color: #999;
					margin-bottom: 2px;
				}

				.membership {
					font-size: 12px;
					color: #999;
				}
			}
		}

		.edit-btn {
			text-align: right;
			color: #4285f4;
			font-size: 14px;
			position: absolute;
			top: 10px;
			right: 20px;
		}
	}

	.balance-card {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin: 0 16px 16px;
		background: linear-gradient(135deg, #4285f4 0%, #6fa8f5 100%);
		border-radius: 12px;
		padding: 16px;
		color: white;

		.balance-header {
			display: flex;
			justify-content: space-between;
			align-items: center;
			margin-bottom: 6px;

			.balance-label {
				font-size: 14px;
				opacity: 0.9;
			}
		}

		.balance-amount {
			font-size: 28px;
			font-weight: bold;
		}
	}

	.membership-section {
		margin: 0 16px 16px;

		.membership-grid {
			display: flex;
			gap: 8px;

			.membership-item {
				flex: 1;
				background: white;
				border-radius: 12px;
				padding: 16px 12px;
				text-align: center;
				position: relative;
				border: 2px solid transparent;
				transition: all 0.3s;
				overflow: hidden;

				&.active {
					border-color: #4285f4;
					background-color: #f0f7ff;
				}

				.tag {
					position: absolute;
					top: 0px;
					left: 0;
					padding: 2px 8px;
					border-radius: 0 0 10px 0;
					font-size: 10px;
					color: white;
					background: #ff3333;
				}

				.plan-name {
					font-size: 14px;
					color: #333;
					margin: 12px 0 8px;
				}

				.plan-price {
					font-size: 20px;
					font-weight: bold;
					color: #ff3333;
					margin-bottom: 4px;
				}

				.plan-discount {
					font-size: 12px;
					color: #999;
				}
			}
		}
	}

	.payment-section {
		margin: 0 16px 24px;

		.payment-item {
			display: flex;
			align-items: center;
			justify-content: space-between;
			background: white;
			border-radius: 12px;
			padding: 16px;
			margin-bottom: 8px;
			border: 1px solid #e5e5e5;
			transition: all 0.3s;

			&.active {
				border-color: #4285f4;
				background-color: #f0f7ff;
			}

			&:last-child {
				margin-bottom: 0;
			}

			.payment-info {
				display: flex;
				align-items: center;
				gap: 12px;

				.payment-name {
					font-size: 14px;
					color: #333;
				}
			}
		}
	}

	.bottom-section {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		background: white;
		padding: 16px;
		border-top: 1px solid #e5e5e5;

		.agreement {
			text-align: center;
			font-size: 12px;
			color: #999;
			margin-top: 12px;

			.link {
				color: #4285f4;
			}
		}
	}
</style>ۭ/m x! 		/D8ٗۉ^t=`tCbSx R`gF?f?x% 100644 login.vue [qDI$x@\vNMxЌ'x8W<>
							手机号qcolor:'#666778'
用户名"0w8W+"code.png" alt="">
							验证码29Bcolor:'#666778'> #4D82FD" @click="getCode">{{tips}
			<div class="wechatBox">z5A></uv-icon>
			</div>
		</div	<S
	d""(

	const tips = ref('获取验证码')6
	}.J
			
		if(!userInfo.phone) {
,<title:'请填写手机号',
				icon:'none'
			});
			returnp'正在获取验证码'
			})6#Q+,title:'验证码已发送',
					icon:'none'*q
,title:'#',
				icon:'none'
			})
		}
	}
$:'',
		password: '',
	})
	const rules = ref({
		'phone'A%I'请填写手机号',
			trigger: ['blur', 'change']
		},
		'password'A%?'请填写验证码',
			trigger: ['blur', 'change']
		}
	})

		}
	})Q9@
		console.log(userInfo.value)9S<'accessToken')
 67:
O=});
		}, 800);
	}? L@ n@_
			.formLabel {ACB0
				.img {
					width: 20px;
					height: 20px;]B`
				}
			}
			.wechatBox {
				position: fixed;
				width: 100%;
				left: 0;
				bottom: 15vh;A
				flex-direction: column;C
			}
		}
	}
</style>
EU
	.wechatBox {
		.uv-divider {
			margin-bottom: 30px;
			width: 90%;
		}
	}
</style>x! 		/MV`[Bqdͻ
Cb=
x Z40000 consumption BRơ85c]O[4?^40000 index 2:>$*qI_40000 login `gF?40000 mine  1)&2ѹ40000 order {zf'^F&x+ 100644 consumption.vue W5['"HRlUx EEJKJCx$ 100644 mine.vue %_2<\|yA')WYQ9xP Px?张三A	U12345678 
 M
T5
%Iu-button type="default" size="small" shape="round" @click="recharge">
  
  </u-buttQ
j* newEJ popular yearly
/^Sp=-icon name="alipay-circle-fill" color="#1677ff" size="24"></uZ%-icon
          :name="
           Y
              ? 'checkmark-circle-fill'
              : 'radio-button-off'
          j\	
^Ó"6Z%-icon
          :name="
           Y
              ? 'checkmark-circle-fill'
              : 'radio-button-off'
          *@\	
=N)r-button`ԓ5q"alipay"); // 默认选中支付宝-& g  try {
    const pf"3"*"};

    // 这里调用支付API0" post('/api/payment', params)

P+$y)...",
      icon: "loading",
*"});

    // 模拟支付过程
1+6'01/  .
  }, 2000)m+t-P+D6，请重试P!&.v/agreement/\/9Mmin-height: 100vhL@"Z:<&;.<D:A<{=?;$]@W20@8JA|32px;
QEA024B4fC>-6px;
        left: 50%;
        transform: translateX(-50%)D58px;1EkDW
        &.new {
          background: #ff6b6b;
        }

        &.popular {
  D$  }

        &.yearly {
  D$  }EDeITx! 		/k!]~`\3wwCbmx ƥčA22Lh$,x% 100644 order.vue 4bpSKmxA[Ym
				class="tab-item" 
				~(
				!all')"
			$
				class="tab-item" 
				~!recharge' }"
				!recharge')"
			A$
				class="tab-item" 
				~!monthly' }"
				!monthly')"
			$
				class="tab-item" 
				~!season' }"
				!
			=$
				class="tab-item" 
				~!yearly' }"
				!yearly')"
			g
				!
				4 
				:key="order.id"
			c{{ order.typeLabel }}</viewq	%
						class="order-status" 
						q
					Nu-button 
							!
(size="small"
U(:>
						取消订单
					</u-button>
					<u-button 
(size="small"
						@click="deleteOrder(order)"
					>
						删除订单
					</u-button>
					<u-button 
						type="pri"mary" 
						size="small"
						-
					>
						查看详情
					</u-button	 --button>
						<uc.#"w
		Xt						[						N~												N2!		""			"=				"		$r			s$				$U					L%L					%				=&`					&L					&O					8'^			'+				'					F(8					~(E					(=						)K						K)7						)g			)@flex-endP*i				}
			+P				+/					,X				`,@					,		m-`=z4BN1g&/ݿ|Cz\o