Commit 0633d9fecd9e36ec2ccca6cf1c35473065246485

Authored by 刘汉宸
0 parents
Exists in master

初始化

.gitignore 0 → 100644
  1 +++ a/.gitignore
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +.DS_Store
  2 +node_modules
0 \ No newline at end of file 3 \ No newline at end of file
components/amount/index.scss 0 → 100644
  1 +++ a/components/amount/index.scss
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +.zui-amount.numerical {
  2 + font-family: DINPro-Medium, DIN Alternate, "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
  3 +}
0 \ No newline at end of file 4 \ No newline at end of file
components/amount/index.vue 0 → 100644
  1 +++ a/components/amount/index.vue
@@ -0,0 +1,209 @@ @@ -0,0 +1,209 @@
  1 +<template>
  2 + <text class="zui-amount" :class="{ numerical: !isCapital }">
  3 + <slot v-if="$slots.prefix" name="prefix"></slot>
  4 + <template v-else-if="prefix">
  5 + {{ prefix }}
  6 + </template>
  7 + <template v-if="!isCapital">
  8 + {{ Number(value || 0) | doPrecision(precision > 0 ? precision : 0, isRoundUp) | doFormat(hasSeparator, separator) }}
  9 + </template>
  10 + <template v-else>
  11 + {{ Number(value || 0) | doPrecision(4, isRoundUp) | doCapital }}
  12 + </template>
  13 + </text>
  14 +</template>
  15 +
  16 +<script>
  17 +/* istanbul ignore file */
  18 +var formatValueByGapStep = function(step, value, gap, direction, range, isAdd, oldValue) {
  19 + var gap = gap || ' ';
  20 + var direction = direction || 'right';
  21 + var isAdd = isAdd || 1;
  22 + var oldValue = oldValue || 0;
  23 + if (value.length == 0) {
  24 + return { value: value, range: range };
  25 + }
  26 + var arr = value && value.split('');
  27 + var _range = range;
  28 + var showValue = '';
  29 + if (direction == 'right') {
  30 + for (var j = arr.length - 1, k = 0; j >= 0; j--, k++) {
  31 + var m = arr[j];
  32 + showValue = k > 0 && k % step == 0 ? m + gap + showValue : m + '' + showValue;
  33 + }
  34 + if (isAdd == 1) {
  35 + // 在添加的情况下,如果添加前字符串的长度减去新的字符串的长度为2,说明多了一个间隔符,需要调整range
  36 + if (oldValue.length - showValue.length == -2) {
  37 + _range = range + 1;
  38 + }
  39 + } else {
  40 + // 在删除情况下,如果删除前字符串的长度减去新的字符串的长度为2,说明少了一个间隔符,需要调整range
  41 + if (oldValue.length - showValue.length == 2) {
  42 + _range = range - 1;
  43 + }
  44 + // 删除到最开始,range 保持 0
  45 + if (_range <= 0) {
  46 + _range = 0;
  47 + }
  48 + }
  49 + } else {
  50 + arr.some(function(n, i) {
  51 + showValue = i > 0 && i % step == 0 ? showValue + gap + n : showValue + '' + n;
  52 + });
  53 + var adapt = range % (step + 1) == 0 ? 1 * isAdd : 0;
  54 + _range = typeof range !== 'undefined' ? (range == 0 ? 0 : range + adapt) : showValue.length;
  55 + }
  56 + return { value: showValue, range: _range };
  57 +};
  58 +var numberCapital = function(number) {
  59 + var cnNums = ['\u96f6', '\u58f9', '\u8d30', '\u53c1', '\u8086', '\u4f0d', '\u9646', '\u67d2', '\u634c', '\u7396'];
  60 + // 拾 \u62fe 佰 \u4f70 仟 \u4edf
  61 + var cnIntRadice = ['', '\u62fe', '\u4f70', '\u4edf'];
  62 + // 万 \u4e07 亿 \u4ebf 兆 \u5146
  63 + var cnIntUnits = ['', '\u4e07', '\u4ebf', '兆'];
  64 + // 角 \u89d2 分 \u5206 毫 \u6beb 厘 \u5398
  65 + var cnDecUnits = ['\u89d2', '\u5206', '\u6beb', '\u5398'];
  66 + var cnInteger = '\u6574'; // 整 \u6574
  67 + var cnIntLast = '\u5143'; // 元 \u5143
  68 + var cnNegative = '\u8d1f'; // 负
  69 + // Maximum number
  70 + var maxNum = 999999999999999.9999;
  71 + var negative;
  72 + // Integral part
  73 + var integerNum;
  74 + // Decimal part
  75 + var decimalNum;
  76 + // Capital number
  77 + var capitalStr = '';
  78 + var parts;
  79 + /* istanbul ignore if */
  80 + if (number == '') {
  81 + return '';
  82 + }
  83 + number = parseFloat(number);
  84 + if (number < 0) {
  85 + negative = true;
  86 + number = Math.abs(number);
  87 + }
  88 + /* istanbul ignore if */
  89 + if (number >= maxNum) {
  90 + return '';
  91 + }
  92 + /* istanbul ignore if */
  93 + if (number == 0) {
  94 + capitalStr = cnNums[0] + cnIntLast + cnInteger;
  95 + return capitalStr;
  96 + }
  97 + // Convert to String
  98 + number += '';
  99 + if (number.indexOf('.') == -1) {
  100 + integerNum = number;
  101 + decimalNum = '';
  102 + } else {
  103 + parts = number.split('.');
  104 + integerNum = parts[0];
  105 + decimalNum = parts[1].substr(0, 4);
  106 + }
  107 + // Convert integer part
  108 + if (parseInt(integerNum, 10) > 0) {
  109 + var zeroCount = 0;
  110 + for (var i = 0, IntLen = integerNum.length; i < IntLen; i++) {
  111 + var n = integerNum.substr(i, 1);
  112 + var p = IntLen - i - 1;
  113 + var q = p / 4;
  114 + var m = p % 4;
  115 + if (n == '0') {
  116 + zeroCount++;
  117 + } else {
  118 + if (zeroCount > 0) {
  119 + capitalStr += cnNums[0];
  120 + }
  121 + zeroCount = 0;
  122 + capitalStr += cnNums[parseInt(n)] + cnIntRadice[m];
  123 + }
  124 + if (m == 0 && zeroCount < 4) {
  125 + capitalStr += cnIntUnits[q];
  126 + }
  127 + }
  128 + capitalStr += cnIntLast;
  129 + }
  130 + // Convert decimal part
  131 + if (decimalNum !== '') {
  132 + for (var i = 0, decLen = decimalNum.length; i < decLen; i++) {
  133 + var n = decimalNum.substr(i, 1);
  134 + if (n !== '0') {
  135 + capitalStr += cnNums[Number(n)] + cnDecUnits[i];
  136 + }
  137 + }
  138 + }
  139 + /* istanbul ignore if */
  140 + if (capitalStr == '') {
  141 + capitalStr += cnNums[0] + cnIntLast + cnInteger;
  142 + } else if (decimalNum == '') {
  143 + capitalStr += cnInteger;
  144 + }
  145 + if (negative) {
  146 + capitalStr = '' + cnNegative + capitalStr;
  147 + }
  148 + return capitalStr;
  149 +};
  150 +export default {
  151 + name: 'zui-amount',
  152 + filters: {
  153 + doPrecision: function(value, precision, isRoundUp) {
  154 + var exponentialForm = Number(value + 'e' + precision);
  155 + var rounded = isRoundUp ? Math.round(exponentialForm) : Math.floor(exponentialForm);
  156 + return Number(rounded + 'e-' + precision).toFixed(precision);
  157 + },
  158 + doFormat: function(value, hasSeparator, separator) {
  159 + if (!hasSeparator) {
  160 + return value;
  161 + }
  162 + var numberParts = value.split('.');
  163 + var integerValue = numberParts[0];
  164 + var decimalValue = numberParts[1] || '';
  165 + var sign = '';
  166 + if (integerValue.startsWith('-')) {
  167 + integerValue = integerValue.substring(1);
  168 + sign = '-';
  169 + }
  170 + var formateValue = formatValueByGapStep(3, integerValue, separator, 'right', 0, 1);
  171 + return decimalValue ? '' + sign + formateValue.value + '.' + decimalValue : '' + sign + formateValue.value;
  172 + },
  173 + doCapital: function(value) {
  174 + return numberCapital(value);
  175 + }
  176 + },
  177 + props: {
  178 + value: {
  179 + type: [Number, String],
  180 + default: 0
  181 + },
  182 + precision: {
  183 + type: Number,
  184 + default: 2
  185 + },
  186 + isRoundUp: {
  187 + type: Boolean,
  188 + default: true
  189 + },
  190 + hasSeparator: {
  191 + type: Boolean,
  192 + default: false
  193 + },
  194 + separator: {
  195 + type: String,
  196 + default: ','
  197 + },
  198 + isCapital: {
  199 + type: Boolean,
  200 + default: false
  201 + },
  202 + prefix: String
  203 + },
  204 +};
  205 +</script>
  206 +
  207 +<style lang="scss">
  208 +@import './index.scss';
  209 +</style>
