10 Commits

Author SHA1 Message Date
e2hang
b52398f22f HuajisheHealthDaemon V1.0 2026-02-21 08:54:28 +08:00
e2hang
f6c025ed5e New APP PhotoSaver 2026-02-08 21:37:41 +08:00
e2hang
cc4bbbb3a6 New Tool: JsonParser 2026-01-12 10:50:17 +08:00
e2hang
d143bbc65c Renew Projects 2025-12-31 13:22:56 +08:00
e2hang
4b60ced553 deleted build 2025-12-30 20:11:29 +08:00
e2hang
3734ffcc35 SnakeGame 2025-12-30 19:59:45 +08:00
e2hang
fd77d3aca9 EditorSDL 2025-12-24 13:15:25 +08:00
e2hang
4ef0464969 SDL3.3.6 2025-12-22 15:45:29 +08:00
e2hang
6a82badf77 About LISENCES 2025-10-07 20:56:20 +08:00
e2hang
80be8ae3cf New Huajishe Check ChaoXing 2025-10-01 10:01:52 +08:00
3039 changed files with 1377281 additions and 0 deletions

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1,25 @@
#include <iostream>
#include <cstring>
#include "delivery_method.h"
#include "package.h"
#include "user.h"
#include "stock.h"
class Package;
Method::Method() {
pkg = new Package;
money = 0;
danger = false;
}
Method::Method(Package* x, double m, bool b) {
pkg = x;
money = m;
danger = b;
}
void Method::fee() {
money = pkg->create_fee();
}
void Method::set_yndanger(bool flag) {
danger = flag;
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <iostream>
#include "user.h"
#include "package.h"
#include "stock.h"
class Package;
class Method {
private:
Package* pkg;
double money;
bool danger;
public:
Method();
Method(Package* x, double m, bool b);
void fee();
void set_yndanger(bool flag);
};

View File

@@ -0,0 +1,30 @@
#include <iostream>
#include "exception.h"
using std::cout;
using std::endl;
/*
std::string Exception::User_Phone_Number_Error() {
return "电话号码不是11位数字请重新输入";
}
std::string Exception::Package_Time_Format_Error() {
return "输入时间格式不正确请按照2025-05-10-10-05-00的格式输入";
}
std::string Exception::Stock_Used_More_Than_All_Error() {
return "货架可存储量大于使用量!请检查输入是否正确!";
}
*/
std::runtime_error Etest::User_Phone_Number_Error() {
return std::runtime_error("电话号码不是11位数字请重新输入");
}
std::runtime_error Etest::Package_Time_Format_Error()
{
return std::runtime_error("输入时间格式不正确请按照2025-05-10-10-05-00的格式输入");
}
std::runtime_error Etest::Stock_Used_More_Than_All_Error()
{
return std::runtime_error("货架可存储量大于使用量!请检查输入是否正确!");
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <iostream>
#include <cstring>
#include <stdexcept>
/*
class Exception {
public:
std::string User_Phone_Number_Error();
std::string Package_Time_Format_Error();
std::string Stock_Used_More_Than_All_Error();
};*/
class Etest : public std::runtime_error{
public:
static std::runtime_error User_Phone_Number_Error();
static std::runtime_error Package_Time_Format_Error();
static std::runtime_error Stock_Used_More_Than_All_Error();
};

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1,217 @@
/*
Developed By
...:::^^^^^^^^^:::..
.::^^~~~~~~~~~~~~~~~~~^::..
.:~?JYY?~^~^^^^^^^~~~~~~~~?YYJ?!:.
.:!7!!!7J5!^^^^^^^^^^^^~^!5Y7!!!7!^:.
.:^~~~~^^^^~7^^^^^^^^^^^^^^7!^~~~~~~~~:.
.:~!!^::::::::^^::::::::^^^!!^::::^^^~~~^:.
.:::5GGY. ..::::::^::YGG5. .^^:.
.^:.7YY7:::::::....::..::^..!YY?^:^^:::....^~:.
:~~~^^^^~~^^^:::::......:::^:^^^~~~~~~~~~~~!~^.
.:~~~~~~~~~~^^:::........:::::^^^~~~~~~~~~~~!~^:
.^~~~~~~^^^^^^:::::::::::::::^^^^^~~~~~~~~~~!~^:
.^~~~~~~^^^^^^^::::::::::::^^^^^^^~~~~~~~~~~!~^:
.:~~~~~7!^^^^^^^^^^^:::^^^^^^^^^~~~~~~~7!~~!!~^.
.^~~~~!J!^^^^^^^^^^^^^^^^^^^^~~~~~~~~?J~~!!!~:.
.:^~~~~!Y?~^^~~^^^^^^^^^^^~~~~~~~~~7YJ!~!!!~^.
.:^~~~~~J5J7~~^^^^~~~~~~~~~~~~~!?YY?~~!!!~^.
.:^~~~~~!?Y55J?7!!~~~~~~!77JY55Y7~~!!!~~:.
.:^~~~~~~!7JY555P5555P555Y?7!~~!!!!~^:.
.:^~~!~~~~~~~!!!!!!!!~~~~~!!!!~~^:.
.::^~~!!!!!~~~~~~!!!!!!!!~~^:..
..:^^~~~~~~!!!~~~~~^^::..
....:::::::::...
*/
#include <iostream>
#include <cstring>
#include <stdexcept>
#include "package.h"
#include "user.h"
#include "stock.h"
#include "delivery_method.h"
#include "exception.h"
#define Endl std::endl
//Exception E;
Package* k;
User* p;
std::string Crypt(std::string x, std::string y);
using std::cin;
using std::cout;
using std::endl;
using std::string;
extern Stock cainiao[10];
extern User temp;
extern void PRINT_LIU_YING();
int main() {
//先print一下哈哈
//PRINT_LIU_YING();
//初始化人员列表
p = new User[20];
p[1].reg("Zhang", "111111198301", "000011");
p[2].reg("Wang", "12211198301", "000012");
p[3].reg("Li", "13311198301", "000013");
p[4].reg("Zhao", "14411198301", "000014");
p[5].reg("Sun", "15511198301", "000015");
p[6].reg("Zhou", "16611198301", "000016");
p[7].reg("Xu", "17711198301", "000017");
p[8].reg("Wan", "18811198301", "000018");
p[9].reg("Liu", "19911198301", "000019");
p[10].reg("Su", "10011198301", "000020");
p[11].reg("Green", "10111198301", "000021");
//测试检测手机号是否为11位功能
/*旧版
try {
std::string test01, test02, test03;
test01 = "ERROR";
test02 = "98301";
test03 = "000022";
p[12].reg(test01, test02, test03);
if (test02.size() != 11) {
throw E.User_Phone_Number_Error();
delete &p[12];
}
}
catch (const std::string& x) {
cout << x << endl;
}*/
//新版
try {
std::string test01, test02, test03;
test01 = "ERROR";
test02 = "98301";
test03 = "000022";
p[12].reg(test01, test02, test03);
if (test02.size() != 11) {
throw Etest::User_Phone_Number_Error();
delete& p[12];
}
}
catch (const std::runtime_error& x) {
cout << x.what() << endl;
}
k = new Package[TOTAL0];
k[1] = Package("Dildo", "pid1919810", "2025-05-08-00-00-00", "2025-05-09-10-00-00", &temp, 5.4, 10.0, 10.3, false);
k[2] = Package("Clothes", "10002", "2025-05-06-14-15-00", "2025-05-08-11-30-00", &p[2], 1.5, 8.0, 5.6, false);
k[3] = Package("Laptop", "10003", "2025-05-05-10-00-00", "2025-05-06-09-20-00", &p[3], 3.0, 15.0, 20.2, false);
k[4] = Package("Shoes", "10004", "2025-05-07-16-00-00", "2025-05-09-08-00-00", &p[4], 2.8, 9.5, 6.1, false);
k[5] = Package("Snacks", "10005", "2025-05-08-09-45-00", "2025-05-09-14-00-00", &p[5], 1.2, 5.0, 3.7, false);
k[6] = Package("Monitor", "10006", "2025-05-06-11-20-00", "2025-05-07-10-10-00", &p[6], 6.5, 20.0, 18.9, false);
k[7] = Package("Tablet", "10007", "2025-05-07-13-50-00", "2025-05-08-17-00-00", &p[3], 1.8, 14.0, 10.5, false);
k[8] = Package("Camera", "10008", "2025-05-05-07-30-00", "2025-05-06-08-00-00", &p[3], 2.6, 11.0, 9.2, false);
k[9] = Package("Glasses", "10009", "2025-05-06-12-00-00", "2025-05-07-15-30-00", &p[9], 0.8, 4.0, 2.0, false);
k[10] = Package("Headphones", "10010", "2025-05-08-10-00-00", "2025-05-09-13-00-00", &p[10], 1.1, 6.0, 4.4, false);
k[11] = Package("Books", "10011", "2025-05-07-08-30-00", "2025-05-08-10-00-00", &p[1], 2.3, 12.5, 8.0, false);
//测试用户系统
cout << "Display User :" << endl;
temp.display();
p[2].display();
cout << "Alter p2" << Endl;
p[2].alt_name("W..");
p[2].alt_pn("110");
p[2].display();
cout << "测试结束" << endl;
cout << endl;
//测试包裹存储驿站、超额警报
cout << "检测: Stock k1 ~ k11 to Stock0, Stock1" << Endl;
cainiao[0].inStock(k[1]);
cainiao[0].inStock(k[2]);
cainiao[0].inStock(k[3]);
cainiao[0].inStock(k[4]);
cainiao[0].inStock(k[5]);
cainiao[0].inStock(k[6]);
cainiao[0].inStock(k[7]);
cainiao[0].inStock(k[8]);
cainiao[0].inStock(k[9]);
cainiao[1].inStock(k[10]);
cainiao[1].inStock(k[11]);
cout << "已存入" << Endl;
cout << "展示库存DisPlay Stock" << Endl;
for (int i = 0;i < 10;i++) {
cout << *(cainiao[0].Check_ProductAll() + i) << " ";
}
cout << Endl;
for (int i = 0;i < 10;i++) {
cout << *(cainiao[1].Check_ProductAll() + i) << " ";
}
cout << endl;
cout << "测试结束" << endl;
//测试取出包裹的对应
//k1.display();
cout << "测试取出包裹的对应" << Endl;
k[1].create_vc();
string Code = Crypt(temp.Check_uid(), k[1].Check_pid());
k[1].verifing(Code, "2025-05-10-10-00-00");
k[1].display();
cout << endl;
cout << "展示库存变化" << Endl;
for (int i = 0;i < 10;i++) {
cout << *(cainiao[0].Check_ProductAll() + i) << " ";
}
cout << Endl;
for (int i = 0;i < 10;i++) {
cout << *(cainiao[1].Check_ProductAll() + i) << " ";
}
cout << Endl;
//向空Stock加入包裹从小往上加
cout << "测试向空Stock加入包裹从小往上加" << endl;
cainiao[0].inStock(k[1]);
for (int i = 0;i < 10;i++) {
cout << *(cainiao[0].Check_ProductAll() + i) << " ";
}
cout << Endl;
for (int i = 0;i < 10;i++) {
cout << *(cainiao[1].Check_ProductAll() + i) << " ";
}
cout << "测试结束" << endl;
cout << Endl;
//查询用户的包裹
cout << "测试查询用户包裹" << Endl;
int dw = 3;
cout << " 先展示用户信息" << endl;
p[dw].display();
cout << "再展示货物信息" << Endl;
k[3].display();
cout << "下面开始查询" << Endl;
Package* pkgs = p[dw].Check_Package();
for (int i = 0;i < TOTAL0 - 1;i++){
if(pkgs[i].Check_pid() != "#UNDEFINED_P:P" )
cout << pkgs[i].Check_pid() << " ";
}
cout << Endl;
//查询包裹状态,拥有者
k[2].display();
//测试付费系统
cout << "Test Over" << endl;
return 0;
}

View File

@@ -0,0 +1,144 @@
#include <iostream>
#include <cstring>
#include "package.h"
#include "user.h"
extern std::string Crypt(std::string x,std::string y){
std::string temp;
temp = x;
int t;
t = (int)y[0];
t /= 5;
for (int i = 0;i < x.size();i++) {
temp[i] += t;
}
return temp;
}
Package::Package() {
name = "#UNDEFINED_N:P";
pid = "#UNDEFINED_P:P";
owner = new User;
jichu_time = "#UNDEINFED_JT:P";
songda_time = "#UNDEINFED_SD:P";
quhuo_time = "#UNDEFINED_QH:P";
is_picked = false;
volume = -1;
mass = -1;
distance = -1;
stockin = NULL;
stock_num = 0;
is_vfast = false;
}
Package::Package(std::string n, std::string pi, std::string j, std::string s, User* o, double v, double m, double d,bool v0) {
//owner = new User;
name = n;
pid = pi;
owner = o;
jichu_time = j;
songda_time = s;
quhuo_time = "#REQUIRD";
is_picked = false;
volume = v;
distance = d;
mass = m;
is_vfast = v0;
stockin = NULL;
stock_num = 0;
}
//有Bug懒得改了尽量不用用Stock里面的inStock
Package& Package::stocked(Stock* x) {
stockin = x;
stock_num = x->Check_used();
x->inStock(*this);
if (pid == x->Check_Product(x->Check_used())) {
cout << "Successfully Stocked" << endl;
}
else {
cout << "Stock Error! Please Try Again" << endl;
}
return *this;
}
void Package::create_vc() {
verify_code = Crypt(owner->Check_uid(), pid);
cout << "Verify Code Created" << endl;
}
void Package::verifing(std::string n,std::string time) {
if (verify_code == n) {
quhuo_time = time;
is_picked = true;
stockin->outStock(*this);
return;
}
else {
cout << "Verify Code WRONG!" << endl;
return;
}
if (stockin->Check_Product(stock_num) == "-1") {
cout << "Successfully Picked!" << endl;
}
else {
cout << "Can't Be Selected" << endl;
}
}
Package& Package::alter_stock_num(int n) {
stock_num = n;
return *this;
}
Package& Package::alter_stockin(Stock& x) {
stockin = &x;
return *this;
}
std::string Package::Check_pid() {
return pid;
}
std::string Package::Check_vc() {
return verify_code;
}
int Package::Check_stock_num() {
return stock_num;
}
User* Package::Check_User() {
return owner;
}
double Package::create_fee() {
double fee;
if (!is_vfast) fee = 5 * mass + 0.5 * volume;
if (is_vfast) fee = 1.3 * (5 * mass + 0.5 * volume);
return fee;
}
Package& Package::operator=(const Package& x) {
name = x.name;
pid = x.pid;
owner = x.owner;
jichu_time = x.jichu_time;
songda_time = x.songda_time;
quhuo_time = x.quhuo_time;
is_picked = x.is_picked;
verify_code = x.verify_code;
volume = x.volume;
mass = x.mass;
distance = x.distance;
is_vfast = x.is_vfast;
stockin = x.stockin;
stock_num = x.stock_num;
return *this;
}
void Package::display() {
cout << "Package Name : " << name << endl;
cout << "Package Pid : " << pid << endl;
cout << "Package Owner : (Displayed Down)" << endl;
owner->display();
cout << "Package jichu_time : " << jichu_time << endl;
cout << "Package songda_time : " << songda_time << endl;
cout << "Package quhuo_time : " << quhuo_time << endl;
cout << "Package Picked? : " << is_picked << endl;
cout << "Package Mass : " << mass << endl;
cout << "Package Volume : " << volume << endl;
cout << "Package Distance : " << distance << endl;
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include <iostream>
#include <cstring>
#include "user.h"
#include "stock.h"
using std::cin;
using std::cout;
using std::endl;
using std::string;
class User;
class Stock;
class Package {
private:
std::string name;
std::string pid;//auto
User* owner;
std::string jichu_time;
std::string songda_time;//time format: 2025-05-08-23-15-03(eazy to cmp and check)
std::string quhuo_time;
bool is_picked;
std::string verify_code;
double volume;
double mass;
double distance;
bool is_vfast;
Stock* stockin;
int stock_num;
public:
Package();
Package(std::string n, std::string pid, std::string j, std::string s, User* o,double v , double m, double d,bool v0);
void create_vc();
void verifing(std::string n, std::string time);
std::string Check_pid();
std::string Check_vc();
double create_fee();
int Check_stock_num();
void display();
Package& stocked(Stock* x);
Package& alter_stock_num(int n);
Package& alter_stockin(Stock& x);
User* Check_User();
Package& operator=(const Package& x);
};

View File

@@ -0,0 +1,97 @@
#include <iostream>
#include <cstring>
#include "stock.h"
#include "user.h"
#include "package.h"
class Package;
int min(int a, int b) {
return a > b ? b : a;
}
Stock::Stock() {
all = 10;
used = 0;
for (int i = 0;i < 10;i++) {
pid_code[i] = "-1";
}
}
Stock::Stock(int a, int l, int* p) {
all = a;
used = l;
for (int i = 0;i < 10;i++) {
pid_code[i] = *(p + i);
}
}
int Stock::Check_used() {
return used;
}
Stock& Stock::inStock(Package& x) {
if (used != ALL0 && all - used > (int)(all * 0.2)) {
int tmp = 0;
for (int i = 0;i < ALL0;i++) {
if (this->pid_code[i] == "-1") {
tmp = i;
break;
}
}
pid_code[tmp] = x.Check_pid();
x.alter_stock_num(tmp);
x.alter_stockin(*this);
used++;
return *this;
}
else if (all - used <= (int)(all * 0.2)) {
int tmp = 0;
for (int i = 0;i < ALL0;i++) {
if (this->pid_code[i] == "-1") {
tmp = i;
break;
}
}
pid_code[tmp] = x.Check_pid();
x.alter_stock_num(tmp);
x.alter_stockin(*this);
used++;
this->alert();
return *this;
}
else {
cout << "This Stock is FULL. Search for Another One" << endl;
return *this;
}
}
Stock& Stock::outStock(Package& x) {
//Óðü¹ü¶ÔÏóÈ¡»õ
int s = x.Check_stock_num();
if (s >= 0 && s <= ALL0) {
pid_code[s] = "-1";
this->refresh();
}
return *this;
}
//x=pid
Stock& Stock::refresh() {
int cnt = 0;
for (int i = 0;i < ALL0;i++) {
if (pid_code[i] == "-1") {
cnt++;
}
}
cnt = used;
return *this;
}
Stock& Stock::alert() {
cout << "This Stock is ALMOST FULL." << endl;
return *this;
}
std::string Stock::Check_Product(int n) {
return pid_code[n-1];
}
std::string* Stock::Check_ProductAll() {
return pid_code;
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include <iostream>
#include "user.h"
#include "package.h"
#define USED0 0
#define ALL0 10
#define TOTAL0 100
#define STOCK_NUM 10
/*默认:
all(这个货架能放几个货物) =10
used = 0
后期可在配置文件中调整
*/
class Package;
class Stock {
private:
int all;
int used;
std::string pid_code[ALL0];
public:
Stock();
Stock(int a, int l, int* p);
Stock& inStock(Package& x);//x=pid
//Stock& outStock(std::string x);//x=pid
Stock& refresh();
Stock& alert();
int Check_used();
std::string Check_Product(int n);
std::string* Check_ProductAll();
Stock& outStock(Package& x);
};

View File

@@ -0,0 +1,135 @@
#include <iostream>
#include <cstring>
#include "package.h"
#include "user.h"
#include "stock.h"
class Package;
class Stock;
extern Stock cainiao[STOCK_NUM];
extern Package* k;
//Package package_num();//用Package类
User::User() {
name = "#UNDEFINED_N";
phone_num = "#UNDEFINED_P";
uid = "#UNDEFINED_U";
jingyan = -1;
}
User::User(std::string n, std::string p, std::string u) {
name = n;
phone_num = p;
uid = u;
jingyan = 0;
}
User& User::reg(std::string n, std::string p, std::string u) {
name = n;
phone_num = p;
uid = u;
jingyan = 0;
if (p.size() == 11) cout << n + ", Your are registered!" << endl;
else
{
cout << "Hello " + n + " ";
}
return *this;
}
User& User::alt_name(string n) {
name = n;
cout << "Name altered to " + n << endl;
return *this;
}
User& User::alt_pn(string p) {
phone_num = p;
cout << "Phone Number altered to " + p << endl;
return *this;
}
void User::del() {
name = "#DELETED_" + name;
phone_num = "#DELETED_" + phone_num;
uid = "#DELETED_" + uid;
cout << "User Deleted" << endl;
}
void User::display() {
cout << " Name :" + name << endl;
cout << " Phone Number: " + phone_num << endl;
cout << " uid :" + uid << endl;
}
std::string User::Check_uid() {
return uid;
}
std::string User::Check_name() {
return name;
}
std::string User::Check_phone() {
return phone_num;
}
User& User::operator=(const User& x) {
name = x.name;
phone_num = x.phone_num;
uid = x.uid;
jingyan = x.jingyan;
return *this;
}
bool User::operator==(const User& x) {
if (name == x.name &&
phone_num == x.phone_num &&
uid == x.uid &&
jingyan == x.jingyan
)
return true;
else
return false;
}
Package* User::Check_Package() {
Package *tp = new Package [TOTAL0];
int cnt = 0;
cout << "Chekcing Packages" << endl;
for (int i = 0;i < TOTAL0; i++) {
//extern k[i]的问题,查询系统是正确的
if (*(k[i].Check_User()) == *this) {
tp[cnt] = k[i];
//cout << "YES" << endl;
cnt++;
}
}
if (cnt == 0) {
cout << "没有查询到包裹" << endl;
}
return tp;
}
User& User::add_exp(int s) {
jingyan += s;
return *this;
}
User& User::refresh() {
if (jingyan >= 100) {
VIP* temp = new VIP;
temp->reg(*this);
return *temp;
}
return *this;
}
VIP::VIP() {
flag = true;
}
VIP::VIP(User& x,bool f) : User(x.Check_name(), x.Check_phone(),x.Check_uid()) {
flag = f;
}
VIP& VIP::reg(User& x){
flag = true;
return *this;
}
User::~User() {
//delete[] temp;
}

View File

@@ -0,0 +1,47 @@
#pragma once
#include <iostream>
#include <cstring>
#include "package.h"
#include "stock.h"
class Package;
class User {
private:
std::string name;
std::string phone_num;
//这里先不使用,后面可以直接统计包裹//用Package类
std::string uid;//外部存储user总数user的uid最大值
int jingyan;
public:
User();
User(std::string n, std::string p, std::string u);
~User();
User& reg(std::string n, std::string p, std::string u);
User& alt_name(std::string n);
User& alt_pn(std::string p);
void del();
std::string Check_uid();
void display();
std::string Check_name();
std::string Check_phone();
User& add_exp(int s);
User& refresh();
Package* Check_Package();
User& operator=(const User& x);
bool operator==(const User& x);
};
class VIP : public User {
private:
//std::string name;
//std::string phone_num;
//std::string uid;
//int jingyan;
bool flag;
public:
VIP();
VIP(User& x, bool f);
VIP& reg(User& x);
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1,21 @@
FROM node:lts-alpine
ENV TZ=Asia/Shanghai
RUN apk add --no-cache tzdata \
&& cp /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& apk del tzdata
WORKDIR /app
COPY package*.json ./
RUN npm config set strict-ssl false \
&& npm install --omit=dev
COPY . ./
EXPOSE 8080
CMD [ "node", "ci.js" ]

View File

@@ -0,0 +1,22 @@
FROM node:lts-alpine
ENV TZ=Asia/Shanghai
RUN apk add --no-cache tzdata \
&& cp /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& apk del tzdata
WORKDIR /app
COPY package*.json ./
RUN npm config set registry https://mirrors.huaweicloud.com/repository/npm/ \
&& npm config set strict-ssl false \
&& npm install --omit=dev
COPY . ./
EXPOSE 8080
CMD [ "node", "ci.js" ]

View File

@@ -0,0 +1,3 @@
# 小程序端部署教程
已迁移到 [官方文档](https://doc.micono.eu.org/advance/miniprogram.html)

View File

@@ -0,0 +1,81 @@
import config from '@utils/config';
import util from '@utils/util';
import log from '@utils/log';
import baidu_sdk from '@utils/sdk/mtj-wx-sdk';
App({
onLaunch(options) {
log.info("App 启动参数", options)
this.autoUpdate();
this.setCaptureListener();
},
autoUpdate() { // 更新小程序
if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager();
updateManager.onCheckForUpdate(res => {
if (res.hasUpdate) {
wx.showModal({
title: '更新提示',
content: '检测到新版本,是否下载新版本并重启小程序?',
showCancel: false, // 隐藏取消按钮
confirmText: "确定更新", // 只保留确定更新按钮
complete: () => {
wx.showLoading();
updateManager.onUpdateReady(function () {
wx.hideLoading()
updateManager.applyUpdate()
})
updateManager.onUpdateFailed(function () {
wx.showModal({
title: '已经有新版本了哟~',
content: '新版本已经上线啦~,请您重新打开当前小程序哟~',
})
})
}
})
}
})
}
else {
wx.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
},
setCaptureListener() { // 监听截屏事件
wx.onUserCaptureScreen(() => {
return {
'query': "from=capture",
'promise': new Promise(resolve => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1]; // 当前页面
const query = Object.entries({
...currentPage.options,
'from': 'capture',
})
.map(([key, value]) => `${key}=${value}`)
.join('&');
log.info("用户截屏", {
"route": currentPage.route,
'query': query,
})
util.showInfo("您已截屏\n请注意隐私安全")
resolve({
'query': query,
})
})
}
})
wx.onScreenRecordingStateChanged(res => {
if (res.state == 'start')
util.showInfo("您正在录屏\n请注意隐私安全")
if (res.state == 'stop')
util.showInfo("您已录屏\n请注意隐私安全")
})
},
})

View File

@@ -0,0 +1,24 @@
{
"pages": [
"pages/home/home"
],
"resolveAlias": {
"~/*": "/*",
"@utils/*": "utils/*"
},
"requiredPrivateInfos": [
"chooseLocation",
"getLocation"
],
"permission": {
"scope.userLocation": {
"desc": "获取您的位置用于签到"
}
},
"window": {
"backgroundTextStyle": "light",
"navigationStyle": "custom"
},
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}

View File

@@ -0,0 +1,5 @@
{
"adapteByMiniprogram": {
"userName": "gh_e0e47fd2af64"
}
}

View File

@@ -0,0 +1,12 @@
/**app.wxss**/
page {
background: #f6f6f6;
}
.shadow-radius {
box-shadow: 0rpx 8rpx 10rpx -5rpx rgba(0, 0, 0, 0.08), 0rpx 16rpx 24rpx 2rpx rgba(0, 0, 0, 0.04), 0rpx 6rpx 30rpx 5rpx rgba(0, 0, 0, 0.05);
border-radius: 20rpx;
--td-button-border-radius: 20rpx;
overflow: hidden;
}

147
HuajisheCheckChaoXing/ci.js Normal file
View File

@@ -0,0 +1,147 @@
const ci = require('miniprogram-ci');
const express = require('express');
const axios = require('axios');
const fs = require('fs');
const app = express();
const port = 8080;
app.use(express.urlencoded({
extended: true
}));
const task = {
"appid": null,
"result": null,
};
/**
* 上传小程序
*/
app.post('/ci/upload', (req, res) => {
const {
appid,
key,
mobile,
callback
} = req.body;
if (task.appid) {
res.json(task)
if (task.result != 'doing')
process.exit(0);
} else {
task.appid = appid;
task.result = "doing";
res.json(task)
console.info(` ------ ✨ 开始执行编译上传 ${appid} ${new Date().toLocaleString()} ------ `);
upload(appid, key, mobile)
.then(res => {
task.appid = res.appid;
task.result = res.result;
task.mobile = mobile || null;
task.key = res.key || null;
console.info(` ------ 🎉 小程序上传完成 ${res.appid} ${res} ------ `);
if (res.result == "done" && callback)
axios.post(callback, task, {
params: {
"appid": appid,
}
})
.then(resp => { })
.catch(e => { });
})
}
});
/**
* 获取任务状态
*/
app.get("/ci/status", (req, res) => {
res.json({
"status": 0,
"msg": `服务正常,当前任务 ${task.appid || "无"} ${task.result || ""}`,
})
})
/**
* 停止服务
*/
app.post('/ci/stop', (req, res) => {
task.result = "fail";
res.json(task);
process.exit(0);
})
const server = app.listen(port, () => {
console.info(` ------ ✨ CI服务已启动端口 ${port},正在等待任务 ------ `);
});
server.setTimeout(3 * 60 * 1000);
process.on('SIGTERM', () => {
server.close(() => { })
})
/**
* 上传小程序
* @param {*} appid
* @param {*} privateKey
* @param {*} username
* @returns
*/
const upload = (appid, privateKey, username) => {
const formate = (key) => {
key = key.replace(/\n/g, '').replace(/\r/g, '');
const header = "-----BEGIN RSA PRIVATE KEY-----";
const footer = "-----END RSA PRIVATE KEY-----";
key = key.replace(header, '').replace(footer, '').trim();
let formattedKey = '';
for (let i = 0; i < key.length; i += 64)
formattedKey += key.substr(i, 64) + '\n';
return header + '\n' + formattedKey + footer;
}
return new Promise(async resolve => {
const privateKeyPath = `/tmp/miniprogram-${appid}.private.key`;
privateKey = formate(privateKey);
fs.writeFileSync(privateKeyPath, privateKey);
fs.writeFileSync("./utils/ci.config.js", `module.exports = {username: '${username}'}`)
try {
const now = new Date();
await ci.upload({
project: new ci.Project({
appid: appid,
type: 'miniProgram',
projectPath: './',
privateKeyPath: privateKeyPath,
ignores: [],
}),
version: `开源版 v0.${now.getFullYear()}.${String(now.getMonth() + 1).padStart(2, '0')}.${String(now.getDate()).padStart(2, '0')}`,
robot: Number(process.env.ROBOT || "5"),
desc: "御坂网络 Misaka",
setting: {
es6: true,
es7: true,
minify: true,
codeProtect: true,
ignoreUploadUnusedFiles: true,
},
onProgressUpdate: res => {
if (res._status != "doing") {
fs.unlink(privateKeyPath, () => { });
console.info(` ------ ✨ 编译上传结果 ${res} ------ `);
resolve(Object.assign(res, {
"appid": appid,
"result": res._status,
"key": privateKey,
}))
}
}
})
} catch (err) {
resolve({
'appid': appid,
"result": String(err),
})
}
})
}

View File

@@ -0,0 +1,147 @@
const ci = require('miniprogram-ci');
const express = require('express');
const axios = require('axios');
const fs = require('fs');
const app = express();
const port = 8080;
app.use(express.urlencoded({
extended: true
}));
const task = {
"appid": null,
"result": null,
};
/**
* 上传小程序
*/
app.post('/ci/upload', (req, res) => {
const {
appid,
key,
mobile,
callback
} = req.body;
if (task.appid) {
res.json(task)
if (task.result != 'doing')
process.exit(0);
} else {
task.appid = appid;
task.result = "doing";
res.json(task)
console.info(` ------ ✨ 开始执行编译上传 ${appid} ${new Date().toLocaleString()} ------ `);
upload(appid, key, mobile)
.then(res => {
task.appid = res.appid;
task.result = res.result;
task.mobile = mobile || null;
task.key = res.key || null;
console.info(` ------ 🎉 小程序上传完成 ${res.appid} ${res} ------ `);
if (res.result == "done" && callback)
axios.post(callback, task, {
params: {
"appid": appid,
}
})
.then(resp => { })
.catch(e => { });
})
}
});
/**
* 获取任务状态
*/
app.get("/ci/status", (req, res) => {
res.json({
"status": 0,
"msg": `服务正常,当前任务 ${task.appid || "无"} ${task.result || ""}`,
})
})
/**
* 停止服务
*/
app.post('/ci/stop', (req, res) => {
task.result = "fail";
res.json(task);
process.exit(0);
})
const server = app.listen(port, () => {
console.info(` ------ ✨ CI服务已启动端口 ${port},正在等待任务 ------ `);
});
server.setTimeout(3 * 60 * 1000);
process.on('SIGTERM', () => {
server.close(() => { })
})
/**
* 上传小程序
* @param {*} appid
* @param {*} privateKey
* @param {*} username
* @returns
*/
const upload = (appid, privateKey, username) => {
const formate = (key) => {
key = key.replace(/\n/g, '').replace(/\r/g, '');
const header = "-----BEGIN RSA PRIVATE KEY-----";
const footer = "-----END RSA PRIVATE KEY-----";
key = key.replace(header, '').replace(footer, '').trim();
let formattedKey = '';
for (let i = 0; i < key.length; i += 64)
formattedKey += key.substr(i, 64) + '\n';
return header + '\n' + formattedKey + footer;
}
return new Promise(async resolve => {
const privateKeyPath = `/tmp/miniprogram-${appid}.private.key`;
privateKey = formate(privateKey);
fs.writeFileSync(privateKeyPath, privateKey);
fs.writeFileSync("./utils/ci.config.js", `module.exports = {username: '${username}'}`)
try {
const now = new Date();
await ci.upload({
project: new ci.Project({
appid: appid,
type: 'miniProgram',
projectPath: './',
privateKeyPath: privateKeyPath,
ignores: [],
}),
version: `开源版 v0.${now.getFullYear()}.${String(now.getMonth() + 1).padStart(2, '0')}.${String(now.getDate()).padStart(2, '0')}`,
robot: 1,
desc: "御坂网络 Misaka",
setting: {
es6: true,
es7: true,
minify: true,
codeProtect: true,
ignoreUploadUnusedFiles: true,
},
onProgressUpdate: res => {
if (res._status != "doing") {
fs.unlink(privateKeyPath, () => { });
console.info(` ------ ✨ 编译上传结果 ${res} ------ `);
resolve(Object.assign(res, {
"appid": appid,
"result": res._status,
"key": privateKey,
}))
}
}
})
} catch (err) {
resolve({
'appid': appid,
"result": String(err),
})
}
})
}

View File

@@ -0,0 +1,16 @@
Component({
properties: {
text: {
type: String,
value: '暂无数据',
},
desc: {
type: String,
value: '',
},
},
lifetimes: {
attached() { },
},
methods: {}
})

View File

@@ -0,0 +1,3 @@
{
"component": true
}

View File

@@ -0,0 +1,5 @@
<view class="no-data">
<image class="no-data" src="/static/svg/illustration/no-data.svg" mode="aspectFit"></image>
<text class="no-data">{{text}}</text>
<text class="no-data" wx:if="{{desc}}">{{desc}}</text>
</view>

View File

@@ -0,0 +1,18 @@
view.no-data {
width: 100%;
text-align: center;
margin-top: calc(50vh - 300rpx);
color: gray;
}
image.no-data {
display: block;
width: 160rpx;
height: 160rpx;
margin: 20rpx auto;
}
text.no-data {
font-size: 26rpx;
display: block;
}

View File

@@ -0,0 +1,12 @@
Component({
properties: {
waterText: {
type: String,
value: '小程序水印',
}
},
lifetimes: {
attached() { },
},
methods: {}
})

View File

@@ -0,0 +1,3 @@
{
"component": true
}

View File

@@ -0,0 +1,21 @@
<!--components/watermark/watermark.wxml-->
<view class="water_top" style="pointer-events: none;">
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
<view class="water-text">{{waterText}}</view>
</view>

View File

@@ -0,0 +1,20 @@
/* components/watermark/watermark.wxss */
/* 想要改水印大小或者稀疏通过样式调整即可 */
.water_top {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
transform: rotate(-10deg);
z-index: 9;
}
.water-text {
float: left;
width: 375rpx;
color: rgba(0, 0, 0, 0.15);
text-align: center;
font-size: 15px;
margin: 120rpx 0;
}

View File

@@ -0,0 +1,11 @@
{
"ios": {
"name": "工具箱"
},
"android": {
"name": "工具箱"
},
"common": {
"name": "工具箱"
}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"ios": {
"name": "工具箱"
},
"android": {
"name": "工具箱"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"base": {
"ios": {
"name": "工具箱"
},
"android": {
"name": "工具箱"
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
:: BASE_DOC ::
## API
### ActionSheet Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
align | String | center | `0.29.0`。options: center/left | N
cancel-text | String | - | \- | N
count | Number | 8 | \- | N
description | String | - | `0.29.0` | N
items | Array | - | required。Typescript`Array<string \| ActionSheetItem>` `interface ActionSheetItem {label: string; color?: string; disabled?: boolean;icon?: string;suffixIcon?: string; }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | Y
popup-props | Object | {} | Typescript`PopupProps`[Popup API Documents](./popup?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | N
show-cancel | Boolean | true | \- | N
show-overlay | Boolean | true | \- | N
theme | String | list | options: list/grid | N
using-custom-navbar | Boolean | false | \- | N
visible | Boolean | false | required | Y
default-visible | Boolean | undefined | required。uncontrolled property | Y
### ActionSheet Events
name | params | description
-- | -- | --
cancel | \- | \-
close | `(trigger: TriggerSource)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'command' \| 'select' `<br/>
selected | `(selected: ActionSheetItem \| string, index: number)` | \-
### ActionSheet External Classes
className | Description
-- | --
t-class | \-
t-class-cancel | \-
t-class-content | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-action-sheet-border-color | @gray-color-1 | -
--td-action-sheet-border-radius | @radius-extra-large | -
--td-action-sheet-cancel-color | @font-gray-1 | -
--td-action-sheet-cancel-height | 96rpx | -
--td-action-sheet-color | @font-gray-1 | -
--td-action-sheet-description-color | @font-gray-3 | -
--td-action-sheet-list-item-disabled-color | @font-gray-4 | -
--td-action-sheet-list-item-height | 112rpx | -
--td-action-sheet-text-align | center | -

View File

@@ -0,0 +1,140 @@
---
title: ActionSheet 动作面板
description: 由用户操作后触发的一种特定的模态弹出框 ,呈现一组与当前情境相关的两个或多个选项。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-89%25-blue" /></span>
<div style="background: #ecf2fe; display: flex; align-items: center; line-height: 20px; padding: 14px 24px; border-radius: 3px; color: #555a65">
<svg fill="none" viewBox="0 0 16 16" width="16px" height="16px" style="margin-right: 5px">
<path fill="#0052d9" d="M8 15A7 7 0 108 1a7 7 0 000 14zM7.4 4h1.2v1.2H7.4V4zm.1 2.5h1V12h-1V6.5z" fillOpacity="0.9"></path>
</svg>
该组件于 0.9.0 版本上线,请留意版本。
</div>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-action-sheet": "tdesign-miniprogram/action-sheet/action-sheet",
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/EM7cxim37USn" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 组件类型
列表型动作面板
{{ list }}
宫格型动作面板
{{ grid }}
### 组件状态
宫格型动作面板
{{ status }}
### 组件样式
列表型对齐方式
{{ align }}
### 支持指令调用
```javascript
import ActionSheet, { ActionSheetTheme } from 'tdesign-miniprogram/action-sheet/index';
// 指令调用不同于组件引用不需要传入visible
const basicListOption: ActionSheetShowOption = {
theme: ActionSheetTheme.List,
selector: '#t-action-sheet',
items: [
{
label: '默认选项',
},
{
label: '失效选项',
disabled: true,
},
{
label: '警告选项',
color: '#e34d59',
},
],
};
const handler = ActionSheet.show(basicListOption);
```
指令调用的关闭如下
```javascript
handler.close();
```
## API
### ActionSheet Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
align | String | center | `0.29.0`。水平对齐方式。可选项center/left | N
cancel-text | String | - | 设置取消按钮的文本 | N
count | Number | 8 | 设置每页展示菜单的数量,仅当 type=grid 时有效 | N
description | String | - | `0.29.0`。动作面板描述文字 | N
items | Array | - | 必需。菜单项。TS 类型:`Array<string \| ActionSheetItem>` `interface ActionSheetItem {label: string; color?: string; disabled?: boolean;icon?: string;suffixIcon?: string; }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | Y
popup-props | Object | {} | popupProps透传。TS 类型:`PopupProps`[Popup API Documents](./popup?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | N
show-cancel | Boolean | true | 是否显示取消按钮 | N
show-overlay | Boolean | true | 是否显示遮罩层 | N
theme | String | list | 展示类型列表和表格形式展示。可选项list/grid | N
using-custom-navbar | Boolean | false | 是否使用了自定义导航栏 | N
visible | Boolean | false | 必需。显示与隐藏 | Y
default-visible | Boolean | undefined | 必需。显示与隐藏。非受控属性 | Y
### ActionSheet Events
名称 | 参数 | 描述
-- | -- | --
cancel | \- | 点击取消按钮时触发
close | `(trigger: TriggerSource)` | 关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'command' \| 'select' `<br/>
selected | `(selected: ActionSheetItem \| string, index: number)` | 选择菜单项时触发
### ActionSheet External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-cancel | 取消样式类
t-class-content | 内容样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-action-sheet-border-color | @gray-color-1 | -
--td-action-sheet-border-radius | @radius-extra-large | -
--td-action-sheet-cancel-color | @font-gray-1 | -
--td-action-sheet-cancel-height | 96rpx | -
--td-action-sheet-color | @font-gray-1 | -
--td-action-sheet-description-color | @font-gray-3 | -
--td-action-sheet-list-item-disabled-color | @font-gray-4 | -
--td-action-sheet-list-item-height | 112rpx | -
--td-action-sheet-text-align | center | -

View File

@@ -0,0 +1,87 @@
import { SuperComponent } from '../common/src/index';
export default class ActionSheet extends SuperComponent {
static show: (options: import("./show").ActionSheetShowOption) => WechatMiniprogram.Component.TrivialInstance;
behaviors: string[];
externalClasses: string[];
properties: {
align?: {
type: StringConstructor;
value?: "center" | "left";
};
cancelText?: {
type: StringConstructor;
value?: string;
};
count?: {
type: NumberConstructor;
value?: number;
};
description?: {
type: StringConstructor;
value?: string;
};
items: {
type: ArrayConstructor;
value?: (string | import("./type").ActionSheetItem)[];
required?: boolean;
};
popupProps?: {
type: ObjectConstructor;
value?: import("../popup").TdPopupProps;
};
showCancel?: {
type: BooleanConstructor;
value?: boolean;
};
showOverlay?: {
type: BooleanConstructor;
value?: boolean;
};
theme?: {
type: StringConstructor;
value?: "list" | "grid";
};
usingCustomNavbar?: {
type: BooleanConstructor;
value?: boolean;
};
visible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
defaultVisible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
};
data: {
prefix: string;
classPrefix: string;
gridThemeItems: any[];
currentSwiperIndex: number;
defaultPopUpProps: {};
defaultPopUpzIndex: number;
};
controlledProps: {
key: string;
event: string;
}[];
observers: {
'visible, items'(visible: boolean): void;
};
methods: {
init(): void;
memoInitialData(): void;
splitGridThemeActions(): void;
show(options: any): void;
close(): void;
onPopupVisibleChange({ detail }: {
detail: any;
}): void;
onSwiperChange(e: WechatMiniprogram.TouchEvent): void;
onSelect(event: WechatMiniprogram.TouchEvent): void;
onCancel(): void;
};
}

View File

@@ -0,0 +1,111 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { chunk } from '../common/utils';
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import { ActionSheetTheme, show } from './show';
import props from './props';
import useCustomNavbar from '../mixins/using-custom-navbar';
const { prefix } = config;
const name = `${prefix}-action-sheet`;
let ActionSheet = class ActionSheet extends SuperComponent {
constructor() {
super(...arguments);
this.behaviors = [useCustomNavbar];
this.externalClasses = [`${prefix}-class`, `${prefix}-class-content`, `${prefix}-class-cancel`];
this.properties = Object.assign({}, props);
this.data = {
prefix,
classPrefix: name,
gridThemeItems: [],
currentSwiperIndex: 0,
defaultPopUpProps: {},
defaultPopUpzIndex: 11500,
};
this.controlledProps = [
{
key: 'visible',
event: 'visible-change',
},
];
this.observers = {
'visible, items'(visible) {
if (!visible)
return;
this.init();
},
};
this.methods = {
init() {
this.memoInitialData();
this.splitGridThemeActions();
},
memoInitialData() {
this.initialData = Object.assign(Object.assign({}, this.properties), this.data);
},
splitGridThemeActions() {
if (this.data.theme !== ActionSheetTheme.Grid)
return;
this.setData({
gridThemeItems: chunk(this.data.items, this.data.count),
});
},
show(options) {
this.setData(Object.assign(Object.assign(Object.assign({}, this.initialData), options), { visible: true }));
this.splitGridThemeActions();
this.autoClose = true;
this._trigger('visible-change', { visible: true });
},
close() {
this.triggerEvent('close', { trigger: 'command' });
this._trigger('visible-change', { visible: false });
},
onPopupVisibleChange({ detail }) {
if (!detail.visible) {
this.triggerEvent('close', { trigger: 'overlay' });
this._trigger('visible-change', { visible: false });
}
if (this.autoClose) {
this.setData({ visible: false });
this.autoClose = false;
}
},
onSwiperChange(e) {
const { current } = e.detail;
this.setData({
currentSwiperIndex: current,
});
},
onSelect(event) {
const { currentSwiperIndex, items, gridThemeItems, count, theme } = this.data;
const { index } = event.currentTarget.dataset;
const isSwiperMode = theme === ActionSheetTheme.Grid;
const item = isSwiperMode ? gridThemeItems[currentSwiperIndex][index] : items[index];
const realIndex = isSwiperMode ? index + currentSwiperIndex * count : index;
if (item) {
this.triggerEvent('selected', { selected: item, index: realIndex });
if (!item.disabled) {
this.triggerEvent('close', { trigger: 'select' });
this._trigger('visible-change', { visible: false });
}
}
},
onCancel() {
this.triggerEvent('cancel');
if (this.autoClose) {
this.setData({ visible: false });
this.autoClose = false;
}
},
};
}
};
ActionSheet.show = show;
ActionSheet = __decorate([
wxComponent()
], ActionSheet);
export default ActionSheet;

View File

@@ -0,0 +1,10 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {
"t-icon": "../icon/icon",
"t-popup": "../popup/popup",
"t-grid": "../grid/grid",
"t-grid-item": "../grid-item/grid-item"
}
}

View File

@@ -0,0 +1,49 @@
<wxs src="./action-sheet.wxs" module="_this" />
<wxs src="../common/utils.wxs" module="_" />
<import src="./template/list.wxml" />
<import src="./template/grid.wxml" />
<view id="{{classPrefix}}" style="{{_._style([style, customStyle])}}" class="{{classPrefix}} class {{prefix}}-class">
<t-popup
visible="{{visible}}"
placement="bottom"
usingCustomNavbar="{{usingCustomNavbar}}"
bind:visible-change="onPopupVisibleChange"
show-overlay="{{showOverlay}}"
z-index="{{ popupProps.zIndex || defaultPopUpzIndex }}"
overlay-props="{{ popupProps.overlayProps || defaultPopUpProps }}"
>
<view
class="{{_.cls(classPrefix + '__content', [['grid', gridThemeItems.length]])}} {{prefix}}-class-content"
tabindex="0"
>
<view wx:if="{{description}}" tabindex="0" class="{{_.cls(classPrefix + '__description', [align])}}"
>{{description}}</view
>
<block wx:if="{{gridThemeItems.length}}">
<template is="grid" data="{{classPrefix, prefix, gridThemeItems, count, currentSwiperIndex}}" />
</block>
<view wx:elif="{{items && items.length}}" class="{{classPrefix}}__list">
<block wx:for="{{ items }}" wx:key="index">
<template
is="list"
data="{{index, classPrefix, listThemeItemClass: _.cls(classPrefix + '__list-item', [align, [disabled, item.disabled]]), item}}"
/>
</block>
</view>
</view>
<slot />
<view wx:if="{{showCancel}}" class="{{classPrefix}}__footer">
<view class="{{classPrefix}}__gap-{{theme}}" />
<view
class="{{classPrefix}}__cancel {{prefix}}-class-cancel"
hover-class="{{classPrefix}}__cancel--hover"
hover-stay-time="70"
bind:tap="onCancel"
aria-role="button"
>
{{ cancelText || '取消' }}
</view>
</view>
</t-popup>
</view>

View File

@@ -0,0 +1,19 @@
var getListThemeItemClass = function (props) {
var classPrefix = props.classPrefix;
var item = props.item;
var prefix = props.prefix;
var classList = [classPrefix + '__list-item'];
if (item.disabled) {
classList.push(prefix + '-is-disabled');
}
return classList.join(' ');
};
var isImage = function (name) {
return name.indexOf('/') !== -1;
};
module.exports = {
getListThemeItemClass: getListThemeItemClass,
isImage: isImage,
};

View File

@@ -0,0 +1,169 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-action-sheet__content {
color: var(--td-action-sheet-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
border-top-left-radius: var(--td-action-sheet-border-radius, var(--td-radius-extra-large, 24rpx));
border-top-right-radius: var(--td-action-sheet-border-radius, var(--td-radius-extra-large, 24rpx));
background-color: var(--td-bg-color-container, var(--td-font-white-1, #ffffff));
overflow: hidden;
}
.t-action-sheet__content--grid {
padding-top: 16rpx;
}
.t-action-sheet__content:focus {
outline: 0;
}
.t-action-sheet__grid {
padding-bottom: 16rpx;
}
.t-action-sheet__grid--swiper {
padding-bottom: 48rpx;
}
.t-action-sheet__description {
color: var(--td-action-sheet-description-color, var(--td-text-color-placeholder, var(--td-font-gray-3, rgba(0, 0, 0, 0.4))));
line-height: 44rpx;
font-size: 28rpx;
text-align: var(--td-action-sheet-text-align, center);
padding: 24rpx 32rpx;
position: relative;
}
.t-action-sheet__description:focus {
outline: 0;
}
.t-action-sheet__description::after {
content: '';
display: block;
position: absolute;
top: unset;
bottom: 0;
left: unset;
right: unset;
background-color: var(--td-action-sheet-border-color, var(--td-border-level-1-color, var(--td-gray-color-3, #e7e7e7)));
}
.t-action-sheet__description::after {
height: 1px;
left: 0;
right: 0;
transform: scaleY(0.5);
}
.t-action-sheet__description--left {
text-align: left;
}
.t-action-sheet__description--left::after {
left: 32rpx;
}
.t-action-sheet__list-item {
display: flex;
align-items: center;
justify-content: center;
position: relative;
height: var(--td-action-sheet-list-item-height, 112rpx);
padding: 0 32rpx;
}
.t-action-sheet__list-item::after {
content: '';
display: block;
position: absolute;
top: unset;
bottom: 0;
left: unset;
right: unset;
background-color: var(--td-action-sheet-border-color, var(--td-border-level-1-color, var(--td-gray-color-3, #e7e7e7)));
}
.t-action-sheet__list-item::after {
height: 1px;
left: 0;
right: 0;
transform: scaleY(0.5);
}
.t-action-sheet__list-item:focus {
outline: 0;
}
.t-action-sheet__list-item--left {
justify-content: start;
}
.t-action-sheet__list-item--left::after {
left: 32rpx;
}
.t-action-sheet__list-item--disabled {
color: var(--td-action-sheet-list-item-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
}
.t-action-sheet__list-item-text {
font-size: var(--td-font-size-m, 32rpx);
word-wrap: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.t-action-sheet__list-item-icon {
margin-right: 16rpx;
}
.t-action-sheet__list-item-icon--suffix {
margin-left: auto;
}
.t-action-sheet__swiper-wrap {
margin-top: 8rpx;
position: relative;
}
.t-action-sheet__footer {
background-color: var(--td-bg-color-container, var(--td-font-white-1, #ffffff));
}
.t-action-sheet__gap-list {
height: 16rpx;
background-color: var(--td-action-sheet-gap-color, var(--td-bg-color-page, var(--td-gray-color-1, #f3f3f3)));
}
.t-action-sheet__gap-grid {
height: 1rpx;
background-color: var(--td-action-sheet-border-color, var(--td-border-level-1-color, var(--td-gray-color-3, #e7e7e7)));
}
.t-action-sheet__cancel {
display: flex;
align-items: center;
justify-content: center;
color: var(--td-action-sheet-cancel-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
height: var(--td-action-sheet-cancel-height, 96rpx);
}
.t-action-sheet__dots {
position: absolute;
left: 50%;
bottom: 32rpx;
transform: translateX(-50%);
display: flex;
flex-direction: row;
}
.t-action-sheet__dots-item {
width: 16rpx;
height: 16rpx;
background-color: #dcdcdc;
border-radius: 50%;
margin: 0 16rpx;
transition: all 0.4s ease-in;
}
.t-action-sheet__dots-item.t-is-active {
background-color: #0052d9;
}

View File

@@ -0,0 +1,8 @@
/// <reference types="miniprogram-api-typings" />
import { ActionSheetItem, ActionSheetTheme, ActionSheetShowOption } from './show';
export { ActionSheetItem, ActionSheetTheme, ActionSheetShowOption };
declare const _default: {
show(options: ActionSheetShowOption): WechatMiniprogram.Component.TrivialInstance;
close(options: ActionSheetShowOption): void;
};
export default _default;

View File

@@ -0,0 +1,10 @@
import { show, close, ActionSheetTheme } from './show';
export { ActionSheetTheme };
export default {
show(options) {
return show(options);
},
close(options) {
return close(options);
},
};

View File

@@ -0,0 +1,3 @@
import { TdActionSheetProps } from './type';
declare const props: TdActionSheetProps;
export default props;

View File

@@ -0,0 +1,53 @@
const props = {
align: {
type: String,
value: 'center',
},
cancelText: {
type: String,
value: '',
},
count: {
type: Number,
value: 8,
},
description: {
type: String,
value: '',
},
items: {
type: Array,
required: true,
},
popupProps: {
type: Object,
value: {},
},
showCancel: {
type: Boolean,
value: true,
},
showOverlay: {
type: Boolean,
value: true,
},
theme: {
type: String,
value: 'list',
},
usingCustomNavbar: {
type: Boolean,
value: false,
},
visible: {
type: Boolean,
value: null,
required: true,
},
defaultVisible: {
type: Boolean,
value: false,
required: true,
},
};
export default props;

View File

@@ -0,0 +1,31 @@
/// <reference types="miniprogram-api-typings" />
/// <reference types="miniprogram-api-typings" />
export interface ActionSheetItem {
label: string;
color?: string;
disabled?: boolean;
icon?: string;
}
declare type Context = WechatMiniprogram.Page.TrivialInstance | WechatMiniprogram.Component.TrivialInstance;
export declare enum ActionSheetTheme {
List = "list",
Grid = "grid"
}
interface ActionSheetProps {
align: 'center' | 'left';
cancelText?: string;
count?: number;
description: string;
items: Array<string | ActionSheetItem>;
showCancel?: boolean;
theme?: ActionSheetTheme;
visible: boolean;
defaultVisible?: boolean;
}
export interface ActionSheetShowOption extends Omit<ActionSheetProps, 'visible'> {
context?: Context;
selector?: string;
}
export declare const show: (options: ActionSheetShowOption) => WechatMiniprogram.Component.TrivialInstance;
export declare const close: (options: ActionSheetShowOption) => void;
export {};

View File

@@ -0,0 +1,33 @@
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { getInstance } from '../common/utils';
export var ActionSheetTheme;
(function (ActionSheetTheme) {
ActionSheetTheme["List"] = "list";
ActionSheetTheme["Grid"] = "grid";
})(ActionSheetTheme || (ActionSheetTheme = {}));
export const show = function (options) {
const _a = Object.assign({}, options), { context, selector = '#t-action-sheet' } = _a, otherOptions = __rest(_a, ["context", "selector"]);
const instance = getInstance(context, selector);
if (instance) {
instance.show(Object.assign({}, otherOptions));
return instance;
}
console.error('未找到组件,请确认 selector && context 是否正确');
};
export const close = function (options) {
const { context, selector = '#t-action-sheet' } = Object.assign({}, options);
const instance = getInstance(context, selector);
if (instance) {
instance.close();
}
};

View File

@@ -0,0 +1,51 @@
<template name="grid">
<block wx:if="{{gridThemeItems.length === 1}}">
<t-grid align="center" t-class="{{classPrefix}}__grid" column="{{count / 2}}" class="{{classPrefix}}__single-wrap">
<t-grid-item
t-class="{{classPrefix}}__grid-item"
class="{{classPrefix}}__square"
wx:for="{{gridThemeItems[0]}}"
wx:key="index"
bind:tap="onSelect"
data-index="{{index}}"
icon="{{ { name: item.icon, color: item.color } }}"
text="{{item.label || ''}}"
image="{{item.image || ''}}"
style="--td-grid-item-text-color: {{item.color}}"
>
</t-grid-item>
</t-grid>
</block>
<block wx:elif="{{gridThemeItems.length > 1}}">
<view class="{{classPrefix}}__swiper-wrap">
<swiper style="height: 456rpx" autoplay="{{false}}" current="{{currentSwiperIndex}}" bindchange="onSwiperChange">
<swiper-item wx:for="{{gridThemeItems}}" wx:key="index">
<t-grid align="center" t-class="{{classPrefix}}__grid {{classPrefix}}__grid--swiper" column="{{count / 2}}">
<t-grid-item
t-class="{{classPrefix}}__grid-item"
class="{{classPrefix}}__square"
wx:for="{{item}}"
wx:key="index"
data-index="{{index}}"
bind:tap="onSelect"
icon="{{ { name: item.icon, color: item.color } }}"
text="{{item.label || ''}}"
image="{{item.image || ''}}"
style="--td-grid-item-text-color: {{item.color}}"
>
</t-grid-item>
</t-grid>
</swiper-item>
</swiper>
<view class="{{classPrefix}}__nav">
<view class="{{classPrefix}}__dots">
<view
wx:for="{{gridThemeItems.length}}"
wx:key="index"
class="{{classPrefix}}__dots-item {{index === currentSwiperIndex ? prefix + '-is-active' : ''}}"
/>
</view>
</view>
</view>
</block>
</template>

View File

@@ -0,0 +1,20 @@
<template name="list">
<view
data-index="{{index}}"
style="{{ item.color ? 'color: ' + item.color : '' }}"
class="{{listThemeItemClass}}"
bind:tap="onSelect"
aria-role="{{ariaRole || 'button'}}"
aria-label="{{item.label || item}}"
tabindex="0"
>
<t-icon wx:if="{{item.icon}}" name="{{item.icon}}" class="{{classPrefix}}__list-item-icon" size="48rpx"></t-icon>
<view class="{{classPrefix}}__list-item-text">{{item.label || item}}</view>
<t-icon
wx:if="{{item.suffixIcon}}"
name="{{item.suffixIcon}}"
class="{{classPrefix}}__list-item-icon {{classPrefix}}__list-item-icon--suffix"
size="48rpx"
></t-icon>
</view>
</template>

View File

@@ -0,0 +1,61 @@
import { PopupProps } from '../popup/index';
export interface TdActionSheetProps {
align?: {
type: StringConstructor;
value?: 'center' | 'left';
};
cancelText?: {
type: StringConstructor;
value?: string;
};
count?: {
type: NumberConstructor;
value?: number;
};
description?: {
type: StringConstructor;
value?: string;
};
items: {
type: ArrayConstructor;
value?: Array<string | ActionSheetItem>;
required?: boolean;
};
popupProps?: {
type: ObjectConstructor;
value?: PopupProps;
};
showCancel?: {
type: BooleanConstructor;
value?: boolean;
};
showOverlay?: {
type: BooleanConstructor;
value?: boolean;
};
theme?: {
type: StringConstructor;
value?: 'list' | 'grid';
};
usingCustomNavbar?: {
type: BooleanConstructor;
value?: boolean;
};
visible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
defaultVisible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
}
export interface ActionSheetItem {
label: string;
color?: string;
disabled?: boolean;
icon?: string;
suffixIcon?: string;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,28 @@
import { SuperComponent, RelationsOptions } from '../common/src/index';
export default class AvatarGroup extends SuperComponent {
externalClasses: string[];
properties: import("./type").TdAvatarGroupProps;
data: {
prefix: string;
classPrefix: string;
hasChild: boolean;
length: number;
className: string;
};
options: {
multipleSlots: boolean;
};
relations: RelationsOptions;
lifetimes: {
attached(): void;
ready(): void;
};
observers: {
'cascading, size'(): void;
};
methods: {
setClass(): void;
handleMax(): void;
onCollapsedItemClick(e: WechatMiniprogram.CustomEvent): void;
};
}

View File

@@ -0,0 +1,81 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import avatarGroupProps from './props';
const { prefix } = config;
const name = `${prefix}-avatar-group`;
let AvatarGroup = class AvatarGroup extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-content`, `${prefix}-class-image`];
this.properties = avatarGroupProps;
this.data = {
prefix,
classPrefix: name,
hasChild: true,
length: 0,
className: '',
};
this.options = {
multipleSlots: true,
};
this.relations = {
'../avatar/avatar': {
type: 'descendant',
},
};
this.lifetimes = {
attached() {
this.setClass();
},
ready() {
this.setData({
length: this.$children.length,
});
this.handleMax();
},
};
this.observers = {
'cascading, size'() {
this.setClass();
},
};
this.methods = {
setClass() {
const { cascading, size } = this.properties;
const direction = cascading.split('-')[0];
const classList = [
name,
`${prefix}-class`,
`${name}-offset-${direction}`,
`${name}-offset-${direction}-${size.indexOf('px') > -1 ? 'medium' : size || 'medium'}`,
];
this.setData({
className: classList.join(' '),
});
},
handleMax() {
const { max } = this.data;
const len = this.$children.length;
if (!max || max > len)
return;
const restAvatars = this.$children.splice(max, len - max);
restAvatars.forEach((child) => {
child.hide();
});
},
onCollapsedItemClick(e) {
this.triggerEvent('collapsed-item-click', e.detail);
},
};
}
};
AvatarGroup = __decorate([
wxComponent()
], AvatarGroup);
export default AvatarGroup;

View File

@@ -0,0 +1,7 @@
{
"component": true,
"styleIsolation": "shared",
"usingComponents": {
"t-avatar": "../avatar/avatar"
}
}

View File

@@ -0,0 +1,21 @@
<wxs src="../common/utils.wxs" module="_" />
<view style="{{_._style([style, customStyle])}}" class="{{className}} class">
<slot />
<!-- 自定义折叠元素 -->
<view class="{{classPrefix}}__collapse--slot">
<slot name="collapse-avatar" />
</view>
<!-- 默认折叠元素 -->
<view class="{{classPrefix}}__collapse--default" wx:if="{{max && (max < length)}}" bindtap="onCollapsedItemClick">
<t-avatar
t-class-image="{{prefix}}-avatar--border {{prefix}}-avatar--border-{{size}} {{prefix}}-class-image"
t-class-content="{{prefix}}-class-content"
size="{{size}}"
shape="{{shape}}"
icon="{{ collapseAvatar ? '' : 'user-add'}}"
aria-role="none"
>{{collapseAvatar}}</t-avatar
>
</view>
</view>

View File

@@ -0,0 +1,214 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-avatar-group {
display: inline-flex;
flex-wrap: wrap;
align-items: center;
}
.t-avatar-group-offset-left .t-avatar__wrapper,
.t-avatar-group-offset-right .t-avatar__wrapper {
padding: var(--td-avatar-group-line-spacing, 4rpx) 0;
}
.t-avatar-group-offset-left-small,
.t-avatar-group-offset-right-small {
--td-avatar-margin-left: var(--td-avatar-group-margin-left-small, -16rpx);
}
.t-avatar-group-offset-left-medium,
.t-avatar-group-offset-right-medium {
--td-avatar-margin-left: var(--td-avatar-group-margin-left-medium, -16rpx);
}
.t-avatar-group-offset-left-large,
.t-avatar-group-offset-right-large {
--td-avatar-margin-left: var(--td-avatar-group-margin-left-large, -16rpx);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(1) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 1);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(2) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 2);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(3) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 3);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(4) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 4);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(5) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 5);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(6) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 6);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(7) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 7);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(8) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 8);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(9) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 9);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(10) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 10);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(11) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 11);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(12) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 12);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(13) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 13);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(14) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 14);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(15) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 15);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(16) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 16);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(17) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 17);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(18) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 18);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(19) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 19);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(20) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 20);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(21) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 21);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(22) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 22);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(23) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 23);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(24) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 24);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(25) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 25);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(26) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 26);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(27) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 27);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(28) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 28);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(29) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 29);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(30) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 30);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(31) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 31);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(32) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 32);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(33) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 33);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(34) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 34);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(35) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 35);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(36) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 36);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(37) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 37);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(38) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 38);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(39) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 39);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(40) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 40);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(41) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 41);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(42) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 42);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(43) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 43);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(44) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 44);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(45) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 45);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(46) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 46);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(47) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 47);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(48) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 48);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(49) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 49);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(50) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 50);
}
.t-avatar-group__collapse--slot,
.t-avatar-group__collapse--default {
z-index: 0;
font-weight: 600;
}
.t-avatar-group__collapse--slot {
float: left;
}
.t-avatar-group__collapse--slot:not(:empty) + .t-avatar-group__collapse--default {
display: none;
float: left;
}
.t-avatar-group__collapse--slot:empty + .t-avatar-group__collapse--default {
display: block;
float: left;
}

