kps-component
v2.0.0
Published
- [KPS-Component Api/Components Document](#kps-component-apicomponents-document) - [1. Reference](#1-reference) - [1/1 Shotgun Api Document](#11-shotgun-api-document) - [1/2 Introduction](#12-introduction) - [2. Read/Create/Update/Delete](
Downloads
18
Readme
KPS-Component Api/Components Document
- KPS-Component Api/Components Document
1. Reference
1/1 Shotgun Api Document
https://developer.shotgunsoftware.com/rest-api/?javascript
1/2 Introduction
在./src/index.js 中必需配置服务器信息
//./src/.index.js
import Api, { CorsImage, CorsVideo, ImageViewer } from 'kps-components'
Api.config = {
//全部必填实际信息
grant_type: '',
client_id: '',
client_secret: '',
host: '',
hostApi: '',
}
const dev = process.env.NODE_ENV === 'development'
if (!dev) {
Api.trackClient() // 注册追踪页面接口,开发环境下不追踪
}
2. Read/Create/Update/Delete
entityName 必须属于类似下面 entity type 中的类型,即 shotgun entity 在后台的名字
'Asset',
'Attachment',
'Department',
'EventLogEntry',
'Group',
'HumanUser',
'Note',
'Page',
'Phase',
'PhysicalAsset',
'Project',
'Reply',
'Software',
'Status',
'Step',
'Tag',
'Task',
'Version',
'CustomNonProjectEntity12',
'PermissionRuleSet'
......
2/1 Read
id 查询一个条目示例
Api.getEntityFromId({
entityName: 'Task', //必填
id: 23844, //必填
fields: ['id', 'content', 'created_at'], //必填 填入要查询的字段列表
linkEntities: [
//选填
{
fieldName: 'sg_title_type', //在上面fields中必须写入
fieldType: 'CustomNonProjectEntity12',
fields: ['id', 'code', 'sg_title_level'],
multiple: false, //field 类型是entity or multi-entity
},
{
fieldName: 'tags',
fieldType: 'Tag',
fields: ['id', 'name', 'sg_tag_type'],
multiple: true,
},
], //查询关联entity的详细Field,默认查询只有entity的id和name, [{fieldName:'some_field',fieldType: 'someEntityType', multiple: false/true, fields: ['id', 'code', ...]}], 注意linkEntities次级查询总条目数上限5000
}).then((res) => {
console.log('res', res)
})
查询符合条件的一组数据示例
Api.getEntityList({
entityName: 'HumanUser', //必填
fields: ['id', 'name', 'sg_title_type', 'department', 'tags'], //选填 填入要查询的字段列表
filters: [//必填,可以是array或hash形式,hash形式示例见下个示例
['sg_status_list', 'is', 'act'],
['name', 'contains', 'li'],
],
options: { sort: '-created_at', number: 1, size: 500 }, //选填 使用方式见上方kpsapi.getEntityFromId()
linkEntities: [] //选填 使用方式见上方kpsapi.getEntityFromId()
totalCount = true, //选填 是否返回符合条件的总条目数,分页时使用
}).then((res) => {
console.log('res', res)
})
筛选 hash 形式示例
Api.getEntityList({
entityName: 'HumanUser',
fields: ['id', 'name', 'sg_title_type', 'department', 'tags'],
filters: {
logical_operator: 'and',
conditions: [
['sg_status_list', 'is', 'act'],
['name', 'contains', 'li'],
//可继续添加复杂条件嵌套
//{
// logical_operator: 'and',
// conditions: [
// ['name', 'is', 'Demo Project'],
// ['sg_status_list', 'is', 'res'],
// ],
//},
],
},
options: { size: 500 },
}).then((res) => {
console.log('res', res)
})
获取统计信息示例
Api.getSummarize({
entityName: 'HumanUser',
filters: [['sg_status_list', 'is', 'act']],
fields: [{ field: 'id', type: 'count' }],
grouping: [{ field: 'sg_asset_type', type: 'exact', direction: 'asc' }],
//or 不分组grouping: null
}).then((res) => {
console.log('res', res)
})
//统计信息 type 类型详见文档
//https://developer.shotgunsoftware.com/rest-api/?javascript#summarize-field-data
//常用:record_count, count, sum, maximum, minimum, average, earliest, latest...
2/2 Create
创建一个条目
Api.createEntity({
entityName: 'Task', //必填
fields: ['content', 'project', 'id'], //选填 返回的相关字段信息
variables: {
//必填 有些entity类型必填project字段
content: 'task create demo',
project: { id: 94, type: 'Project' },
//other_field:value
},
linkEntities: [], //选填 返回的关联entity信息
}).then((res) => {
console.log('res', res)
})
批量创建条目
Api.batchCreate({
entityName: 'Task', //必填
fields: ['content', 'project', 'id'], //选填
variables: [ //必填 array形式
{
content: 'task create demo 0',
project: { id: 94, type: 'Project' },
//other_field:value
},
{
content: 'task create demo 1',
project: { id: 94, type: 'Project' },
//other_field:value
},
],
linkEntities:[] //选填 返回的关联entity信息
options: null //选填
totalCount: false //选填
}).then((res) => {
console.log('res', res)
})
2/3 Update
更新一个条目
Api.updateEntity({
entityName: 'Task', //必填
id: 24347, //必填
variables: {
//必填
content: 'Cool task update',
project: { id: 94, type: 'Project' },
//other_field:value
},
fields: ['id', 'start_date'],
linkEntities: [], //选填 返回的关联entity信息
}).then((res) => {
console.log('res', res)
})
批量更新条目
Api.batchUpdate({
entityName: 'Task', //必填
variables: [ //必填 array形式
{
id: 123,
content: 'Cool task create update 1',
project: { id: 94, type: 'Project' },
//other_field:value
},
{
id: 124,
content: 'Cool task create update 2',
project: { id: 97, type: 'Project' },
//other_field:value
},
],
fields: ['id', 'start_date'],
linkEntities:[] //选填 返回的关联entity信息
options: null //选填
totalCount: false //选填
}).then((res) => {
console.log('res', res)
})
2/4 Delete
删除一个条目
Api.deleteEntity({
entityName: 'Version',
id: 43691,
}).then((res) => {
console.log('res', res)
})
批量删除条目
Api.batchDelete({
entityName: 'Version',
ids: [121, 122, 123, 124],
}).then((res) => {
console.log('res', res)
})
2/5 Track
1. normal track
建议在每个应用的./src/App.js 中定义全局配置,保证重复信息只输入一次
window.track = (e) => {
e.channel = 'Application Center' //当前频道名
e.code = 'Digital Center' //当前应用名
if (window.userInfo) {
//在查询到当前用户信息后赋值
e.userInfo = { type: 'HumanUser', id: parseInt(window.userInfo.id) }
}
Api.track(e)
}
在需要的节点传入相应值,调用 window.track(e),某个 track 示例:
window.track({
page: 'issue management', //以下根据需要选填
module: 'issue card',
component: 'add button',
actionType: 'click',
actionResult: 'add',
desc: '',
projectId: 123,
})
2. client track
在 App.js 的初始 useEffect()注册
// ./App.js
// function App(){
useEffect(() => {
Api.trackClient()
}, [])
// }
2/6 Tools
使用时直接调用 Api.isImage(...)
const specialCode =
/[(\~)(\!)(\@)(\#)(\$)(\%)(\^)(\&)(\()(\))(\+)(\=)(\[)(\])(\{)(\})(\;)(\')(\,)(\,)]+/g
const fileTypeIcon = {
ppt: 'https://z3.ax1x.com/2021/08/11/fNDrtK.png',
pptx: 'https://z3.ax1x.com/2021/08/11/fNDrtK.png',
doc: 'https://z3.ax1x.com/2021/08/11/fNDOns.png',
docx: 'https://z3.ax1x.com/2021/08/11/fNDOns.png',
xls: 'https://z3.ax1x.com/2021/08/11/fNDMmn.png',
xlsx: 'https://z3.ax1x.com/2021/08/11/fNDMmn.png',
wire: 'https://z3.ax1x.com/2021/08/11/fNDItf.png',
igs: 'https://z3.ax1x.com/2021/08/11/fNDUX9.png',
iges: 'https://z3.ax1x.com/2021/08/11/fNDUX9.png',
other: 'https://z3.ax1x.com/2021/08/11/fNDw01.png',
psd: 'https://z3.ax1x.com/2021/08/11/fNDc1e.png',
ps: 'https://z3.ax1x.com/2021/08/11/fNDc1e.png',
sketch: 'https://z3.ax1x.com/2021/08/11/fNDWnA.png',
ai: 'https://z3.ax1x.com/2021/08/11/fNDuOs.png',
img: 'https://z3.ax1x.com/2021/08/11/fNDdmR.png',
zip: 'https://z3.ax1x.com/2021/08/11/fNDXBn.png',
rar: 'https://z3.ax1x.com/2021/08/11/fNDXBn.png',
video: 'https://z3.ax1x.com/2021/08/11/fNDh7t.png',
txt: 'https://z3.ax1x.com/2021/08/11/fNDf0I.png',
stp: 'https://z3.ax1x.com/2021/08/11/fND5AP.png',
step: 'https://z3.ax1x.com/2021/08/11/fND5AP.png',
pdf: 'https://z3.ax1x.com/2021/08/11/fND0Tx.png',
eps: 'https://z3.ax1x.com/2021/08/11/fNDnyj.png',
'3dm': 'https://z3.ax1x.com/2021/08/11/fNDlT0.png',
gh: 'https://z3.ax1x.com/2021/08/11/fNDQwq.png',
}
const haveSpecialCode = (name) => {
return specialCode.test(name)
}
const replaceSpecialCode = (name, toCode = '_') => {
return name.replace(specialCode, toCode)
}
const isImage = (origUrl) => {
return /\.(png|tif|tiff|jpg|gif|jpeg|webp)$/i.test(origUrl)
}
const isVideo = (origUrl) => {
return /\.(mp4|ogg|webm|m4v)$/i.test(origUrl)
}
const isVersionImage = (item) => {
return (
item.sg_uploaded_movie &&
/\.(png|tif|tiff|jpg|gif|jpeg|webp)$/i.test(item.sg_uploaded_movie.name)
)
}
const isVersionVideo = (item) => {
return (
item.sg_uploaded_movie &&
/\.(mp4|ogg|webm|m4v)$/i.test(item.sg_uploaded_movie.name)
)
}
const getReplaceThumbnailIcon = (name) => {
const strList = name.split('.')
const sub = strList[strList.length - 1].toLowerCase()
if (strList.length === 1 || Object.keys(fileTypeIcon).indexOf(sub) < 0) {
return fileTypeIcon.other
} else {
return fileTypeIcon[sub]
}
}
const getVersionThumb = (item) => {
// sg_thumb_image, sg_trans_image, image, sg_uploaded_movie
let thumbUrl
if (!item.sg_uploaded_movie) {
thumbUrl = fileTypeIcon.other
} else if (item.sg_thumb_image) {
thumbUrl = item.sg_thumb_image.url
} else if (
item.image &&
item.image.indexOf('/transient/thumbnail_pending.png') < 0
) {
thumbUrl = item.image
} else {
if (isImage(item.sg_uploaded_movie.name)) {
thumbUrl = fileTypeIcon.img
} else if (isVideo(item.sg_uploaded_movie.name)) {
thumbUrl = fileTypeIcon.video
} else {
thumbUrl = getReplaceThumbnailIcon(item.sg_uploaded_movie.name)
}
}
return thumbUrl
}
const getVersionThumbType = (item) => {
let type = 'original'
if (!item.sg_uploaded_movie) {
type = 'original'
} else if (item.sg_thumb_image) {
type = 'original'
} else if (
item.image &&
item.image.indexOf('/transient/thumbnail_pending.png') < 0
) {
type = 'original'
} else {
type = 'icon'
}
return type
}
const getVersionShow = (item) => {
let url
if (!item.sg_uploaded_movie) {
url = fileTypeIcon.other
} else if (item.sg_trans_image) {
url = item.sg_trans_image.url
} else {
url = item.sg_uploaded_movie.url
}
return url
}
const isGroupOverlap = (a1, a2, targetKey = 'id') => {
/*
a1 = [{id:1, name:1},{id:2, name:2}]
a2 = [{id:1, name:1},{id:3, name:3}]
return true
*/
let isIn = false
a1.some((e1) => {
if (a2.findIndex((e2) => e2[targetKey] === e1[targetKey]) > -1) {
isIn = true
return true
}
return false
})
return isIn
}
const isAppPermissioned = (userInfo, appInfo) => {
// 判断用户是否拥有用户权限,参数是用户信息(含有'userInfo.groups' Fields)和app信息(含有四个权限Fields)
if (
appInfo.sg_excluding_people.data.length > 0 &&
appInfo.sg_excluding_people.data.findIndex((e) => e.id === userInfo.id) >= 0
) {
return false
}
if (
appInfo.sg_including_people.data.length > 0 &&
appInfo.sg_including_people.data.findIndex((e) => e.id === userInfo.id) >= 0
) {
return true
}
if (
appInfo.sg_excluding_groups.data.length > 0 &&
isGroupOverlap(userInfo.groups.data, appInfo.sg_excluding_groups.data)
) {
return false
}
if (appInfo.sg_including_groups.data.length > 0) {
return isGroupOverlap(
userInfo.groups.data,
appInfo.sg_including_groups.data
)
} else {
return true
}
}
export const tools = {
isAppPermissioned,
isGroupOverlap,
haveSpecialCode,
replaceSpecialCode,
isImage,
isVideo,
isVersionImage,
isVersionVideo,
getVersionThumb,
getVersionShow,
getVersionThumbType,
getReplaceThumbnailIcon,
}
2/7 Download
// 单个文件下载
Api.downloadFile({
entityName: 'Version',
field: 'sg_uploaded_movie' //entity文件类型的字段
fileList: {
name: '1.jpg', // 带有实际文件名后缀
id: 123, // entity的id,不是file的id
},
}).then(res=>{
// 成功返回 'success'
}).catch(err=>{
// 失败返回 'fail'
})
// 多个文件下载
Api.downloadFileList({
entityName: 'Version',
field: 'sg_uploaded_movie' //entity文件类型的字段
fileList: [
{
name: '1.jpg', //带有实际文件名后缀
id: 123, //entity的id,不是file的id
},
{
name: '2.jpg',
id: 124,
},
],
}) //没有返回值
2/8 获取 SG 文件或图片信息
// 获取单个文件内容
Api.getFileContent({
entityName: 'Version', //必填
fileInfo: {
id: 123, // entity id
name: '123.jpg', // file name
},
field: 'sg_uploaded_movie', // 文件所在field
}).then((res) => {
console.log('res', res)
})
## 3. Other Options
### 3/1. Filter / Search
使用复杂的条件 query
> "filters": [[field, relation, value(s)]]
Array Style
```js
//dmeo1:
"filters": [["name", "contains", "template"]]
//demo2:
"filters": [
["name", "contains", "template"],
["is_demo", "is", true]
]
Hash Style 多组及嵌套
"filters": {
"logical_operator": "or", //'and'
"conditions": [
["is_demo", "is", true],
["sg_status", "in", ["Hold", "Lost"]]
]
}
"filters":{
"logical_operator": "or",
"conditions": [
{
"logical_operator": "and",
"conditions": [
["name", "is", "Demo Project"]
["sg_status_list", "is" "res"]
]
},
["name", "is", "Game Demo"]
]
}
3/2. Operators and Arguments
操作符和对应的参数列表
| Operator | Arguments | Notes | | ------------------- | --------------------------------------------------------------------- | ----- | | 'is' | [field_value] / None | | 'is_not' | [field_value] / None | | 'less_than' | [field_value] | None | | 'greater_than' | [field_value] / None | | 'contains' | [field_value] / None | | 'not_contains' | [field_value] / None | | 'starts_with' | [string] | | 'ends_with' | [string] | | 'between' | [[field_value] / None, [field_value]/ None] | | 'not_between' | [[field_value] / None, [field_value] / None] | | 'in_last' | [[int], 'HOUR' / 'DAY' / 'WEEK'/ 'MONTH' / 'YEAR'] | | 'in_next' | [[int], 'HOUR'/ 'DAY' / 'WEEK' / 'MONTH' / 'YEAR'] | | 'in' | [[field_value] / None, ...] # Array of field values | | 'type_is' | [string] / None # Shotgun entity type | | 'type_is_not' | [string] / None # Shotgun entity type | | 'in_calendar_day' | [int] # Offset (e.g. 0 = today, 1 = tomorrow, -1 = yesterday) | | 'in_calendar_week' | [int] # Offset (e.g. 0 = this week, 1 = next week, -1 = last week) | | 'in_calendar_month' | [int] # Offset (e.g. 0 = this month, 1 = next month, -1 = last month) | | 'name_contains' | [string] | | 'name_not_contains' | [string] | | 'name_starts_with' | [string] | | 'name_ends_with' | [string] |
3/3. Valid Operators By Data Type
不同类型 Field 识别的操作符
| Field type | Operators | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | addressing | 'is'/'is_not'/'contains'/'not_contains'/'in'/'type_is' /'type_is_not'/'name_contains' / 'name_not_contains'/'name_starts_with'/'name_ends_with' | | checkbox | 'is'/'is_not' | | currency | 'is'/'is_not'/'less_than'/'greater_than'/'between'/'not_between'/'in'/'not_in'/date/ 'is'/'is_not'/'greater_than'/'less_than'/'in_last'/'not_in_last'/'in_next'/'not_in_next' /'in_calendar_day'/'in_calendar_week'/'in_calendar_month' /'in_calendar_year' /'between'/'in'/'not_in' | | date_time | 'is'/'is_not'/'greater_than'/'less_than'/'in_last'/'not_in_last'/'in_next'/'not_in_next' / 'in_calendar_day'/'in_calendar_week'/'in_calendar_month'/ 'in_calendar_year'/'between'/'in'/'not_in' | | duration | 'is'/'is_not'/'greater_than'/'less_than'/'between'/'in'/'not_in' | | entity | 'is'/'is_not'/'type_is'/'type_is_not'/'name_contains'/'name_not_contains'/'name_is'/'in'/'not_in' | | float | 'is'/'is_not'/'greater_than'/'less_than'/'between'/'in'/'not_in' | | image | 'is'/'is_not' ** Note: For both 'is' and 'is_not', the only supported value is None, ** which supports detecting the presence or lack of a thumbnail. | | list | 'is'/'is_not'/'in'/'not_in' | | multi_entity | 'is' ** Note: when used on multi_entity, this functions as you would expect 'contains' to function/ 'is_not'/'type_is'/'type_is_not'/ 'name_contains'/'name_not_contains'/'in'/'not_in' | | number | 'is'/'is_not'/'less_than'/'greater_than'/'between'/'not_between'/'in'/'not_in' | | password | ** Filtering by this data type field not supported | | percent | 'is'/'is_not'/'greater_than'/'less_than'/'between'/'in'/'not_in' | | serializable | ** Filtering by this data type field not supported | | status_list | 'is'/'is_not'/'in'/'not_in' | | summary | ** Filtering by this data type field not supported | | text | 'is'/ is_not'/'contains'/'not_contains'/'starts_with'/'ends_with'/'in'/'not_in' | | timecode | 'is'/'is_not'/'greater_than'/'less_than'/'between'/'in'/'not_in' | | url | ** Filtering by this data type field is not supported |
3/4. Data Types
写入不同类型 Field 的数据类型
| Name | Type | Example/Format | Notes | | --------------------- | ------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | addressing | array | [{'type': "HumanUser" or "Group", "id": }, ...] | | | checkbox | bool | true / false | | | color | string | 255,0,0 / pipeline_step | pipeline_step indicates the Task color inherits from the Pipeline Step color. | | currency | float / null | | Range: -9999999999999.99 to 9999999999999.99 | | date | string / null | YYYY-MM-DD | Year must be >= 1970 | | date_time | string / null | YYYY-MM-DDThh:mm:ssZ | Datetimes must be in the ISO8601 format. | | duration | int / null | | Range: -2147483648 to 2147483647. Length of time, in minutes | | entity | object / null | {'type': , "id": } | | | float | float / null | | Range: -9999999999999.99 to 9999999999999.99 | | footage | string / null | FF-ff | Frames must be < Preferences value for “Advanced > Number of frames per foot of film”> Format matches Preference value for “Formatting > Display of footage fields”. Example above is default.F=Feet f=Frames. | | image | string / null | | | | list | string / null | | | | multi_entity | array | [{'type': , "id": }, ...] | | | password | string / null | | | | number | int / null | | | | serializable | object / null | | | | status_list | string / null | | | | text | string / null | | | | timecode | int / null | | Range: -2147483648 to 2147483647. Length of time, in milliseconds (1000 = 1 second) | | url (file/link field) | object / null |
3/5. Updating a multi-entity field
更新某条目的某个属性是 multi entity 的字段,如 task 的 task_owners,version 的 tags
Simple assignment example (setting users to [436, 536])
{
"users": [
{
"type": "HumanUser",
"id": 436
},
{
"type": "HumanUser",
"id": 536
}
]
}
Add multi-entity update mode example (adding users [574, 538] to the field)
{
"users": {
"multi_entity_update_mode": "add",
"value": [
{
"type": "HumanUser",
"id": 574
},
{
"type": "HumanUser",
"id": 538
}
]
}
}
Remove multi-entity update mode example (removing users [103, 203] from the field)
{
"users": {
"multi_entity_update_mode": "remove",
"value": [
{
"type": "HumanUser",
"id": 103
},
{
"type": "HumanUser",
"id": 203
}
]
}
}
Set multi-entity update mode example (setting users to [436, 536])
{
"users": {
"multi_entity_update_mode": "set",
"value": [
{
"type": "HumanUser",
"id": 436
},
{
"type": "HumanUser",
"id": 536
}
]
}
}
4. Upload Files
4/1 Upload Api
上传并返回生成的 version 的 id
Api.createUploadVersion({
file: fileToUpload, //必填
variables: {
//必填 version的其它信息
code: 'upload version',
project: { type: 'Project', id: 97 },
//other_filed: value
},
})
用于直接上传到各 entity 内的 file 类型 field,如已知 version 更新文件
Api.uploadFileToField({
entityName: 'Version', //必填
id: 1234, //必填
field: 'sg_uploaded_movie', //必填 要上传到的字段
file: fileToUpload, //必填
})
4/2 React Upload Demo
import React, { useState, useEffect } from 'react'
import { Upload, Progress, Badge, Button, message } from 'antd'
import { InboxOutlined } from '@ant-design/icons'
const { Dragger } = Upload
export default function UploadModuleReact(props) {
const [fileList, setFileList] = useState([])
const [progressMock, setProgressMock] = useState(0)
const uploadProps = {
name: 'file',
multiple: true,
showUploadList: false,
fileList,
beforeUpload: (file, newAddFileList) => {
// 如果需要立即上传,在此处拦截
setFileList([...fileList, ...newAddFileList])
return false
},
}
const handleUpload = async () => {
console.log('fileList', fileList)
let createList = [],
pMock = 1,
sizeAll = 0
fileList.forEach((f) => {
sizeAll = sizeAll + f.size / 750000
createList.push(
Api.createUploadVersion({
file: f,
variables: {
//TODO: your version variables here
project: {
type: 'Project',
id: 0,
},
code: f.name,
sg_task: {
type: 'Task',
id: 0,
},
},
})
)
})
let mock = setInterval(() => {
if (pMock <= 99) {
pMock = parseFloat((pMock + 99 / sizeAll).toFixed(1))
pMock = Math.min(99, pMock)
setProgressMock(pMock)
}
}, 500)
let versionRes = await Promise.all(createList)
console.log('created versions: ', versionRes)
clearInterval(mock)
setProgressMock(100)
setFileList([])
setTimeout(() => {
setProgressMock(0)
message.success('Upload successfully')
}, 1000)
// write your finish functions here
// for images, use 'sg_thumb_image' to show image immediately
// use 'sg_trans_image' to show image at web page
}
return (
<div
style={{
width: '400px',
}}>
<Dragger {...uploadProps}>
<div
style={{
height: '68px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
{progressMock > 0 ? (
<Progress
percent={progressMock}
type='circle'
status='active'
width={72}
/>
) : (
<Badge count={fileList.length}>
<InboxOutlined style={{ fontSize: '46px', color: '#40a9ff' }} />
</Badge>
)}
</div>
<p
style={{
margin: ' 0 0 4px',
color: 'rgba(0, 0, 0, 0.85)',
fontSize: '16px',
}}>
{progressMock === 0
? 'Click or drag file here'
: progressMock === 99
? 'Finishing...'
: 'Click or drag file here'}
</p>
</Dragger>
<Button
onClick={handleUpload}
disabled={fileList.length === 0 || progressMock > 0}>
Start
</Button>
</div>
)
}
COMPONENTS
基于 React 和 Antd
// index.js
// 配置见 文档开头配置处
Image
跨域图片获取,必包含 info 内的内容
versions.map((v) => (
<CorsImage
key={v.id}
info={{
id: v.id,
type: 'Version',
name: v.sg_uploaded_movie.name, //此键值也可以是code, content, 分别对应version,task等,选一即可
field: 'sg_thumb_image',
className: 'hello-image',
}}
style={{
width: '300px',
height: '200px',
padding: '10px',
objectFit: 'auto', // 不填或'auto',则自动判断contain或cover
}}
/>
))
Video
跨域图片获取,必包含 info 内的内容
versions.map((v) => (
<CorsVideo
key={v.id}
info={{
id: v.id,
type: 'Version',
name: v.sg_uploaded_movie.name, //此键值也可以是code, content, 分别对应version,task等,选一即可
field: 'sg_thumb_image',
className: 'hello-image'
autoply:'autoplay',
loop:'loop',
controls: 'controls'
}}
style={{
width: '300px',
height: '200px',
}}
/>
))
ImageViewer
基本的图片列表和看图组件,包含右键下载和删除功能
TODO Update:
- 滚轮放大和缩小,左键拖拽
- 与父级框选操作冲突问题
import { ImageViewer } from 'kps-component'
...
const versionList = [........]
...
// Basic Demo
versionList.map(v => <ImageViewer
key={v.id}
item={v} //必填
itemList={versionList} //必填
onDelete={()=>{}} //默认undefined,必填,此处需要更新传入的VersionList
style={{}} //img wrapper style, 选填
showName={true} //默认false, 选填
onCloseViewModal={()=>{}} //默认undefined, 选填
onClickLeft={()=>{}} //默认undefined, 选填
onClickRight={()=>{}} //默认undefined, 选填
onDownload={()=>{}} //默认undefined, 选填
/>)
KpsIcons
kps 2.0 新图标svg icon,使用方式与antd icon相同
图标与与图片对应关系见...shotgun.../page/57145