components/button/index.scss 0 → 100644
  1 +++ a/components/button/index.scss
@@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
  1 +.zui-button {
  2 + color: #323233;
  3 + background-color: #fff;
  4 + border: 1upx solid $color-border;
  5 + padding: $h-gap-md $v-gap-md;
  6 + font-size: $font-md;
  7 + cursor: pointer;
  8 + transition: all 150ms;
  9 + display: flex;
  10 + align-items: center;
  11 + justify-content: center;
  12 + border-radius: 10upx;
  13 + &.sm {
  14 + padding: $h-gap-sm $v-gap-sm;
  15 + font-size: $font-sm;
  16 + }
  17 + &.lg {
  18 + padding: $h-gap-lg $v-gap-lg;
  19 + font-size: $font-lg;
  20 + }
  21 + &.active {
  22 + background-color: $bg-active;
  23 + border-color: $bg-active;
  24 + }
  25 + &.primary {
  26 + background-color: $color-primary;
  27 + border-color: $color-primary;
  28 + color: #FFF;
  29 + &.active {
  30 + background-color: darken($color-primary, 3%);
  31 + border-color: darken($color-primary, 3%);
  32 + }
  33 + }
  34 + &.secondary {
  35 + background-color: lighten($color-primary, 40%);
  36 + border-color: lighten($color-primary, 40%);
  37 + color: $color-primary;
  38 + &.active {
  39 + background-color: lighten($color-primary, 30%);
  40 + border-color: lighten($color-primary, 30%);
  41 + color: darken($color-primary, 3%);
  42 + }
  43 + }
  44 + &.link {
  45 + padding: $h-gap-sm $v-gap-sm;
  46 + background: inherit;
  47 + border: inherit;
  48 + color: $color-primary;
  49 + &.active {
  50 + color: darken($color-primary, 5%);
  51 + }
  52 + }
  53 + &.disabled {
  54 + border-color: $bg-disabled;
  55 + background-color: $bg-disabled;
  56 + color: $color-disabled;
  57 + cursor: not-allowed;
  58 + &.active {
  59 + border-color: $bg-disabled;
  60 + background-color: $bg-disabled;
  61 + }
  62 + }
  63 + &.round {
  64 + border-radius: 48upx;
  65 + }
  66 + &.square {
  67 + border-radius: 0upx;
  68 + }
  69 +}