View File

@@ -0,0 +1,3 @@
import { TdAvatarGroupProps } from './type';
declare const props: TdAvatarGroupProps;
export default props;

View File

@@ -0,0 +1,20 @@
const props = {
cascading: {
type: String,
value: 'left-up',
},
collapseAvatar: {
type: String,
},
max: {
type: Number,
},
shape: {
type: String,
},
size: {
type: String,
value: '',
},
};
export default props;

View File

@@ -0,0 +1,24 @@
import { ShapeEnum } from '../common/common';
export interface TdAvatarGroupProps {
cascading?: {
type: StringConstructor;
value?: CascadingValue;
};
collapseAvatar?: {
type: StringConstructor;
value?: string;
};
max?: {
type: NumberConstructor;
value?: number;
};
shape?: {
type: StringConstructor;
value?: ShapeEnum;
};
size?: {
type: StringConstructor;
value?: string;
};
}
export declare type CascadingValue = 'left-up' | 'right-up';

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,91 @@
:: BASE_DOC ::
## API
### Avatar Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
alt | String | - | show it when url is not valid | N
badge-props | Object | - | Typescript`BadgeProps`[Badge API Documents](./badge?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
bordered | Boolean | false | \- | N
hide-on-load-failed | Boolean | false | hide image when loading image failed | N
icon | String / Object | - | \- | N
image | String | - | images url | N
image-props | Object | - | Typescript`ImageProps`[Image API Documents](./image?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
shape | String | - | shape。options: circle/round。Typescript`ShapeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | size | N
### Avatar Events
name | params | description
-- | -- | --
error | - | trigger on image load failed
### Avatar External Classes
className | Description
-- | --
t-class | \-
t-class-alt | \-
t-class-content | \-
t-class-icon | \-
t-class-image | \-
### AvatarGroup Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
cascading | String | 'left-up' | multiple images cascading。options: left-up/right-up。Typescript`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar-group/type.ts) | N
collapse-avatar | String / Slot | - | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
max | Number | - | \- | N
shape | String | - | shape。options: circle/round。Typescript`ShapeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | size | N
### AvatarGroup Events
name | params | description
-- | -- | --
collapsed-item-click | - | \-
### AvatarGroup External Classes
className | Description
-- | --
t-class | \-
t-class-content | \-
t-class-image | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-avatar-group-init-z-index | @avatar-group-init-zIndex) - @i | -
--td-avatar-group-line-spacing | 4rpx | -
--td-avatar-group-margin-left-large | -16rpx | -
--td-avatar-group-margin-left-medium | -16rpx | -
--td-avatar-group-margin-left-small | -16rpx | -
--td-avatar-bg-color | @brand-color-light-active | -
--td-avatar-border-color | #fff | -
--td-avatar-border-width-large | 6rpx | -
--td-avatar-border-width-medium | 4rpx | -
--td-avatar-border-width-small | 2rpx | -
--td-avatar-circle-border-radius | @radius-circle | -
--td-avatar-content-color | @brand-color | -
--td-avatar-icon-large-font-size | 64rpx | -
--td-avatar-icon-medium-font-size | 48rpx | -
--td-avatar-icon-small-font-size | 40rpx | -
--td-avatar-large-width | 128rpx | -
--td-avatar-margin-left | 0 | -
--td-avatar-medium-width | 96rpx | -
--td-avatar-round-border-radius | @radius-default | -
--td-avatar-small-width | 80rpx | -
--td-avatar-text-large-font-size | @font-size-xl | -
--td-avatar-text-medium-font-size | @font-size-m | -
--td-avatar-text-small-font-size | @font-size-base | -

View File

@@ -0,0 +1,151 @@
---
title: Avatar 头像
description: 用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-99%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-85%25-blue" /></span>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-avatar": "tdesign-miniprogram/avatar/avatar",
"t-avatar-group": "tdesign-miniprogram/avatar-group/avatar-group"
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/a86Sfimw7VSO" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 头像类型
图片头像
{{ image-avatar }}
字符头像
{{ character-avatar }}
图标头像
{{ icon-avatar }}
徽标头像
{{ badge-avatar }}
### 组合头像
纯展示
{{ exhibition }}
带操作
{{ action }}
### 头像尺寸
头像 large/medium/small 尺寸
{{ size }}
## API
### Avatar Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
alt | String | - | 头像替换文本,仅当图片加载失败时有效 | N
badge-props | Object | - | 头像右上角提示信息,继承 Badge 组件的全部特性。如小红点或者数字。TS 类型:`BadgeProps`[Badge API Documents](./badge?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
bordered | Boolean | false | 已废弃。是否显示外边框 | N
hide-on-load-failed | Boolean | false | 加载失败时隐藏图片 | N
icon | String / Object | - | 图标。值为字符串表示图标名称,值为 `Object` 类型,表示透传至 `icon`。 | N
image | String | - | 图片地址 | N
image-props | Object | - | 透传至 Image 组件。TS 类型:`ImageProps`[Image API Documents](./image?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
shape | String | - | 形状。优先级高于 AvatarGroup.shape 。Avatar 单独存在时,默认值为 circle。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.shape 决定。可选项circle/round。TS 类型:`ShapeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | 尺寸示例值small/medium/large/24px/38px 等。优先级高于 AvatarGroup.size 。Avatar 单独存在时,默认值为 medium。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.size 决定 | N
### Avatar Events
名称 | 参数 | 描述
-- | -- | --
error | - | 图片加载失败时触发
### Avatar External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-alt | 替代文本样式类
t-class-content | 内容样式类
t-class-icon | 图标样式类
t-class-image | 图片样式类
### AvatarGroup Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
cascading | String | 'left-up' | 图片之间的层叠关系可选值左侧图片在上和右侧图片在上。可选项left-up/right-up。TS 类型:`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar-group/type.ts) | N
collapse-avatar | String / Slot | - | 头像数量超出时,会出现一个头像折叠元素。该元素内容可自定义。默认为 `+N`。示例:`+5``...`, `更多`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
max | Number | - | 能够同时显示的最多头像数量 | N
shape | String | - | 形状。优先级低于 Avatar.shape。可选项circle/round。TS 类型:`ShapeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | 尺寸示例值small/medium/large/24px/38px 等。优先级低于 Avatar.size | N
### AvatarGroup Events
名称 | 参数 | 描述
-- | -- | --
collapsed-item-click | - | 点击头像折叠元素触发
### AvatarGroup External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-content | 内容样式类
t-class-image | 图片样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-avatar-group-init-z-index | @avatar-group-init-zIndex) - @i | -
--td-avatar-group-line-spacing | 4rpx | -
--td-avatar-group-margin-left-large | -16rpx | -
--td-avatar-group-margin-left-medium | -16rpx | -
--td-avatar-group-margin-left-small | -16rpx | -
--td-avatar-bg-color | @brand-color-light-active | -
--td-avatar-border-color | #fff | -
--td-avatar-border-width-large | 6rpx | -
--td-avatar-border-width-medium | 4rpx | -
--td-avatar-border-width-small | 2rpx | -
--td-avatar-circle-border-radius | @radius-circle | -
--td-avatar-content-color | @brand-color | -
--td-avatar-icon-large-font-size | 64rpx | -
--td-avatar-icon-medium-font-size | 48rpx | -
--td-avatar-icon-small-font-size | 40rpx | -
--td-avatar-large-width | 128rpx | -
--td-avatar-margin-left | 0 | -
--td-avatar-medium-width | 96rpx | -
--td-avatar-round-border-radius | @radius-default | -
--td-avatar-small-width | 80rpx | -
--td-avatar-text-large-font-size | @font-size-xl | -
--td-avatar-text-medium-font-size | @font-size-m | -
--td-avatar-text-small-font-size | @font-size-base | -

