Chart Series Summary Type eklendi

This commit is contained in:
Sedat Öztürk 2025-09-28 21:09:07 +03:00
parent d136fb2447
commit 531b924f5e
7 changed files with 103 additions and 61 deletions

View file

@ -91,6 +91,11 @@ public class ChartSeriesDto
/// FullStackedBarSeries,BubbleSeries,
/// </summary>
public string ValueField { get; set; }
/// <summary> Değer özetleme işlevini belirtir.
/// Accepted Values: 'avg' | 'count' | 'custom' | 'max' | 'min' | 'sum'
/// Default Value: 'sum'
/// </summary>
public string SummaryType { get; set; } = "sum";
/// <summary> Serinin görünür olup olmayacağını belirtir.
/// </summary>
public bool Visible { get; set; } = true;

View file

@ -40,6 +40,8 @@ public class ChartSeries : ValueObject
public string Type { get; private set; }
[JsonPropertyName("ValueField")]
public string ValueField { get; private set; }
[JsonPropertyName("SummaryType")]
public string SummaryType { get; private set; }
[JsonPropertyName("Visible")]
public bool Visible { get; private set; } = true;
[JsonPropertyName("Width")]
@ -69,6 +71,7 @@ public class ChartSeries : ValueObject
yield return ShowInLegend;
yield return Type;
yield return ValueField;
yield return SummaryType;
yield return Visible;
yield return Width;
yield return Label;

View file