0 \ No newline at end of file 70 \ No newline at end of file
components/button/index.vue 0 → 100644
  1 +++ a/components/button/index.vue
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +<template>
  2 + <view class="zui-button" hover-class="active" :class="classRender" :style="style" @click="onClick">
  3 + <slot></slot>
  4 + </view>
  5 +</template>
  6 +
  7 +<script>
  8 +export default {
  9 + name: 'zui-button',
  10 + props: {
  11 + type: {
  12 + type: String,
  13 + default: 'default'
  14 + },
  15 + size: {
  16 + type: String,
  17 + default: 'md'
  18 + },
  19 + block: {
  20 + type: Boolean,
  21 + default: false
  22 + },
  23 + round: Boolean,
  24 + square: Boolean,
  25 + disabled: Boolean,
  26 + },
  27 + computed: {
  28 + style: function() {
  29 + return `display: ${this.block ? '' : 'inline-block'};` ;
  30 + },
  31 + classRender: function() {
  32 + return [this.size, this.disabled ? 'disabled' : '', this.block ? 'block' : '', this.type, this.round ? 'round' : '', this.square ? 'square' : ''];
  33 + }
  34 + },
  35 + methods: {
  36 + onClick: function() {
  37 + if (!this.disabled) {
  38 + this.$emit('click');
  39 + }
  40 + }
  41 + }
  42 +}
  43 +</script>
  44 +
  45 +<style lang="scss">
  46 +@import "./index.scss";
  47 +</style>