View File

@@ -0,0 +1,22 @@
/// <reference types="miniprogram-api-typings" />
import { SuperComponent, RelationsOptions } from '../common/src/index';
export default class Avatar extends SuperComponent {
options: WechatMiniprogram.Component.ComponentOptions;
externalClasses: string[];
properties: import("./type").TdAvatarProps;
data: {
prefix: string;
classPrefix: string;
isShow: boolean;
zIndex: number;
systemInfo: WechatMiniprogram.WindowInfo | WechatMiniprogram.SystemInfo;
};
relations: RelationsOptions;
observers: {
icon(icon: any): void;
};
methods: {
hide(): void;
onLoadError(e: WechatMiniprogram.CustomEvent): void;
};
}

View File

@@ -0,0 +1,73 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import avatarProps from './props';
import { setIcon, systemInfo } from '../common/utils';
const { prefix } = config;
const name = `${prefix}-avatar`;
let Avatar = class Avatar extends SuperComponent {
constructor() {
super(...arguments);
this.options = {
multipleSlots: true,
};
this.externalClasses = [
`${prefix}-class`,
`${prefix}-class-image`,
`${prefix}-class-icon`,
`${prefix}-class-alt`,
`${prefix}-class-content`,
];
this.properties = avatarProps;
this.data = {
prefix,
classPrefix: name,
isShow: true,
zIndex: 0,
systemInfo,
};
this.relations = {
'../avatar-group/avatar-group': {
type: 'ancestor',
linked(parent) {
this.parent = parent;
this.setData({
shape: this.data.shape || parent.data.shape || 'circle',
size: this.data.size || parent.data.size,
bordered: true,
});
},
},
};
this.observers = {
icon(icon) {
const obj = setIcon('icon', icon, '');
this.setData(Object.assign({}, obj));
},
};
this.methods = {
hide() {
this.setData({
isShow: false,
});
},
onLoadError(e) {
if (this.properties.hideOnLoadFailed) {
this.setData({
isShow: false,
});
}
this.triggerEvent('error', e.detail);
},
};
}
};
Avatar = __decorate([
wxComponent()
], Avatar);
export default Avatar;