@ -316,6 +316,7 @@ export interface ChartSeriesDto {
showInLegend: boolean
type?: string
valueField?: string
summaryType?: string
visible: boolean
width: number
label: ChartLabelDto

View file

@ -157,6 +157,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
<Th>Name</Th>
<Th>Argument Field</Th>
<Th>Value Field</Th>
<Th>Summary Type</Th>
<Th>Pane</Th>
<Th>Axis</Th>
</Tr>
@ -207,6 +208,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
<Td>{row.name}</Td>
<Td>{row.argumentField}</Td>
<Td>{row.valueField}</Td>
<Td>{row.summaryType}</Td>
<Td>{row.pane}</Td>
<Td>{row.axis}</Td>
</Tr>
@ -215,11 +217,11 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
</Table>
</Card>
<JsonRowOpDialogSeries
listFormCode={listFormValues.listFormCode!}
isOpen={isJsonRowOpDialogOpen}
setIsOpen={setIsJsonRowOpDialogOpen}
data={jsonRowOpModalData}
setData={setJsonRowOpModalData}
fieldList={fieldList}
/>
</TabContent>
<TabContent value="series_common">

View file

@ -29,6 +29,7 @@ import {
chartSeriesDashStyleOptions,
chartSeriesSelectionModeOptions,
chartSeriesTypeOptions,
columnSummaryTypeListOptions,
} from '../options'
import { ChartPanesDto, ChartSeriesDto, ChartValueAxisDto } from '@/proxy/admin/charts/models'
import { getListFormFields } from '@/services/admin/list-form-field.service'
@ -41,8 +42,9 @@ const schema = object().shape({
ignoreEmptyPoints: boolean().notRequired(),
type: string().notRequired(),
name: string().required('Name Required'),
argumentField: string().notRequired(),
valueField: string().notRequired(),
argumentField: string().required('Argument Field Required'),
valueField: string().required('Value Field Required'),
summaryType: string().required('Summary Type Required'),
axis: string().notRequired(),
pane: string().notRequired(),
dashStyle: string().notRequired(),
@ -68,21 +70,20 @@ const schema = object().shape({
})
function JsonRowOpDialogSeries({
listFormCode,
isOpen,
setIsOpen,
data,
setData,
fieldList,
}: {
listFormCode: string
isOpen: boolean
setIsOpen: Dispatch<SetStateAction<boolean>>
data: JsonRowDialogData | undefined
setData: Dispatch<SetStateAction<JsonRowDialogData | undefined>>
fieldList?: SelectBoxOption[]
}) {
const { translate } = useLocalization()
const { setJsonValue } = useStoreActions((a) => a.admin)
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const handleClose = async (e?: any) => {
if (e) {
@ -117,44 +118,6 @@ function JsonRowOpDialogSeries({
}))
}
const getFields = async () => {
if (!listFormCode) {
return
}
try {
const resp = await getListFormFields({
listFormCode,
sorting: 'ListOrderNo',
maxResultCount: 1000,
})
if (resp.data?.items) {
const fieldNames = groupBy(resp?.data?.items, 'fieldName')
setFieldList(
Object.keys(fieldNames).map((a) => ({
value: a,
label: a,
})),
)
}
} catch (error: any) {
toast.push(
<Notification type="danger" duration={2000}>
Alanlar getirilemedi
{error.toString()}
</Notification>,
{
placement: 'top-end',
},
)
}
}
useEffect(() => {
if (isOpen && data) {
getFields()
}
}, [isOpen, data])
if (!data) {
return null
}
@ -310,7 +273,7 @@ function JsonRowOpDialogSeries({
form={form}
isClearable={true}
options={fieldList}
value={fieldList.find(
value={fieldList?.find(
(option) => option.value === values.argumentField,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
@ -334,7 +297,7 @@ function JsonRowOpDialogSeries({
form={form}
isClearable={true}
options={fieldList}
value={fieldList.find((option) => option.value === values.valueField)}
value={fieldList?.find((option) => option.value === values.valueField)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
menuPlacement="auto"
maxMenuHeight={150}
@ -343,6 +306,38 @@ function JsonRowOpDialogSeries({
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormFieldEdit.PivotSettingSummaryType')}
invalid={
errors.summaryType &&
touched.summaryType
}
errorMessage={errors.summaryType}
>
<Field
type="text"
autoComplete="off"
name="summaryType"
placeholder={translate(
'::ListForms.ListFormFieldEdit.PivotSettingSummaryType',
)}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={columnSummaryTypeListOptions}
value={columnSummaryTypeListOptions.filter(
(option: any) =>
option.value === values.summaryType,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label="Axis"
invalid={errors.axis && touched.axis}

View file

@ -9,6 +9,11 @@ import { Helmet } from 'react-helmet'
import { useParams, useSearchParams } from 'react-router-dom'
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
import { GridDto } from '@/proxy/form/models'
import { usePermission } from '@/utils/hooks/usePermission'
import { Button } from '@/components/ui'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { usePWA } from '@/utils/hooks/usePWA'
import { FaInfoCircle } from 'react-icons/fa'
interface ChartProps extends CommonProps, Meta {
listFormCode: string
@ -22,6 +27,8 @@ interface ChartProps extends CommonProps, Meta {
const Chart = (props: ChartProps) => {
const { listFormCode, filter, isSubForm, level, gridDto } = props
const { translate } = useLocalization()
const { checkPermission } = usePermission()
const isPwaMode = usePWA()
const [searchParams] = useSearchParams()
const [chartOptions, setChartOptions] = useState<any>()
@ -33,10 +40,10 @@ const Chart = (props: ChartProps) => {
useEffect(() => {
if (!gridDto) return
console.log(
gridDto.gridOptions?.seriesDto?.map((s) => `${s.argumentField} asc false`).join(', '),
)
console.log(gridDto.gridOptions?.seriesDto?.map((s) => `${s.valueField} count`).join(', '))
// console.log(
// gridDto.gridOptions?.seriesDto?.map((s) => `${s.argumentField} asc false`).join(', '),
// )
// console.log(gridDto.gridOptions?.seriesDto?.map((s) => `${s.valueField} count`).join(', '))
const dataSource = createSelectDataSource(
gridDto.gridOptions,
@ -59,7 +66,9 @@ const Chart = (props: ChartProps) => {
//theme: s(chartDto.commonDto?.theme, 'generic.light'),
title: gridDto.gridOptions.titleDto,
size: gridDto.gridOptions.sizeDto?.useSize ? gridDto.gridOptions.sizeDto : null,
size: gridDto.gridOptions.sizeDto?.useSize
? { width: gridDto.gridOptions.sizeDto.width, height: gridDto.gridOptions.sizeDto.height }
: { width: '100%', height: window.innerHeight - 210 },
legend: gridDto.gridOptions.legendDto,
margin: gridDto.gridOptions.marginDto,
adaptiveLayout: gridDto.gridOptions.adaptivelayoutDto,
@ -74,13 +83,13 @@ const Chart = (props: ChartProps) => {
valueAxis: gridDto.gridOptions.valueAxisDto,
tooltip: gridDto.gridOptions.tooltipDto,
series:gridDto.gridOptions.seriesDto,
// gridDto.gridOptions.seriesDto?.length > 0
// ? gridDto.gridOptions.seriesDto.map((s) => ({
// argumentField: 'key',
// valueField: 'summary',
// }))
// : undefined,
series: gridDto.gridOptions.seriesDto,
// gridDto.gridOptions.seriesDto?.length > 0
// ? gridDto.gridOptions.seriesDto.map((s) => ({
// argumentField: 'key',
// valueField: 'summary',
// }))
// : undefined,
panes: gridDto.gridOptions.panesDto?.length > 0 ? gridDto.gridOptions.panesDto : undefined,
commonSeriesSettings: gridDto.gridOptions.commonSeriesSettingsDto,
commonPaneSettings: gridDto.gridOptions.commonPaneSettingsDto,
@ -106,7 +115,32 @@ const Chart = (props: ChartProps) => {
></Helmet>
)}
{_listFormCode && chartOptions && (
<DxChart key={'DxChart' + _listFormCode} {...chartOptions}></DxChart>
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 ">
<div className="flex justify-end items-center">
<div className="relative pb-1 flex gap-1 border-b-1">
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
<Button
size="xs"
variant={'default'}
className="text-sm"
onClick={() => {
window.open(
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
':listFormCode',
listFormCode,
),
isPwaMode ? '_self' : '_blank',
)
}}
title="Form Manager"
>
<FaInfoCircle className="w-3 h-3" />
</Button>
)}
</div>
</div>
<DxChart key={'DxChart' + _listFormCode} {...chartOptions}></DxChart>
</div>
)}
</Container>
)

View file

@ -8,7 +8,7 @@ import classNames from 'classnames'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { GridDto } from '@/proxy/form/models'
import Card from './Card'
import { Button } from '@/components/ui'
import { Badge, Button } from '@/components/ui'
import Pivot from './Pivot'
import { getList } from '@/services/form.service'
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
@ -73,6 +73,8 @@ const List = () => {
<h4 className="text-slate-700 text-sm font-medium leading-none">
{translate('::' + gridDto?.gridOptions?.title) || ''}
</h4>
<Badge content={viewMode} />
</div>
{gridDto?.gridOptions?.description === gridDto?.gridOptions?.title ? (
@ -111,7 +113,7 @@ const List = () => {
<FaTh className="w-4 h-4" />
</Button>
)}
{gridDto?.gridOptions?.layoutDto.pivot && (
<Button
size="xs"