0 \ No newline at end of file 48 \ No newline at end of file
components/cell/index.scss 0 → 100644
  1 +++ a/components/cell/index.scss
@@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
  1 +.zui-cell {
  2 + position: relative;
  3 + display: flex;
  4 + box-sizing: border-box;
  5 + width: 100%;
  6 + padding: $h-gap-lg $v-gap-md;
  7 + border-bottom: 1upx solid $color-border;
  8 + overflow: hidden;
  9 + background-color: #fff;
  10 + &--clickable {
  11 + cursor: pointer;
  12 + transition: background-color 150ms;
  13 + &.active {
  14 + background-color: $bg-active;
  15 + }
  16 + }
  17 + &__left-icon, &__right-icon {
  18 + display: flex;
  19 + align-items: center;
  20 + font-size: 42upx;
  21 + }
  22 + &__left-icon {
  23 + margin-left: $v-gap-sm;
  24 + }
  25 + &__right-icon {
  26 + margin-left: $v-gap-sm;
  27 + color: $color-disabled;
  28 + }
  29 + &__title, &__value {
  30 + flex: 1;
  31 + display: flex;
  32 + }
  33 + &__title {
  34 + flex-direction: column;
  35 + justify-content: center;
  36 + }
  37 + &__value {
  38 + align-items: center;
  39 + justify-content: flex-end;
  40 + position: relative;
  41 + overflow: hidden;
  42 + color: $color-minor;
  43 + text-align: right;
  44 + vertical-align: middle;
  45 + word-wrap: break-word;
  46 + }
  47 + &__label {
  48 + padding-top: $h-gap-sm;
  49 + color: $color-minor;
  50 + font-size: $font-sm;
  51 + }
  52 +}
components/cell/index.vue 0 → 100644
  1 +++ a/components/cell/index.vue
@@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
  1 +<template>
  2 + <view class="zui-cell" hover-class="active" :class="classRender" @click="onClick">
  3 + <view v-if="$slots.icon || icon" class="zui-cell__left-icon">
  4 + <slot v-if="$slots.icon" name="icon"></slot>
  5 + <zui-icon v-else-if="icon" class="zui-cell__left-icon" :name="icon"></zui-icon>
  6 + </view>
  7 + <view v-if="$slots.title" class="zui-cell__title">
  8 + <slot name="title"></slot>
  9 + <view v-if="$slots.label" class="zui-cell__label">
  10 + <slot name="label"></slot>
  11 + </view>
  12 + <view v-else-if="label" class="zui-cell__label">
  13 + <text>{{ label }}</text>
  14 + </view>
  15 + </view>
  16 + <view v-else-if="title" class="zui-cell__title">
  17 + <text>{{ title }}</text>
  18 + <view v-if="$slots.label" class="zui-cell__label">
  19 + <slot name="label"></slot>
  20 + </view>
  21 + <view v-else-if="label" class="zui-cell__label">
  22 + <text>{{ label }}</text>
  23 + </view>
  24 + </view>
  25 + <view v-if="$slots.default" class="zui-cell__value">
  26 + <slot></slot>
  27 + </view>
  28 + <view v-else-if="value" class="zui-cell__value">{{ value }}</view>
  29 + <view v-if="$slots.right || rightIcon" class="zui-cell__right-icon">
  30 + <slot v-if="$slots.right" name="right"></slot>
  31 + <zui-icon v-else-if="rightIcon && isLink" :name="rightIcon"></zui-icon>
  32 + </view>
  33 + </view>
  34 +</template>
  35 +
  36 +<script>
  37 +import ZuiIcon from '@/components/zui/icon';
  38 +
  39 +export default {
  40 + name: "zui-cell",
  41 + components: {
  42 + ZuiIcon
  43 + },
  44 + props: {
  45 + icon: String,
  46 + title: String,
  47 + value: String,
  48 + label: String,
  49 + isLink: Boolean,
  50 + rightIcon: {
  51 + type: String,
  52 + default: "enter"
  53 + }
  54 + },
  55 + computed: {
  56 + classRender: function() {
  57 + return [this.isLink ? 'zui-cell--clickable' : ''];
  58 + }
  59 + },
  60 + methods: {
  61 + onClick: function() {
  62 + if (this.$listeners["click"]) {
  63 + this.$emit("click");
  64 + }
  65 + }
  66 + }
  67 +};
  68 +</script>
  69 +
  70 +<style lang="scss">
  71 +@import "./index.scss";
  72 +</style>