View File

@@ -0,0 +1,9 @@
{
"component": true,
"styleIsolation": "shared",
"usingComponents": {
"t-icon": "../icon/icon",
"t-badge": "../badge/badge",
"t-image": "../image/image"
}
}

View File

@@ -0,0 +1,54 @@
<import src="../common/template/icon.wxml" />
<wxs src="../common/utils.wxs" module="_" />
<wxs src="./avatar.wxs" module="_this" />
<view
class="{{classPrefix}}__wrapper class {{prefix}}-class"
style="{{_._style([_this.getStyles(isShow), style, customStyle])}}"
>
<t-badge
color="{{badgeProps.color || ''}}"
content="{{badgeProps.content || ''}}"
count="{{badgeProps.count || 0}}"
dot="{{badgeProps.dot || false}}"
max-count="{{badgeProps.maxCount || 99}}"
offset="{{badgeProps.offset || []}}"
shape="{{badgeProps.shape || 'circle'}}"
show-zero="{{badgeProps.showZero || false}}"
size="{{badgeProps.size || 'medium'}}"
t-class="{{badgeProps.tClass}}"
t-class-content="{{badgeProps.tClassContent}}"
t-class-count="{{badgeProps.tClassCount}}"
>
<view
class="{{_this.getClass(classPrefix, size || 'medium', shape, bordered)}} {{prefix}}-class-image"
style="{{_this.getSize(size, systemInfo)}}"
aria-label="{{ ariaLabel || alt ||'头像'}}"
aria-role="{{ ariaRole || 'img'}}"
aria-hidden="{{ ariaHidden }}"
>
<t-image
wx:if="{{image}}"
t-class="{{prefix}}-image {{classPrefix}}__image"
t-class-load="{{prefix}}-class-alt"
style="{{imageProps && imageProps.style || ''}}"
src="{{image}}"
mode="{{imageProps && imageProps.mode || 'aspectFill'}}"
lazy="{{imageProps && imageProps.lazy || false}}"
loading="{{imageProps && imageProps.loading || 'default'}}"
shape="{{imageProps && imageProps.shape || 'round'}}"
webp="{{imageProps && imageProps.webp || false}}"
error="{{alt || 'default'}}"
bind:error="onLoadError"
/>
<template
wx:elif="{{iconName || _.isNoEmptyObj(iconData)}}"
is="icon"
data="{{tClass: classPrefix + '__icon ' + prefix + '-class-icon', name: iconName, ...iconData}}"
/>
<view wx:else class="{{classPrefix}}__text {{prefix}}-class-content">
<slot />
</view>
</view>
</t-badge>
</view>