0 \ No newline at end of file 73 \ No newline at end of file
components/icon/index.scss 0 → 100644
  1 +++ a/components/icon/index.scss
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +.zui-icon {
  2 + position: relative;
  3 + display: inline-block;
  4 + text-rendering: auto;
  5 + -webkit-font-smoothing: antialiased;
  6 +}
  7 +
  8 +.zui-info {
  9 + position: absolute;
  10 + top: 0;
  11 + right: 0;
  12 + box-sizing: border-box;
  13 + min-width: 32upx;
  14 + padding: 0 4upx;
  15 + color: #fff;
  16 + font-weight: 500;
  17 + font-size: 20upx;
  18 + font-family: PingFang SC, Helvetica Neue, Arial, sans-serif;
  19 + line-height: 1.5;
  20 + text-align: center;
  21 + background-color: $color-error;
  22 + border: 1upx solid #fff;
  23 + border-radius: 1rem;
  24 + transform: translate(50%, -50%);
  25 + transform-origin: 100%;
  26 + &.dot {
  27 + height: 24upx;
  28 + width: 24upx;
  29 + min-width: 24upx !important;
  30 + }
  31 +}
components/icon/index.vue 0 → 100644
  1 +++ a/components/icon/index.vue
@@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
  1 +<template>
  2 + <view class="zui-icon" :class="classRender" :style="styleRender">
  3 + <view v-if="info || dot" class="zui-info" :class="dot ? 'dot' : ''">{{ dot ? '' : info }}</view>
  4 + </view>
  5 +</template>
  6 +
  7 +<script>
  8 +export default {
  9 + name: 'zui-icon',
  10 + props: {
  11 + name: {
  12 + type: String,
  13 + default: '',
  14 + },
  15 + fontFamily: {
  16 + type: String,
  17 + default: 'iconfont',
  18 + },
  19 + classPrefix: {
  20 + type: String,
  21 + default: 'icon-'
  22 + },
  23 + size: String,
  24 + color: String,
  25 + info: [Number, String],
  26 + dot: Boolean,
  27 + },
  28 + computed: {
  29 + classRender: function() {
  30 + var fontFamily = this.fontFamily || '';
  31 + var iconClass = this.classPrefix + this.name;
  32 + return [fontFamily, iconClass];
  33 + },
  34 + styleRender: function() {
  35 + return `${this.size ? `font-size: ${this.size};` : ''} ${this.color ? `color: ${this.color}` : ''};`;
  36 + },
  37 + },
  38 +}
  39 +</script>
  40 +
  41 +<style lang="scss">
  42 +@import "./index.scss";
  43 +</style>
0 \ No newline at end of file 44 \ No newline at end of file
components/loading/index.scss 0 → 100644
  1 +++ a/components/loading/index.scss
@@ -0,0 +1,126 @@ @@ -0,0 +1,126 @@
  1 +.zui-loading {
  2 + color: $color-minor;
  3 + display: inline-flex;
  4 + align-items: center;
  5 + justify-content: center;
  6 + &__spinner {
  7 + position: relative;
  8 + display: inline-block;
  9 + width: 50upx;
  10 + max-width: 100%;
  11 + height: 50upx;
  12 + max-height: 100%;
  13 + vertical-align: middle;
  14 + animation: zui-rotate 0.8s linear infinite;
  15 + &--spinner {
  16 + animation-timing-function: steps(12);
  17 + .zui-loading__dot {
  18 + position: absolute;
  19 + top: 0;
  20 + left: 0;
  21 + width: 100%;
  22 + height: 100%;
  23 + &::before {
  24 + display: block;
  25 + width: 2upx;
  26 + height: 25%;
  27 + margin: 0 auto;
  28 + background-color: currentColor;
  29 + border-radius: 40%;
  30 + content: ' ';
  31 + }
  32 + &:nth-of-type(1) {
  33 + transform: rotate(30deg);
  34 + opacity: 1;
  35 + }
  36 + &:nth-of-type(2) {
  37 + transform: rotate(60deg);
  38 + opacity: 0.9375;
  39 + }
  40 + &:nth-of-type(3) {
  41 + transform: rotate(90deg);
  42 + opacity: 0.875;
  43 + }
  44 + &:nth-of-type(4) {
  45 + transform: rotate(120deg);
  46 + opacity: 0.8125;
  47 + }
  48 + &:nth-of-type(5) {
  49 + transform: rotate(150deg);
  50 + opacity: 0.75;
  51 + }
  52 + &:nth-of-type(6) {
  53 + transform: rotate(180deg);
  54 + opacity: 0.6875;
  55 + }
  56 + &:nth-of-type(7) {
  57 + transform: rotate(210deg);
  58 + opacity: 0.625;
  59 + }
  60 + &:nth-of-type(8) {
  61 + transform: rotate(240deg);
  62 + opacity: 0.5625;
  63 + }
  64 + &:nth-of-type(9) {
  65 + transform: rotate(270deg);
  66 + opacity: 0.5;
  67 + }
  68 + &:nth-of-type(10) {
  69 + transform: rotate(300deg);
  70 + opacity: 0.4375;
  71 + }
  72 + &:nth-of-type(11) {
  73 + transform: rotate(330deg);
  74 + opacity: 0.375;
  75 + }
  76 + &:nth-of-type(12) {
  77 + transform: rotate(360deg);
  78 + opacity: 0.3125;
  79 + }
  80 + }
  81 + }
  82 + &--circular {
  83 + border: 1upx solid transparent;
  84 + border-top-color: currentColor;
  85 + border-radius: 100%;
  86 + }
  87 + }
  88 + &__text {
  89 + margin-left: $v-gap-sm;
  90 + color: $color-minor;
  91 + font-size: $font-md;
  92 + }
  93 + &--vertical {
  94 + flex-direction: column;
  95 + .zui-loading__text {
  96 + margin: $h-gap-sm 0 0;
  97 + }
  98 + }
  99 +}
  100 +
  101 +@keyframes zui-circular {
  102 + 0% {
  103 + stroke-dasharray: 1, 200;
  104 + stroke-dashoffset: 0;
  105 + }
  106 +
  107 + 50% {
  108 + stroke-dasharray: 90, 150;
  109 + stroke-dashoffset: -40;
  110 + }
  111 +
  112 + 100% {
  113 + stroke-dasharray: 90, 150;
  114 + stroke-dashoffset: -120;
  115 + }
  116 +}
  117 +
  118 +@keyframes zui-rotate {
  119 + from {
  120 + transform: rotate(0deg);
  121 + }
  122 +
  123 + to {
  124 + transform: rotate(360deg);
  125 + }
  126 +}
components/loading/index.vue 0 → 100644
  1 +++ a/components/loading/index.vue
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +<template>
  2 + <view :class="classRender">
  3 + <view
  4 + :class="innerClassRender"
  5 + :style="styleRender"
  6 + >
  7 + <template v-if="type === 'spinner'">
  8 + <view
  9 + v-for="index in 12"
  10 + :key="index"
  11 + class="zui-loading__dot"
  12 + />
  13 + </template>
  14 + </view>
  15 + <view class="zui-loading__text" :style="textSizeRender">
  16 + <slot v-if="$slots.default"></slot>
  17 + </view>
  18 + </view>
  19 +</template>
  20 +
  21 +<script>
  22 +export default {
  23 + name: 'zui-loading',
  24 + props: {
  25 + color: String,
  26 + size: {
  27 + type: [Number, String],
  28 + default: '2rem'
  29 + },
  30 + vertical: Boolean,
  31 + textSize: [Number, String],
  32 + type: {
  33 + type: String,
  34 + default: 'circular',
  35 + },
  36 + },
  37 + computed: {
  38 + classRender: function() {
  39 + return ['zui-loading', this.type ? `zui-loading--${this.type}` : '', this.vertical ? 'zui-loading--vertical' : ''];
  40 + },
  41 + innerClassRender: function() {
  42 + return ['zui-loading__spinner', `zui-loading__spinner--${this.type}`];
  43 + },
  44 + styleRender: function() {
  45 + const iconSize = typeof this.textSize === 'number' ? this.textSize + 'px' : this.textSize;
  46 + return `color: ${this.color}; width: ${iconSize}; height: ${iconSize}`;
  47 + },
  48 + textSizeRender: function() {
  49 + return `font-size: ${this.textSize}${typeof this.textSize === 'number' ? 'px' : ''};`;
  50 + }
  51 + }
  52 +};
  53 +</script>
  54 +
  55 +<style lang="scss">
  56 +@import "./index.scss";
  57 +</style>