View File

@@ -0,0 +1,30 @@
module.exports = {
getClass: function (classPrefix, size, shape, bordered) {
var hasPx = (size || '').indexOf('px') > -1;
var borderSize = hasPx ? 'medium' : size;
var classNames = [
classPrefix,
classPrefix + (shape === 'round' ? '--round' : '--circle'),
bordered ? classPrefix + '--border' + ' ' + classPrefix + '--border-' + borderSize : '',
hasPx ? '' : classPrefix + '--' + size,
];
return classNames.join(' ');
},
getSize: function (size = 'medium', systemInfo) {
var res = getRegExp('^([0-9]+)(px|rpx)$').exec(size);
if (res && res.length >= 3) {
var px = res[1];
if (res[2] === 'rpx') {
px = Math.floor((systemInfo.windowWidth * res[1]) / 750);
}
return 'width:' + size + ';height:' + size + ';font-size:' + ((px / 8) * 3 + 2) + 'px';
}
},
getStyles: function (isShow) {
return isShow ? '' : 'display: none;';
},
};

View File

@@ -0,0 +1,104 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-avatar {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
background-color: var(--td-avatar-bg-color, var(--td-brand-color-light-active, var(--td-primary-color-2, #d9e1ff)));
color: var(--td-avatar-content-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
}
.t-avatar__wrapper {
display: inline-flex;
position: relative;
vertical-align: top;
margin-left: var(--td-avatar-margin-left, 0);
}
.t-avatar--large {
width: var(--td-avatar-large-width, 128rpx);
height: var(--td-avatar-large-width, 128rpx);
font-size: var(--td-avatar-text-large-font-size, var(--td-font-size-xl, 40rpx));
}
.t-avatar--large .t-avatar__icon {
font-size: var(--td-avatar-icon-large-font-size, 64rpx);
}
.t-avatar--medium {
width: var(--td-avatar-medium-width, 96rpx);
height: var(--td-avatar-medium-width, 96rpx);
font-size: var(--td-avatar-text-medium-font-size, var(--td-font-size-m, 32rpx));
}
.t-avatar--medium .t-avatar__icon {
font-size: var(--td-avatar-icon-medium-font-size, 48rpx);
}
.t-avatar--small {
width: var(--td-avatar-small-width, 80rpx);
height: var(--td-avatar-small-width, 80rpx);
font-size: var(--td-avatar-text-small-font-size, var(--td-font-size-base, 28rpx));
}
.t-avatar--small .t-avatar__icon {
font-size: var(--td-avatar-icon-small-font-size, 40rpx);
}
.t-avatar .t-image,
.t-avatar__image {
width: 100%;
height: 100%;
}
.t-avatar--circle {
border-radius: var(--td-avatar-circle-border-radius, var(--td-radius-circle, 50%));
overflow: hidden;
}
.t-avatar--round {
border-radius: var(--td-avatar-round-border-radius, var(--td-radius-default, 12rpx));
overflow: hidden;
}
.t-avatar__text,
.t-avatar__icon {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.t-avatar__text:empty,
.t-avatar__icon:empty {
width: 0;
height: 0;
}
.t-avatar--border {
border-color: var(--td-avatar-border-color, #fff);
border-style: solid;
}
.t-avatar--border-small {
border-width: var(--td-avatar-border-width-small, 2rpx);
}
.t-avatar--border-medium {
border-width: var(--td-avatar-border-width-medium, 4rpx);
}
.t-avatar--border-large {
border-width: var(--td-avatar-border-width-large, 6rpx);
}

View File

@@ -0,0 +1,3 @@
import { TdAvatarProps } from './type';
declare const props: TdAvatarProps;
export default props;

View File

@@ -0,0 +1,35 @@
const props = {
alt: {
type: String,
value: '',
},
badgeProps: {
type: Object,
},
bordered: {
type: Boolean,
value: false,
},
hideOnLoadFailed: {
type: Boolean,
value: false,
},
icon: {
type: null,
},
image: {
type: String,
value: '',
},
imageProps: {
type: Object,
},
shape: {
type: String,
},
size: {
type: String,
value: '',
},
};
export default props;

View File

@@ -0,0 +1,41 @@
import { BadgeProps } from '../badge/index';
import { ImageProps } from '../image/index';
import { ShapeEnum } from '../common/common';
export interface TdAvatarProps {
alt?: {
type: StringConstructor;
value?: string;
};
badgeProps?: {
type: ObjectConstructor;
value?: BadgeProps;
};
bordered?: {
type: BooleanConstructor;
value?: boolean;
};
hideOnLoadFailed?: {
type: BooleanConstructor;
value?: boolean;
};
icon?: {
type: null;
value?: string | object;
};
image?: {
type: StringConstructor;
value?: string;
};
imageProps?: {
type: ObjectConstructor;
value?: ImageProps;
};
shape?: {
type: StringConstructor;
value?: ShapeEnum;
};
size?: {
type: StringConstructor;
value?: string;
};
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,41 @@
:: BASE_DOC ::
## API
### BackTop Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
fixed | Boolean | true | \- | N
icon | String / Boolean / Object / Slot | true | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
scroll-top | Number | 0 | \- | N
text | String | '' | \- | N
theme | String | round | options: round/half-round/round-dark/half-round-dark | N
visibility-height | Number | 200 | \- | N
### BackTop Events
name | params | description
-- | -- | --
to-top | \- | \-
### BackTop External Classes
className | Description
-- | --
t-class | \-
t-class-icon | \-
t-class-text | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-back-top-round-bg-color | @font-white-1 | -
--td-back-top-round-border-color | @component-border | -
--td-back-top-round-border-radius | @radius-circle | -
--td-back-top-round-color | @font-gray-1 | -
--td-back-top-round-dark-bg-color | @gray-color-14 | -
--td-back-top-round-dark-color | @font-white-1 | -

View File

@@ -0,0 +1,72 @@
---
title: BackTop 返回顶部
description: 用于当页面过长往下滑动时,帮助用户快速回到页面顶部。
spline: navigation
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-100%25-blue" /></span>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-back-top": "tdesign-miniprogram/back-top/back-top",
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/2aR1demj7aS2" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
<img src="https://tdesign.gtimg.com/miniprogram/readme/backtop-1.png" width="375px" height="50%">
### 基础返回顶部
{{ base }}
## API
### BackTop Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
fixed | Boolean | true | 是否绝对定位固定到屏幕右下方 | N
icon | String / Boolean / Object / Slot | true | 图标。值为 `false` 表示不显示图标。不传表示使用默认图标 `'backtop'`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
scroll-top | Number | 0 | 页面滚动距离 | N
text | String | '' | 文案 | N
theme | String | round | 预设的样式类型。可选项round/half-round/round-dark/half-round-dark | N
visibility-height | Number | 200 | 滚动高度达到此参数值才出现 | N
### BackTop Events
名称 | 参数 | 描述
-- | -- | --
to-top | \- | 点击触发
### BackTop External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-icon | 图标样式类
t-class-text | 文本样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-back-top-round-bg-color | @font-white-1 | -
--td-back-top-round-border-color | @component-border | -
--td-back-top-round-border-radius | @radius-circle | -
--td-back-top-round-color | @font-gray-1 | -
--td-back-top-round-dark-bg-color | @gray-color-14 | -
--td-back-top-round-dark-color | @font-white-1 | -

View File

@@ -0,0 +1,26 @@
import { SuperComponent, RelationsOptions } from '../common/src/index';
export default class BackTop extends SuperComponent {
externalClasses: string[];
options: {
multipleSlots: boolean;
};
properties: import("./type").TdBackTopProps;
relations: RelationsOptions;
data: {
prefix: string;
classPrefix: string;
_icon: any;
hidden: boolean;
};
observers: {
icon(): void;
scrollTop(value: number): void;
};
lifetimes: {
ready(): void;
};
methods: {
setIcon(v: any): void;
toTop(): void;
};
}

View File

@@ -0,0 +1,73 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
import { calcIcon } from '../common/utils';
const { prefix } = config;
const name = `${prefix}-back-top`;
let BackTop = class BackTop extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-icon`, `${prefix}-class-text`];
this.options = {
multipleSlots: true,
};
this.properties = props;
this.relations = {
'../pull-down-refresh/pull-down-refresh': {
type: 'ancestor',
},
};
this.data = {
prefix,
classPrefix: name,
_icon: null,
hidden: true,
};
this.observers = {
icon() {
this.setIcon();
},
scrollTop(value) {
const { visibilityHeight } = this.properties;
this.setData({ hidden: value < visibilityHeight });
},
};
this.lifetimes = {
ready() {
const { icon } = this.properties;
this.setIcon(icon);
},
};
this.methods = {
setIcon(v) {
this.setData({
_icon: calcIcon(v, 'backtop'),
});
},
toTop() {
var _a;
this.triggerEvent('to-top');
if (this.$parent) {
(_a = this.$parent) === null || _a === void 0 ? void 0 : _a.setScrollTop(0);
this.setData({ hidden: true });
}
else {
wx.pageScrollTo({
scrollTop: 0,
duration: 300,
});
}
},
};
}
};
BackTop = __decorate([
wxComponent()
], BackTop);
export default BackTop;

View File

@@ -0,0 +1,7 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {
"t-icon": "../icon/icon"
}
}

View File

@@ -0,0 +1,17 @@
<import src="../common/template/icon.wxml" />
<wxs src="../common/utils.wxs" module="_" />
<view
style="{{_._style([style, customStyle])}}"
class="class {{prefix}}-class {{_.cls(classPrefix, [['fixed', fixed], theme])}}"
bindtap="toTop"
aria-role="button"
hidden="{{hidden}}"
>
<view class="{{classPrefix}}__icon" aria-hidden>
<slot name="icon" />
<template wx:if="{{_icon}}" is="icon" data="{{tClass: prefix + '-class-icon', ..._icon }}" />
</view>
<view wx:if="{{!!text}}" class="{{classPrefix}}__text--{{theme}} {{prefix}}-class-text">{{text}}</view>
<slot />
</view>

View File

@@ -0,0 +1,91 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-back-top {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: transparent;
overflow: hidden;
box-sizing: border-box;
transition: height 0.2s;
height: auto;
}
.t-back-top--fixed {
position: fixed;
right: var(--td-spacer, 16rpx);
bottom: calc(var(--td-spacer-2, 32rpx) + env(safe-area-inset-bottom));
}
.t-back-top--round,
.t-back-top--round-dark {
width: 96rpx;
height: 96rpx;
border-radius: var(--td-back-top-round-border-radius, var(--td-radius-circle, 50%));
}
.t-back-top--round,
.t-back-top--half-round {
color: var(--td-back-top-round-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
border: 1rpx solid var(--td-back-top-round-border-color, var(--td-component-border, var(--td-gray-color-4, #dcdcdc)));
background-color: var(--td-back-top-round-bg-color, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
}
.t-back-top--round-dark,
.t-back-top--half-round-dark {
color: var(--td-back-top-round-dark-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
background-color: var(--td-back-top-round-dark-bg-color, var(--td-gray-color-13, #242424));
}
.t-back-top--half-round,
.t-back-top--half-round-dark {
width: 120rpx;
height: 80rpx;
border-radius: 0;
border-top-left-radius: var(--td-back-top-half-round-border-radius, var(--td-radius-round, 999px));
border-bottom-left-radius: var(--td-back-top-half-round-border-radius, var(--td-radius-round, 999px));
flex-direction: row;
right: 0;
}
.t-back-top__text--round,
.t-back-top__text--round-dark,
.t-back-top__text--half-round,
.t-back-top__text--half-round-dark {
font-size: var(--td-font-size, 20rpx);
line-height: 24rpx;
}
.t-back-top__text--half-round,
.t-back-top__text--half-round-dark {
width: 48rpx;
}
.t-back-top__icon:not(:empty) + .t-back-top__text--half-round,
.t-back-top__icon:not(:empty) + .t-back-top__text--half-round-dark {
margin-left: 8rpx;
}
.t-back-top__icon {
display: flex;
justify-content: center;
align-items: center;
font-size: 44rpx;
}

View File

@@ -0,0 +1,3 @@
import { TdBackTopProps } from './type';
declare const props: TdBackTopProps;
export default props;

View File

@@ -0,0 +1,31 @@
const props = {
fixed: {
type: Boolean,
value: true,
},
icon: {
type: null,
value: true,
},
scrollTop: {
type: Number,
value: 0,
},
style: {
type: String,
value: '',
},
text: {
type: String,
value: '',
},
theme: {
type: String,
value: 'round',
},
visibilityHeight: {
type: Number,
value: 200,
},
};
export default props;

View File

@@ -0,0 +1,30 @@
export interface TdBackTopProps {
fixed?: {
type: BooleanConstructor;
value?: boolean;
};
icon?: {
type: null;
value?: string | boolean | object;
};
scrollTop?: {
type: NumberConstructor;
value?: number;
};
style?: {
type: StringConstructor;
value?: string;
};
text?: {
type: StringConstructor;
value?: string;
};
theme?: {
type: StringConstructor;
value?: 'round' | 'half-round' | 'round-dark' | 'half-round-dark';
};
visibilityHeight?: {
type: NumberConstructor;
value?: number;
};
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,45 @@
:: BASE_DOC ::
## API
### Badge Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
color | String | - | \- | N
content | String | - | \- | N
count | String / Number / Slot | 0 | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
dot | Boolean | false | \- | N
max-count | Number | 99 | \- | N
offset | Array | - | Typescript`Array<string \| number>` | N
shape | String | circle | options: circle/square/bubble/ribbon | N
show-zero | Boolean | false | \- | N
size | String | medium | options: medium/large | N
### Badge External Classes
className | Description
-- | --
t-class | \-
t-class-content | \-
t-class-count | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-badge-basic-height | 32rpx | -
--td-badge-basic-padding | 8rpx | -
--td-badge-basic-width | 32rpx | -
--td-badge-bg-color | @error-color | -
--td-badge-border-radius | 4rpx | -
--td-badge-bubble-border-radius | 20rpx 20rpx 20rpx 1px | -
--td-badge-dot-size | 16rpx | -
--td-badge-font-size | @font-size-xs | -
--td-badge-font-weight | 600 | -
--td-badge-large-font-size | @font-size-s | -
--td-badge-large-height | 40rpx | -
--td-badge-large-padding | 10rpx | -
--td-badge-text-color | @font-white-1 | -

View File

@@ -0,0 +1,86 @@
---
title: Badge 徽标
description: 用于告知用户,该区域的状态变化或者待处理任务的数量。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-100%25-blue" /></span>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-badge": "tdesign-miniprogram/badge/badge"
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/TgaeQimG73SD" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 组件类型
{{ base }}
### 组件样式
{{ theme }}
### 组件尺寸
{{ size }}
## FAQ
### 如何处理由 ribbon 徽标溢出导致页面出现横向滚动?
角标溢出问题建议从父容器组件处理。如 <a href="https://github.com/Tencent/tdesign-miniprogram/issues/3063" title="如 #3063 " target="_blank" rel="noopener noreferrer"> #3063 </a>,可以给父容器 `cell` 组件添加 `overflow: hidden`,处理溢出造成页面出现横向滚动的问题。
## API
### Badge Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
color | String | - | 颜色 | N
content | String | - | 徽标内容,示例:`content='自定义内容'`。也可以使用默认插槽定义 | N
count | String / Number / Slot | 0 | 徽标右上角内容。可以是数字,也可以是文字。如:'new'/3/99+。特殊:值为空表示使用插槽渲染。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
dot | Boolean | false | 是否为红点 | N
max-count | Number | 99 | 封顶的数字值 | N
offset | Array | - | 设置状态点的位置偏移,示例:[-10, 20] 或 ['10em', '8rem']。TS 类型:`Array<string \| number>` | N
shape | String | circle | 形状。可选项circle/square/bubble/ribbon | N
show-zero | Boolean | false | 当数值为 0 时,是否展示徽标 | N
size | String | medium | 尺寸。可选项medium/large | N
### Badge External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-content | 内容样式类
t-class-count | 计数样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-badge-basic-height | 32rpx | -
--td-badge-basic-padding | 8rpx | -
--td-badge-basic-width | 32rpx | -
--td-badge-bg-color | @error-color | -
--td-badge-border-radius | 4rpx | -
--td-badge-bubble-border-radius | 20rpx 20rpx 20rpx 1px | -
--td-badge-dot-size | 16rpx | -
--td-badge-font-size | @font-size-xs | -
--td-badge-font-weight | 600 | -
--td-badge-large-font-size | @font-size-s | -
--td-badge-large-height | 40rpx | -
--td-badge-large-padding | 10rpx | -
--td-badge-text-color | @font-white-1 | -

View File

@@ -0,0 +1,21 @@
import { SuperComponent } from '../common/src/index';
import type { TdBadgeProps } from './type';
export interface BadgeProps extends TdBadgeProps {
}
export default class Badge extends SuperComponent {
options: {
multipleSlots: boolean;
};
externalClasses: string[];
properties: TdBadgeProps;
data: {
prefix: string;
classPrefix: string;
value: string;
labelID: string;
descriptionID: string;
};
lifetimes: {
ready(): void;
};
}

View File

@@ -0,0 +1,43 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
import { uniqueFactory } from '../common/utils';
const { prefix } = config;
const name = `${prefix}-badge`;
const getUniqueID = uniqueFactory('badge');
let Badge = class Badge extends SuperComponent {
constructor() {
super(...arguments);
this.options = {
multipleSlots: true,
};
this.externalClasses = [`${prefix}-class`, `${prefix}-class-count`, `${prefix}-class-content`];
this.properties = props;
this.data = {
prefix,
classPrefix: name,
value: '',
labelID: '',
descriptionID: '',
};
this.lifetimes = {
ready() {
const uniqueID = getUniqueID();
this.setData({
labelID: `${uniqueID}_label`,
descriptionID: `${uniqueID}_description`,
});
},
};
}
};
Badge = __decorate([
wxComponent()
], Badge);
export default Badge;

View File

@@ -0,0 +1,5 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {}
}

View File

@@ -0,0 +1,34 @@
<wxs src="./badge.wxs" module="_this" />
<wxs src="../common/utils.wxs" module="_" />
<!--
1. labelID 用于描述当前元素的文本
2. descriptionID 用于描述badge消息的文本
3. role=option一般用于多个内容合并焦点连续朗读
-->
<view
style="{{_._style([style, customStyle])}}"
class="{{_this.getBadgeOuterClass({shape})}} class {{prefix}}-class"
aria-labelledby="{{labelID}}"
aria-describedby="{{descriptionID}}"
aria-role="{{ ariaRole || 'option'}}"
>
<view id="{{labelID}}" class="{{classPrefix}}__content {{prefix}}-class-content" aria-hidden="true">
<slot wx:if="{{!content}}" class="{{classPrefix}}__content-slot" />
<text wx:else class="{{classPrefix}}__content-text">{{content}}</text>
</view>
<view
aria-hidden="true"
aria-label="{{ ariaLabel || _.getBadgeAriaLabel({dot, count, maxCount}) }}"
wx:if="{{_this.isShowBadge({dot,count,showZero})}}"
id="{{descriptionID}}"
class="{{_this.getBadgeInnerClass({dot, size, shape, count})}} {{prefix}}-has-count {{prefix}}-class-count"
style="{{_._style([_this.getBadgeStyles({color, offset})])}}"
aria-hidden="true"
aria-label="{{ ariaLabel || _.getBadgeAriaLabel({dot, count, maxCount}) }}"
>
{{ _this.getBadgeValue({dot, count, maxCount}) }}
</view>
<slot name="count" />
</view>

View File

@@ -0,0 +1,71 @@
var getBadgeValue = function (props) {
if (props.dot) {
return '';
}
if (isNaN(props.count) || isNaN(props.maxCount)) {
return props.count;
}
return parseInt(props.count) > props.maxCount ? props.maxCount + '+' : props.count;
};
var hasUnit = function (unit) {
return (
unit.indexOf('px') > 0 ||
unit.indexOf('rpx') > 0 ||
unit.indexOf('em') > 0 ||
unit.indexOf('rem') > 0 ||
unit.indexOf('%') > 0 ||
unit.indexOf('vh') > 0 ||
unit.indexOf('vm') > 0
);
};
var getBadgeStyles = function (props) {
var styleStr = '';
if (props.color) {
styleStr += 'background:' + props.color + ';';
}
if (props.offset[0]) {
styleStr +=
'left: calc(100% + ' + (hasUnit(props.offset[0].toString()) ? props.offset[0] : props.offset[0] + 'px') + ');';
}
if (props.offset[1]) {
styleStr += 'top:' + (hasUnit(props.offset[1].toString()) ? props.offset[1] : props.offset[1] + 'px') + ';';
}
return styleStr;
};
var getBadgeOuterClass = function (props) {
var baseClass = 't-badge';
var classNames = [baseClass, props.shape === 'ribbon' ? baseClass + '__ribbon-outer' : ''];
return classNames.join(' ');
};
var getBadgeInnerClass = function (props) {
var baseClass = 't-badge';
var classNames = [
baseClass + '--basic',
props.dot ? baseClass + '--dot' : '',
baseClass + '--' + props.size,
baseClass + '--' + props.shape,
!props.dot && props.count ? baseClass + '--count' : '',
];
return classNames.join(' ');
};
var isShowBadge = function (props) {
if (props.dot) {
return true;
}
if (!props.showZero && !isNaN(props.count) && parseInt(props.count) === 0) {
return false;
}
if (props.count == null) return false;
return true;
};
module.exports.getBadgeValue = getBadgeValue;
module.exports.getBadgeStyles = getBadgeStyles;
module.exports.getBadgeOuterClass = getBadgeOuterClass;
module.exports.getBadgeInnerClass = getBadgeInnerClass;
module.exports.isShowBadge = isShowBadge;

View File

@@ -0,0 +1,113 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-badge {
position: relative;
display: inline-flex;
align-items: start;
}
.t-badge--basic {
z-index: 100;
padding: 0 var(--td-badge-basic-padding, 8rpx);
font-size: var(--td-badge-font-size, var(--td-font-size-xs, var(--td-font-size, 20rpx)));
color: var(--td-badge-text-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
background-color: var(--td-badge-bg-color, var(--td-error-color, var(--td-error-color-6, #d54941)));
text-align: center;
height: var(--td-badge-basic-height, 32rpx);
line-height: var(--td-badge-basic-height, 32rpx);
font-weight: var(--td-badge-font-weight, 600);
border-radius: var(--td-badge-border-radius, 4rpx);
}
.t-badge--dot {
height: var(--td-badge-dot-size, 16rpx);
border-radius: 50%;
min-width: var(--td-badge-dot-size, 16rpx);
padding: 0;
}
.t-badge--count {
min-width: var(--td-badge-basic-width, 32rpx);
white-space: nowrap;
box-sizing: border-box;
}
.t-badge--circle {
border-radius: calc(var(--td-badge-basic-height, 32rpx) / 2);
}
.t-badge__ribbon-outer {
position: absolute;
top: 0;
right: 0;
}
.t-badge--ribbon {
position: relative;
display: inline-block;
transform-origin: center center;
transform: translate(calc(50% - var(--td-badge-basic-height, 32rpx) + 1rpx), calc(-50% + var(--td-badge-basic-height, 32rpx) - 1rpx)) rotate(45deg);
border-radius: 0;
}
.t-badge--ribbon::before,
.t-badge--ribbon::after {
content: '';
position: absolute;
width: 0;
height: 0;
bottom: 0;
border-bottom: var(--td-badge-basic-height, 32rpx) solid var(--td-badge-bg-color, var(--td-error-color, var(--td-error-color-6, #d54941)));
font-size: 0;
}
.t-badge--ribbon::before {
left: calc(-1 * var(--td-badge-basic-height, 32rpx) + 1rpx);
border-left: var(--td-badge-basic-height, 32rpx) solid transparent;
}
.t-badge--ribbon::after {
right: calc(-1 * var(--td-badge-basic-height, 32rpx) + 1rpx);
border-right: var(--td-badge-basic-height, 32rpx) solid transparent;
}
.t-badge--bubble {
border-radius: var(--td-badge-bubble-border-radius, 20rpx 20rpx 20rpx 1px);
}
.t-badge--large {
font-size: var(--td-badge-large-font-size, var(--td-font-size-s, 24rpx));
height: var(--td-badge-large-height, 40rpx);
min-width: var(--td-badge-large-height, 40rpx);
line-height: var(--td-badge-large-height, 40rpx);
padding: 0 var(--td-badge-large-padding, 10rpx);
}
.t-badge--large.t-badge--circle {
border-radius: calc(var(--td-badge-large-height, 40rpx) / 2);
}
.t-badge__content:not(:empty) + .t-has-count {
transform-origin: center center;
transform: translate(-50%, -50%);
position: absolute;
left: 100%;
top: 0;
}
.t-badge__content-text {
display: block;
line-height: 48rpx;
color: var(--td-badge-content-text-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
}

View File

@@ -0,0 +1,3 @@
export * from './type';
export * from './props';
export * from './badge';

View File

@@ -0,0 +1,3 @@
export * from './type';
export * from './props';
export * from './badge';

View File

@@ -0,0 +1,3 @@
import { TdBadgeProps } from './type';
declare const props: TdBadgeProps;
export default props;

View File

@@ -0,0 +1,41 @@
const props = {
color: {
type: String,
value: '',
},
content: {
type: String,
value: '',
},
count: {
type: null,
value: 0,
},
dot: {
type: Boolean,
value: false,
},
externalClasses: {
type: Array,
},
maxCount: {
type: Number,
value: 99,
},
offset: {
type: Array,
},
shape: {
type: String,
value: 'circle',
},
showZero: {
type: Boolean,
value: false,
},
size: {
type: String,
value: 'medium',
},
};
export default props;

Some files were not shown because too many files have changed in this diff Show More