0 \ No newline at end of file 58 \ No newline at end of file
components/tag/index.scss 0 → 100644
  1 +++ a/components/tag/index.scss
@@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
  1 +.zui-tag {
  2 + font-size: $font-sm;
  3 + text-align: center;
  4 + display: inline-block;
  5 + -webkit-user-select: none;
  6 + .default {
  7 + background: rgba(0,0,0,0);
  8 + color: $color-error;
  9 + border-color: $color-error;
  10 + }
  11 + .shape-dot {
  12 + border-radius: 50%;
  13 + height: 32upx;
  14 + width: 32upx;
  15 + &.size-tiny {
  16 + height: 16upx;
  17 + width: 16upx;
  18 + }
  19 + }
  20 + .shape-square {
  21 + padding: 0 $v-gap-sm;
  22 + border-radius: 0;
  23 + }
  24 + .shape-fillet {
  25 + padding: $h-gap-sm $v-gap-sm;
  26 + }
  27 + .shape-bubble {
  28 + width: 50upx;
  29 + padding: 7upx 0;
  30 + border-radius: 50%;
  31 + border-bottom-left-radius: 0;
  32 + box-sizing: border-box;
  33 + &.size-small {
  34 + width: 40upx;
  35 + padding: 5upx 0;
  36 + }
  37 + &.size-tiny {
  38 + width: 30upx;
  39 + padding: 2upx 0;
  40 + }
  41 + }
  42 + .type-fill {
  43 + color: #fff;
  44 + }
  45 + .type-ghost {
  46 + border: 1px solid $color-error;
  47 + background: rgba(0,0,0,0);
  48 + }
  49 + .font-weight-normal {
  50 + font-weight: normal;
  51 + }
  52 + .font-weight-bold {
  53 + font-weight: bold;
  54 + }
  55 + .font-weight-bolder {
  56 + font-weight: bolder;
  57 + }
  58 + .size-large {
  59 + font-size: $font-md;
  60 + }
  61 + .size-small {
  62 + font-size: $font-sm;
  63 + }
  64 + .size-tiny {
  65 + font-size: $font-sm * 0.9;
  66 + }
  67 +}
  68 +
components/tag/index.vue 0 → 100644
  1 +++ a/components/tag/index.vue
@@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
  1 +<template>
  2 + <view class="zui-tag">
  3 + <template v-if="showQuarter">
  4 + <view :class="computedClass">
  5 + <view class="quarter-content">
  6 + <slot></slot>
  7 + </view>
  8 + <view class="quarter-bg" :style="colorStyle"></view>
  9 + </view>
  10 + </template>
  11 + <template v-else-if="showCoupon">
  12 + <view :class="computedClass">
  13 + <view class="coupon-container" :style="colorStyle">
  14 + <view class="left-coupon" :style="leftCoupon" v-if="showCoupon"></view>
  15 + <slot></slot>
  16 + <view class="right-coupon" :style="rightCoupon" v-if="showCoupon"></view>
  17 + </view>
  18 + </view>
  19 + </template>
  20 + <template v-else>
  21 + <view :class="computedClass" :style="[colorStyle, sizeStyle]">
  22 + <slot></slot>
  23 + </view>
  24 + </template>
  25 + </view>
  26 +</template>
  27 +
  28 +<script>
  29 +export default {
  30 + name: "Tag",
  31 + props: {
  32 + size: {
  33 + type: String, // tiny, small, large
  34 + default: "large"
  35 + },
  36 + shape: {
  37 + // square, circle, fillet, quarter, coupon, bubble
  38 + type: String,
  39 + default: "square"
  40 + },
  41 + sharp: {
  42 + // top-left, top-right, bottom-left, bottom-right
  43 + type: String,
  44 + default: ""
  45 + },
  46 + type: {
  47 + // fill ghost
  48 + type: String,
  49 + default: "ghost"
  50 + },
  51 + fillColor: {
  52 + type: String,
  53 + default: ""
  54 + },
  55 + fontWeight: {
  56 + // normal, bold, bolder
  57 + type: String,
  58 + default: "normal"
  59 + },
  60 + fontColor: {
  61 + type: String,
  62 + default: ""
  63 + },
  64 + dotSize: String,
  65 + radius: String,
  66 + },
  67 + data: function() {
  68 + return {
  69 + sizeStyle: {}
  70 + };
  71 + },
  72 + mounted: function() {
  73 + this.$nextTick(function() {
  74 + if (this.shape == "circle") {
  75 + var radius = this.$el.offsetHeight / 2;
  76 + this.$set(this.sizeStyle, "paddingLeft", radius / 2 + "px");
  77 + this.$set(this.sizeStyle, "paddingRight", radius / 2 + "px");
  78 + this.$set(this.sizeStyle, "borderRadius", radius + "px");
  79 + if (this.sharp) {
  80 + this.$set(
  81 + this.sizeStyle,
  82 + this.transformCamelCase("border-" + this.sharp + "-radius"),
  83 + 0
  84 + );
  85 + }
  86 + }
  87 + });
  88 + },
  89 + computed: {
  90 + computedClass: function() {
  91 + return [
  92 + "default",
  93 + "size-" + this.size,
  94 + "shape-" + this.shape,
  95 + "type-" + this.type,
  96 + "font-weight-" + this.fontWeight
  97 + ];
  98 + },
  99 + colorStyle: function() {
  100 + var style = {};
  101 + if (this.type == "fill") {
  102 + // eslint-disable-next-line
  103 + style.background = this.fillColor || '#ff5151';
  104 + }
  105 + if (this.shape == 'dot') {
  106 + style.height = this.dotSize;
  107 + style.width = this.dotSize;
  108 + style.display = 'flex';
  109 + style.alignItems = 'center';
  110 + style.justifyContent = 'center';
  111 + }
  112 + if (this.fontColor) {
  113 + if (this.type == "ghost") {
  114 + style.borderColor = this.fontColor;
  115 + }
  116 + style.color = this.fontColor;
  117 + }
  118 + if (this.radius) {
  119 + style.borderRadius = this.radius;
  120 + }
  121 + return style;
  122 + },
  123 + leftCoupon: function() {
  124 + return {
  125 + background: this.fillColor
  126 + ? "radial-gradient(circle at left, transparent 33%, " +
  127 + this.fillColor +
  128 + " 33%)"
  129 + : ""
  130 + };
  131 + },
  132 + rightCoupon: function() {
  133 + return {
  134 + background: this.fillColor
  135 + ? "radial-gradient(circle at right, transparent 33%, " +
  136 + this.fillColor +
  137 + " 33%)"
  138 + : ""
  139 + };
  140 + },
  141 + showQuarter: function() {
  142 + return this.shape == "quarter";
  143 + },
  144 + showCoupon: function() {
  145 + return this.shape == "coupon";
  146 + }
  147 + },
  148 + methods: {
  149 + transformCamelCase: function(str) {
  150 + var re = /-(\w)/g;
  151 + return str.replace(re, function($0, $1) {
  152 + return $1.toUpperCase();
  153 + });
  154 + },
  155 + }
  156 +};
  157 +</script>
  158 +
  159 +<style lang="scss">
  160 +@import "./index.scss";
  161 +</style>
0 \ No newline at end of file 162 \ No newline at end of file
index.js 0 → 100644
  1 +++ a/index.js
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +import Amount from './components/amount';
  2 +import Button from './components/button';
  3 +import Cell from './components/cell';
  4 +import Icon from './components/icon';
  5 +import Loading from './components/loading';
  6 +import Tag from './components/tag';
  7 +
  8 +export default {
  9 + Amount,
  10 + Button,
  11 + Cell,
  12 + Icon,
  13 + Loading,
  14 + Tag
  15 +};
0 \ No newline at end of file 16 \ No newline at end of file
package.json 0 → 100644
  1 +++ a/package.json
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +{
  2 + "name": "zui-uniapp",
  3 + "version": "1.0.0",
  4 + "main": "index.js",
  5 + "repository": "git@114.55.84.72:frontend/zui-uniapp.git",
  6 + "author": "刘汉宸 <liuhanchen@zeyihuoyun.com>",
  7 + "license": "MIT",
  8 + "private": true
  9 +}